0

I'm using Hero widget to pop up a selector page where you can select your preferred color to use as background. If I tap on "Change color!" then the main page container background changes perfectly, but on the selector page it remains in the build "state". After closing and reopening my selector page, then - of course - the background will filled with the good color...

Any idea?

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

class TestPage extends StatefulWidget {
  @override
  _TestPageState createState() => _TestPageState();
}

class CustomRectTween extends RectTween {
  final Rect? begin;
  final Rect? end;

  CustomRectTween({
    required this.begin,
    required this.end,
  }) : super(begin: begin, end: end);

  @override
  Rect lerp(double t) {
    final elasticCurveValue = Curves.easeOut.transform(t);
    double? xLeft = begin!.left;
    double yLeft = end!.left;
    double xRight = begin!.right;
    double yRight = end!.right;
    double xTop = begin!.top;
    double yTop = end!.top;
    double xBottom = begin!.bottom;
    double yBottom = end!.bottom;
    return Rect.fromLTRB(
      lerpDouble(xLeft, yLeft, elasticCurveValue)!,
      lerpDouble(xTop, yTop, elasticCurveValue)!,
      lerpDouble(xRight, yRight, elasticCurveValue)!,
      lerpDouble(xBottom, yBottom, elasticCurveValue)!,
    );
  }
}

class _TestPageState extends State<TestPage> {
  int actNum = 1;

  @override
  void initState() {
    // initState vagyis itt kerülnek beállításra az alapértékek
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Scaffold(
          body: Stack(
        children: [
          Container(
            color: actNum == 1 ? Colors.greenAccent : Colors.white,
            child: Hero(
              tag: "akcio",
              transitionOnUserGestures: true,
              createRectTween: (begin, end) {
                return CustomRectTween(begin: begin, end: end);
              },
              child: GestureDetector(
                  onTap: () {
                    Navigator.of(context).push(new PageRouteBuilder(
                        opaque: false,
                        maintainState: false,
                        barrierDismissible: false,
                        transitionDuration: Duration(milliseconds: 450),
                        pageBuilder: (BuildContext context, _, __) {
                          return Container(
                            height: MediaQuery.of(context).size.height,
                            width: MediaQuery.of(context).size.width,
                            child: Stack(
                              children: [
                                Positioned(
                                  bottom: 100.0,
                                  child: Hero(
                                    tag: "akcio",
                                    child: GestureDetector(
                                      onDoubleTap: () {
                                        Navigator.of(context).pop();
                                      },
                                      onTap: () {
                                        if (actNum == 1) {
                                          actNum = 0;
                                        } else {
                                          actNum = 1;
                                        }
                                        setState(() {});
                                      },
                                      child: Container(
                                        height: 100.0,
                                        width:
                                            MediaQuery.of(context).size.width,
                                        color: actNum == 1
                                            ? Colors.greenAccent
                                            : Colors.white,
                                        child: Container(
                                            child: Text('Change color!')),
                                      ),
                                    ),
                                  ),
                                )
                              ],
                            ),
                          );
                        }));
                  },
                  child: Icon(
                    Icons.play_circle_fill,
                    color: Colors.black,
                    size: 75.0,
                  )),
            ),
          )
        ],
      )),
    );
  }
}
Zoltan
  • 43
  • 1
  • 8

1 Answers1

0

Wrap your pageBuilder's Container with Scaffold widget, it will solve the issue. It is just overlaying with main widget.

  transitionDuration: Duration(milliseconds: 450),
                        pageBuilder: (BuildContext context, _, __) {
                          return Scaffold(
                            body: Container(
                              height: MediaQuery.of(context).size.height,
                              width: MediaQuery.of(context).size.width,
                              child: Stack(

Also, another solution is MaterialPageRoute

  GestureDetector(
                  onTap: () async {
                    final result =
                        await Navigator.of(context).push(MaterialPageRoute(
                      builder: (context) => NewWidget(),
                    ));

                    print("result isactNum0 $result");

                    setState(() {
                      actNum = result ? 1 : 0;
                    });
                  },

NewWidget is the nextPage


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

  @override
  State<NewWidget> createState() => _NewWidgetState();
}

class _NewWidgetState extends State<NewWidget> {
  bool isactNum0 = true;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.transparent,
      body: Container(
        height: MediaQuery.of(context).size.height,
        width: MediaQuery.of(context).size.width,
        child: Stack(
          children: [
            Positioned(
              bottom: 100.0,
              child: Hero(
                tag: "akcio",
                child: GestureDetector(
                  onDoubleTap: () {
                    Navigator.of(context).pop(isactNum0); // pass current state isactNum0
                  },
                  onTap: () {
                    setState(() {
                      isactNum0 = !isactNum0;
                    });
                  },
                  child: Container(
                    height: 100.0,
                    width: MediaQuery.of(context).size.width,
                    color: isactNum0 ? Colors.greenAccent : Colors.white,
                    child: Container(child: Text('Change color!')),
                  ),
                ),
              ),
            )
          ],
        ),
      ),
    );
  }
}

push returns future and we can wait for result. While it will pop, we will get current state from NewWidget and updating UI based on it.

Main page wasn't updating because it is from different route.

Check question comments to learn more about Difference between MaterialPageRoute and PageRouteBuilder

Md. Yeasin Sheikh
  • 54,221
  • 7
  • 29
  • 56
  • When I wrap it with Scaffold, it looks better, but the issue remains, setState changes only the main page container's color. I also tried your second solution which only works if my selector page is really a full page, because with this idea the transparent Scaffold in NewWidget shows a black background (I think its because the pages isn't overlaping in Navigator and the black color is the system default "container's" color). – Zoltan Dec 02 '21 at 08:59
  • 1
    updated the answer. I will suggest you using `state-management` that will help on long run – Md. Yeasin Sheikh Dec 02 '21 at 09:10
  • Does it solve yout issue? – Md. Yeasin Sheikh Dec 02 '21 at 09:27
  • Testing, testing... :) It passes info well between widgets, but my main problem is that the NewWidget should not cover the whole screen (the Play icon in the upper left corner should be visible all the time...) – Zoltan Dec 02 '21 at 09:37
  • In that case you can use `Dialog` or `Stack` – Md. Yeasin Sheikh Dec 02 '21 at 09:43
  • Yes, but I think I will lose Hero transition animation if I use Dialog or Stack... :/ – Zoltan Dec 02 '21 at 09:57
  • 1
    You can use AnimatedPosition with AnimatedOpacity to get the same effect on stack – Md. Yeasin Sheikh Dec 02 '21 at 12:53
  • I'm playing with these... It will be a working solution, thanks! :) – Zoltan Dec 02 '21 at 15:27