How to switch images in the list? - flutter

I am getting a list with images. I receive several images, when I click on the image, the _showImageDialog method works for me and an image with buttons for scrolling is displayed (I attached a screenshot below). station.photos![index]. How can I switch to the next image when I click on the button? I tried to change the index but it didn't work for me why?
void _showImageDialog(
BuildContext context, PublicChargingStationModel station) {
int index = 0;
showGeneralDialog(
context: context,
pageBuilder: (context, Animation<double> animation,
Animation<double> secondaryAnimation) {
return SafeArea(
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 15),
color: Colors.black.withOpacity(0.6),
alignment: Alignment.center,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: Align(
alignment: Alignment.topRight,
child: GestureDetector(
onTap: () => Navigator.pop(context),
child: SvgPicture.asset(
constants.Assets.closeBold,
color: constants.Colors.greyLight,
height: 26,
),
),
),
),
const SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
GestureDetector(
onTap: () {},
child: SvgPicture.asset(
constants.Assets.arrowLeft,
color: constants.Colors.greyLight,
height: 48,
),
),
const SizedBox(width: 20),
SizedBox(
width: MediaQuery.of(context).size.width / 1.6,
height: MediaQuery.of(context).size.width / 1.1,
child: station.photos!.isNotEmpty
? CachedNetworkImage(
imageUrl: station.photos![index].url,
imageBuilder: (context, imageProvider) =>
Container(
// width: MediaQuery.of(context).size.width / 1.6,
height: 116,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16),
image: DecorationImage(
image: imageProvider,
fit: BoxFit.cover,
),
),
),
placeholder: (context, url) => Center(
child: Container(
// width: MediaQuery.of(context).size.width / 1.6,
height: 116,
alignment: Alignment.center,
child: const CircularProgressIndicator(
color: constants.Colors.purpleMain,
),
),
),
errorWidget: (context, url, error) => const Icon(
Icons.error,
color: constants.Colors.purpleMain,
),
)
: Image.asset(
constants.Assets.publicStation,
fit: BoxFit.cover,
),
),
const SizedBox(width: 20),
GestureDetector(
onTap: () {
if (index < station.photos!.length) {
setState(() {
index++;
});
station.photos![index].url;
}
},
child: SvgPicture.asset(
constants.Assets.arrowRight,
color: constants.Colors.greyLight,
height: 48,
),
),
],
),
],
),
),
);
},
);
}

i am also facing same issue in mobile development then i know we have to rebuild the whole dialog and then it will work well
Reference for solve this same
int selectedRadio = 0; // Declare your variable outside the builder
return AlertDialog(
content: StatefulBuilder( // You need this, notice the parameters below:
builder: (BuildContext context, StateSetter setState) {
return Column( // Then, the content of your dialog.
mainAxisSize: MainAxisSize.min,
children: List<Widget>.generate(4, (int index) {
return Radio<int>(
value: index,
groupValue: selectedRadio,
onChanged: (int value) {
// Whenever you need, call setState on your variable
setState(() => selectedRadio = value);
},
);
}),
);
},
),
);

When you call setState then it call the build method and a dialog is not a part of this context.so the simple solution is **wrap your dialog with statefulbuilder widget and then you will get a setstate method for dialog. **
You can checkout this video for solution
https://www.google.com/search?q=setstate+in+dialog+johannes+milki&oq=setstate+in+dialog+johannes+milki&aqs=chrome..69i57j33i160l5.11920j0j7&client=ms-android-samsung&sourceid=chrome-mobile&ie=UTF-8#

Related

Flutter - How to update single item in pagination list

