flutter-Imitation WeChat project combat one (tabbar, pubpec.yaml)

foreword

I have done a lot flutterof content before, here is a little actual combat, and we will write the first four pages tabbaron to exercise our actual combat ability.

---- Imitate WeChat source address

Also look at the effect (not detailed):

1649747576667.png

MaterialApp

Like most other applications, our development mainstarts with functions, here we use MaterialAppstyle as our basic component (at least no other components have been used so far), which contains our Routernavigation, etc.

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's HomePage

HomePage is an interface of the Tabbar we wrote, which controls chat (chat), contact (contact), discovery (discover), mine (mine), and other pages can use empty components by default to occupy the place, waiting for subsequent writing

In addition, each new interface needs to Scaffoldbe included using components, which contain appbarand bottombarsettings for our subsequent development (of course, simple encapsulated UI widgets are not required)

In addition, the Tabarcomponents we use the system BottomNavigationBarare far from enough, we use PageViewvariables that hold the other four pages, and (in the following, we will explain why we don't iosput 4 UI components in an array like the same)

Then through the PageControllercontrol of the actual display interface, theBottomNavigationBar UI effect of the simple setting at this time, and the linkage , are responsible for the jump functionbarPageViewPageController

//编写时我们继承自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()
        ],
      ),
    );
  }
}
复制代码

Problems with tabbars

Error demonstration

I have some doubts after reading the face, I tried it, put the four pages into an array, and then directly according indexto the actual page to switch body, as shown below, I wrote it for the first time ( 这里是错误示范)

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

body: _pageList[_pageIndex]
复制代码

question

问题一

The components we declare have a basic component declaration by default build. This is the component we declare. We can normally control a certain interface through variables 显示和隐藏, and at the same time control some components.创建和销毁

Therefore, when our component is mounted bodyin , it means that the component is switched every time, then the switched component will be released, and what we _pageListstore is only the unrendered unrendered state, just widget小组件like we put a Text directly, Each toggle recreates the current component and rendering, and forces the content of the previous component to be released, so its state cannot be saved

问题二

Then you may try and find that if you use it PageView, why initState and buildwill be replayed? This involves flutterthe rendering mechanism of , which will only render the content of the current screen by default, and will not save the default state of the component. Once you switch to other pages , the initial state needs to be re-initialized, but at one point the component is not released, our component has been held PageViewin , so it is not released

The system provides us with a maxinclass AutomaticKeepAliveClientMixin, we can use multiple inheritance, inherit from it, then this state will be saved, no need to re-render

For example: chatcomponent, when we inherit multiple ( withit) AutomaticKeepAliveClientMixin, we need to rewrite his wantKeepAliveproperty , set it to true, and then call it buildinsuper.build

There will be code examples in the following chapters to introduce AutomaticKeepAliveClientMixinthe use of

pubpec.yaml

This file contains our sdk version number, third-party warehouse, image resource name, etc.

//平时用不到,当迁移文件或者改名,记得改一下
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
复制代码

Guess you like

Origin juejin.im/post/7087422347619074085