'Carousel image on different page with onPressed index
I am kinda new to flutter. I need help on Carousel images. I have carousel images using carousel_pro package. And i can open image on new page when pressed using GestureDetector. But i would like to open same carousel images on new page but with onPressed index at first. i mean for ex. i have 5 images. When i press on 3rd image it has to open on new carousel with that image not first one. I hope i made myself clear. Below is one-page-for-one-image kinda way. i need carousel with starting index of pressed image in carousel of images. Thanks in advance.
import 'package:carousel_slider/carousel_slider.dart';
import './image_screen.dart';
void main() => runApp(MaterialApp(home: Demo()));
class Demo extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<Demo> {
@override
Widget build(BuildContext context) {
Widget image_carousel = new Container(
height: 345.0,
child: CarouselSlider(
height: 400.0,
items: [
'http://pic3.16pic.com/00/55/42/16pic_5542988_b.jpg',
'http://photo.16pic.com/00/38/88/16pic_3888084_b.jpg',
'http://pic3.16pic.com/00/55/42/16pic_5542988_b.jpg',
'http://photo.16pic.com/00/38/88/16pic_3888084_b.jpg'
].map((i) {
return Builder(
builder: (BuildContext context) {
return Container(
width: MediaQuery.of(context).size.width,
margin: EdgeInsets.symmetric(horizontal: 5.0),
decoration: BoxDecoration(color: Colors.amber),
child: GestureDetector(
child: Image.network(i, fit: BoxFit.fill),
onTap: () {
Navigator.push<Widget>(
context,
MaterialPageRoute(
builder: (context) => ImageScreen(i),
),
);
}));
},
);
}).toList(),
));
return Scaffold(
body: new Column(
children: <Widget>[
image_carousel,
],
),
);
}
}
EDIT: I have added above code for sample. It is not what i need. I need smth like this: Page 1 has carousel with 5 images. When i press 3rd image, on Page2 same carousel of images opens with index of that pressed 3rd image. i mean on Page 2 carousel has to start with 3rd image. I hope i made myself clear this time.
Solution 1:[1]
ANSWER VERSION 2.0
See, the UI element works correct, what needs to be done, is to find a way out to set the item at first and then push all the elements after that
Here, we need to understand what DART SUBLIST is. Please read about it carefully to understand the concepts.
ALGORITHM
1. Select index of the image urls
2. If the item which is selected is first, then normal list would be passed
3. If not, then we get firstElements which is a sublist of (0, index), index not included [for example => If we select 3 from 1,2,3,4 => firstElements = [1,2]]
4. We maintain the lastElements, which is a sublist of (index, list.length), where list.length is ignore. [for example => If we select 3 from 1,2,3,4 => lastElements= [3,4]]
4. Finally we make a final list by adding lastElements + firstElements = [3,4,1,2]
And this is what we're trying to achieve, don't we?
CODE IMPLEMENTATION
// suppose we have an array of Ints
List<int> data = [1,2,3,4];
// to keep a pointer, which one is selected
// here we selected 3, so index will have 2 as it's value,
// which is the index of 3
int index = data.indexOf(3);
// now let say, we want to push 3 to the top, keeping
// 4, after it, and 1,2 after 4 in the same format
// similar to what you want to do with the selected image
// CHECKS FOR FIRST ELEMENT IS SELECTED OR NOT, WHICH HAS INDEX 0
if(index != 0){
// get the sublist from 0 to index-1
var firstElements = data.sublist(0, index);
// get the sublist from index, to last
var restElements = data.sublist(index, data.length);
// restElements should be pushed to top, since we have want the
// to be there, then comes firstElements
print(restElements+firstElements);
}else{
// since the first item is selected
print(data);
}
print(items);
// OUTPUT => [3, 4, 1, 2]
See, how the above item 3
, pushed to the first position with 4
after it, and rest is pushed to it's other position respectively. This is what we're trying to achieve. You can go ahead, and test out for some other values too
REMEMBER: Logic should be clear, and rest UI can take care of itself
I have not used any CarouselSlider
, just used my own ListView
to show, how it is done. If you get the idea, I am sure, you get how to work on it as well.
HomePage
class _MyHomePageState extends State<MyHomePage> {
// In the list, I have used all the images as different to show you the difference
// in a clear way
List<String> _imageUrls = [
'http://pic3.16pic.com/00/55/42/16pic_5542988_b.jpg',
'http://photo.16pic.com/00/38/88/16pic_3888084_b.jpg',
'https://static.toiimg.com/thumb/msid-54559212,width-748,height-499,resizemode=4,imgsize-307081/Bangalore.jpg',
'https://images.unsplash.com/photo-1535332371349-a5d229f49cb5?ixlib=rb-1.2.1&w=1000&q=80'
];
// This is the widget which is responsible for creating
// list of images as a slider
Widget get myWidget{
List<Widget> _widgets = [SizedBox(width: 20.0)];
for(int i=0; i<_imageUrls.length; i++){
_widgets.add(
GestureDetector(
onTap: (){
Navigator.of(context).push(
// Our new page, takes ImageUrls list, and the selected index
// top perform an operation
MaterialPageRoute(
builder: (context) => NewPage(imgUrls: _imageUrls, index: i)
)
);
},
child: Container(
width: 300.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15.0),
image: DecorationImage(
fit: BoxFit.cover,
image: NetworkImage(_imageUrls[i])
)
)
)
)
);
_widgets.add(SizedBox(width: 20.0));
}
return Container(
height: 400.0,
child: ListView(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
children: _widgets
)
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Container(
height: double.infinity,
width: double.infinity,
child: Center(
child: this.myWidget
)
)
);
}
}
NewPage
class _NewPageState extends State<NewPage> {
// This will keep a copy of all the items coming from immutable imageUrls
// We will be doing operation in this list only
// it has to be initialized as an empty array
List<String> _newImageUrls = [];
@override
void initState(){
super.initState();
// same algo which is explained above
if(widget.index != 0){
// get the sublist from 0 to index-1
var firstElements = widget.imgUrls.sublist(0, widget.index);
// get the sublist from index, to last
var restElements = widget.imgUrls.sublist(widget.index, widget.imgUrls.length);
setState(() => _newImageUrls = restElements + firstElements);
}else{
// since the first item is selected
// no _newImageUrls = widget.imgUrls cos, machine will
// understand that both the items are same, so if one changes,
// that means another has to change. So strict no-no to that
widget.imgUrls.forEach((item){
_newImageUrls.add(item);
});
}
}
// now this is same as our HomePage
// just a height change of the images and we're using our new
// list, not the passed one, since, it has changed data now
Widget get myWidget{
List<Widget> _widgets = [SizedBox(width: 20.0)];
for(int i=0; i<_newImageUrls.length; i++){
_widgets.add(
Container(
width: 300.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15.0),
image: DecorationImage(
fit: BoxFit.cover,
image: NetworkImage(_newImageUrls[i])
)
)
)
);
_widgets.add(SizedBox(width: 20.0));
}
return Container(
height: 500.0,
child: ListView(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
children: _widgets
)
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('New Page'),
),
body: Container(
height: double.infinity,
width: double.infinity,
child: Center(
child: this.myWidget
)
)
);
}
}
The result you will get is pretty much the one which you want. That is, If the 3rd item is selected from 1,2,3,4 the other NewPage will show 3,4,1,2 and so on..
RESULT OF OUR NEW WORK WITH CORRECT REQUIREMENTS
Can you see the difference, in the code for NewPage
? It is just the logic, else, the UI was as same as before. This is what I was trying to tell you.
Solution 2:[2]
Here is a code sample that might help you out.
main Screen
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("test"),
),
body: Container(
height: 345.0,
child: CarouselSlider(
options: CarouselOptions(
height: 400,
),
items: [
'http://pic3.16pic.com/00/55/42/16pic_5542988_b.jpg',
'http://photo.16pic.com/00/38/88/16pic_3888084_b.jpg',
'http://pic3.16pic.com/00/55/42/16pic_5542988_b.jpg',
'http://photo.16pic.com/00/38/88/16pic_3888084_b.jpg'
].map(
(i) {
return Container(
width: MediaQuery.of(context).size.width,
margin: EdgeInsets.symmetric(horizontal: 5.0),
decoration: BoxDecoration(color: Colors.amber),
child: GestureDetector(
child: Image.network(i, fit: BoxFit.fill),
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => Screen2(
image: i,
),
),
);
},
),
);
},
).toList(),
),
),
);
}
}
Screen2: a screen with a carousel and appBar to back into first screen
class Screen2 extends StatelessWidget {
final List<String> images;
final String selectedImages;
Screen2({this.images, this.selectedImages});
@override
Widget build(BuildContext context) {
images.removeWhere((i) => i == selectedImages);
images.insert(0, selectedImages);
return Scaffold(
appBar: AppBar(),
body: Container(
height: double.maxFinite,
width: double.maxFinite,
child: CarouselSlider(
options: CarouselOptions(
viewportFraction: 1.0,
height: double.maxFinite,
),
items: [
...images.map(
(image) => Image.network(
image,
fit: BoxFit.fill,
),
),
],
),
),
);
}
}
Solution 3:[3]
You should pass desired index along with your images list and set it to initialPage
property of CarouselOptions. https://pub.dev/packages/carousel_slider#params
import 'package:carousel_slider/carousel_slider.dart';
import 'package:flutter/material.dart';
import 'package:test_eclipse_digital/model/album/photo.dart';
class PhotoCarouselPage extends StatelessWidget {
final List<Photo> photos;
final int startFrom;
const PhotoCarouselPage({
Key? key,
required this.photos,
required this.startFrom
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Builder(
builder: (context) {
final double height = MediaQuery.of(context).size.height;
return CarouselSlider(
options: CarouselOptions(
height: height,
viewportFraction: 1,
enlargeCenterPage: false,
initialPage: startFrom,
),
items: photos.map((photo) => Center(
child: Image.network(
photo.url,
fit: BoxFit.cover,
height: height,),
)).toList(),
);
},
),
);
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | halfer |
Solution 2 | |
Solution 3 | tanyapog |