📖 前言

StatefulWidgetStatelessWidget 是 Flutter 中所有组件的基类,它们是 Flutter 框架的核心概念。理解这两个组件的区别和使用场景,是掌握 Flutter 开发的基础。本教程将带你深入了解 StatefulWidgetStatelessWidget 的各种用法和生命周期。


🎯 什么是 StatefulWidget 和 StatelessWidget?

StatelessWidget(无状态组件)

StatelessWidget 是不可变的组件,一旦创建后,其属性就不会改变。它适用于展示静态内容,不需要维护状态。

StatefulWidget(有状态组件)

StatefulWidget 是可变的组件,可以在运行时改变其状态。它适用于需要响应用户交互、数据变化或动画的场景。

基本语法

// StatelessWidget
class MyStatelessWidget extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return Text('Hello, World!');
  }
}

// StatefulWidget
class MyStatefulWidget extends StatefulWidget {
  
  State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}

class _MyStatefulWidgetState extends State<MyStatefulWidget> {
  
  Widget build(BuildContext context) {
    return Text('Hello, World!');
  }
}

🚀 StatelessWidget 基础用法

1. 最简单的 StatelessWidget

class SimpleStatelessWidget extends StatelessWidget {
  const SimpleStatelessWidget({super.key});

  
  Widget build(BuildContext context) {
    return Text('Hello, StatelessWidget!');
  }
}

这是最基础的用法,直接继承 StatelessWidget 并实现 build 方法。

image-20260201203930849

2. 带参数的 StatelessWidget

class GreetingWidget extends StatelessWidget {
  final String name;
  
  const GreetingWidget({
    super.key,
    required this.name,
  });

  
  Widget build(BuildContext context) {
    return Text('Hello, $name!');
  }
}

通过构造函数传递参数,使组件更加灵活。

image-20260201203959597

3. 组合多个子组件的 StatelessWidget

class CardWidget extends StatelessWidget {
  final String title;
  final String content;
  
  const CardWidget({
    super.key,
    required this.title,
    required this.content,
  });

  
  Widget build(BuildContext context) {
    return Container(
      padding: EdgeInsets.all(16),
      decoration: BoxDecoration(
        color: Colors.white,
        borderRadius: BorderRadius.circular(8),
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(title, style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
          SizedBox(height: 8),
          Text(content),
        ],
      ),
    );
  }
}

image-20260201204025971


🔄 StatefulWidget 基础用法

1. 最简单的 StatefulWidget

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

  
  State<SimpleStatefulWidget> createState() => _SimpleStatefulWidgetState();
}

class _SimpleStatefulWidgetState extends State<SimpleStatefulWidget> {
  
  Widget build(BuildContext context) {
    return Text('Hello, StatefulWidget!');
  }
}

image-20260201204056202

2. 带状态的 StatefulWidget

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

  
  State<CounterWidget> createState() => _CounterWidgetState();
}

class _CounterWidgetState extends State<CounterWidget> {
  int _count = 0;

  void _increment() {
    setState(() {
      _count++;
    });
  }

  
  Widget build(BuildContext context) {
    return Column(
      children: [
        Text('Count: $_count'),
        ElevatedButton(
          onPressed: _increment,
          child: Text('Increment'),
        ),
      ],
    );
  }
}

使用 setState() 方法来更新状态,这会触发 build 方法重新执行。

image-20260201204126626

3. 带初始参数的 StatefulWidget

class CounterWidget extends StatefulWidget {
  final int initialCount;
  
  const CounterWidget({
    super.key,
    this.initialCount = 0,
  });

  
  State<CounterWidget> createState() => _CounterWidgetState();
}

class _CounterWidgetState extends State<CounterWidget> {
  late int _count;

  
  void initState() {
    super.initState();
    _count = widget.initialCount;
  }

