阅读 167

Flutter —— 状态管理和仿微信项目搭建

1. 状态管理

状态是一个概念。在iOS中,任何控件都有一些响应,响应后都会改变样式。在flutter中只要部件有变化,就需要改变状态。在flutter中是增量渲染,如果属性发生则会重新构建Widget树,即重新创建新的 Widget 实例来替换旧的 Widget 实例,所以允许 Widget 的属性变化是没有意义的,因为一旦 Widget 自己的属性变了自己就会被替换。这也是为什么 Widget 中定义的属性必须是 final 的原因。Flutter中页面逻辑和数据逻辑是分开的,它会保留数据,替换页面。Flutter设置了一个保留数据逻辑的widget就是StatefulWidget,StatefulWidget里面封装了数据逻辑和页面逻辑。

创建一个StatelessWidget,在点击的时候进行count++。

class StateManagerDemo extends StatelessWidget {
  //const StateManagerDemo({Key? key}) : super(key: key);

  int count = 0;

  @override
  Widget build(BuildContext context) {
    return
      Scaffold(
        backgroundColor: Colors.grey[100],
        appBar: AppBar(
          title: const Text("Layout Demo"),
        ),
        body:  Center(
          child: Chip(label:Text("$count"),),
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () {
            count++;
            print("$count");
          },
          child: const Icon(Icons.add),
        ),
      );

  }
}复制代码

运行后发现count发生改变,但是ui没有变化。

在这里插入图片描述

这个时候就需要使用StatefulWidget了。

class StateManagerDemo extends StatefulWidget {
  const StateManagerDemo({Key? key}) : super(key: key);

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

class _StateManagerDemoState extends State<StateManagerDemo> {
  int count = 0;
  @override
  Widget build(BuildContext context) {
    return   Scaffold(
      backgroundColor: Colors.grey[100],
      appBar: AppBar(
        title: const Text("Layout Demo"),
      ),
      body:  Center(
        child: Chip(label:Text("$count"),),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          count++;
          print("$count");
        },
        child: const Icon(Icons.add),
      ),
    );
  }
}复制代码

这个时候点击后还是没有变化,但是在热重载之后,中间的数字就变了,说明数据还是被保留了下来。因为这里还需要在走一遍build方法才能变化,所以需要把count++放在setState里面,这样页面就会跟着变化了,因为调用setState就会重新build一次,build里面还是增量渲染。

  onPressed: () {
          setState(() {
            count++;

          });
          print("$count");
        },复制代码

_StateManagerDemoState类是私有的类,外界无法访问状态管理者,_StateManagerDemoState不能直接接受数据。StateManagerDemo里面则是有对外暴露的所有接口。_StateManagerDemoState可以访问到StateManagerDemo里面的数据然后进行保留。也就是说,数据的管理在_StateManagerDemoState里面。

2. 项目搭建

2.1 底部导航栏

创建一个新工程。将MyHomePage改成下面的结构。

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

  @override
  Widget build(BuildContext context) {
    return Container(
      
    );
  }
}复制代码

将MyHomePage返回的Widget改成Scaffold,并且添加bottomNavigationBar。

 return Scaffold(
      bottomNavigationBar: BottomNavigationBar(
        type:   BottomNavigationBarType.fixed,
        fixedColor: Colors.green,
        items: const [
          BottomNavigationBarItem(icon: Icon(Icons.chat), label: "微信"),
          BottomNavigationBarItem(icon: Icon(Icons.bookmark), label: "通讯录"),
          BottomNavigationBarItem(icon: Icon(Icons.history), label: "发现"),
          BottomNavigationBarItem(icon: Icon(Icons.person), label: "我"),
        ],
      ),
    );复制代码

接下来要切换选中的item,那么就需要保存数据,那么MyHomePage就要变成StatefulWidget,并且在BottomNavigationBar里面的onTap调用setState修改_currentIndex。

class MyHomePage extends StatefulWidget {
 const MyHomePage({Key? key}) : super(key: key);

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

class _MyHomePageState extends State<MyHomePage> {
 int _currentIndex = 0;

