flutter-仿微信项目实战一(tabbar、pubpec.yaml)

前言

之前弄了不少flutter的内容,这里直接小小实战一下,就编写微信的 tabbar 上面的前四个页面来锻炼一下我们的实战能力

---- 仿微信源码地址

另外看看效果(没细搞):

1649747576667.png

MaterialApp

跟其他大多数应用一样,我们的开发都是从main函数开始的,这里我们采用 MaterialApp风格作为我们基本组件(至少目前没用过其他组件),这里面包含了我们的 Router导航等

void main() {
  runApp(const App());
}

//由于没有涉及到状态的变更,一次使用 StatelessWidget 即可
class App extends StatelessWidget {
  const App({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    //MaterialApp代表我们主题纸墨风格框架,我们一般开发都用这个
    return MaterialApp(
      //去掉debug自选
      debugShowCheckedModeBanner: false,
      //Android任务管理器界面title,可以设置称自己的app名字
      title: "Flutter Demo",
      //设置我么你的颜色等
      theme: ThemeData(
        scaffoldBackgroundColor: Colors.white,
        brightness: Brightness.light,
        //设置一些card组件的背景颜色,例如一些弹窗组件的背景颜色
        cardColor: const Color.fromRGBO(0x33, 0x33, 0x33, 0.8),
      ),
      //这里就是我们的默认主页了
      home: const HomePage()
    );
  }
}
复制代码

Tabbar的HomePage

HomePage 是我们编写的 Tabbar的一个界面,其控制聊天(chat)、联系人(contact)、发现(discover)、我的(mine),其他几个页面默认使用空组件占位即可,等待后续编写

另外,每开始一个新界面都需要使用Scaffold组件进行包括,其包含着 appbarbottombar的设置,以便于我们后续开发(当然单纯封装的UI小组件不需要)

另外 Tabar组件,我们使用系统的 BottomNavigationBar 还远远不够,我们使用了PageView持有了其他四个页面的变量,而(在后面讲解为什么不是像ios一样放了4个UI组件在一个数组)

然后通过 PageController控制实际显示界面,此时 BottomNavigationBar单纯设置 bar 的UI效果,PageViewPageController联动,则负责跳转功能

//编写时我们继承自StatefulWidget,因为内部会更新状态
class HomePage extends StatefulWidget {
  const HomePage({Key? key}) : super(key: key);

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  //初始化pagecontroller,用来控制page页面
  final _controller = PageController(
    initialPage: 0
  );
  //声明到这里,可以默认保存,避免内次切换都要重新初始化,如果想重新初始化,可以特殊处理
  int _pageIndex = 0;
  