  void _increment() {
    setState(() {
      _count++;
    });
  }

  
  Widget build(BuildContext context) {
    return Column(
      children: [
        Text('Count: $_count'),
        ElevatedButton(
          onPressed: _increment,
          child: Text('Increment'),
        ),
      ],
    );
  }
}

image-20260201204150992


🔄 StatefulWidget 生命周期

生命周期方法详解

StatefulWidget 的生命周期包含以下关键方法:

1. createState()

StatefulWidget 被创建时调用,用于创建对应的 State 对象。


State<MyWidget> createState() => _MyWidgetState();
2. initState()

State 对象被插入到 widget 树时调用,只调用一次。适合进行初始化操作。


void initState() {
  super.initState();
  // 初始化操作
  _controller = AnimationController(vsync: this);
  _loadData();
}

image-20260201204223529

3. didChangeDependencies()

initState() 之后调用,或者在依赖的 InheritedWidget 发生变化时调用。


void didChangeDependencies() {
  super.didChangeDependencies();
  // 依赖变化时的操作
}
4. build()

构建 widget 树,每次 setState() 调用后都会重新执行。


Widget build(BuildContext context) {
  return Container(
    child: Text('Hello'),
  );
}
5. didUpdateWidget()

当 widget 的配置发生变化时调用(父组件重建时传入新的 widget)。


void didUpdateWidget(MyWidget oldWidget) {
  super.didUpdateWidget(oldWidget);
  // 对比新旧 widget,执行必要的更新
  if (oldWidget.value != widget.value) {
    _updateValue();
  }
}

image-20260201204246364

6. setState()

通知框架当前状态已改变,需要重新构建 widget。

void _updateCounter() {
  setState(() {
    _count++;
  });
}
7. deactivate()

State 对象从树中移除时调用,但可能还会被重新插入。


void deactivate() {
  super.deactivate();
  // 清理操作
}
8. dispose()

State 对象被永久移除时调用,适合进行资源清理。


void dispose() {
  _controller.dispose();
  _subscription.cancel();
  super.dispose();
}

image-20260201204353610

完整生命周期示例

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

  
  State<LifecycleWidget> createState() => _LifecycleWidgetState();
}

class _LifecycleWidgetState extends State<LifecycleWidget> {
  int _counter = 0;
  late AnimationController _controller;

  
  void initState() {
    super.initState();
    print('initState: 初始化');
    _controller = AnimationController(vsync: this);
  }

  
  void didChangeDependencies() {
    super.didChangeDependencies();
    print('didChangeDependencies: 依赖变化');
  }

  
  Widget build(BuildContext context) {
    print('build: 构建 widget');
    return Column(
      children: [
        Text('Counter: $_counter'),
        ElevatedButton(
          onPressed: () {
            setState(() {
              _counter++;
            });
          },
          child: Text('Increment'),
        ),
      ],
    );
  }

  
  void didUpdateWidget(LifecycleWidget oldWidget) {
    super.didUpdateWidget(oldWidget);
    print('didUpdateWidget: widget 更新');
  }

  
  void deactivate() {
    super.deactivate();
    print('deactivate: 移除');
  }

  
  void dispose() {
    print('dispose: 销毁');
    _controller.dispose();
    super.dispose();
  }
}

💡 实际应用场景

场景1:静态展示组件(使用 StatelessWidget)

class ProductCard extends StatelessWidget {
  final String name;
  final double price;
  final String imageUrl;
  
  const ProductCard({
    super.key,
    required this.name,
    required this.price,
    required this.imageUrl,
  });

  
  Widget build(BuildContext context) {
    return Card(
      child: Column(
        children: [
          Image.network(imageUrl),
          Text(name),
          Text('\$$price'),
        ],
      ),
    );
  }
}

image-20260201204722264

场景2:计数器(使用 StatefulWidget)

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

  
  State<Counter> createState() => _CounterState();
}

class _CounterState extends State<Counter> {
  int _count = 0;

