Using flutter, my CircleAvatar with a MemoryImage flickers every time I reload a ListView - flutter

I am rendering a base64 image using MemoryImage in a CircleAvatar's backgroundImage property and reloading a ListView every so often and every time the ListView reloads, a very obvious flicker in the image appears, starting out as a blue circle then turning into the appropriate image. I was wondering how to get rid of the flickering.
Here is a complete example:
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Image Flickering Example',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Image Flickering Example'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String img = "\/9j\/4QBqRXhpZgAATU0AKgAAAAgABAEAAAQAAAABAAAASwEBAAQAAAABAAAAZIdpAAQAAAABAAAAPgESAAMAAAABAAAAAAAAAAAAAZIIAAQAAAABAAAAAAAAAAAAAQESAAMAAAABAAAAAAAAAAD\/4AAQSkZJRgABAQAAAQABAAD\/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH\/2wBDAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH\/wAARCABkAEsDASIAAhEBAxEB\/8QAHgAAAgIDAQEBAQAAAAAAAAAABwgGCQAEBQMBAgr\/xAAvEAACAgICAQMEAgICAQUAAAABAgMEBREGEiEABxMUIjFBFTIII1FhQglDUnGB\/8QAGwEAAwEAAwEAAAAAAAAAAAAAAwQFAgABBgf\/xAAyEQABAwIEAwYFBAMAAAAAAAABAhEhAzEAEkFRBGFxEyIygZHBBUKhsfAUI9HhM1Ky\/9oADAMBAAIRAxEAPwCjBtBYRvYL9XJbwAIJ2UDx+RJrydAdfHkD17xwkSoo8LMG8EeNfE7aBP7BUfbo\/nYI3v17pGrdgQCVL\/sEAqQqkbXaD7wNq2m+4a879fYtxypJ\/YRElST42wI1rWvKuP8AnySe2j4+OFXlEegILSLx9jfH1wAxzy+ja20j6F3BxtPTVk7KQv3KgHUje10y9RohQeuyBrR8NrR9c2xUaWJ1ZVOtjZJLaIYgDQ2QewGzs7\/78eu7E6sVOv7mRyDodGArneurAb0Rsga22\/2B6QwFgyeSJGKk62RtguzrWiOq6\/WgdkDQ9ZTUII1ZuvPZ9fW+NsGIZh06F+f9YC3IaNmoVmgdowVLSdVDJsKsn3IVK7kKBWcBJVj2qSRkdvQ1jls3bLRTqoEZA2jN9zFIwW6EExEsZPt7ynWgZPJUsvmcOtqKaIRg9xKqgDRUsoVeu\/7aB6\/sKQvjW29BKngb9rOPiKlV7GRsWBBBWRV7PJrsCzOVjSJYx8sk8hSOKFTLLJHErutClVSpBcgMNWi2ssBPTrheohlJZ2J9eRG8acsa9evohPI1rQGjtQ2taGifwAoII8gkkaBZn279l7GWEeS5XDax1JZIfpsOR9PctohMksl+Q\/76NVgDGYEEeRlDTzLLRWKvLZk\/t17WUMAYcnm46+RzcUyTVtGWWljFiYrE8SdYhPa7uJ5LUqEV5EjWqIjG1uywVQMNAd3ILF1Dg\/J1G1A7gdvkDa0Ci\/7NM4Xq3qdxPFmU0zP+20\/L\/Ju3R2qdGxUH2T\/O55er2xIcZThqww1KcEVaCCKOOCCvFHDWhjiTQhhjQKsUSwiJVSIKiDSgkgIJMK5QdfvBBOwIWlAOySO\/xyb0dgr3JQ7Q6K6H4xNKDqDP0lBRgUaPcZidCyM6MB9jGIq7lkhKyMhVyJNzwQyaHWLqugVBWyp0fI8R2okGx5+yNR58b\/sZalgXckz66vhkBobbR9tByv6Q81ax7+cHWwsM+9DyS0tZR\/Zta6hxvQJ\/H9d72kj2idfywlKjt4OiFA\/48aAA8nz9p\/G\/scbCZ1by6rCxUn+xLzAg+Ng94ydEE\/snfn17iMrJGUA0I5yBoH\/3k672P23YedN+vIbXqsoEkQRD8nYnzLN6bNhQWFz+Ny9uj42BAWZF\/R7BWP2nZCaJP414\/Q\/ZA8gAetS1UMzwx2YJJ4CxkiWaMyx77dS6bZ4+xUhSy9SQ2iV362o1Uoq6JYspVlX8faCv5OgT+vBG+x8gH0pnJO8XMeTyIxWQZeCRZEJV0aPFYsBlZSGRkZewcEEFQVOtD0XheG\/VKqIC+zKaZUDlzOcyUt4gw715tbAeJ4gcOlCsmcKXlIzZSBlKn8J2Ibnexw30cPbs\/cAgkEaB89tHf5\/AAOifAPYnfkSLA0qdN7FivWrRWpldpbCwxpPMsURKLJMFWZ1jCt8aFyiglgAWZvSpca5byukUWG99ZVj7Ax5FPqU2xDaEvdLTsugQpsfEikdl0qL6JXGveGrdqwy5PE2KpswwuJKk8dtY\/q40LNKJFqOqQdjITGJ3kAbrGzajbFf4dxlMKyAVEjxGkWLQwyHKok7JBtjujxvDrAzE01F2CxEBLkKDhpEnLdmw1GNswMxicGNhFov48Ru7qraKN9w6Oe0yskaqVClRskjGwQSFCHQFysqmII8krvHtS7kOIxKI2iX5B8f9VV4mGlBHF+U4HJ2pHo5erM9mhX61ZJBDcWKObIxSTfR2DHZXT6Uv8YVuu0YowPos4iNYJhJG\/VZkkEpAVwT8TQqCpDCUlQpX\/X47jQHyMTFqlaCQoKSRcEFKp3CmLu+2r4pUyhQCkKCgYzAhQ01D9d2wYMTCvcGFPk6diXGwiECYM8krEkaeP4pVRZJ4JJOxTqxcEtK5ZEPeNftXx8PbWgB5KxOuzrZ0xAJIGtaAswOVkh0bMImjj+Nu8PQTvtoxpkkZY267Lltqo7yIEVT2cwVOQ4D6aHU9ZQE0FnmWvMApIAkhmnWVWAA+51BkGpNacelu2SdRpc9NC3QeWC5TEbWHoP65tuMVXnHsru2v7xqCfP5R5X\/BJ\/Jm2T\/bXjyOututjRK6qVLHbqR2AHliF0BrWyp8aG1+\/a+AZDHAJXmVUCrFKI\/6nW3r1pQNeDsqTokqB31o6Prr43Hq8s3XeglZgSu238swYhSQOq9xo6OyxPYBtD0qg8EbfaPpiQFERp+cxiLpjG6johOvIXYBPX5ADvYPgozD8nx+TvXpS+QYmxHyjOS3opK0dvLFa5mQwi2xpQaWsW+yUmOCRmEZYgRSABTG5jfL+PVC7a0FgRAGUr1Je03nwwY+CQCwBJ0d7LFG7TPDyDK2Fd1JytiVXQsjxlCqB0ZepVk6eWUht78ltH0\/8LSrtauVv8WoM95BgvBJ3BZt5CfHkGlTef3H6dxQPVn32fn0cPVXvHX69UJAjH6BOj1152XHnydljons\/ricOxjWcbiJWBWA4+gZCANyD6eAsiBiPu8n7vwNa0RseiLgKVuxaNnskgd0aazYhhtSSMqL0VZbEcrfJ16\/erAogXzoRhtTgpju8e42giSF4MZj5ZxEzLLahkpR6jf52sRRxIZVdDWiieOSGFZWeNpEmrFKu93RLCC7Fi9wnUQQ8ziaGdPeMBbAgDWmGEm\/k1nONbJY8xcsmrRRq0Q41gJo1QDTizlOTRqqKoOwy1lC6H3Aa2TsejJVzPKOK2uMRV81ZeLK1srkJIrEn8hAseMsYOJIVWwsjRKBkHjspVaKXbuiv3jhkHMx+Lxbc6nhsG\/WnfhvHJ6cbpWvL8cmb5eawMqjGsrv1yMhYxzCOL6aNO7ysIZweNzXuRcJitTVmmhw\/LUiwsEs73bItX+CPft1bFiKrQfFYhoUNxfmr5R\/r45KeNn+aU11atGlVypq0gtOWUqQFjwxICh4gC4Li5IZ8Fp1KlPvU1lJzGUqKXAXq7FwCYaS4GHD9qsbkuYcfFy\/BBFkVsISKizLFYqSMr1LfSUyfGJtzxhVmlDiFbKPGs8UUZZk9sbBcnrOQQpBUN1KlQV0ew2Na8gAH8gaPqY\/4scTyE2LzCzRVfgxwx1eNVsU7EzrNFLYpbjhtz2YFrRSTwJ8levXfqKtd5LOOvRV3Hj4MAupEZ27P5WJ1AXu3SMAxsdRJ1j3vz03ob0PF8bwVMcTVTSSAgKSUhLkB0pUQJs5s8CNgL\/D8arskdorvMxJuWUQC25Ac7ktYlqGY6Gu7oCRLMQ+wy7MapCQN6BIEagkggAa2D4HUr0nRh1GjIkYb9\/aGDgDXTe1UaH5HZh+B56FGAtVJKkMbWQJJIJAF+1GhKkAHaxAgH8KGA8L4kVSnG8so6qBHMsKqfAA+NZQOwZeoCud7JJY\/wDaj1cV9BF+mrPrqIe5dsL44clOT4mYA6+BHJ0rdTt+wB8hgr6J2Rr8eD+EMFP62\/ekPlP5G+JHA2C0duZOib39w1o7\/qF2QR1DWcV6ETpD2iDKA6SqVBDKzS9QVKgEbBjbRP586Oz61pfbTgmVVlyfDOMZEyCuGN3B420W7Aqe4lrOWKjRBb7RobP3AFjhOJHDLWpSCrMnLBAIkF2IP51gHEUTWQEhQSys0i8NcW9DhIuLCOCSKiwEcTHUDb0EZidoA2x\/tP40SWlJHV2lJEa9taD\/AMHxe91HWLDYeRVk7FZm+grF0kXa9omG1lAA77ZNnb6scwPtX7c0qlSCrwjjFSIfGBFUwuPqDtKds4SvWi32Ys7EAMxdnYj8mb4L2a9tpJGqjiOMirR0qa1atRZqcUCxzWY1jrRU5YViT4kjhRFQKEjjVSpQD04r4ogAtRqSQ8p0ZupJMnUvGFBwK3BK0hgoADNJJTrDeEvGvIDFfmQT+R9xZ56gZPl4Pwv4yOymOdeRe4SyjuAD2gZQWZAPwJE2CGDCy4\/G2eN8fv8AwxNyLGZRsXDdRFjvdcpA122tdoWEscd58Lj5m6gblxkSJ2+lVvTYQ\/4x+0WZuULVnjN+rrH2op5MVy7mWClnMdyvPTWe3h8\/RnnjhMl34YJZpokNuVQihtA48X\/xt9rTj8dE\/HLUuQrQ17NZpeR8llRcqcRdqpZmSfLyLM0ZvWY1Myy\/GJ32O2mUZ+I0jl\/brBrMEm4a+cO4O2O1cKsfMiS4lW4JgJNvzbEk\/wAPIKWQxGfoWmRcrYp4yS1WBYOywC\/WtyIUAVVH1ePAMe0SScLG7Ort6fM4WFOquIUYJH2Vinbt0Ukn\/Z\/5H7h\/0R4H49Cv2o9t\/bPgeSmu8auY7H5F4Y4MxBZz8luxFjZIZvjrNVt3pPpWkysVCyliWETv1atG6pK0ZaiPAYu7FDbeBJzYhhlEzfODIrxqUY9J1XynX8KN\/k7OyZtbLWqrqhKhnKYUA8BI3OgS0xEPjOYoAS7tzIElwLCZ29cfy\/QxRJXhYlVV4jIBoEN8r\/IrEa0C\/wAmzrYHcN+l9fuXKUKVmx8k6BGnXyWQgFYYE8E61pgT+QpI156gkW5TlTUqNetG6vLXopCzdgNvDWVS35\/O1P8AbRYk7H7IevcjuX2mmksPvbugVz16\/JKAAR12Nr4bwp0NliPDIQVdPu7EDXf662w+FgACS341xZ28o5NZJ7kYOlIzfJHIAdMB\/wDEV4dFjpVJ+QOWPna6P2kn1EOQe9t9j8fHq1Ybigje7NqWWGaVlhSWKEdoTJV38wEwmSWR0R4lRH+RU7Fy5kLseNq2EFi0SEaaSRYwRC7kM8KSOftjYApE47ggjX3CRYjA53G05\/maveDutiR1tQwOrJ9GDDBFPKHswkRzETt8RLCNGhUSO0ZE0EAAqLQAxLPYaNf8vjOckskWgmIgOAJJn+7RZB7E5CpnuO4yHMGDIW7L2pr0mSVbbNPLkbQX4o5hIlavFXSusVaFIq8Ji3DCvjTCYK3Q\/l7uMFatAKebuVojWjgRPpILDxiEiNAoEQQR\/r7lYNpwR6pJ5\/708y4dxaTHcXyNjjxjjhhku1kmp3rKSZKN7aC6rQ264Isz1RYx08MxjVZILaEq4Yf\/ABX988fxXFRxZCvPkMDkY1uz1qCwrkMTl1iWG01MTWIo7VS1KsSzQ2LcLCD4LlYpZWxWyXKnCEIFR4XCQLadA2wsw3xqnUFRa0CV00glOpcsWkTyZ5iHxa9l50xeUheCUxRWbEKoQraTcfRvA8IHZdknYJIPkEgmHjUoTkcaraZ1zODTkvxQo0cFeR5W4y9QH5XVws3FZLsJCRxxHKzQJBGIGms165T\/ACh4xlOTTcexdENJRkoLTvXJJJo7UU0EM3zmpD9NPUdbLWagSy5cLXW2Y\/p7UXol8t557lUuGWPcbhXI6lHM8RqyWeQUr1bDpj5PbqpDmMrmJUgy1eSvG\/H7065yxK1+pdmxFfORd7mTjw+NsAFFQKXhyGeLkH7GBd9scLlJFiAUknQulnueuxd8OT71e+3Hv8e\/avk\/unn8dmOQ08FUrVqmEwz1ocjkMlmblbFY6L552VKVCK9chly1\/wCG3Lj8THcux0MhLFHTsKrhf\/XB4dBiqMU3sJZmljgVXkf3JrxOzAn+6DghAcf1ZtkyMDISSx9CPD+8t\/3PxiY33lxuG5BhJkIOOyGIxMuBvKkgld7mFsoKVgosfWNp1ZIt7jQq05lWz3R\/wo9p+a895Fyvh3ubS9u+PZ2xVyFPhuF4HjMtiMLYlx9QZVMbat+5mGeGldyy3slWxkGJxuPwkVxcNi6VfGUKkSt0xSYpWCC7hTBQIgWOZjciPO+BHhhBqUhVgN3qiWcjVCkuCDYy48grWbzCzfKquTp3VmDfpiygjQA\/8XBIHgg\/g61DjJJ9N0HYljYC6BMjO1uUhFXXZm\/2D7OvnR87C9mhq8Z4XSmaX+OoySFPjZbLyZGLqzq5PxZCexXEg6L8ciIsgAZFfUkhMmq2+O4uD4K8+OpQRtsVqsaQVlaRmaRlSuojEjHuzhQoZm7FmJ36B2w0QpVrx9gfeCza42aaj8wEFyATtzDe2F09vfaLnvM+VQvVxgxNLHSXHvZHkRmxUEbjF5y5UhhgavJkrrWVxs9aJ6NCzXr3bOOrXJqr5OgJyrzPiOd9ueQvxjkiVlvxV4bSyUpJbOPuV5mnjSxj8g0MVTJVTLXmgF3HtYovPDPBHZeWvMsZExHvF7d8bzceJyXI46tjK1yar2KOX+jf6YWJJA+TOPGKgaIK6uli7FJ8k1SMLJJdgQz\/AJ5dwnvAuFyWJKS4XE8fg47Uy717MEtizDYuZC9dxrZHHVZkigu3Wx4mp\/V0bbY9m+pmgmlqxkK6oSmrUQE0FABKRTWC7kP2hXlU5CoCExEsSRoyZ1UkqdSXJOdJB7qT4AnMky0qVoWnC5UYMVIjJeweBztayGis0c7hqGWpzRuv3xSQ3IJl+9H6lWR1ZOwKEd\/UgrcM9qrKWWp4e37eZK21+VLfF5+mGXI2khFSZ8JZWxjq2Noyxlv4nBx8cgswT2a7zxuKdqlq5riue4tN9RDG+TwnZmFmBJHtU4UriZpMlEkYWJIyJw1yIPWaKATTLTNiGudyjYSwi9WXTbJ\/Y3oEnR1sn9D\/AIBIBBHrvMCHQs5TMKLWEFNgRzD7bkoJQoKYZhqwduSr\/UjliV4r2WlyfIeOtjc7x3I0JbUtTL8huSS4bJQYiPD5S7H82LaHKQ2zNyj+Oq1qkeXlSvUuZTJtPVd5KFixHhXEFxbUL13O25Wgr1dVcIwoUjMjPPKJbwaxdtRrOY5KtqucVOFiVpFYSNClbVea3Tk+WhZlqOCDqOQiNmDb++NiV8\/jYUMfOiNnZ\/8Abn3Cyis1ezkZqVmIJIgjeR4LYUnZ+N+8QMble8c3dSj7USAuEGsrIDkEDyN\/MC7QNMaK85JcgqbQDQDQCYdyxJJPIN6\/s77XW8RNhp+IcRzFAV8fUxuH5rxLB8xwGPjx8lZq5kr5OoudyEiRV06yXuSSypbWO6WZ4liYrxzWMdFBRxPE+ISUK0EEUDLmLnHkBEKGaOLDQcXz0VCCKwZYoI1y1wvCkcztE8jQRBziPKL+TqTST9ZTXeMCVQqySqwkfbxr1Qsg6gGMRBl13BbbNMVzcRUFp2U\/sNHIp\/8A1SARsefP\/wB+gmq8EqMks77TMTyfrbGCk6h7Bw7xazFhzi++KeEw1Sw8aymdhIoY\/wC38GTZbqCpAA148eCSfLeRJMXw7BWJGaeq0xVo1X5HDgBye2gykDYUDwNePWes9cUSASCQdxBvguoGjGNNMTWrhcRQjT6TG0oT8qqGWtEXG0LkiRlZyew35YgbJA2FKySKVukRbTjbp0bfXSl1B+0q2+sYUjt1KkggggDPWegkk3JPXHBr19hgdcv5jmcdi8nYpNWrtVgssojg0JDEjshlk7\/OSCo20csbkkt276YBDimcv35pJbDoWmt2HYBToF2V2692cjzIQNklVVQpAB3nrPTFDXz9sYqaeftgqQsQSPHgjzr87dD5A0PBOxoDyBvevUqwjtDfoMh0Szg\/rwAT+tfnQB3+gPWes9GX4T5fcYxTunp7Ycjg2TtUq9AQMoFh7IlDLsMIkg6+AR+jpt7B9GCWJGctojsEYgE6BZFJA3s6G\/GyTr8k+s9Z6Rwyq\/r\/ANHH\/9k=";
Widget body = Text("...");
void _updateListView() {
Widget listView = ListView.builder(
itemCount: 1,
itemBuilder: (BuildContext context, int index){
return Card(
child: CircleAvatar(
backgroundImage: MemoryImage(base64Decode(img)),
),
);
},
);
setState(() {
body = listView;
});
}
Timer listRefreshTimer;
void listRefresher(){
const oneSec = const Duration(seconds: 1);
listRefreshTimer = new Timer.periodic(oneSec,(Timer t){
_updateListView();
});
}
#override
void initState() {
// TODO: implement initState
super.initState();
listRefresher();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body:body
);
}
}