https://github.com/vedartm/pagination_view
I use the above library for pagination in a flutter.
I want to update single item on tap on heart sign.(without refreshing all items.)
I used paginatio_view library it's work perfect. but i want change pericualr item on tap on heart icon without refresh all list.
https://i.stack.imgur.com/BVof0.png
Expanded(
flex: 1,
child: Padding(
padding: const EdgeInsets.all(5.0),
child: PaginationView < ProductList > (
key: key,
paginationViewType: PaginationViewType.gridView,
scrollDirection: Axis.vertical,
pageFetch: (page) => pageFetch(page),
pullToRefresh: true,
itemBuilder:
(BuildContext context, ProductList user, int index) {
return GridTile(
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0),
),
child: Column(
children: [
Align(
alignment: Alignment.topRight,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: InkWell(
onTap: () => {
controller.addToWishList({
"ProductId": user.productId
}),
key
},
child: Image.asset(
height: 20,
width: 20,
user.flag ?
"assets/images/ic_like_heart.png" :
"assets/images/ic_unlike_heart.png")),
),
),
Expanded(
flex: 1,
child: CachedNetworkImage(
imageUrl: user.image,
imageBuilder: (context, imageProvider) =>
Container(
decoration: BoxDecoration(
image: DecorationImage(
image: imageProvider,
fit: BoxFit.contain,
),
),
),
progressIndicatorBuilder:
(context, url, progress) => Center(
child: CircularProgressIndicator(
value: progress.progress,
),
),
errorWidget: (context, url, error) =>
const Icon(Icons.warning_amber_rounded),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(user.productName),
)
],
),
),
);
},
onError: (dynamic error) =>
const Center(
child: Text(
'Some error occurred',
style: TextStyle(fontSize: 18),
),
),
onEmpty: const Center(
child: Text(
'Sorry! This is empty',
style: TextStyle(fontSize: 18),
),
),
bottomLoader: const Center( // optional
child: CircularProgressIndicator(),
),
initialLoader: const Padding(
padding: EdgeInsets.all(8.0),
child: Center(
child: CircularProgressIndicator(
backgroundColor: Colors.transparent),
),
),
),
),
)
Here is the method to get list.
Future < List < ProductList >> pageFetch(int offset) async {
page = (offset / 10).round() + 1;
_logger.d("Offset number::$offset Page number::$page");
var data = {
'Category': '',
'Search': _search,
'PageNumber': page,
'PageCount': 10
};
return await controller.getProductsList(data, page);
}

Flutter: How do I show an AlertBox as soon as my network image is loaded and only for once after app opens

I am trying to show an image on my screen, in an AlertBox. I am fetching the image from the network and then displaying it in the UI. I have a variable announcementImage, which is fetching data from API and stores the url in the variable. I want, as soon as I receive the image URL and as soon as the image loads, my AlertBox should appear. And this should happen only once, i.e. after the app starts. It should not appear again after I come back from another page.
Here is the code of initState -
#override
void initState() {
super.initState();
print("\n \n \n \n Started initialize \n \n");
Future.delayed(Duration.zero).then((value) {
showDialog(
context: context,
builder: (BuildContext buildContext) {
const double iconSize = 27;
return LayoutBuilder(
builder: (context, constraints) => AlertDialog(
backgroundColor: Colors.transparent,
elevation: 0,
contentPadding: EdgeInsets.zero,
content: SizedBox(
width: constraints.maxWidth * .75,
height: constraints.maxHeight * .71,
child: Stack(
children: [
Align(
alignment: Alignment.center,
child: ValueListenableBuilder(
valueListenable: announcementImage,
builder: (BuildContext context, String? url, Widget? child) {
return Image.network(
url??"",
width: constraints.maxWidth * .72 - iconSize,
height: constraints.maxHeight * .72 - iconSize,
);
},
),
),
Align(
alignment: Alignment.topRight,
child: GestureDetector(
onTap: () {
Navigator.of(context).pop();
},
child: Container(
decoration: const BoxDecoration(
color: Colors.white,
shape: BoxShape.circle,
),
child: Padding(
padding: const EdgeInsets.all(7.0),
child: const Icon(
Icons.close,
size: iconSize,
color: colorPrimary,
),
),
),
),
)
],
),
),
),
);
},
);
});
}

Updating single item in GridView.Builder() without rebuilding whole tree