  void _increment() {
    setState(() {
      _count++;
    });
  }

  void _decrement() {
    setState(() {
      _count--;
    });
  }

  
  Widget build(BuildContext context) {
    return Row(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        IconButton(
          icon: Icon(Icons.remove),
          onPressed: _decrement,
        ),
        Text('$_count', style: TextStyle(fontSize: 24)),
        IconButton(
          icon: Icon(Icons.add),
          onPressed: _increment,
        ),
      ],
    );
  }
}

image-20260201205003232

场景3:表单输入(使用 StatefulWidget)

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

  
  State<LoginForm> createState() => _LoginFormState();
}

class _LoginFormState extends State<LoginForm> {
  final _formKey = GlobalKey<FormState>();
  final _usernameController = TextEditingController();
  final _passwordController = TextEditingController();
  bool _isLoading = false;

  
  void dispose() {
    _usernameController.dispose();
    _passwordController.dispose();
    super.dispose();
  }

  Future<void> _handleSubmit() async {
    if (_formKey.currentState!.validate()) {
      setState(() {
        _isLoading = true;
      });
      
      // 模拟登录
      await Future.delayed(Duration(seconds: 2));
      
      setState(() {
        _isLoading = false;
      });
    }
  }

  
  Widget build(BuildContext context) {
    return Form(
      key: _formKey,
      child: Column(
        children: [
          TextFormField(
            controller: _usernameController,
            decoration: InputDecoration(labelText: '用户名'),
            validator: (value) {
              if (value == null || value.isEmpty) {
                return '请输入用户名';
              }
              return null;
            },
          ),
          TextFormField(
            controller: _passwordController,
            decoration: InputDecoration(labelText: '密码'),
            obscureText: true,
            validator: (value) {
              if (value == null || value.isEmpty) {
                return '请输入密码';
              }
              return null;
            },
          ),
          ElevatedButton(
            onPressed: _isLoading ? null : _handleSubmit,
            child: _isLoading
                ? CircularProgressIndicator()
                : Text('登录'),
          ),
        ],
      ),
    );
  }
}

image-20260201205046388

场景4:动画组件(使用 StatefulWidget)

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

  
  State<AnimatedBox> createState() => _AnimatedBoxState();
}

class _AnimatedBoxState extends State<AnimatedBox>
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation<double> _animation;

  
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: Duration(seconds: 1),
      vsync: this,
    );
    _animation = Tween<double>(begin: 0, end: 1).animate(_controller);
    _controller.repeat(reverse: true);
  }

  
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  
  Widget build(BuildContext context) {
    return FadeTransition(
      opacity: _animation,
      child: Container(
        width: 100,
        height: 100,
        color: Colors.blue,
      ),
    );
  }
}

🔧 常用属性和方法详解

StatelessWidget

build(BuildContext context)

构建 widget 树,每次父组件重建时都会调用。


Widget build(BuildContext context) {
  return Container(
    child: Text('Hello'),
  );
}

StatefulWidget

createState()

创建对应的 State 对象。


State<MyWidget> createState() => _MyWidgetState();

State

widget

访问对应的 StatefulWidget 实例。

final value = widget.initialValue;
context

获取 BuildContext,用于访问主题、媒体查询等。

final theme = Theme.of(context);
final size = MediaQuery.of(context).size;
mounted

检查 State 对象是否还在 widget 树中。

if (mounted) {
  setState(() {
    _value = newValue;
  });
}
setState()

通知框架状态已改变,需要重新构建。

setState(() {
  _count++;
});

🎯 实战案例

案例1:开关切换组件

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

  
  State<ToggleSwitch> createState() => _ToggleSwitchState();
}

class _ToggleSwitchState extends State<ToggleSwitch> {
  bool _isOn = false;

