1

I am trying to create the build method without side effects (without blinking). I solved this problem using StatefulBuilder, but I read that I should rebuild 1000x times without any change or effect.

The Staggered Grid View Builder Widget are rebuilt when the keyboard is opening, or whenever I open again the page, or add/remove an item from it. That's good, normally, but with side effects like you see below. Maybe there is any solution to animate the remove/add functionality, or the infinite reloading and keep the rest of the items in cache. So I need to limit the builder recreate inside Grid View Builder?

On other applications I don't see this ugly "blinking". Where is the problem and how can I solve it? I used Animation Limiter but it's not working for me, neither PrecacheImage, somehow I need to rebuild without blink (first items).

enter image description here

enter image description here

My code:

 class VisionBoard extends StatefulWidget {
      const VisionBoard({Key? key}) : super(key: key);
    
      @override
      _VisionBoardState createState() => _VisionBoardState();
    }
    
    class _VisionBoardState extends State<VisionBoard>  with SingleTickerProviderStateMixin {
      ScreenshotController screenshotController = ScreenshotController();
      String saveGoalsButtonText = "SAVE GOALS";
      String wallpaperButtonText = "CREATE WALLPAPER";
      String saveWallpaperButtonText = "SAVE";
      bool createWallpaper = false;
      bool isWallpaperCreated = false;
      late File imageFile;
      late String newImage;
      late Uint8List imageRaw;
      int noOfImages = 0;
      late Uint8List wallpaperBytes;
      String title = "My Vision Board";
      String goals = "";
      late List<String> visions = <String>[];
      final TextEditingController _textFieldController = TextEditingController();
      final TextEditingController _goalsController = TextEditingController();
      static final _formKey = GlobalKey<FormState>();
    
      @override
      void initState() {
        super.initState();
        loadVisionBoardTitleAndImages();
      }
      void loadVisionBoardTitleAndImages() async {
        SharedPreferences prefs = await SharedPreferences.getInstance();
        //await prefs.clear();
        setState(() {
          _textFieldController.text = prefs.getString('titlu') ?? title;
          visions = prefs.getStringList('visions') ?? <String>[];
          _goalsController.text = prefs.getString('goals') ?? goals;
        });
      }
        void _removeVisions(int index) async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    setState(() {
        isButtonDisabled=true;
        visions.removeAt(index);
        prefs.setStringList('visions', visions);
        createWallpaper = false;
        wallpaperButtonText = "CREATE WALLPAPER";
        isWallpaperCreated = false;
    });
    await CreateWallpaperLayouts().createWallpaper(visions).then((value) {
      setState(() {
        wallpaperBytes = value;
        wallpaper = Image.memory(wallpaperBytes);
        precacheImage(wallpaper.image, context);
        isButtonDisabled=false;
      });
     });
  }
      @override
      Widget build(BuildContext context) {
        return Sizer(
            builder: (context, orientation, deviceType) {
          return GestureDetector(
            onTap: () {
              FocusScopeNode currentFocus = FocusScope.of(context);
    
              if (!currentFocus.hasPrimaryFocus) {
                currentFocus.unfocus();
              }
            },
            child: Scaffold(
                body: AnimationLimiter(
                  child: Container(
                    decoration: const BoxDecoration(
                      image: DecorationImage(
                          image: AssetImage("assets/background-marmura.jpeg"), fit: BoxFit.cover)),
                    child: SafeArea(
                      child: SingleChildScrollView(
                        child: Container(
                          margin: const EdgeInsets.fromLTRB(20, 0, 20, 0),
                          child: Column(
                            children: [ 
                              StatefulBuilder(
                                builder: (BuildContext context, StateSetter setState) {
                                  return Row(
                                children: [
                                  Flexible(
                                    child: Text(_textFieldController.text,
                                    style: const TextStyle(
                                      fontWeight: FontWeight.w700,
                                      fontSize: 21,
                                      color: Color(0xff393432),
                                    ),
                                    ),
                                  ),
                                  IconButton(
                                    icon: const Icon(
                                      Icons.edit,
                                      size: 21,
                                      color: Color(0xff393432),
                                    ),
                                    onPressed: () {
                                      showAlertDialog(context, setState);
                                    },
                                  )
                                ]);
                                }
                              ),
                              const SizedBox(height: 5),
                              GridView.builder(
                                  clipBehavior: Clip.none,
                                  physics: const ScrollPhysics(),
                                  shrinkWrap: true,
                                  gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
                                      maxCrossAxisExtent: SizeConfig.screenWidth!/3,),
                                  itemCount: (visions.length == 12) ? visions.length : visions.length + 1,
                                  itemBuilder: (BuildContext ctx, index) {
                                    if (index < visions.length) {
                                      return AnimationConfiguration.staggeredGrid(
                                        position: index,
                                        duration: const Duration(milliseconds: 1000),
                                        columnCount: 3,
                                        child: ScaleAnimation(
                                        child: FadeInAnimation(
                                        child:  OpacityAnimatedWidget.tween(
                                        opacityEnabled: 1, //define start value
                                        opacityDisabled: 0, //and end value
                                        enabled: index < visions.length, //bind with the boolean
                                        child: Stack(
                                          alignment: Alignment.center,
                                          children: [
                                            Container(
                                              width: 25.w,
                                              height: 25.w,
                                              decoration: BoxDecoration(
                                                image: DecorationImage(
                                                    image: CleverCloset.imageFromBase64String(visions[index]).image,
                                                    fit: BoxFit.fill),
                                                borderRadius: const BorderRadius.all(
                                                    Radius.circular(
                                                        5.0) //                 <--- border radius here
                                                ),
                                              ),
                                            ),
                                            Positioned(
                                              top:0,
                                              right:0,
                                              child: ClipOval(
                                                child: InkWell(
                                                  onTap: () {
                                                    _removeVisions(index);
                                                  },
                                                  child: Container(
                                                    padding: const EdgeInsets.all(5),
                                                    color: Colors.white,
                                                    child:
                                                      const Icon(
                                                          Icons.delete,
                                                          size: 16,
                                                          color: Color(0xff393432)),
                                                  ),
                                                ),
                                              ),
                                            ),
                                          ],
                                          clipBehavior: Clip.none,
                                        ),
                                    ),
                                        ),
                                        ),
                                      );
                                    }
                                    else if(index<12){
                                      return InkWell(
                                        onTap: () {
                                          _openGallery(context);
                                        },
                                        child:
                                        Stack(
                                          alignment: Alignment.center,
                                          children:[
                                            Container(
                                            width: 25.w,
                                              height: 25.w,
                                              decoration:
                                              BoxDecoration(
                                                border: Border.all(color: const Color(0xff393432)),
                                                borderRadius: const BorderRadius.all(Radius.circular(5.0)),
                                              ),
                                              child:
                                                const Icon(
                                                  Icons.add,
                                                  size: 25,
                                                  color: Color(0xff393432),
                                                )
                                          ),
                                          ],
                                        ),
                                      );
                                    }
                                    else {
                                      return  Container(color: Colors.red);
                                    }
                                  }
                              ),
                              const SizedBox(height: 10),
    
                              Row(
                                mainAxisAlignment: MainAxisAlignment.start,
                                children: const [
                                  Text("You can add up to 12 pictures.",
                                  style: TextStyle(
                                    fontSize: 15,
                                    fontWeight: FontWeight.w400,
                                    fontStyle: FontStyle.italic,
                                  ),),
                                ],
                              ),
    
                              const SizedBox(height: 10),
                              StatefulBuilder(
                                builder: (BuildContext context, StateSetter setState) {
                                  return Column (
                                  children: [
                                    if(visions.isNotEmpty && visions.length>1 && !isWallpaperCreated)  Row(
                                            children: [
                                              SizedBox(
                                                width: 50.w,
                                                child: OpacityAnimatedWidget.tween(
                                                  opacityEnabled: 1, //define start value
                                                  opacityDisabled: 0, //and end value)
                                                  enabled: !isWallpaperCreated &&
                                                      visions.isNotEmpty && visions.length > 1,
                                                  child: OutlinedButton(
                                                    onPressed: visions.isNotEmpty &&
                                                        visions.length > 1 ? () async{
                                                      setState(() {
                                                        wallpaperButtonText = "CREATING...";
                                                        //_createWallpaper();
                                                      });
                                                      wallpaperBytes = await CreateWallpaperLayouts().createWallpaper(visions);
                                                      setState(() {
                                                        noOfImages = visions.length;
                                                        isWallpaperCreated = true;
                                                        createWallpaper = true;
                                                      });
                                                      //Navigator.pushReplacementNamed(context, '/masterclasses');
                                                    } : null,
                                                    style: OutlinedButton.styleFrom(
                                                      primary: const Color(0xffE4BCB4),
                                                      shape: RoundedRectangleBorder(
                                                        borderRadius: BorderRadius.circular(
                                                            18.0),
                                                      ),
                                                      side: const BorderSide(
                                                          width: 3, color: Color(0xffE4BCB4)),
                                                    ),
                                                    child: Text(
                                                        wallpaperButtonText,
                                                        style: const TextStyle(
                                                          color: Color(0xff393432),
                                                          fontSize: 14,
                                                          fontWeight: FontWeight.w700,
                                                        )
                                                    ),
                                                  ),
                                                ),
                                              ),
                                            ],
                                          ),
                                    const SizedBox(height:40),
                                    if(createWallpaper==true) OpacityAnimatedWidget.tween(
                                      opacityEnabled: 1, //define start value
                                      opacityDisabled: 0, //and end value
                                      enabled: createWallpaper, //bind with the boolean
                                      child: Row(
                                        children: const [
                                          Flexible(
                                            child: Text("Wallpaper",
                                              style: TextStyle(
                                                fontWeight: FontWeight.w700,
                                                fontSize: 21,
                                                color: Color(0xff393432),
                                              ),
                                            ),
                                          ),
                                        ],
                                      ),
                                    ),
                                    if(createWallpaper==true) const SizedBox(height:15),
                                    if(createWallpaper==true)
                                      OpacityAnimatedWidget.tween(
                                        opacityEnabled: 1, //define start value
                                        opacityDisabled: 0, //and end value
                                        enabled: createWallpaper,
                                        child: Row(
                                          mainAxisAlignment: MainAxisAlignment.start,
                                          children:[ Container(
                                            width: 50.w,//double.infinity,
                                            height: 50.h,//SizeConfig.screenHeight,
                                            decoration: BoxDecoration(
                                                image: DecorationImage(
                                                  image: Image.memory(wallpaperBytes).image,
                                                  fit: BoxFit.fill,
                                                )
                                            ),
                                            //child: CreateWallpaperLayouts().createWallpaper(visions),
                                          ),],
                                        ),
                                      ),
    
    
                                    if(createWallpaper==true) const SizedBox(height:10),
                                    if(createWallpaper==true) StatefulBuilder(
                                        builder: (BuildContext context, StateSetter setState) {
                                          return OpacityAnimatedWidget.tween(
                                            opacityEnabled: 1, //define start value
                                            opacityDisabled: 0, //and end value
                                            enabled: createWallpaper,
                                            child: Row(
                                              children: [
                                                SizedBox(
                                                  width: 50.w,
                                                  child: OutlinedButton(
                                                    onPressed: () {
                                                      _saveWallpaper(wallpaperBytes);
                                                      setState(()  {
                                                        saveWallpaperButtonText = "SAVED!";
                                                      });
                                                      Future.delayed(const Duration(milliseconds: 1300), () {
                                                        setState(() {
                                                          saveWallpaperButtonText = "SAVE";
                                                        });
                                                      });
                                                      //Navigator.pushReplacementNamed(context, '/masterclasses');
                                                    },
                                                    style: OutlinedButton.styleFrom(
                                                      primary: const Color(0xffE4BCB4),
                                                      shape: RoundedRectangleBorder(
                                                        borderRadius: BorderRadius.circular(18.0),
                                                      ),
                                                      side: const BorderSide(width: 3, color: Color(0xffE4BCB4)),
                                                    ),
                                                    child: Text(
                                                        saveWallpaperButtonText,
                                                        style: const TextStyle(
                                                          color: Color(0xff393432),
                                                          fontSize: 14,
                                                          fontWeight: FontWeight.w700,
                                                        )
                                                    ),
                                                  ),
                                                ),
                                                const SizedBox(width: 10),
                                              ],
                                            ),
                                          );
                                        }
                                    ),
                                    if(createWallpaper==true) const SizedBox(height:50),
                                    Row(
                                      children: const [
                                        Flexible(
                                          child: Text("Goals & Affirmations",
                                            style: TextStyle(
                                              fontWeight: FontWeight.w700,
                                              fontSize: 21,
                                              color: Color(0xff393432),
                                            ),
                                          ),
                                        ),
                                      ],
                                    ),
                                  ],
                                );
                          }
                        ),
    
    
                              const SizedBox(height: 10),
                              Row(
                                mainAxisAlignment: MainAxisAlignment.start,
                                children: const [
                                  Text("Add goals and affirmations.",
                                    style: TextStyle(
                                      fontSize: 15,
                                    ),),
                                ],
                              ),
                              const SizedBox(height: 10),
                              StatefulBuilder(
                              builder: (BuildContext context, StateSetter setState) {
                                return Column(
                                  children: [
                                    Card(
                                        elevation: 0,
                                        color: const Color(0xffEFEFEF),
                                        child: Padding(
                                          padding: const EdgeInsets.all(10.0),
                                          child: TextFormField(
                                            key: _formKey,
                                            controller: _goalsController,
                                            maxLines: 8,
                                            decoration: const InputDecoration(border: InputBorder.none),
                                          ),
                                        )
                                    ),
                                    const SizedBox(height: 10),
                                    Row(
                                      children: [
                                        Container(
                                          width: 50.w,
                                          margin: const EdgeInsets.fromLTRB(0, 0, 0, 40),
                                          child: OutlinedButton(
    
                                            onPressed: () async{
                                              setState(() {
                                                saveGoalsButtonText = "SAVED!";
                                              });
                                              Future.delayed(const Duration(seconds: 1), () {
                                                setState(() {
                                                  saveGoalsButtonText = "SAVE GOALS";
                                                });
                                              });
                                              SharedPreferences prefs = await SharedPreferences.getInstance();
                                              setState(() {
                                                goals = _goalsController.text;
                                                prefs.setString('goals', goals);
                                              });
    
                                              //Navigator.pushReplacementNamed(context, '/masterclasses');
                                            },
                                            style: OutlinedButton.styleFrom(
                                              primary: const Color(0xffE4BCB4),
                                              shape: RoundedRectangleBorder(
                                                borderRadius: BorderRadius.circular(18.0),
                                              ),
                                              side: const BorderSide(width: 3, color: Color(0xffE4BCB4)),
                                            ),
    
                                            child: Text(
                                                saveGoalsButtonText,
                                                style: const TextStyle(
                                                  color: Color(0xff393432),
                                                  fontSize: 14,
                                                  fontWeight: FontWeight.w700,
                                                )
                                            ),
                                          ),
                                        ),
                                      ],
                                    ),
                                  ],
                                );
                              }
                              ),
    
                            ],
                          ),
                        ),
                      ),
                    ),
                  ),
                ),
            ),
          );
      }
        );
      }
    }
Roland Iordache
  • 325
  • 4
  • 20
  • you could try to use keys and more granular StatefulWidgets, so not every action in your page triggers a complete rebuild. – scrimau Mar 16 '22 at 08:56
  • I used for most of the widgets, but when I remove an item from Grid View, I need to remove it from the screen of course, and the grid view is rebuilding. Also, I read that it doesn't matter how many times I rebuild, the screen needs to stay immutable, without blinking or changes I don't want. – Roland Iordache Mar 16 '22 at 08:59
  • For example, the items you return in one GridView are `AnimationConfiguration.staggeredGrid`, these items dont have keys. And youre using StatefulBuilder all over the place. You could try to capsulate those into classes extending StatefulWidget or StatelessWidget and also create them with a key argument, which can help flutter to reuse old state in the GridView. You can look at Flutter performance and rebuild stats to make further analysis. But yeah, blinking is often caused by rebuilds and build performance. – scrimau Mar 16 '22 at 09:04
  • Use 'StreamBuilder' –  Mar 23 '22 at 05:16

0 Answers0