Move the result of the decoding into a variable, so it won't be re-run on every state update:
class _MyHomePageState extends State<MyHomePage> {
final img = base64Decode("\/9j\/4QBqRXhpZgAATU0AKgAAAAgABAEAAAQAAAABAAAASwEBAAQAAAABAAAAZIdpAAQAAAABAAAAPgESAAMAAAABAAAAAAAAAAAAAZIIAAQAAAABAAAAAAAAAAAAAQESAAMAAAABAAAAAAAAAAD\/4AAQSkZJRgABAQAAAQABAAD\/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH\/2wBDAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH\/wAARCABkAEsDASIAAhEBAxEB\/8QAHgAAAgIDAQEBAQAAAAAAAAAABwgGCQAEBQMBAgr\/xAAvEAACAgICAQMEAgICAQUAAAABAgMEBREGEiEABxMUIjFBFTIII1FhQglDUnGB\/8QAGwEAAwEAAwEAAAAAAAAAAAAAAwQFAgABBgf\/xAAyEQABAwIEAwYFBAMAAAAAAAABAhEhAzEAEkFRBGFxEyIygZHBBUKhsfAUI9HhM1Ky\/9oADAMBAAIRAxEAPwCjBtBYRvYL9XJbwAIJ2UDx+RJrydAdfHkD17xwkSoo8LMG8EeNfE7aBP7BUfbo\/nYI3v17pGrdgQCVL\/sEAqQqkbXaD7wNq2m+4a879fYtxypJ\/YRElST42wI1rWvKuP8AnySe2j4+OFXlEegILSLx9jfH1wAxzy+ja20j6F3BxtPTVk7KQv3KgHUje10y9RohQeuyBrR8NrR9c2xUaWJ1ZVOtjZJLaIYgDQ2QewGzs7\/78eu7E6sVOv7mRyDodGArneurAb0Rsga22\/2B6QwFgyeSJGKk62RtguzrWiOq6\/WgdkDQ9ZTUII1ZuvPZ9fW+NsGIZh06F+f9YC3IaNmoVmgdowVLSdVDJsKsn3IVK7kKBWcBJVj2qSRkdvQ1jls3bLRTqoEZA2jN9zFIwW6EExEsZPt7ynWgZPJUsvmcOtqKaIRg9xKqgDRUsoVeu\/7aB6\/sKQvjW29BKngb9rOPiKlV7GRsWBBBWRV7PJrsCzOVjSJYx8sk8hSOKFTLLJHErutClVSpBcgMNWi2ssBPTrheohlJZ2J9eRG8acsa9evohPI1rQGjtQ2taGifwAoII8gkkaBZn279l7GWEeS5XDax1JZIfpsOR9PctohMksl+Q\/76NVgDGYEEeRlDTzLLRWKvLZk\/t17WUMAYcnm46+RzcUyTVtGWWljFiYrE8SdYhPa7uJ5LUqEV5EjWqIjG1uywVQMNAd3ILF1Dg\/J1G1A7gdvkDa0Ci\/7NM4Xq3qdxPFmU0zP+20\/L\/Ju3R2qdGxUH2T\/O55er2xIcZThqww1KcEVaCCKOOCCvFHDWhjiTQhhjQKsUSwiJVSIKiDSgkgIJMK5QdfvBBOwIWlAOySO\/xyb0dgr3JQ7Q6K6H4xNKDqDP0lBRgUaPcZidCyM6MB9jGIq7lkhKyMhVyJNzwQyaHWLqugVBWyp0fI8R2okGx5+yNR58b\/sZalgXckz66vhkBobbR9tByv6Q81ax7+cHWwsM+9DyS0tZR\/Zta6hxvQJ\/H9d72kj2idfywlKjt4OiFA\/48aAA8nz9p\/G\/scbCZ1by6rCxUn+xLzAg+Ng94ydEE\/snfn17iMrJGUA0I5yBoH\/3k672P23YedN+vIbXqsoEkQRD8nYnzLN6bNhQWFz+Ny9uj42BAWZF\/R7BWP2nZCaJP414\/Q\/ZA8gAetS1UMzwx2YJJ4CxkiWaMyx77dS6bZ4+xUhSy9SQ2iV362o1Uoq6JYspVlX8faCv5OgT+vBG+x8gH0pnJO8XMeTyIxWQZeCRZEJV0aPFYsBlZSGRkZewcEEFQVOtD0XheG\/VKqIC+zKaZUDlzOcyUt4gw715tbAeJ4gcOlCsmcKXlIzZSBlKn8J2Ibnexw30cPbs\/cAgkEaB89tHf5\/AAOifAPYnfkSLA0qdN7FivWrRWpldpbCwxpPMsURKLJMFWZ1jCt8aFyiglgAWZvSpca5byukUWG99ZVj7Ax5FPqU2xDaEvdLTsugQpsfEikdl0qL6JXGveGrdqwy5PE2KpswwuJKk8dtY\/q40LNKJFqOqQdjITGJ3kAbrGzajbFf4dxlMKyAVEjxGkWLQwyHKok7JBtjujxvDrAzE01F2CxEBLkKDhpEnLdmw1GNswMxicGNhFov48Ru7qraKN9w6Oe0yskaqVClRskjGwQSFCHQFysqmII8krvHtS7kOIxKI2iX5B8f9VV4mGlBHF+U4HJ2pHo5erM9mhX61ZJBDcWKObIxSTfR2DHZXT6Uv8YVuu0YowPos4iNYJhJG\/VZkkEpAVwT8TQqCpDCUlQpX\/X47jQHyMTFqlaCQoKSRcEFKp3CmLu+2r4pUyhQCkKCgYzAhQ01D9d2wYMTCvcGFPk6diXGwiECYM8krEkaeP4pVRZJ4JJOxTqxcEtK5ZEPeNftXx8PbWgB5KxOuzrZ0xAJIGtaAswOVkh0bMImjj+Nu8PQTvtoxpkkZY267Lltqo7yIEVT2cwVOQ4D6aHU9ZQE0FnmWvMApIAkhmnWVWAA+51BkGpNacelu2SdRpc9NC3QeWC5TEbWHoP65tuMVXnHsru2v7xqCfP5R5X\/BJ\/Jm2T\/bXjyOututjRK6qVLHbqR2AHliF0BrWyp8aG1+\/a+AZDHAJXmVUCrFKI\/6nW3r1pQNeDsqTokqB31o6Prr43Hq8s3XeglZgSu238swYhSQOq9xo6OyxPYBtD0qg8EbfaPpiQFERp+cxiLpjG6johOvIXYBPX5ADvYPgozD8nx+TvXpS+QYmxHyjOS3opK0dvLFa5mQwi2xpQaWsW+yUmOCRmEZYgRSABTG5jfL+PVC7a0FgRAGUr1Je03nwwY+CQCwBJ0d7LFG7TPDyDK2Fd1JytiVXQsjxlCqB0ZepVk6eWUht78ltH0\/8LSrtauVv8WoM95BgvBJ3BZt5CfHkGlTef3H6dxQPVn32fn0cPVXvHX69UJAjH6BOj1152XHnydljons\/ricOxjWcbiJWBWA4+gZCANyD6eAsiBiPu8n7vwNa0RseiLgKVuxaNnskgd0aazYhhtSSMqL0VZbEcrfJ16\/erAogXzoRhtTgpju8e42giSF4MZj5ZxEzLLahkpR6jf52sRRxIZVdDWiieOSGFZWeNpEmrFKu93RLCC7Fi9wnUQQ8ziaGdPeMBbAgDWmGEm\/k1nONbJY8xcsmrRRq0Q41gJo1QDTizlOTRqqKoOwy1lC6H3Aa2TsejJVzPKOK2uMRV81ZeLK1srkJIrEn8hAseMsYOJIVWwsjRKBkHjspVaKXbuiv3jhkHMx+Lxbc6nhsG\/WnfhvHJ6cbpWvL8cmb5eawMqjGsrv1yMhYxzCOL6aNO7ysIZweNzXuRcJitTVmmhw\/LUiwsEs73bItX+CPft1bFiKrQfFYhoUNxfmr5R\/r45KeNn+aU11atGlVypq0gtOWUqQFjwxICh4gC4Li5IZ8Fp1KlPvU1lJzGUqKXAXq7FwCYaS4GHD9qsbkuYcfFy\/BBFkVsISKizLFYqSMr1LfSUyfGJtzxhVmlDiFbKPGs8UUZZk9sbBcnrOQQpBUN1KlQV0ew2Na8gAH8gaPqY\/4scTyE2LzCzRVfgxwx1eNVsU7EzrNFLYpbjhtz2YFrRSTwJ8levXfqKtd5LOOvRV3Hj4MAupEZ27P5WJ1AXu3SMAxsdRJ1j3vz03ob0PF8bwVMcTVTSSAgKSUhLkB0pUQJs5s8CNgL\/D8arskdorvMxJuWUQC25Ac7ktYlqGY6Gu7oCRLMQ+wy7MapCQN6BIEagkggAa2D4HUr0nRh1GjIkYb9\/aGDgDXTe1UaH5HZh+B56FGAtVJKkMbWQJJIJAF+1GhKkAHaxAgH8KGA8L4kVSnG8so6qBHMsKqfAA+NZQOwZeoCud7JJY\/wDaj1cV9BF+mrPrqIe5dsL44clOT4mYA6+BHJ0rdTt+wB8hgr6J2Rr8eD+EMFP62\/ekPlP5G+JHA2C0duZOib39w1o7\/qF2QR1DWcV6ETpD2iDKA6SqVBDKzS9QVKgEbBjbRP586Oz61pfbTgmVVlyfDOMZEyCuGN3B420W7Aqe4lrOWKjRBb7RobP3AFjhOJHDLWpSCrMnLBAIkF2IP51gHEUTWQEhQSys0i8NcW9DhIuLCOCSKiwEcTHUDb0EZidoA2x\/tP40SWlJHV2lJEa9taD\/AMHxe91HWLDYeRVk7FZm+grF0kXa9omG1lAA77ZNnb6scwPtX7c0qlSCrwjjFSIfGBFUwuPqDtKds4SvWi32Ys7EAMxdnYj8mb4L2a9tpJGqjiOMirR0qa1atRZqcUCxzWY1jrRU5YViT4kjhRFQKEjjVSpQD04r4ogAtRqSQ8p0ZupJMnUvGFBwK3BK0hgoADNJJTrDeEvGvIDFfmQT+R9xZ56gZPl4Pwv4yOymOdeRe4SyjuAD2gZQWZAPwJE2CGDCy4\/G2eN8fv8AwxNyLGZRsXDdRFjvdcpA122tdoWEscd58Lj5m6gblxkSJ2+lVvTYQ\/4x+0WZuULVnjN+rrH2op5MVy7mWClnMdyvPTWe3h8\/RnnjhMl34YJZpokNuVQihtA48X\/xt9rTj8dE\/HLUuQrQ17NZpeR8llRcqcRdqpZmSfLyLM0ZvWY1Myy\/GJ32O2mUZ+I0jl\/brBrMEm4a+cO4O2O1cKsfMiS4lW4JgJNvzbEk\/wAPIKWQxGfoWmRcrYp4yS1WBYOywC\/WtyIUAVVH1ePAMe0SScLG7Ort6fM4WFOquIUYJH2Vinbt0Ukn\/Z\/5H7h\/0R4H49Cv2o9t\/bPgeSmu8auY7H5F4Y4MxBZz8luxFjZIZvjrNVt3pPpWkysVCyliWETv1atG6pK0ZaiPAYu7FDbeBJzYhhlEzfODIrxqUY9J1XynX8KN\/k7OyZtbLWqrqhKhnKYUA8BI3OgS0xEPjOYoAS7tzIElwLCZ29cfy\/QxRJXhYlVV4jIBoEN8r\/IrEa0C\/wAmzrYHcN+l9fuXKUKVmx8k6BGnXyWQgFYYE8E61pgT+QpI156gkW5TlTUqNetG6vLXopCzdgNvDWVS35\/O1P8AbRYk7H7IevcjuX2mmksPvbugVz16\/JKAAR12Nr4bwp0NliPDIQVdPu7EDXf662w+FgACS341xZ28o5NZJ7kYOlIzfJHIAdMB\/wDEV4dFjpVJ+QOWPna6P2kn1EOQe9t9j8fHq1Ybigje7NqWWGaVlhSWKEdoTJV38wEwmSWR0R4lRH+RU7Fy5kLseNq2EFi0SEaaSRYwRC7kM8KSOftjYApE47ggjX3CRYjA53G05\/maveDutiR1tQwOrJ9GDDBFPKHswkRzETt8RLCNGhUSO0ZE0EAAqLQAxLPYaNf8vjOckskWgmIgOAJJn+7RZB7E5CpnuO4yHMGDIW7L2pr0mSVbbNPLkbQX4o5hIlavFXSusVaFIq8Ji3DCvjTCYK3Q\/l7uMFatAKebuVojWjgRPpILDxiEiNAoEQQR\/r7lYNpwR6pJ5\/708y4dxaTHcXyNjjxjjhhku1kmp3rKSZKN7aC6rQ264Isz1RYx08MxjVZILaEq4Yf\/ABX988fxXFRxZCvPkMDkY1uz1qCwrkMTl1iWG01MTWIo7VS1KsSzQ2LcLCD4LlYpZWxWyXKnCEIFR4XCQLadA2wsw3xqnUFRa0CV00glOpcsWkTyZ5iHxa9l50xeUheCUxRWbEKoQraTcfRvA8IHZdknYJIPkEgmHjUoTkcaraZ1zODTkvxQo0cFeR5W4y9QH5XVws3FZLsJCRxxHKzQJBGIGms165T\/ACh4xlOTTcexdENJRkoLTvXJJJo7UU0EM3zmpD9NPUdbLWagSy5cLXW2Y\/p7UXol8t557lUuGWPcbhXI6lHM8RqyWeQUr1bDpj5PbqpDmMrmJUgy1eSvG\/H7065yxK1+pdmxFfORd7mTjw+NsAFFQKXhyGeLkH7GBd9scLlJFiAUknQulnueuxd8OT71e+3Hv8e\/avk\/unn8dmOQ08FUrVqmEwz1ocjkMlmblbFY6L552VKVCK9chly1\/wCG3Lj8THcux0MhLFHTsKrhf\/XB4dBiqMU3sJZmljgVXkf3JrxOzAn+6DghAcf1ZtkyMDISSx9CPD+8t\/3PxiY33lxuG5BhJkIOOyGIxMuBvKkgld7mFsoKVgosfWNp1ZIt7jQq05lWz3R\/wo9p+a895Fyvh3ubS9u+PZ2xVyFPhuF4HjMtiMLYlx9QZVMbat+5mGeGldyy3slWxkGJxuPwkVxcNi6VfGUKkSt0xSYpWCC7hTBQIgWOZjciPO+BHhhBqUhVgN3qiWcjVCkuCDYy48grWbzCzfKquTp3VmDfpiygjQA\/8XBIHgg\/g61DjJJ9N0HYljYC6BMjO1uUhFXXZm\/2D7OvnR87C9mhq8Z4XSmaX+OoySFPjZbLyZGLqzq5PxZCexXEg6L8ciIsgAZFfUkhMmq2+O4uD4K8+OpQRtsVqsaQVlaRmaRlSuojEjHuzhQoZm7FmJ36B2w0QpVrx9gfeCza42aaj8wEFyATtzDe2F09vfaLnvM+VQvVxgxNLHSXHvZHkRmxUEbjF5y5UhhgavJkrrWVxs9aJ6NCzXr3bOOrXJqr5OgJyrzPiOd9ueQvxjkiVlvxV4bSyUpJbOPuV5mnjSxj8g0MVTJVTLXmgF3HtYovPDPBHZeWvMsZExHvF7d8bzceJyXI46tjK1yar2KOX+jf6YWJJA+TOPGKgaIK6uli7FJ8k1SMLJJdgQz\/AJ5dwnvAuFyWJKS4XE8fg47Uy717MEtizDYuZC9dxrZHHVZkigu3Wx4mp\/V0bbY9m+pmgmlqxkK6oSmrUQE0FABKRTWC7kP2hXlU5CoCExEsSRoyZ1UkqdSXJOdJB7qT4AnMky0qVoWnC5UYMVIjJeweBztayGis0c7hqGWpzRuv3xSQ3IJl+9H6lWR1ZOwKEd\/UgrcM9qrKWWp4e37eZK21+VLfF5+mGXI2khFSZ8JZWxjq2Noyxlv4nBx8cgswT2a7zxuKdqlq5riue4tN9RDG+TwnZmFmBJHtU4UriZpMlEkYWJIyJw1yIPWaKATTLTNiGudyjYSwi9WXTbJ\/Y3oEnR1sn9D\/AIBIBBHrvMCHQs5TMKLWEFNgRzD7bkoJQoKYZhqwduSr\/UjliV4r2WlyfIeOtjc7x3I0JbUtTL8huSS4bJQYiPD5S7H82LaHKQ2zNyj+Oq1qkeXlSvUuZTJtPVd5KFixHhXEFxbUL13O25Wgr1dVcIwoUjMjPPKJbwaxdtRrOY5KtqucVOFiVpFYSNClbVea3Tk+WhZlqOCDqOQiNmDb++NiV8\/jYUMfOiNnZ\/8Abn3Cyis1ezkZqVmIJIgjeR4LYUnZ+N+8QMble8c3dSj7USAuEGsrIDkEDyN\/MC7QNMaK85JcgqbQDQDQCYdyxJJPIN6\/s77XW8RNhp+IcRzFAV8fUxuH5rxLB8xwGPjx8lZq5kr5OoudyEiRV06yXuSSypbWO6WZ4liYrxzWMdFBRxPE+ISUK0EEUDLmLnHkBEKGaOLDQcXz0VCCKwZYoI1y1wvCkcztE8jQRBziPKL+TqTST9ZTXeMCVQqySqwkfbxr1Qsg6gGMRBl13BbbNMVzcRUFp2U\/sNHIp\/8A1SARsefP\/wB+gmq8EqMks77TMTyfrbGCk6h7Bw7xazFhzi++KeEw1Sw8aymdhIoY\/wC38GTZbqCpAA148eCSfLeRJMXw7BWJGaeq0xVo1X5HDgBye2gykDYUDwNePWes9cUSASCQdxBvguoGjGNNMTWrhcRQjT6TG0oT8qqGWtEXG0LkiRlZyew35YgbJA2FKySKVukRbTjbp0bfXSl1B+0q2+sYUjt1KkggggDPWegkk3JPXHBr19hgdcv5jmcdi8nYpNWrtVgssojg0JDEjshlk7\/OSCo20csbkkt276YBDimcv35pJbDoWmt2HYBToF2V2692cjzIQNklVVQpAB3nrPTFDXz9sYqaeftgqQsQSPHgjzr87dD5A0PBOxoDyBvevUqwjtDfoMh0Szg\/rwAT+tfnQB3+gPWes9GX4T5fcYxTunp7Ycjg2TtUq9AQMoFh7IlDLsMIkg6+AR+jpt7B9GCWJGctojsEYgE6BZFJA3s6G\/GyTr8k+s9Z6Rwyq\/r\/ANHH\/9k=");
Widget body = Text("...");
void _updateListView() {
Widget listView = ListView.builder(
itemCount: 1,
itemBuilder: (BuildContext context, int index) {
return Card(
child: CircleAvatar(
maxRadius: 40,
backgroundImage: MemoryImage(img),

Don't use CircleAvatar. Switch to plain Image widget instead, and set gaplessPlayback to true.
Image.memory(
thumbData,
gaplessPlayback: true,
)

Related

How to fix hive box already open error in flutter?

I am trying to use hive to store data on a local machine using hive but each time when I compile the code it gives the error "The box "notebook" is already open and of type Box."
Can someone help me to resolve the issue as I am new to it? Thanks
I am just trying to add data to the database in this app without any change to the state of the app interface. I have tried to change the main method to void but no luck on this.
All the code is located in the main file
import 'package:flutter/material.dart';
import 'package:hive/hive.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'notes.dart';
import 'notesStoring.dart';
Future main() async{
WidgetsFlutterBinding.ensureInitialized();
await Hive.initFlutter();
Hive.registerAdapter(NotesAdapter());
await Hive.openBox<NotesAdapter>('noteBook');
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
#override
void dispose() {
Hive.close();
// TODO: implement dispose
super.dispose();
}
#override
Future incrementCounter(String title) async {
final notes = Notes()
..title = title;
final box =Boxes.getNotesValues();
box.add(notes);
}
final titleForNotes=TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body:
Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'You have pushed the button this many times:',
),
TextField(
controller: titleForNotes,
cursorColor: Colors.pink,
),
ValueListenableBuilder<Box<Notes>>(valueListenable: Boxes.getNotesValues().listenable(), builder: (context,box,_){
final noteBook =box.values.toList().cast<Notes>();
return buildContent(noteBook);
})
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: (){
incrementCounter(titleForNotes.text);
},
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
class Boxes {
static Box<Notes> getNotesValues()=>Hive.box<Notes>('noteBook');
}
Widget buildContent(List<Notes> noteBook){
return Column(
children: [
Expanded(child:
ListView.builder(
padding: EdgeInsets.all(8),
itemCount: noteBook.length,
itemBuilder: (BuildContext context, int index){
final notes= noteBook[index];
return buildTransaction(context, notes);
}
)
)
],
);
}
Widget buildTransaction(
BuildContext context,
Notes notes,
){
return Card(
color: Colors.green,
child: Text(notes.title),
);
}
1.You can open your notebook Box in the main method of your app:
Future<void> main() async {
...
final appDocumentDirectory = await
path_provider.getApplicationDocumentsDirectory();
Hive.init(appDocumentDirectory.path);
Hive.registerAdapter(UserAdapter());
// open the user box
await Hive.openBox('notebook');
_setUpLogging();
runApp(MultiProvider(providers: providers, child:
StartupApplication()));
}
2 Access the previously opened box like below:
class MyHomePage extends StatefulWidget {
const MyHomePage({Key key}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
// user box
Box notebookBox;
#override
void initState() {
super.initState();
// get the previously opened user box
notebookBox = Hive.box('notebook');
}
#override
Widget build(BuildContext context) {
// check for your conditions
return (notebookBox.values.isNotEmpty && notebookBox.get(0).active == 1)
? HomeView()
: Intro();
}
}

InteractiveViewer inside PageView

I'm creating a PageView with a list of images, and I want to add interactiveViewer to each image so it can be resized to view details.
here is what I wrote:
PageView.builder(
dragStartBehavior: DragStartBehavior.start,
physics: _viewing ? NeverScrollableScrollPhysics() : ClampingScrollPhysics(),
controller: _pageController,
itemBuilder: (context, index) {
return Container(
child: Expanded(
child: Image.network(widget.snapshotList[index].imgUrl),
)
);
},
onPageChanged: (index) {
setState(() {
this.position = index;
_transformationController.value = Matrix4.identity();
});
},
itemCount: widget.snapshotList.length,
)
But the two scrollables seem to compete with each other and the behavior is messy.
e.g. once the image is enlarged the scroll gesture also triggers page move,
seems that because the viewport is not enlarged with the image itself.
Any solutions? Thank you anyone out there.
In my case I want to create a simple swipe-able image gallery: swipe horizontally to go from image to image, and use pinch and zoom to zoom in and out. The problem is this: When I zoom in, I can't pan the enlarged image. Instead, the PageView takes over and pages to the next image.
I was able to work around it by using a TransformationController and listening to the onInteractionEnd event on the InteractiveViewer. In that callback, I check whether the image is zoomed in or not. If it's zoomed in, I deactivate paging in the PageView.
Here's a complete sample app that shows how you can implement it:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'InteractiveViewer inside PageView Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
final String title;
const MyHomePage({
Key? key,
required this.title,
}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final List<ImageProvider> _imageProviders = [
Image.network("https://picsum.photos/id/1001/5616/3744").image,
Image.network("https://picsum.photos/id/1003/1181/1772").image,
Image.network("https://picsum.photos/id/1004/5616/3744").image,
Image.network("https://picsum.photos/id/1005/5760/3840").image
];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: EasyImageViewPager(imageProviders: _imageProviders)
),
);
}
}
/// PageView for swiping through a list of images
class EasyImageViewPager extends StatefulWidget {
final List<ImageProvider> imageProviders;
/// Create new instance, using the [imageProviders] to populate the [PageView]
const EasyImageViewPager({ Key? key, required this.imageProviders }) : super(key: key);
#override
_EasyImageViewPagerState createState() => _EasyImageViewPagerState();
}
class _EasyImageViewPagerState extends State<EasyImageViewPager> {
final PageController _pageController = PageController();
bool _pagingEnabled = true;
#override
void dispose() {
_pageController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return PageView.builder(
physics: _pagingEnabled ? const PageScrollPhysics() : const NeverScrollableScrollPhysics(),
itemCount: widget.imageProviders.length,
controller: _pageController,
itemBuilder: (context, index) {
final image = widget.imageProviders[index];
return EasyImageView(
imageProvider: image,
onScaleChanged: (scale) {
setState(() {
// Disable paging when image is zoomed-in
_pagingEnabled = scale <= 1.0;
});
},
);
},
);
}
}
/// A full-sized view that displays the given image, supporting pinch & zoom
class EasyImageView extends StatefulWidget {
/// The image to display
final ImageProvider imageProvider;
/// Minimum scale factor
final double minScale;
/// Maximum scale factor
final double maxScale;
/// Callback for when the scale has changed, only invoked at the end of
/// an interaction.
final void Function(double)? onScaleChanged;
/// Create a new instance
const EasyImageView({
Key? key,
required this.imageProvider,
this.minScale = 1.0,
this.maxScale = 5.0,
this.onScaleChanged,
}) : super(key: key);
#override
_EasyImageViewState createState() => _EasyImageViewState();
}
class _EasyImageViewState extends State<EasyImageView> {
final TransformationController _transformationController = TransformationController();
#override
Widget build(BuildContext context) {
return SizedBox(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: InteractiveViewer(
transformationController: _transformationController,
minScale: widget.minScale,
maxScale: widget.maxScale,
child: Image(image: widget.imageProvider),
onInteractionEnd: (scaleEndDetails) {
double scale = _transformationController.value.getMaxScaleOnAxis();
if (widget.onScaleChanged != null) {
widget.onScaleChanged!(scale);
}
},
)
);
}
}

How to scroll the listview or perform any other operation when popupmenu entry appears?

I have created listView which contains 10 container.I trigger the _showCustomMenu() method while longpress the container to show popupmenu.
But could not scroll the listview when popup menu appears.I want to scroll the listview even when popupmenu appears.
This is my code:
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter/rendering.dart';
void main() => runApp(MyApp());
///
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Popup Menu Usage',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Popup Menu Usage'),
);
}
}
///
class MyHomePage extends StatefulWidget {
///
MyHomePage({Key key, this.title}) : super(key: key);
///
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
var _tapPosition;
void _showCustomMenu() {
final RenderBox overlay = Overlay.of(context).context.findRenderObject();
showMenu(
context: context,
items: <PopupMenuEntry<int>>[PopUpMenuEntry()],
position: RelativeRect.fromRect(
_tapPosition &
const Size(40, 40), // smaller rect, the touch area
Offset.zero & overlay.size // Bigger rect, the entire screen
));
}
void _storePosition(TapDownDetails details) {
_tapPosition = details.globalPosition;
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: GestureDetector(
onTapDown:_storePosition,
onLongPress: (){
_showCustomMenu();
},
child:ListView.builder(
itemCount: 10,
itemBuilder: (context,index) {
return Container(height: 500,child: Center(child: Text(index.toString(),style: TextStyle(fontSize: 16),),),);
},
),
),
);
}
}
///
// ignore: must_be_immutable
class PopUpMenuEntry extends PopupMenuEntry<int> {
#override
double height = 100;
// height doesn't matter, as long as we are not giving
// initialValue to showMenu().
#override
bool represents(int n) => n == 1 || n == -1;
#override
PopUpMenuEntryState createState() => PopUpMenuEntryState();
}
///
class PopUpMenuEntryState extends State<PopUpMenuEntry> {
void _onPressed() {
Navigator.pop(context);
}
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
FlatButton(onPressed: _onPressed, child: Text('Copy',style: TextStyle(fontSize: 20),)),
],
);
}
}
This is the Output:
Please help me to solve this or give me suggestion for any other popup widgets to overcome this problem.

