带有 onPressed 索引的不同页面上的轮播图像
Carousel image on different page with onPressed index
我对 flutter 有点陌生。我需要轮播图片方面的帮助。我有使用 carousel_pro 包的旋转木马图像。当使用 GestureDetector 按下时,我可以在新页面上打开图像。但我想在新页面上打开相同的旋转木马图像,但首先使用 onPressed 索引。我的意思是前任。我有5张图片。当我按下第三张图片时,它必须打开新的轮播,而不是第一张图片。我希望我说清楚了。下面是一页一张图像的一种方式。我需要在图像轮播中带有按下图像起始索引的轮播。提前致谢。
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,
],
),
);
}
}
编辑: 我添加了上面的示例代码。这不是我需要的。我需要这样的东西:第 1 页有带 5 张图片的轮播。当我按下第 3 张图像时,在第 2 页上打开相同的图像轮播,并显示按下的第 3 张图像的索引。我的意思是第 2 页的旋转木马必须从第 3 张图片开始。希望这次我说清楚了。
这是一个可能对您有所帮助的代码示例。
主屏幕
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: 带有旋转木马和 appBar 的屏幕返回到第一个屏幕
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,
),
),
],
),
),
);
}
}
答案版本 2.0
看到了,UI元素工作正常,需要做的是,想办法先设置item,然后再push所有元素
这里,我们需要了解一下DART SUBLIST是什么。请仔细阅读以了解其中的概念。
算法
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]
这就是我们正在努力实现的目标,不是吗?
代码实现
// 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]
看看上面的项目 3
是如何被推到第一个位置的,后面是 4
,其余的分别被推到它的另一个位置。这就是我们正在努力实现的目标。 您可以继续,也可以测试其他一些值
记住:逻辑要清晰,其余UI自己处理
我没有使用任何 CarouselSlider
,只是用我自己的 ListView
来展示它是如何完成的。如果你明白了,我相信你也会明白如何去做。
首页
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
)
)
);
}
}
您将得到的结果几乎就是您想要的结果。也就是说,如果从 1,2,3,4 中选择第 3 个项目,则另一个 NewPage 将显示 3,4,1,2 等等..
RESULT OF OUR NEW WORK WITH CORRECT REQUIREMENTS
你能看出 NewPage
代码中的区别吗?这只是逻辑,否则,UI 和以前一样。 这就是我想告诉你的。
您应该将所需的索引与图像列表一起传递,并将其设置为 CarouselOptions 的 initialPage
属性。 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(),
);
},
),
);
}
}
我对 flutter 有点陌生。我需要轮播图片方面的帮助。我有使用 carousel_pro 包的旋转木马图像。当使用 GestureDetector 按下时,我可以在新页面上打开图像。但我想在新页面上打开相同的旋转木马图像,但首先使用 onPressed 索引。我的意思是前任。我有5张图片。当我按下第三张图片时,它必须打开新的轮播,而不是第一张图片。我希望我说清楚了。下面是一页一张图像的一种方式。我需要在图像轮播中带有按下图像起始索引的轮播。提前致谢。
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,
],
),
);
}
}
编辑: 我添加了上面的示例代码。这不是我需要的。我需要这样的东西:第 1 页有带 5 张图片的轮播。当我按下第 3 张图像时,在第 2 页上打开相同的图像轮播,并显示按下的第 3 张图像的索引。我的意思是第 2 页的旋转木马必须从第 3 张图片开始。希望这次我说清楚了。
这是一个可能对您有所帮助的代码示例。
主屏幕
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: 带有旋转木马和 appBar 的屏幕返回到第一个屏幕
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,
),
),
],
),
),
);
}
}
答案版本 2.0
看到了,UI元素工作正常,需要做的是,想办法先设置item,然后再push所有元素
这里,我们需要了解一下DART SUBLIST是什么。请仔细阅读以了解其中的概念。
算法
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]
这就是我们正在努力实现的目标,不是吗?
代码实现
// 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]
看看上面的项目 3
是如何被推到第一个位置的,后面是 4
,其余的分别被推到它的另一个位置。这就是我们正在努力实现的目标。 您可以继续,也可以测试其他一些值
记住:逻辑要清晰,其余UI自己处理
我没有使用任何 CarouselSlider
,只是用我自己的 ListView
来展示它是如何完成的。如果你明白了,我相信你也会明白如何去做。
首页
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
)
)
);
}
}
您将得到的结果几乎就是您想要的结果。也就是说,如果从 1,2,3,4 中选择第 3 个项目,则另一个 NewPage 将显示 3,4,1,2 等等..
RESULT OF OUR NEW WORK WITH CORRECT REQUIREMENTS
你能看出 NewPage
代码中的区别吗?这只是逻辑,否则,UI 和以前一样。 这就是我想告诉你的。
您应该将所需的索引与图像列表一起传递,并将其设置为 CarouselOptions 的 initialPage
属性。 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(),
);
},
),
);
}
}