Home > Software design >  Updating State of StatefulWidget from other StatefulWidget in Flutter?
Updating State of StatefulWidget from other StatefulWidget in Flutter?

Time:11-10

i am trying to update the state of the animated switcher in the middle area. i am trying to do this using a setstate in the lower area. but it does not work.

  1. the first thing i did is to create a variable with a boolean data type in the home class.
  2. then i passed the variable to both the middle area and the lower area
  3. the idea was that if the same variable is passed to the class whose state i am trying to update, and the class with the set state, it would work. but it seems i am wrong. i would appreciate some assistance. the boolean variable i am trying to make work is the _rep variable

This is the Home widget

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

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
  late AnimationController _animationController;
  late AnimationController _controller;
  late Animation<Offset> _animation;
  late Animation<Offset> _anime;
    bool _rep = true;
  @override
  void initState() {
    _animationController = AnimationController(
        vsync: this,
        duration: Duration(seconds: 2)
    );
    _animation = Tween<Offset>(
      begin:Offset (0.0, 0.0),
      end: Offset (0.0,3.0),
    ).animate(CurvedAnimation(
        parent: _animationController,
        curve: Curves.easeIn));

    _anime = Tween<Offset>(
      begin:Offset (0.0, 0.0),
      end: Offset (0.0,-0.55),
    ).animate(CurvedAnimation(
        parent: _animationController,
        curve: Curves.easeIn));

    super.initState();

  }

  @override
  void dispose() {
    _animationController.dispose();
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SingleChildScrollView(
        scrollDirection: Axis.vertical,
         physics: const NeverScrollableScrollPhysics(),
        child: Padding(
          padding:  EdgeInsets.only(top: 3.h),
          child: Column(
            children: [
              Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: [
                   TopIcon(icons: Icons.arrow_back, color:Colors.grey.shade300 ,),
                  SizedBox(
                    height: 13.h,
                      width: 13.w,
                      child: Image.asset('assets/images/download.png')
                  ),
                  TopIcon(icons: Icons.shopping_bag_outlined, color: Colors.grey.shade300,),
                ],
              ),
               SizedBox(
                height: 3.h,
              ),
               Text('Frappuccino',
                style: TextStyle(
                  fontSize: 27.sp,
                  fontWeight: FontWeight.bold
                ),
              ),
               Padding(
                 padding: const EdgeInsets.all(8.0),
                 child: Text('White Chocolate',
                  style: TextStyle(
                    fontWeight: FontWeight.bold,
                    color: Colors.grey.shade400
                  ),
              ),
               ),
              MiddleArea(
                     controller: _animationController,
                     animation: _animation,
                     rep: _rep,


              ),



               LowerArea(controller: _animationController, anime: _anime, rep = _rep),
            ],
          ),
        ),
      ),
    );
  }
}

This is the middle area

class MiddleArea extends StatefulWidget {
   MiddleArea({Key? key, required this.controller, required this.animation, required this.rep}) : super(key: key);
  AnimationController controller;
  Animation<Offset> animation;
  final bool rep;


  @override
  State<MiddleArea> createState() => _MiddleAreaState();
}

class _MiddleAreaState extends State<MiddleArea> {
  bool _flag = true;
  bool _favourite = true;