Using jumpto and sticky_headers package causes UI issue

I created a new flutter project and added the sticky_headers package.
Afterwards I implemented a list builder that has a ScrollController.
I call setState 3 times at a 5 seconds interval and modify a global offset variable which will be used on the build method to jump the list to a new offset (using SchedulerBinding.instance.addPostFrameCallback).
The problem is that after I call the jumpto method, the headers are messed up ( if I manual scroll the headers will come back to a normal position).
Example:
The code:
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:sticky_headers/sticky_headers.dart';
double offset = 0;
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
ScrollController _scrollController = ScrollController();
#override
void initState() {
super.initState();
Future.delayed(Duration(seconds: 5)).then((_) => setState(() {
offset = 3000;
})).then((_) async => await Future.delayed(Duration(seconds: 5))).then((_) => setState(() {
offset = 1000;
})).then((_) async => await Future.delayed(Duration(seconds: 5))).then((_) => setState(() {
offset = 5000;
}));
}
#override
Widget build(BuildContext context) {
SchedulerBinding.instance.addPostFrameCallback((_) {
print(offset);
_scrollController.jumpTo(offset);
});
return Scaffold(body: Container(padding: EdgeInsets.only(top: 20),child: _buildList(context)));
}
Widget _buildList(BuildContext context) {
return NotificationListener<ScrollNotification>(
child: ListView.builder(
controller: _scrollController,
itemCount: 100,
itemBuilder: (BuildContext context, int sectionIndex) => StickyHeader(
header: Container(
height: 50,
alignment: Alignment.center,
color: Colors.blue,
child: Text("$sectionIndex")),
content: ListView.builder(
itemCount: 10,
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemBuilder: (context, rowIndex) => Container(
color: Colors.white,
child: Text("$sectionIndex"))))),
onNotification: (ScrollNotification scrollNotification) {
offset = _scrollController.offset;
print(offset);
return true;
});
}
}

