[Flutter] #2 stateful widget

     

stateful widget

  • stateful is the widget that it can change some value like text, image and any state in checkbox, radiobutton. the other, stateless is the widget can't change.
  • when state change, setState() method will run and do somethong to change values.

how to make statful widget

  • First, make a class extends StatefulWidget.
class ExStatefulWidget extends StatefulWidget{
    @override
    _ExStatefulWidgetState createState() => _ExStatefulWidgetState()
}
  • This class has a one override method createState(). So we have to make State Class.
class _ExStatefulWidgetState extends State<ExStatfulWidget>{
    return someWidget()
}
  • This class return a widget has state. If you want to change some value, write a setState().
class _FavoriteWidgetState extends State<FavoriteWidget>{
  bool _isfavorited = true;
  int _favoriteCount = 41;

  void _toggleFavorite(){
    setState(() {
      if(_isfavorited){
        _favoriteCount --;
      }else{
        _favoriteCount ++;
      }
      _isfavorited = !_isfavorited;
    });
  }

  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Row(
      mainAxisSize: MainAxisSize.min,
      children: [
        Container(
          padding: EdgeInsets.all(0),
          child: IconButton(
            padding: EdgeInsets.all(0),
            alignment: Alignment.centerRight,
            icon: (_isfavorited ? Icon(Icons.star) : Icon(Icons.star_border)),
            color: Colors.red[500],
            onPressed: _toggleFavorite,
          ),
        ),
        SizedBox(
          width: 18,
            child: Container(
              child:Text('$_favoriteCount'),
            ),
        )
      ],
    );
  }
}

ways to deal state

  • There are two way to deal state. 1. widget manages it's own state. 2. parent widget manage child state.
  • We need to choice best way to manage state. First way is simple, but sometimes we let parent control some state of child. There are two stateful widget codes.
class TabBoxA extends StatefulWidget{
  @override
  State<StatefulWidget> createState() {
    return _TabBoxAState();
  }
}

class _TabBoxAState extends State<TabBoxA>{
  bool _active = true;

  void _onTap(){
    setState(() {
      _active = !_active;
    });
  }

  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return GestureDetector(
      onTap: _onTap,
      child: Container(
        width: 200,
        height: 200,
        child: Center(
          child: Text(
            _active ? 'Active' : 'Inactive',
            style: TextStyle(
              fontSize: 20,
              color: Colors.white,
            ),
          ),
        ),
        decoration: BoxDecoration(
          color: _active ? Colors.green : Colors.grey,
        ),
      ),
    );
  }
}


class ParentWidget extends StatefulWidget{
  @override
  State<StatefulWidget> createState() {
    return _ParentWidgetState();
  }

}

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

  void _onTap(bool newValue){
    setState(() {
      _active = newValue;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      child: TabBoxB(
        active: _active,
          onChanged: _onTap,
      ),
    );
  }
}


class TabBoxB extends StatelessWidget{
  TabBoxB({Key? key, this.active: true, required this.onChanged}):super(key:key);

  final bool active;
  final ValueChanged<bool> onChanged;

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

  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: _onTap,
      child: Container(
        width: 200,
        height: 200,
        child: Center(
          child: Text(
            active ? 'Active' : 'Inactive',
            style: TextStyle(
              color: Colors.white,
              fontSize: 20
            ),
          ),
        ),
        decoration: BoxDecoration(
          color: active ? Colors.green : Colors.grey,
        ),
      ),
    );
  }
}
  • TabBoxA is managing own state, TabBoxB's state is managed by parent.
  • And there are mix way to manage states.
class MixParentWidget extends StatefulWidget{
  @override
  State<StatefulWidget> createState() {
    return _MixParentWidgetState();
  }

}

class _MixParentWidgetState extends State<MixParentWidget>{
  bool _active = true;

  void _onTap(bool newValue){
    setState(() {
      _active = newValue;
    });
  }

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

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

  final bool active;
  final ValueChanged<bool> onChanged;

  @override
  State<StatefulWidget> createState() {
    return _TabBoxCState();
  }
}

class _TabBoxCState 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,
      onTapCancel: _handleTapCancel,
      onTap: _handleTap,
      child: Container(
        width: 200,
        height: 200,
        child: Center(
          child: Text(
            widget.active ? 'Active' : 'Inactive',
            style: TextStyle(
              color: Colors.white,
              fontSize: 32,
            ),
          ),
        ),
        decoration: BoxDecoration(
          color: widget.active ? Colors.green : Colors.grey,
          border: _highLight ? Border.all(
            color: Colors.teal[700]!,
            width: 10) : null
          ),
        ),
      );
  }
}
반응형

댓글

Designed by JB FACTORY