I am trying to update a single image in my gridview of images when a user taps on the image but whenever I update a single element of array, it updates the entire gridview. This itself is not bad but since user will be selecting multiple images, it does not look ideal or good. I would appreciate it if someone can guide me to update single element of gridview without updating the entire widget
I am using provider for my state management but I have also tried it with setState. I have include all the code of the gridview file but let me know if you need for info.
Thanks
return Consumer<RemoverList>(
builder: (context, data, child) {
return WillPopScope(
onWillPop: () async {
data.remover.clear();
data.removerBool.clear();
// Provider.of<RemoverList>(context).remover.clear();
return true;
},
child: Scaffold(
body: Container(
height: height,
width: width,
color: Theme.of(context).backgroundColor,
child: SafeArea(
child: Column(
children: [
GestureDetector(
onTap: () {
Navigator.pushNamed(context, 'options');
},
child: Container(
height: height * 0.05,
width: width * 0.95,
margin: const EdgeInsets.symmetric(vertical: 20),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(2),
border: Border.all(color: Colors.white)),
child: Center(
child: Text(
widget.album.name,
style: const TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 25),
),
),
),
),
Expanded(
child: Container(
padding: const EdgeInsets.fromLTRB(0, 5, 0, 5),
// color: Colors.green,
width: width * 0.95,
decoration: BoxDecoration(
color: Colors.grey,
borderRadius: BorderRadius.circular(5)),
child: GridView.builder(
itemCount: widget.album.images.length,
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
mainAxisSpacing: 5,
crossAxisSpacing: 5,
crossAxisCount: 3),
itemBuilder: (context, i) {
data.generateRemoverList(widget.album.images);
var image = Uint8List.fromList(widget
.album.images[i].image['data']
.cast<int>());
return GestureDetector(
onLongPress: () {
// data.tapped(i);
if (data.removerBool.isNotEmpty) {
if (data.removerBool[i] == true) {
setState(() {
data.removerBool[i] = false;
});
} else {
setState(() {
data.removerBool[i] = true;
});
}
}
print(data.removerBool[i]);
print(data.remover);
setState(() {
active = true;
});
data.addToList(
widget.album.images[i].originalName);
},
onTap: () {
if (active == false) {
Navigator.push(context,
MaterialPageRoute(builder: (context) {
return OpenImage(unit: image);
}));
} else if (active == true) {
data.addToList(
widget.album.images[i].originalName);
print(data.remover);
data.removerBool[i] = !data.removerBool[i];
// data.tapped(i);
}
// data.tapped(i);
// print(data.removerBool[i]);
},
child: Container(
decoration: BoxDecoration(
color: Colors.black,
image: DecorationImage(
image: MemoryImage(image),
fit: BoxFit.cover)),
child: Center(
child: data.remover.contains(
widget.album.images[i].originalName)
? const Icon(
Icons.check_box_rounded,
color: Colors.black,
)
: Container(),
),
));
}),
)),
Container(
width: width * 0.95,
margin: const EdgeInsets.symmetric(vertical: 10),
alignment: Alignment.bottomCenter,
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
width: width * 0.45,
child: ElevatedButton(
onPressed: () {},
child: const Text('Add Photos')),
),
Container(
width: width * 0.45,
child: ElevatedButton(
onPressed: () {},
child: const Text('Remove Seleted')),
)
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
width: width * 0.45,
child: ElevatedButton(
onPressed: () {},
child: const Text('Save')),
),
Container(
width: width * 0.45,
child: ElevatedButton(
onPressed: () {},
child: const Text('Delete Album')),
)
],
)
],
),
)
],
),
),
),
),
);
},
);
}
}

How to change position of Container inside Stack?