  @override
  Widget build(BuildContext context) {
    //每开始一个新界面都需要使用Scaffold进行包括,其包含着 appbar和bottombar的设置
    return Scaffold(
      //这是一个 Widget 类型,可以自定义 tabbar,这里使用系统的来测试
      bottomNavigationBar: BottomNavigationBar(
        //设置当前的index
        currentIndex: _pageIndex,
        //点击后可以用来 index 的选中效果,通过更新页面跳转
        onTap: (int index) {
          setState(() {
            _pageIndex = index;
          });
          //除了更新bottombar图标,还要更新显示哪个页面
          _controller.jumpToPage(index);
        },
        //设置了默认会显示字体,否则只有选中的才显示字体
        unselectedItemColor: Colors.black,
        selectedItemColor: Colors.green,
        //设置为混合类型,默认未选中只显示一个icon图片
        type: BottomNavigationBarType.fixed,
        selectedFontSize: 12,
        unselectedFontSize: 12,
        //设置里面组件
        items: <BottomNavigationBarItem>[
          BottomNavigationBarItem(
              label: "聊天",
              icon: Image.asset('images/tabbar_chat.png',
                  width: 20,
                  height: 20
              ),
              activeIcon: Image.asset('images/tabbar_chat_hl.png',
                  width: 20,
                  height: 20
              )
          ),
          BottomNavigationBarItem(
              label: "联系人",
              icon: Image.asset('images/tabbar_contact.png',
                  width: 20,
                  height: 20
              ),
              activeIcon: Image.asset('images/tabbar_contact_hl.png',
                  width: 20,
                  height: 20
              )
          ),
          BottomNavigationBarItem(
              label: "发现",
              icon: Image.asset('images/tabbar_discover.png',
                  width: 20,
                  height: 20
              ),
              activeIcon: Image.asset('images/tabbar_discover_hl.png',
                  width: 20,
                  height: 20
              )
          ),
          BottomNavigationBarItem(
            label: "我的",
              icon: Image.asset('images/tabbar_mine.png',
                  width: 20,
                  height: 20
              ),
              activeIcon: Image.asset('images/tabbar_mine_hl.png',
                  width: 20,
                  height: 20
              )
          )
        ],
      ),
      body: PageView(
        controller: _controller,
        //不设置默认可以左右活动,如果不想左右滑动如下设置,可以根据ios或者android来设置
        // physics: const NeverScrollableScrollPhysics(),
        //界面切换后的回调,主要是针对android左右滑动回调,此时与bottombar无关了
        onPageChanged: (int index) {
          setState(() {
            _pageIndex = index;
          });
        },
        //设置我们要切换的页面,放到一个数组
        children: const [
          ChatList(),
          Contact(),
          Discover(),
          Mine()
        ],
      ),
    );
  }
}
复制代码

tabbar的问题点

错误示范

看了相面估计有疑问,我试了一下,将四个页面放到一个数组中,然后直接根据index切换body的实际页面也可以呀,如下所示,我第一次也这么写的(这里是错误示范)

//错误示范,但看起来效果也是一样
final List _pageList = [ChatList(), Contact(), Discover(), Mine()];

body: _pageList[_pageIndex]
复制代码

问题

问题一

我们声明的组件默认在build中有一个基本组件的声明,这是我们声明的组件,我们正常可以通过变量来控制某个界面的显示和隐藏,于此同时也控制着一些组件的创建和销毁

因此,当我们的组件挂载到 body中时,也就意味着每次都切换组件,那么被切换的组件就会释放,而我们 _pageList 存放的只是没有状态未渲染的widget小组件,跟我们直接放一个Text一样,每一次切换会重新创建当前组件和渲染,并且强制释放上一个组件的内容,因此其状态无法保存

问题二

然后可能会尝试,发现使用了 PageView,为什么 initState 和 build也会重走呢,这就涉及到了 flutter 的渲染机制,其默认只会渲染当前一屏的内容,且不会保存组件的默认状态,一旦切换其他页面,需要重新初始状态,但有一点该组件并没有释放,我们的组件一直在 PageView中持有,因此没有释放

系统给我们提供了一个 maxinAutomaticKeepAliveClientMixin,我们可以采用多继承的方式,继承自它,那么这个状态就会被保存,就不需要重新渲染后

例如: chat组件,当我们多继承(with它) AutomaticKeepAliveClientMixin,需要重写他的 wantKeepAlive 属性,设置为 true,然后在 build 中 调用一下 super.build即可

后面章节都会有代码实例,介绍 AutomaticKeepAliveClientMixin 的使用

pubpec.yaml

这个文件包含了我们的的 sdk版本号、三方仓库、图片资源名称等

//平时用不到,当迁移文件或者改名,记得改一下
name: flutter_wechat_demo
description: 一个仿微信的实战测试demo

//环境sdk版本,一般默认的即可,如果几台电脑不一样,可以根据情况设置最低版本
environment:
  sdk: ">=2.16.1"

//三方依赖,一般使用 flutter pub get + 三方库 方式导入
//在这里导入,需要点击右上角 Pub get更新
dependencies:
  flutter:
    sdk: flutter

  http: ^0.13.4

//测试版本依赖
dev_dependencies:
  flutter_test:
    sdk: flutter

  flutter_lints: ^1.0.0

//图片资源库地址,图片仓库名字一般与我们ios、android仓库同级
//放入图片后,只需要右键复制路径,粘到这里即可
flutter:
  uses-material-design: true

  assets:
   - images/tabbar_chat.png
   - images/tabbar_chat_hl.png
   - images/tabbar_contact.png
复制代码

猜你喜欢

转载自juejin.im/post/7087422347619074085