  void _toggle() {
    setState(() {
      _isOn = !_isOn;
    });
  }

  
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: _toggle,
      child: Container(
        width: 60,
        height: 30,
        decoration: BoxDecoration(
          color: _isOn ? Colors.green : Colors.grey,
          borderRadius: BorderRadius.circular(15),
        ),
        child: Stack(
          children: [
            AnimatedPositioned(
              duration: Duration(milliseconds: 200),
              curve: Curves.easeInOut,
              left: _isOn ? 30 : 0,
              top: 0,
              bottom: 0,
              child: Container(
                width: 30,
                decoration: BoxDecoration(
                  color: Colors.white,
                  shape: BoxShape.circle,
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

案例2:列表项展开/收起

class ExpandableListItem extends StatefulWidget {
  final String title;
  final String content;
  
  const ExpandableListItem({
    super.key,
    required this.title,
    required this.content,
  });

  
  State<ExpandableListItem> createState() => _ExpandableListItemState();
}

class _ExpandableListItemState extends State<ExpandableListItem> {
  bool _isExpanded = false;

  
  Widget build(BuildContext context) {
    return Column(
      children: [
        ListTile(
          title: Text(widget.title),
          trailing: Icon(
            _isExpanded ? Icons.expand_less : Icons.expand_more,
          ),
          onTap: () {
            setState(() {
              _isExpanded = !_isExpanded;
            });
          },
        ),
        if (_isExpanded)
          Padding(
            padding: EdgeInsets.all(16),
            child: Text(widget.content),
          ),
      ],
    );
  }
}

案例3:定时器组件

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

  
  State<TimerWidget> createState() => _TimerWidgetState();
}

class _TimerWidgetState extends State<TimerWidget> {
  int _seconds = 0;
  Timer? _timer;

  
  void initState() {
    super.initState();
    _startTimer();
  }

  void _startTimer() {
    _timer = Timer.periodic(Duration(seconds: 1), (timer) {
      if (mounted) {
        setState(() {
          _seconds++;
        });
      }
    });
  }

  
  void dispose() {
    _timer?.cancel();
    super.dispose();
  }

  
  Widget build(BuildContext context) {
    return Text(
      'Timer: $_seconds 秒',
      style: TextStyle(fontSize: 24),
    );
  }
}

⚠️ 常见问题与解决方案

问题1:setState() called after dispose()

问题描述:在组件销毁后调用 setState() 导致错误。

解决方案

if (mounted) {
  setState(() {
    _value = newValue;
  });
}

问题2:忘记释放资源

问题描述:在 dispose() 中忘记释放控制器、订阅等资源。

解决方案


void dispose() {
  _controller.dispose();
  _subscription.cancel();
  _timer?.cancel();
  super.dispose();
}

问题3:不必要的重建

问题描述:频繁调用 setState() 导致性能问题。

解决方案

  • 合并多个状态更新
  • 使用 const 构造函数
  • 使用 RepaintBoundary 隔离重绘区域
// 合并更新
void _updateMultipleValues() {
  setState(() {
    _value1 = newValue1;
    _value2 = newValue2;
    _value3 = newValue3;
  });
}

问题4:StatelessWidget vs StatefulWidget 选择

问题描述:不知道应该使用哪个。

解决方案

  • StatelessWidget:用于静态展示,不需要状态管理
  • StatefulWidget:需要响应用户交互、数据变化、动画等

📚 总结

通过本教程,我们学习了:

  1. StatelessWidgetStatefulWidget 的基本概念和区别
  2. StatelessWidget 的基础用法和最佳实践
  3. StatefulWidget 的生命周期方法
  4. setState() 的使用和注意事项
  5. ✅ 实际应用场景和案例
  6. ✅ 常见问题解决方案

StatefulWidgetStatelessWidget 是 Flutter 开发的基础,掌握它们的使用方法和生命周期,能够让你更好地构建 Flutter 应用!


🔗 相关资源

Happy Coding! 🎨✨
欢迎加入开源鸿蒙跨平台社区

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