notify child that somewhere in parent onTap happened

could you please show me how can I notify my statefull child widget that somewhere in parent user clicks on button?
I have two separate .dart files
in the first file I described main screen widget with FAB
and in the second one I have ListWidget (like RecyclerView)
If user tap on FAB I want notify my ListWidget about it so it can e.g. add one more item.
I have java/android background but it's quite hard for me to change my mind flow.
The first option would be to build the child widget each time you add an item to the list, passing the list as a parameter to the child.
But using streams is a nice way to avoid rebuilding the child widget each time. I think the following code is a good starting point (You could also use a StreamBuilder to build the list leveraging the stream).
In main.dart
import 'dart:async';
import 'package:base_test_project/expanding_list.dart';
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
home: new MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
StreamController<int> _controller = StreamController<int>();
int _number = 0;
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
body: new Center(
child: new ExpandingList(stream: _controller.stream),
),
floatingActionButton: new FloatingActionButton(
onPressed: () {_controller.add(_number++);},
child: new Icon(Icons.add),
),
);
}
}
In expanding_list.dart
import 'dart:async';
import 'package:flutter/material.dart';
class ExpandingList extends StatefulWidget {
Stream<int> stream;
ExpandingList({this.stream});
#override
_ExpandingListState createState() => _ExpandingListState();
}
class _ExpandingListState extends State<ExpandingList> {
List<int> _myList = [];
#override
void initState() {
super.initState();
widget.stream.listen((number) {
setState(() { _myList.add(number); });
});
}
#override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: _myList.length,
itemBuilder: (context, index) {
return Padding(
padding: EdgeInsets.all(15.0), child: Text("Item ${_myList[index]}"));
});
}
}