基于 Flutter 3.x 实战跨平台混合开发吾爱

693 阅读4分钟

基于 Flutter 3.x 实战跨平台混合开发吾爱下——栽

下——栽の地 止: 基于 Flutter 3.x 实战跨平台混合开发

Flutter 3.x新特性

令人兴奋的更新包括对 macOS 和 Linux 的更新 Flutter 支持、显着的性能改进、针对移动设备和 Web 的更新以及许多其他功能!此外,我们还带来了减少对旧版本 Windows 的支持以及几项重大更改的消息。让我们直奔主题。

准备好用于生产的完整桌面平台 对 Linux 和 macOS 平台的支持已达到稳定状态,具有以下功能:

级联菜单和 macOS 系统菜单栏支持 您现在可以使用 PlatformMenuBar 小部件在 macOS 上创建平台呈现的菜单栏、插入仅平台菜单并控制在 macOS 应用程序菜单中显示的内容。

完全支持全桌面平台多国文本输入 所有三个桌面平台都完全支持多种文本输入,包括使用文本输入法编辑器 (IME) 的语言,例如中文、日文和韩文。它还支持第三方输入法,例如搜狗和谷歌日语输入法。

全桌面平台无障碍服务 Flutter 支持 Windows、macOS 和 Linux 平台的无障碍服务,包括屏幕文本阅读、无摩擦导航和颜色反转。

macOS 平台默认使用通用二进制文件 在 Flutter 3 中,Flutter macOS 桌面应用程序将构建为通用二进制文件,以原生支持使用 Intel 处理器的 Mac 计算机和由 Apple Silicon 提供支持的新设备。

不再支持使用 Windows 7/8 进行开发 此版本将建议的 Windows 开发版本提升到 Windows 10。虽然我们不会禁止使用旧版本(Windows 7、Windows 8、Windows 8.1)进行开发,但我们只会对这些版本提供有限的测试,因为 Microsoft 不再支持它们。虽然我们尽最大努力支持旧版本,但我们建议您升级。

注意:Flutter 应用程序仍然可以在 Windows 7 和 8 上运行。此更改仅影响我们推荐的开发环境

Flutter入门与实战:构建一个常用的页面框架

图标准备 本次例程需要4个图标,2种颜色,可以从 iconfont 中找到自己需要的图标下载不同的颜色使用。然后在 pubspec.yaml 中的 assets 指定素材所在目录。需要注意的是如果是 png 文件直接指定整个目录即可,但如果是 jpg 格式,则需要同时指定文件名及后缀。

BottomNavigationBar 简介
BottomNavigationBar的构造函数如下:
BottomNavigationBar({
    Key? key,
    required this.items,
    this.onTap,
    this.currentIndex = 0,
    this.elevation,
    this.type,
    Color? fixedColor,
    this.backgroundColor,
    this.iconSize = 24.0,
    Color? selectedItemColor,
    this.unselectedItemColor,
    this.selectedIconTheme,
    this.unselectedIconTheme,
    this.selectedFontSize = 14.0,
    this.unselectedFontSize = 12.0,
    this.selectedLabelStyle,
    this.unselectedLabelStyle,
    this.showSelectedLabels,
    this.showUnselectedLabels,
    this.mouseCursor,
  })

其中常用的属性为:

items:及对应的页面组件数组 currentIndex:默认显示第几个页面 type:组件类型,使用BottomNavigationBarType枚举,有 fixed 和 shifting 两种。fixed 是图标固定位置,而 shifting 的图标点击后会有一个漂移效果,可以实际试一下,一般用fixed 比较多。 onTap:点击后的事件,一般用这个更新状态数据,以便更新页面。

其他属性用于控制样式的,可以根据实际需要设置图标大小,主题色,字体等参数。 构建项目页面结构 首先,新建四个业务页面,分别是 dynamic.dart,message.dart,category.dart 和 mine.dart,分别对应动态、消息、分类浏览和个人中心四个页面。目前这四个页面很简单,只是在页面中间依次显示“岛上码农”四个字。代码都是类似的,以 dynamic 为例:

import 'package:flutter/material.dart';

class DynamicPage extends StatelessWidget {
  const DynamicPage({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Text('岛'),
      ),
    );
  }
}

注意的是这里的 Scaffold 没有 AppBar 了,这是因为在首页已经有了,如果再有 AppBar 就会出现两个。 其次,新建首页,用于管理四个业务页面,命名为 app.dart。app.dart 使用了 BottomNavigationBar 管理四个业务页面的切换。

import 'package:flutter/material.dart';
import 'dynamic.dart';
import 'message.dart';
import 'category.dart';
import 'mine.dart';

class AppHomePage extends StatefulWidget {
  AppHomePage({Key key}) : super(key: key);

  @override
  _AppHomePageState createState() => _AppHomePageState();
}

class _AppHomePageState extends State<AppHomePage> {
  int _index = 0;

  List<Widget> _homeWidgets = [
    DynamicPage(),
    MessagePage(),
    CategoryPage(),
    MinePage(),
  ];

  void _onBottomNagigationBarTapped(index) {
    setState(() {
      _index = index;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('岛上码农'),
      ),
      body: IndexedStack(
        index: _index,
        children: _homeWidgets,
      ),
      bottomNavigationBar: BottomNavigationBar(
        type: BottomNavigationBarType.fixed,
        currentIndex: _index,
        onTap: _onBottomNagigationBarTapped,
        items: [
          _getBottomNavItem(
              '动态', 'images/dynamic.png', 'images/dynamic-hover.png', 0),
          _getBottomNavItem(
              ' 消息', 'images/message.png', 'images/message-hover.png', 1),
          _getBottomNavItem(
              '分类浏览', 'images/category.png', 'images/category-hover.png', 2),
          _getBottomNavItem(
              '个人中心', 'images/mine.png', 'images/mine-hover.png', 3),
        ],
      ),
    );
  }

  BottomNavigationBarItem _getBottomNavItem(
      String title, String normalIcon, String pressedIcon, int index) {
    return BottomNavigationBarItem(
      icon: _index == index
          ? Image.asset(
              pressedIcon,
              width: 32,
              height: 28,
            )
          : Image.asset(
              normalIcon,
              width: 32,
              height: 28,
            ),
      label: title,
    );
  }
}

这里关键的地方有两个,一是使用的 IndexedStack,这是一个管理页面显示层级的容器。使用 index 属性确定当前容器里那个页面在最顶上,容器里的页面通过 children 属性设置,要求是一个 Widget 数组。因此,逻辑就是当 BottomNavigationBar 中的图标被点击后,对应点击事件会回调 onTap属性指定的方法,将当前的点击索引值传递回调函数,因此可以利用这个方式控制 IndexedStack 的页面层级切换。 最后,使用了状态变量_index 存储IndexedStatck当前显示页面的索引值,然后当 BottomNavigationBar的图标点击事件发生后,在回调函数中使用 setState 更新状态变量_index 来刷新当前界面。