Flutter开发

Flutter状态管理

1.UI布局

渲染逻辑是不可变的。管理状态的State的对象是。State。UI界面和状态管理不在一起。


import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

class CountButtonPage extends StatefulWidget  {


  /// 构造方法传入 页面的标题
  const CountButtonPage({super.key,required this.title});

  ///  页面的标题
  final String title;

  @override
  State<CountButtonPage> createState() => _CountButtonPage();

}

// 下划线 内部使用 私有的 状态管理者
class _CountButtonPage extends State<CountButtonPage> {
  int _counter = 0;

  void _incrementCounter() {
    // 重新设置下状态 相当于reload
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {

    return Scaffold(
      appBar: AppBar(

        backgroundColor: Colors.blueAccent,

        title: Text(widget.title),
      ),
      body: Center(

        child: Column(

          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headlineMedium,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

所有的都在State里面管理,而且会保留count。

增量渲染 树状结构 。

构造方法的key是用来唯一定位的。

2. 状态管理

项目搭建

	// 项目的搭建 
/*  顶部nav  底部的tab  */
import 'package:flutter/material.dart';
import 'package:wechat/pages/chat_page.dart';
import 'package:wechat/pages/discover/discover_page.dart';
import 'package:wechat/pages/friends_page.dart';
import 'package:wechat/pages/mine_page.dart';

class RootPage extends StatefulWidget {
  @override
  _RootPageState createState() => _RootPageState();
}

class _RootPageState extends State<RootPage> {
  int _currentIndex = 2;
  List<Widget> _pages = [ChatPage(), FriendsPage(), DiscoverPage(), MinePage()];
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: _pages[_currentIndex],
      bottomNavigationBar: BottomNavigationBar(
        onTap: (index) {
          setState(() {
            _currentIndex = index;
          });
        },
        selectedFontSize: 12.0,
        currentIndex: _currentIndex,
        fixedColor: Colors.green,
        type: BottomNavigationBarType.fixed,
        items: [
          BottomNavigationBarItem(
            icon: Image.asset(
              'images/tabbar_chat.png',
              height: 20,
              width: 20,
            ),
            activeIcon: Image.asset(
              'images/tabbar_chat_hl.png',
              height: 20,
              width: 20,
            ),
            title: Text('微信'),
          ),
          BottomNavigationBarItem(
              icon: Icon(Icons.bookmark), title: Text('通讯录')),
          BottomNavigationBarItem(icon: Icon(Icons.history), title: Text('发现')),
          BottomNavigationBarItem(
              icon: Icon(Icons.person_outline), title: Text('我')),
        ],

        
        

想一个问题,StatefulWidget的状态应该被谁管理?

Widget本身?

父 Widget ?

都会?

还是另外的一个对象?

答案是取决于实际情况。常见的方法。

如何决定使用哪种管理方法?下面是官方给出的一些原则可以帮助你做决定:


 

//------------------------ ParentWidget --------------------------------

class ParentWidget extends StatefulWidget {
  const ParentWidget({super.key});

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

class _ParentWidgetState extends State<ParentWidget> {
  bool _active = false;

  /// 点击按钮 传入一个状态给子Widget 然后变化页面效果 虽然子Widget是无状态的但是通过父Widget可以管理他
  void _handleTapboxChanged(bool newValue) {
    setState(() {
      _active = newValue;
    });
  }

  @override
  Widget build(BuildContext context) {
    return TapboxB(
      active: _active,
      onChanged: _handleTapboxChanged,
    );
  }
}

//------------------------- TapboxB ----------------------------------

class TapboxB extends StatelessWidget {
  const TapboxB({super.key, this.active = false, required this.onChanged});

  final bool active;
  final ValueChanged<bool> onChanged;

  void _handleTap() {
    onChanged(!active);
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: _handleTap,
      child: Container(
        width: 200.0,
        height: 200.0,
        decoration: BoxDecoration(
          color: active ? Colors.lightGreen[700] : Colors.grey[600],
        ),
        child: Center(
          child: Text(
            active ? 'Active' : 'Inactive',
            style: const TextStyle(fontSize: 32.0, color: Colors.white),
          ),
        ),

      ),
    );
  }
}



上面的代码,父视图是有状态的Widget但是子Widget是无状态的。直接使用传值去管理无状态的Widget。具体的情况下具体的分析该谁来管理状态。

混合状态的管理,一些组件自己管理一些状态,父控件管理一些状态。

在下面 TapboxC 示例中,手指按下时,盒子的周围会出现一个深绿色的边框,抬起时,边框消失。点击完成后,盒子的颜色改变。 TapboxC 将其_active状态导出到其父组件中,但在内部管理其_highlight状态。这个例子有两个状态对象_ParentWidgetState_TapboxCState

_ParentWidgetStateC类:

_TapboxCState 对象:




//---------------------------- ParentWidget ----------------------------

class ParentWidgetC extends StatefulWidget {
  const ParentWidgetC({super.key});

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

class _ParentWidgetCState extends State<ParentWidgetC> {
  bool _active = false;

  void _handleTapboxChanged(bool newValue) {
    setState(() {
      _active = newValue;

    });
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      child: TapboxC(
        active: _active,
        //  此处回调 拿到子Widget的传递的状态值
        onChanged: _handleTapboxChanged,
      ),
    );
  }
}

//----------------------------- TapboxC ------------------------------

class TapboxC extends StatefulWidget {
  const TapboxC({Key? key, this.active =  false, required this.onChanged})
      : super(key: key);

  final bool active;
  final ValueChanged<bool> onChanged;

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

class _TapboxCState extends State<TapboxC> {
  bool _highlight = false;

  void _handleTapDown(TapDownDetails details) {
    setState(() {
      _highlight = true;
    });
  }

  void _handleTapUp(TapUpDetails details) {
    setState(() {
      _highlight = false;
    });
  }

  void _handleTapCancel() {
    setState(() {
      _highlight = false;
    });
  }

  void _handleTap() {
    widget.onChanged(!widget.active);
  }

  @override
  Widget build(BuildContext context) {
    // 在按下时添加绿色边框,当抬起时,取消高亮
    return GestureDetector(
      onTapDown: _handleTapDown, // 处理按下事件
      onTapUp: _handleTapUp, // 处理抬起事件
      onTap: _handleTap,
      onTapCancel: _handleTapCancel,
      child: Container(
        width: 200.0,
        height: 200.0,
        decoration: BoxDecoration(
          color: widget.active ? Colors.lightGreen[700] : Colors.grey[600],
          border: _highlight
              ? Border.all(
            color: Colors.teal[700]!,
            width: 10.0,
          )
              : null,
        ),
        child: Center(
          child: Text(
            widget.active ? 'Active' : 'Inactive',
            style: const TextStyle(fontSize: 32.0, color: Colors.white),
          ),
        ),
      ),
    );
  }
}

TapboxC本身就有状态 管理他的边框的颜色的。还传递出去一个状态给父Widget。是混合管理的例子。