 @override
 Widget build(BuildContext context) {
   return Scaffold(
     bottomNavigationBar: BottomNavigationBar(
       type:   BottomNavigationBarType.fixed,
       currentIndex: _currentIndex,
       fixedColor: Colors.green,
       items: const [
         BottomNavigationBarItem(icon: Icon(Icons.chat), label: "微信"),
         BottomNavigationBarItem(icon: Icon(Icons.bookmark), label: "通讯录"),
         BottomNavigationBarItem(icon: Icon(Icons.history), label: "发现"),
         BottomNavigationBarItem(icon: Icon(Icons.person), label: "我"),
       ],
       onTap: (index){
         setState(() {
           _currentIndex = index;
         });
       },
     ),
   );
 }
}复制代码

接下来创建四个界面,这里先都设置为StatefulWidget。但是平时开发一般整个页面是StatelessWidget的,只有在需要改变的页面才设置为StatefulWidget。然后一家一个包含四个页面的List,在Scaffold中的body使用位置为currentIndex 的页面。

class _MyHomePageState extends State<MyHomePage> {
  int _currentIndex = 0;
  List<Widget> _pages = [ChatPage(),FriendsPage(),DiscoverPage(),MinePage()];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: _pages[_currentIndex],
      bottomNavigationBar: BottomNavigationBar(
        type:   BottomNavigationBarType.fixed,
        currentIndex: _currentIndex,
        fixedColor: Colors.green,
        items: const [
          BottomNavigationBarItem(icon: Icon(Icons.chat), label: "微信"),
          BottomNavigationBarItem(icon: Icon(Icons.bookmark), label: "通讯录"),
          BottomNavigationBarItem(icon: Icon(Icons.history), label: "发现"),
          BottomNavigationBarItem(icon: Icon(Icons.person), label: "我"),
        ],
        onTap: (index){
          setState(() {
            _currentIndex = index;
          });
        },
      ),
    );
  }
}复制代码

这时候点击的话,就可以切换页面了。

在这里插入图片描述

看到上面点击切换的时候,会有动画,我们不需要这个动画,那么可以在MaterialApp把其去掉。在MaterialApp中的ThemeData修改highlightColor和splashColor,这样动画就消失了。可以修改primarySwatch来修改主题色。

 return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        highlightColor: const Color.fromRGBO(1, 0, 0, 0.0),
        splashColor:  const Color.fromRGBO(1, 0, 0, 0.0),
        primarySwatch: Colors.green,
      ),
      home: const MyHomePage(),
    );
  }复制代码

这里还有一个字体变大的动画,那么可以在BottomNavigationBar修改selectedFontSize。

 selectedFontSize: 12,复制代码

2.2 程序的名字以及图标

来到android——app——src——main的AndroidManifest.xml。这里可以修改程序的名字以及图标。

  android:label="哈喽哈喽"复制代码

要使用图标的话就要先导入图片。点开上面的res,然后看到这里有,hdpi(相当于iOS的1x),mdpi(相当于iOS的1.5x),xhdpi(相当于iOS的2x),xxhdpi(相当于iOS的3x),xxxhdpi(相当于iOS的4x)。将图片复制到对应的文件夹,命名不能是驼峰以及包含中文。

android:icon="@mipmap/app_icon">复制代码

在这里插入图片描述

启动图片在drawable以及drawable-v21里面配置。

  <item>
        <bitmap
            android:gravity="center"
            android:src="@mipmap/launch_image" />
    </item>复制代码

2.3 Assets

Flutter APP 安装包中会包含代码和 assets(资源)两部分。Assets 是会打包到程序安装包中的,可在运行时访问。常见类型的 assets 包括静态数据(例如JSON文件)、配置文件、图标和图片等。

这里添加一个Images文件夹,然后在images文件夹里面放图片。

在这里插入图片描述

Flutter 使用pubspec.yaml 文件来管理应用程序所需的资源,包的管理也是在pubspec.yaml 文件中的。在文件中添加引用,这里的格式非常重要,多一个少一个空格都不行。

在这里插入图片描述

接下来就可以去 BottomNavigationBar将icon修改成自己的图片,这里需要设置activeIcon来区分选中和未选中状态。

 BottomNavigationBarItem(icon: Image(image: AssetImage("images/tabbar_chat.png"),height: 20,width: 20,),activeIcon: Image(image: AssetImage("images/tabbar_chat_hl.png"),height: 20,width: 20,), label: "微信"),
BottomNavigationBarItem(icon: Image(image: AssetImage("images/tabbar_friends.png"),height: 20,width: 20,),activeIcon: Image(image: AssetImage("images/tabbar_friends_hl.png"),height: 20,width: 20,), label: "通讯录"),
BottomNavigationBarItem(icon: Image(image: AssetImage("images/tabbar_discover.png"),height: 20,width: 20,),activeIcon: Image(image: AssetImage("images/tabbar_discover_hl.png"),height: 20,width: 20,), label: "发现"),
BottomNavigationBarItem(icon: Image(image: AssetImage("images/tabbar_mine.png"),height: 20,width: 20,), activeIcon: Image(image: AssetImage("images/tabbar_mine_hl.png"),height: 20,width: 20,),label: "我"),复制代码

3. 总结

  • Flutter的状态管理

    • 继承StatefulWidget,用于对外提供接口

    • 继承State用来管理状态

    • 实现createState方法方法

    • 实现build方法。访问数据,数据在state里面

    • 通过setState设置/改变数据

    • StatelessWidget 无状态小部件

    • StatefulWidget 有状态小部件


作者:大林晓鹿
链接:https://juejin.cn/post/7028743728000925704


文章分类
代码人生
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