  @override
  Widget build(BuildContext context) {
    print(widget.rep);
    return SizedBox(
      height: 52.h,
      child: Stack(
        children: [
          Column(
              children: [
                Padding(
                  padding: const EdgeInsets.only(top: 135.0),
                  child: Text('STARBUCKS',
                    style: TextStyle(
                        fontFamily: 'Typette',
                        color: Colors.brown.shade200,
                        fontSize: 30.sp,
                        fontWeight: FontWeight.w400
                    ),
                  ),
                ),
                Text('STARBUCKS',
                  style: TextStyle(
                      fontFamily: 'Typette',
                      color: Colors.brown.shade100,
                      fontSize: 30.sp,
                      fontWeight: FontWeight.w400
                  ),
                ),
                Text('STARBUCKS',
                  style: TextStyle(
                      fontFamily: 'Typette',
                      color: Colors.brown.shade50,
                      fontSize: 30.sp,
                      fontWeight: FontWeight.w400
                  ),
                ),
              ],
            ),

          Column(
            children: [
              Row(
                 mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: const [
                  SizeAndFave(text: 'Preference'),
                  SizeAndFave(text: 'Fave!')
                ],
              ),
              Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: [
                  GestureDetector(
                    onTap: (){
                      setState(() {
                         _flag = !_flag;
                      });
                    },
                      child: AnimatedSwitcher(
                        duration: const Duration(milliseconds: 500),
                        transitionBuilder: (Widget child, Animation<double> animation){
                          return FadeTransition(opacity: animation, child: child,);
                        },
                        child: widget.rep == true?Padding(
                          padding: const EdgeInsets.all(14.0),
                          key: const Key('1'),
                          child: Container(
                              height: 40,
                              width: 40,
                              decoration: BoxDecoration(
                                  border: Border.all(
                                      color: Colors.brown.shade300,
                                      width: 3
                                  ),
                                  borderRadius: BorderRadius.circular(10)
                              ),
                              child: const Center(
                                child: Icon(
                                  Icons.coffee_outlined,
                                  size: 20,
                                ),
                              )
                          ),
                        ):null,
                      )
                  ),
                  GestureDetector(
                    onTap: (){
                      setState(() {
                        _favourite = !_favourite;
                      });
                    },
                      child: _favourite? TopIcon(icons: Icons.favorite_border, color: Colors.brown.shade300)
                      :TopIcon(
                          icons: Icons.favorite, color: Colors.brown.shade300)
                  )
                ],
              )
            ],
          ),
              AnimatedSwitcher(
                duration: Duration(seconds: 1),
                transitionBuilder: (Widget child, Animation<double> animation) {
                  return FadeTransition( opacity: animation,
                  child: child);
                },
                  child: _flag == true ? Center(
                    key: const Key('1'),
                    child: SlideTransition(
                      position: widget.animation,
                      child: SizedBox(
                        height: 80.h,
                        width: 80.w,
                         child: Image.asset('assets/images/starcup.png'),
                       ),
                    ),
                  ):Center(
                    key: const Key('2'),
                    child: SlideTransition(
                      position: widget.animation,
                      child: SizedBox(
                        height: 80.h,
                        width: 80.w,
                        child: Image.asset('assets/images/greeen.png'),
                      ),
                    ),
                  ),
                   ),
          Positioned(
              child:
          Align(
            alignment: Alignment.bottomRight,
            child: Padding(
              padding:  EdgeInsets.only(top: 30.h),
              child: TopIcon(
                  icons: Icons.car_crash_outlined, color: Colors.brown.shade300),
            ),
          )),

          const Positioned(
              child:
              Align(
                alignment: Alignment.bottomLeft,
                child: Padding(
                  padding: EdgeInsets.only(top: 330.0, left: 14),
                  child: Text('\$ 5.99',
                  style: TextStyle(
                    fontSize: 27,
                    fontWeight: FontWeight.bold
                  ),
                  ),
                ),
              ))
        ],
      ),
    );

  }
}

and lastly, the lower area

class LowerArea extends StatefulWidget {
  final AnimationController controller;
  final Animation<Offset> anime;
  bool rep;




   LowerArea({Key? key, required this.controller, required this.anime, required this.rep}) : super(key: key);

  @override
  State<LowerArea> createState() => _LowerAreaState();
}

class _LowerAreaState extends State<LowerArea> {
  bool _bigger = true;
  bool _fade = true;