Im trying to displaying a button inside my stack but it not getting the correct position. The button is the reply Button . I added a foot how it looks at the moment you can check it what I want is displaying it on the right side of the window at the bottom with a bit of spacing between bottom and the button.
Hope anyone can help. if you need more information please leave a comment .
#override
Widget build(BuildContext context) {
var size = MediaQuery.of(context).size;
try {
return Scaffold(
body: StreamBuilder(
stream: mystreamofallvideos,
builder: (context, snapshot) {
if (snapshot.hasData &&
snapshot.connectionState != ConnectionState.waiting) {
return PageView.builder(
itemCount: snapshot.data.docs.length,
controller:
PageController(initialPage: 0, viewportFraction: 1),
scrollDirection: Axis.vertical,
itemBuilder: (context, index) {
DocumentSnapshot videos = snapshot.data.docs[index];
return Stack(children: [
Videoplayeritem(widget.videoid),
Column(children: [
Align(
alignment: Alignment.bottomLeft,
child: Container(
height: 100,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: [
IconButton(
icon: Icon(
Icons.close,
color: Colors.white,
size: 35,
),
onPressed: () {
Navigator.of(context).pop();
}),
SizedBox(
width: 190,
),
],
),
),
),
Container(
color: Colors.red,
width: 210,
height: 94,
//color: Colors.blue.withOpacity(0.5),
child: InkWell(
onTap: () => sharevideo(
widget.videoid, videos.data()['id']),
child: Icon(Icons.reply,
size: 55, color: Colors.white),
),
),
]),
//starssonthe right
]);
});
} else {
return Center(child: CircularProgressIndicator());
}
}),
);
} catch (e) {
e.toString();
}
}
}
This is how it looks
enter image description here
Wrap it in an align and add a padding to the bottom:
Align(
alignment: Alignment.bottomRight,
child: Container(
height: 40,
padding: const EdgeInsets.only(bottom: 16),
child: OutlinedButton(
onPressed: () {},
child: Text('mybutton'),
),
)
you can wrap your container with either Positioned or Align widgets
like :
Positioned(
top: 0.0,
left: 0.0,
child: Icon(Icons.message,
size: 128.0, color: Colors.greenAccent[400]), //Icon
),

Flutter UI List Item

I am using the below code but not able to achieve the desired result, I am new to the flutter world so let me know where to improve to get the desired result. Here is the source code of what I have done.
return Expanded(
child: GridView.builder(
controller: _scrollController,
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
itemCount: albumList.length,
itemBuilder: (BuildContext context, int index) {
return buildRow(index);
},
),
);
Widget buildRow(int index) {
return AlbumTile(
index: index,
albumList: albumList,
deleteAlbum: _deleteAlbum,
);
}
This the Album Tile
class AlbumTile extends StatelessWidget {
AlbumTile(
{Key key,
#required this.index,
#required this.albumList,
#required this.deleteAlbum})
: super(key: key);
final int index;
final List<Album> albumList;
final Function deleteAlbum;
#override
build(BuildContext context) {
String thumb;
if (albumList.elementAt(index).thumbUrl != "") {
thumb = WEBSERVICE_IMAGES +
albumList.elementAt(index).userId.toString() +
'/' +
albumList.elementAt(index).id.toString() +
'/' +
albumList.elementAt(index).thumbUrl;
} else {
thumb = "https://cdn.pixabay.com/photo/2015/12/01/20/28/road-1072823__340.jpg";
}
return GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
new AlbumPage(tabIndex: index, albumList: albumList),
),
);
},
child: Container(
// height of the card which contains full item
height: MediaQuery.of(context).size.height * 0.4,
width: MediaQuery.of(context).size.width * 0.28,
// this is the background image code
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.cover,
// url is my own public image url
image: NetworkImage(thumb),
),
borderRadius: BorderRadius.circular(12.0)),
// this is the item which is at the bottom
child: Align(
// aligment is required for this
alignment: Alignment.bottomLeft,
// items height should be there, else it will take whole height
// of the parent container
child: Container(
padding: EdgeInsets.only(left: 10.0, right: 0.0),
height: MediaQuery.of(context).size.height * 0.1,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// Text() using hard coded text right now
Text(albumList.elementAt(index).name,
style: TextStyle(
fontSize: 18.5,
color: Colors.white,
fontWeight: FontWeight.w500)),
SizedBox(height: 3.0),
Text(albumList.elementAt(index).photos.toString() +' photos',
style: TextStyle(
fontSize: 12.5,
color: Colors.white,
fontWeight: FontWeight.w500))
],
),
),
// pop-up item
PopupMenuButton(
icon: Icon(Icons.more_vert, color: Colors.white),
itemBuilder: (_) => <PopupMenuItem<String>>[
new PopupMenuItem<String>(
child: Row(
children: <Widget>[
Icon(Icons.delete),
Text(
'Delete Album',
),
],
),
value: 'Delete',
),
],
onSelected: (value) {
deleteAlbum(albumList.elementAt(index).id, index);
},
),
],
),
),
),
),
);
GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
new AlbumPage(tabIndex: index, albumList: albumList),
),
);
},
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Stack(
fit: StackFit.loose,
children: <Widget>[
ClipRRect(
borderRadius: new BorderRadius.circular(8.0),
child: FadeInImage.assetNetwork(
height: 1000,
placeholder: kPlaceHolderImage,
image: thumb,
fit: BoxFit.cover,
),
),
Align(
alignment: Alignment.bottomLeft,
child: Row(
children: [
Expanded(
child: Padding(
padding: const EdgeInsets.fromLTRB(8, 0, 0, 0),
child: Text(
albumList.elementAt(index).name,
style: TextStyle(
color: Colors.white,
fontSize: 18.5,
),
textAlign: TextAlign.left,
),
),
),
PopupMenuButton(
icon: ImageIcon(
AssetImage("graphics/horizontal_dots.png"),
color: Colors.white,
),
itemBuilder: (_) => <PopupMenuItem<String>>[
new PopupMenuItem<String>(
child: Row(
children: <Widget>[
Icon(Icons.delete),
Text(
'Delete Album',
),
],
),
value: 'Delete',
),
],
onSelected: (value) {
deleteAlbum(albumList.elementAt(index).id, index);
}),
],
),
),
],
),
),
);
}
}
Thank you in advance.
Welcome to the flutter. Amazing platform to start you career on building cross-platform mobile applications.
My code will look a bit different to you, but trust me, this will work out for you.
Please note: You need to change some parts, like changing the image url for NetworkImage(), onTap function, Text() content etc. But not much changes in the Whole Widget code. So please look for those, and make changes accordingly. You will get there :)
GestureDetector(
onTap: () => print('Works!'), // <-- onTap change, I have used print()
child: Container(
// height of the card which contains full item
height: MediaQuery.of(context).size.height * 0.4,
width: MediaQuery.of(context).size.width * 0.28,
// this is the background image code
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.cover,
// url is my own public image url
image: NetworkImage('https://cdn.pixabay.com/photo/2015/12/01/20/28/road-1072823__340.jpg')
),
borderRadius: BorderRadius.circular(12.0)
),
// this is the item which is at the bottom
child: Align(
// aligment is required for this
alignment: Alignment.bottomLeft,
// items height should be there, else it will take whole height
// of the parent container
child: Container(
padding: EdgeInsets.only(left: 10.0, right: 0.0),
height: MediaQuery.of(context).size.height * 0.1,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// Text() using hard coded text right now
Text('Potraits', style: TextStyle(fontSize: 20.0, color: Colors.white, fontWeight: FontWeight.w500)),
SizedBox(height: 3.0),
Text('150 photos', style: TextStyle(fontSize: 17.0, color: Colors.white, fontWeight: FontWeight.w500))
]
)
),
// pop-up item
PopupMenuButton(
icon: Icon(Icons.more_vert, color: Colors.white),
itemBuilder: (_) => <PopupMenuItem<String>>[
new PopupMenuItem<String>(
child: Row(
children: <Widget>[
Icon(Icons.delete),
Text(
'Delete Album',
),
],
),
value: 'Delete',
),
],
onSelected: (value) {
//your function
}
)
]
)
)
)
)
)
Result
EDITS FOR WHOLE UI
So, the change required is in your buildRow Widget. You just need to give some paddings on your sides, and you are pretty much solid. Let me know
Widget buildRow(int index) {
return Padding(
padding: EdgeInsets.all(10.0),
child: AlbumTile(
index: index,
albumList: albumList,
deleteAlbum: _deleteAlbum,
)
);
}
And if you are unsatisfied with the spacings, just keep playing with the EdgeInsets painting class. I hope that helps. Please let me know. :)