  void move(){

  }
  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Container(
          child: Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children:  [
              Padding(
                padding: EdgeInsets.all(1.h),
                child: const Text('Tall Frappuccino',
                  style: TextStyle(
                    fontWeight: FontWeight.w500
                  ),
                ),
              ),
              Padding(
                padding: EdgeInsets.only(right: 5.h),
                child: const Text('Swipe Down',
                  style: TextStyle(
                      fontWeight: FontWeight.w500
                  ),
                ),
              ),
              Padding(
                padding: EdgeInsets.all(2.h),
                child: const Text('Pickup',
                  style: TextStyle(
                      fontWeight: FontWeight.w500
                  ),
                ),
              )
            ],
          ),
        ),
        SlideTransition(
          position: widget.anime,

          child: AnimatedContainer(
            // height: 11.h,
            width: _bigger ? 35.h: 80.h,
            duration: const Duration(milliseconds: 500),
            child: Stack(
              fit: StackFit.loose,
              children: [
                Center(child: Image.asset('assets/images/baggie.png')),
                Center(
                  child: Padding(
                    padding:  EdgeInsets.only(bottom: 4.h),
                    child: GestureDetector(
                      onTap: (){
                           widget.controller.forward();
                           setState(() {
                             _bigger = !_bigger;
                             _fade = !_fade;
                             widget.rep = !widget.rep;

                             print('this is fade $_fade ');

                           });
                      },
                      child: AnimatedSwitcher(
                        duration: Duration(milliseconds: 300),
                        transitionBuilder: (Widget child, Animation<double> animation){
                          return FadeTransition(opacity: animation, child: child,);
                        },
                        child: _fade? Container(
                          key: Key('1'),
                          height: 8.h,
                          width: 7.w,
                          decoration: BoxDecoration(
                            color: Colors.black,
                            borderRadius: BorderRadius.circular(15)
                          ),
                          child: Column(
                            children:  [
                              Padding(
                                padding: EdgeInsets.all(0.3.h),
                                child: Icon(
                                  Icons.lock_outline,
                                  color: Colors.white54,
                                  size: 2.5.h,

                                ),
                              ),
                              Icon(
                                Icons.arrow_drop_down,
                                color: Colors.white12,
                                size: 3.h,
                              ),



                            ],
                          ),
                        ):null,
                      ),
                    ),
                  ),
                )
              ],
            ),
          ),
        )
      ],
    );

  }


CodePudding user response:

use provider pacakges https://pub.dev/packages/provider

Create a class that inherits the functions of ChangeNotifyer to create a flag to control and create a setter.
provider class

class StateController extends ChangeNotifier{
   bool _req = false;
   bool get req => _req; //getter
  
   setReqValue(){
      _req = !_req;
      notifyListener(); 
   }
}

Declare the provider class in the main function. You can change the location of the declaration according to Wiget tree, but first declare it in main
Change main.dart

void main(){
  runApp(
    Multiprovider(
      providers: [
         ChangeNotifierProvider(create: (_) => StateController()),
      ],
      child: HomePage(),
    )
  );
}

The UI is updated by notifyListener().
change UI

child: context.watch<StateController>().req == true ? Padding(
                          padding: const EdgeInsets.all(14.0),
                          key: const Key('1'),
                          child: Container(
                              height: 40,
                              width: 40,
                              decoration: BoxDecoration(
                                  border: Border.all(
                                      color: Colors.brown.shade300,
                                      width: 3
                                  ),
                                  borderRadius: BorderRadius.circular(10)
                              ),
                              child: const Center(
                                child: Icon(
                                  Icons.coffee_outlined,
                                  size: 20,
                                ),
                              )
                          ),
                        ):null,

Change State

onTap: (){
                           widget.controller.forward();
                           setState(() {
                             _bigger = !_bigger;
                             _fade = !_fade;
                             context.read<StateController>().setReqValue();

                             print('this is fade $_fade ');

                           });
                      },

CodePudding user response:

I am too lazy to try understand your code. But if you want to update state of the page after you pop from Navigation to it.

In page you want to update

Navigation.push(context, /* Page that will change something */)
  // Future will trigger then you return to this page.
  .then((_) => setState(() {}))
  • Related