Related
Is it possible to use one ListView.Builder to populate all its items to different rows within the screen's width?
Currently, my makeshift method is having 2 ListView.Builders. This cuts the list I have into half. I would like the ListView.Builder to showcase everything in the list within the screen's width limits. If there's not enough space, then populate the interests to another row.
The name of the list is interests, and it is a list of strings.
Padding(
padding: const EdgeInsets.fromLTRB(6, 6, 0, 0),
child: Container(
height: MediaQuery.of(context).size.height * 0.039,
child: ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
padding: const EdgeInsets.all(1),
itemCount: 5,
itemBuilder: (context, index) {
return Container(
margin: EdgeInsets.only(right: 9),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
border:
Border.all(color: Colors.yellow[100])),
padding: EdgeInsets.symmetric(
horizontal:
MediaQuery.of(context).size.width * 0.030,
vertical: MediaQuery.of(context).size.height *
0.0045),
child: Text(
interests[index],
style: TextStyle(fontSize: 12),
));
}),
),
),
Padding(
padding: const EdgeInsets.fromLTRB(6, 3, 0, 0),
child: Container(
height: MediaQuery.of(context).size.height * 0.039,
child: ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
padding: const EdgeInsets.all(1),
itemCount: 4,
itemBuilder: (context, index) {
return Container(
margin: EdgeInsets.only(right: 9),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
border:
Border.all(color: Colors.yellow[100])),
padding: EdgeInsets.symmetric(
horizontal:
MediaQuery.of(context).size.width * 0.030,
vertical: MediaQuery.of(context).size.height *
0.0045),
child: Text(
interests[5 + index],
style: TextStyle(fontSize: 12),
));
}),
),
),
My current example: 2 Listviews possibly flowing out of the screen.
The results I want:
Container bubbles filling up within screen's width and if the last bubble will overflow the screen, it automatically forms a new row.
Flutter's Wrap widget provides this exact functionality.
By default Wrap lays it's children horizontally and automatically wraps it's children when they are overflowing out of the given contraints.
Use it like this,
// Suppose you have data like this.
List<String> interests = ['Bollywood','Biryani','Running','Punjabi','Dancing'];
// Use them inside build function like this
Container(
height: MediaQuery.of(context).size.height * 0.039,
child: Wrap(
children: interests.map((interest) => Container(
margin: EdgeInsets.only(right: 9),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
border: Border.all(color: Colors.yellow[100])),
padding: EdgeInsets.symmetric(
horizontal: MediaQuery.of(context).size.width * 0.030,
vertical: MediaQuery.of(context).size.height * 0.0045
),
child: Text(
interest,
style: TextStyle(fontSize: 12),
),
)).toList()
),
),
Result is this
I have a program that uses a List, but I get this error, how to fix it?
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(children: [
CustomScrollView(physics: BouncingScrollPhysics(), slivers: [
_list(),
]),
]),
);
}
_list() {
return List.generate(
actions.length,
(i) => _card(actions[i]),
);
}
_card(
String phrase,
) {
return SliverToBoxAdapter(
child: Card(
shape: RoundedRectangleBorder(
side: BorderSide(color: Colors.black26, width: 0.1),
borderRadius: BorderRadius.circular(10),
),
margin: EdgeInsets.only(right: 50, left: 50, top: 20),
child: InkWell(
splashColor: Colors.black12,
borderRadius: BorderRadius.circular(10),
splashFactory: InkRipple.splashFactory,
onTap: () => _speak(phrase),
child: Column(children: <Widget>[
SizedBox(height: 15.0),
Padding(
padding: EdgeInsets.only(left: 15, right: 15),
child: Text(
phrase,
style: TextStyle(
fontFamily: 'Circular',
fontSize: 17.0,
color: Colors.grey[800]),
),
),
SizedBox(height: 15.0),
]),
),
),
);
}
Your method _list() returns a List<Widget>.
Therefore, you should remove the brackets in your CustomScrollView:
CustomScrollView(physics: BouncingScrollPhysics(), slivers: _list()),
I was working on merging few images and display it as one.
I have two dart files one is for adding images and other is for displaying the merged result.
first file code is,
class SingleImageUpload extends StatefulWidget {
#override
_SingleImageUploadState createState() {
return _SingleImageUploadState();
}
}
class _SingleImageUploadState extends State<SingleImageUpload> {
List<Object> images = List<Object>();
File _selectedFile;
bool _inProcess = false;
Map data = {};
Readerservice _readerservice;
#override
void initState() {
// TODO: implement initState
super.initState();
setState(() {
images.add("Add Image");
images.add("Add Image");
images.add("Add Image");
images.add("Add Image");
});
}
#override
Widget build(BuildContext context) {
return new MaterialApp(
debugShowCheckedModeBanner: false,
home: new Scaffold(
appBar: AppBar(
backgroundColor: Colors.white,
leading: Padding(
padding: EdgeInsets.only(left: 12),
child: IconButton(
icon: Icon(Icons.arrow_back_ios,
color: Colors.black,
size: 30,),
onPressed: () {
Navigator.pushNamed(context, '/');
},
),
),
title: Row(
mainAxisAlignment: MainAxisAlignment.center,
children:<Widget>[
Text('Basic AppBar'),
]
),
actions: <Widget>[
IconButton(
icon: Icon(Icons.more_vert,
color: Colors.black,
size: 30,),
onPressed: () {
print('Click start');
},
),
],
),
body:
Column(
children: <Widget>[
SizedBox(height: 10),
Row(children: <Widget>[
Text('Image',
style: TextStyle(
color: Colors.black,
fontSize: 33,
fontWeight: FontWeight.bold,
)),
Text('Merger',
style: TextStyle(
color: Colors.orange,
fontSize: 33,
fontWeight: FontWeight.bold,
)),
]),
SizedBox(height: 40),
Text(' merge it here'),
SizedBox(height: 10),
Expanded(
child: buildGridView(),
),
RaisedButton(
textColor: Colors.white,
color: Colors.orange,
child: Text("Finish",
style: TextStyle(fontSize: 15),),
onPressed: () {
pasimage();
},
shape: new RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(8.0),
),
),
],
),
),
);
}
Widget buildGridView() {
return GridView.count(
shrinkWrap: true,
crossAxisCount: 3,
childAspectRatio: 1,
children: List.generate(images.length, (index) {
if (images[index] is ImageUploadModel) {
ImageUploadModel uploadModel = images[index];
return Card(
clipBehavior: Clip.antiAlias,
child: Stack(
children: <Widget>[
Image.file(
uploadModel.imageFile,
width: 300,
height: 300,
),
Positioned(
right: 5,
top: 5,
child: InkWell(
child: Icon(
Icons.remove_circle,
size: 20,
color: Colors.red,
),
onTap: () {
setState(() {
images.replaceRange(index, index + 1, ['Add Image']);
});
},
),
),
],
),
);
} else {
return Card(
child: IconButton(
icon: Icon(Icons.add),
onPressed: () {
//popup
showDialog(
context: context,
builder: (context) {
return Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10)),
elevation: 16,
child: Container(
height: 180.0,
width: 330.0,
child: ListView(
children: <Widget>[
SizedBox(height: 20),
//Center(
Padding(
padding: const EdgeInsets.only(left: 15.0),
child: Text(
"Add a Receipt",
textAlign: TextAlign.left,
style: TextStyle(
fontSize: 24,
color: Colors.black,
fontWeight: FontWeight.bold),
),
),
// ),
SizedBox(height: 20),
FlatButton(
child: Text(
'Take a photo..',
textAlign: TextAlign.left,
style: TextStyle(fontSize: 20),
),
onPressed: () {
_onAddImageClick(index,ImageSource.camera);
Navigator.of(context).pop();
// picker.getImage(ImageSource.camera);
},
textColor: Colors.black,
),
FlatButton(
child: Text(
'Choose from Library..',
style: TextStyle(fontSize: 20),
textAlign: TextAlign.left,
),
onPressed: () {
_onAddImageClick(index,ImageSource.gallery);
Navigator.of(context).pop();
},
textColor: Colors.black,
),
],
),
),
);
},
);
//pop ends
},
),
);
}
}),
);
}
Future _onAddImageClick(int index, ImageSource source ) async {
setState(() {
_inProcess = true;
});
File image = await ImagePicker.pickImage(source: source);
if(image != null){
File cropped = await ImageCropper.cropImage(
sourcePath: image.path,
maxWidth: 1080,
maxHeight: 1080,
compressFormat: ImageCompressFormat.jpg,
androidUiSettings: AndroidUiSettings(
toolbarColor: Colors.black,
toolbarWidgetColor: Colors.white,
//toolbarTitle: "RPS Cropper",
statusBarColor: Colors.deepOrange.shade900,
backgroundColor: Colors.black,
initAspectRatio: CropAspectRatioPreset.original,
lockAspectRatio: false
),
iosUiSettings: IOSUiSettings(
minimumAspectRatio: 1.0,
)
);
this.setState((){
_selectedFile = cropped ;
_inProcess = false;
});
} else {
this.setState((){
_inProcess = false;
});
}
getFileImage(index);
}
void getFileImage(int index) async {
// var dir = await path_provider.getTemporaryDirectory();
setState(() {
ImageUploadModel imageUpload = new ImageUploadModel();
imageUpload.isUploaded = false;
imageUpload.uploading = false;
imageUpload.imageFile = _selectedFile;
imageUpload.imageUrl = '';
images.replaceRange(index, index + 1, [imageUpload]);
});
}
void pasimage(){
Navigator.pushReplacementNamed(context, '/crop',arguments: {
'imageList':ImagesMerge(
images,///required,images list
direction: Axis.vertical,///direction
backgroundColor: Colors.black26,///background color
fit: false,///scale image to fit others
),
});
}
}
class ImageUploadModel {
bool isUploaded;
bool uploading;
File imageFile;
String imageUrl;
ImageUploadModel({
this.isUploaded,
this.uploading,
this.imageFile,
this.imageUrl,
});
}
when I tap the finish button after adding the images it shows an error
The following _TypeError was thrown while handling a gesture:
type 'List' is not a subtype of type 'List'
The page just on captures the data sent from the code above and display the image.
please if anyone know why is the error and help me .
Change the images to List<Object> images = [].
This is a followup of a question I had a couple off days ago about my first flutter app.
Following advice from PRO I changed my code so that it did what I wanted.
The only problem is that from the function I get only 1 value.
Pro advised to make a list, which worked in the function like it should.
Only how to get these values in a textfield is not clear to me.
I can only show what I want bij sending the full code.
Later I want to build on the same principal with more outcome values.
I use value.toString() as well as value[1].toString().
The first gives me the first value, the second only a caracter.
I hope someone can help
import 'package:flutter/material.dart';
void main() {
runApp(Buis());
}
class Buis extends StatefulWidget {
#override
BuisState createState() => BuisState();
}
class BuisState extends State<Buis> {
var kap2 = '';
var buizen2 = '';
var diam2 = '';
var spev = '';
var spo = '';
var value;
#override
Widget build(BuildContext context) {
TextEditingController kapController = TextEditingController(text: '9.60');
TextEditingController buizenController = TextEditingController(text: '12');
TextEditingController diamController = TextEditingController(text: '51');
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Center(
child: Text("Specifiek buis vermogen"),
),
),
body: Center(
child: Container(
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
SizedBox(height: 20),
// Input kap breedte
Container(
width: 170,
height: 30,
child: TextFormField(
controller: kapController,
keyboardType: TextInputType.number,
style: TextStyle(fontWeight: FontWeight.bold),
decoration: InputDecoration(
contentPadding:
EdgeInsets.symmetric(vertical: 5, horizontal: 8),
labelText: "Kap breedte (mtr)",
hintText: "$kap2",
fillColor: Colors.cyan[200],
filled: true,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(40.0),
borderSide: BorderSide(),
),
),
),
),
SizedBox(height: 10),
// Input aantal buizen
Container(
width: 170,
height: 30,
child: TextFormField(
controller: buizenController,
keyboardType: TextInputType.number,
style: TextStyle(fontWeight: FontWeight.bold),
decoration: InputDecoration(
contentPadding:
EdgeInsets.symmetric(vertical: 5, horizontal: 8),
labelText: "Aantal buizen",
hintText: "$buizen2",
fillColor: Colors.cyan[200],
filled: true,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(40.0),
borderSide: BorderSide(),
),
),
),
),
SizedBox(height: 10),
// Input buis diameter
Container(
width: 170,
height: 30,
child: TextFormField(
controller: diamController,
keyboardType: TextInputType.number,
style: TextStyle(fontWeight: FontWeight.bold),
decoration: InputDecoration(
contentPadding:
EdgeInsets.symmetric(vertical: 5, horizontal: 8),
labelText: "Buis diameter (mm)",
hintText: '$diam2',
fillColor: Colors.cyan[200],
filled: true,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(40.0),
borderSide: BorderSide(),
),
),
),
),
SizedBox(height: 10),
// Uitkomsten
Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
SizedBox(height: 20),
// Berekenen knop
Center(
child: RaisedButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(18.0),
side: BorderSide(color: Colors.red)),
onPressed: () {
value = getValue(kapController.text, buizenController.text, diamController.text).toString();
setState(() {});
},
color: Colors.blue,
textColor: Colors.white,
child: Text("Berekenen".toUpperCase(),
style: TextStyle(fontSize: 14)),
),
),
SizedBox(height: 20),
Text(
'Specifiek vermogen ',
style: TextStyle(
backgroundColor: Colors.white,
fontWeight: FontWeight.bold),
),
// Specifiek vermogen
Container(
alignment: Alignment(0, 0),
width: 80,
height: 30,
margin: const EdgeInsets.only(right: 5.0),
padding: const EdgeInsets.all(3.0),
decoration: BoxDecoration(
color: Colors.red[200],
borderRadius: BorderRadius.horizontal(
left: Radius.circular(40),
right: Radius.circular(40),
),
border: Border.all(width: 1.0),
),
child:Text(
value[2].toString(), //here I read the first outcome
style: TextStyle(
fontSize: 15,
fontWeight: FontWeight.bold,
),
),
),
SizedBox(height: 10),
Text(
'Specifiek oppervlak ',
style: TextStyle(
backgroundColor: Colors.white,
fontWeight: FontWeight.bold),
),
// Specifiek oppervlak
Container(
alignment: Alignment(0, 0),
width: 80,
height: 30,
margin: const EdgeInsets.only(right: 5.0),
padding: const EdgeInsets.all(3.0),
decoration: BoxDecoration(
color: Colors.red[200],
borderRadius: BorderRadius.horizontal(
left: Radius.circular(40),
right: Radius.circular(40),
),
border: Border.all(width: 1.0),
),
child: Text(
value[3].toString(), // and here the second
style: TextStyle(
fontSize: 15,
fontWeight: FontWeight.bold,
),
),
),
SizedBox(height: 20),
SizedBox(height: 60),
],
),
],
),
),
),
),
),
);
}
}
getValue(kap, buizen, diam) {
var kap1 = double.parse(kap);
var buizen1 = double.parse(buizen);
var diam1 = double.parse(diam);
var spev = 1.7 * (diam1 / 51) * (buizen1 / kap1);
spev = num.parse(spev.toStringAsFixed(2));
var spo = (buizen1 * diam1 * 0.1) / kap1;
spo = num.parse(spo.toStringAsFixed(2));
print("Spev is " '$spev');
print("Spo is " '$spo');
List<double> valueList = List<double>();
valueList.add(spev);
valueList.add(spo);
print(valueList);
return valueList;
}
#Pim, there are few errors in your code,
you are explicitly calling list item on widget build, here you don't have the value yet
you are converting list into string with value = getValue(kapController.text, buizenController.text, diamController.text).toString(); , not sure why you're doing this but this in not correct.
Try assigning empty value to your textFields on widget build and then assign actual value on button press and finally refresh the state like so,
class Buis extends StatefulWidget {
#override
BuisState createState() => BuisState();
}
class BuisState extends State<Buis> {
var kap2 = '';
var buizen2 = '';
var diam2 = '';
var spev = '';
var spo = '';
var value;
var firstValue = '';
var secondValue = '';
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
TextEditingController kapController = TextEditingController();
TextEditingController buizenController = TextEditingController();
TextEditingController diamController = TextEditingController();
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Center(
child: Text("Specifiek buis vermogen"),
),
),
body: Center(
child: Container(
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
SizedBox(height: 20),
// Input kap breedte
Container(
width: 170,
height: 30,
child: TextFormField(
controller: kapController,
keyboardType: TextInputType.number,
style: TextStyle(fontWeight: FontWeight.bold),
decoration: InputDecoration(
contentPadding:
EdgeInsets.symmetric(vertical: 5, horizontal: 8),
labelText: "Kap breedte (mtr)",
hintText: "$kap2",
fillColor: Colors.cyan[200],
filled: true,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(40.0),
borderSide: BorderSide(),
),
),
),
),
SizedBox(height: 10),
// Input aantal buizen
Container(
width: 170,
height: 30,
child: TextFormField(
controller: buizenController,
keyboardType: TextInputType.number,
style: TextStyle(fontWeight: FontWeight.bold),
decoration: InputDecoration(
contentPadding:
EdgeInsets.symmetric(vertical: 5, horizontal: 8),
labelText: "Aantal buizen",
hintText: "$buizen2",
fillColor: Colors.cyan[200],
filled: true,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(40.0),
borderSide: BorderSide(),
),
),
),
),
SizedBox(height: 10),
// Input buis diameter
Container(
width: 170,
height: 30,
child: TextFormField(
controller: diamController,
keyboardType: TextInputType.number,
style: TextStyle(fontWeight: FontWeight.bold),
decoration: InputDecoration(
contentPadding:
EdgeInsets.symmetric(vertical: 5, horizontal: 8),
labelText: "Buis diameter (mm)",
hintText: '$diam2',
fillColor: Colors.cyan[200],
filled: true,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(40.0),
borderSide: BorderSide(),
),
),
),
),
SizedBox(height: 10),
// Uitkomsten
Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
SizedBox(height: 20),
// Berekenen knop
Center(
child: RaisedButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(18.0),
side: BorderSide(color: Colors.red)),
onPressed: () {
value = getValue(kapController.text, buizenController.text, diamController.text);
//Depending on how many value you will have;
firstValue = value[0].toString();
secondValue = value[1].toString();
setState(() {});
},
color: Colors.blue,
textColor: Colors.white,
child: Text("Berekenen".toUpperCase(),
style: TextStyle(fontSize: 14)),
),
),
SizedBox(height: 20),
Text(
'Specifiek vermogen ',
style: TextStyle(
backgroundColor: Colors.white,
fontWeight: FontWeight.bold),
),
// Specifiek vermogen
Container(
alignment: Alignment(0, 0),
width: 80,
height: 30,
margin: const EdgeInsets.only(right: 5.0),
padding: const EdgeInsets.all(3.0),
decoration: BoxDecoration(
color: Colors.red[200],
borderRadius: BorderRadius.horizontal(
left: Radius.circular(40),
right: Radius.circular(40),
),
border: Border.all(width: 1.0),
),
child:Text(
firstValue.toString(), //here I read the first outcome
style: TextStyle(
fontSize: 15,
fontWeight: FontWeight.bold,
),
),
),
SizedBox(height: 10),
Text(
'Specifiek oppervlak ',
style: TextStyle(
backgroundColor: Colors.white,
fontWeight: FontWeight.bold),
),
// Specifiek oppervlak
Container(
alignment: Alignment(0, 0),
width: 80,
height: 30,
margin: const EdgeInsets.only(right: 5.0),
padding: const EdgeInsets.all(3.0),
decoration: BoxDecoration(
color: Colors.red[200],
borderRadius: BorderRadius.horizontal(
left: Radius.circular(40),
right: Radius.circular(40),
),
border: Border.all(width: 1.0),
),
child: Text(
secondValue.toString(), // and here the second
style: TextStyle(
fontSize: 15,
fontWeight: FontWeight.bold,
),
),
),
SizedBox(height: 20),
SizedBox(height: 60),
],
),
],
),
),
),
),
),
);
}
}
getValue(kap, buizen, diam) {
var kap1 = double.parse(kap);
var buizen1 = double.parse(buizen);
var diam1 = double.parse(diam);
var spev = 1.7 * (diam1 / 51) * (buizen1 / kap1);
spev = num.parse(spev.toStringAsFixed(2));
var spo = (buizen1 * diam1 * 0.1) / kap1;
spo = num.parse(spo.toStringAsFixed(2));
print("Spev is " '$spev');
print("Spo is " '$spo');
List<double> valueList = List<double>();
valueList.add(spev);
valueList.add(spo);
print(valueList);
return valueList;
}
When you call a string as string[1], you are asking for the second character in the string.
When you set value, you are setting it as a string. Try removing .toString() from the end of value = getValue(kapController.text, buizenController.text, diamController.text).toString(); This way value will be a list and you can get the nth element of that list.
I'd also suggest setting the type of value when you first declare it. Instead of var value; use List<double> value;
I have multiple images each with their own redirect link. Currently this works fine at displaying using a list view build to display the images inside a gesture detector.
However, I’d like to add a dot indicator to show which image is being viewed. How can I get the index of the image being displayed? Or increase / decrease a counter when swiping left or right.
I’ve looked into carousels but they don’t seem to allow each image to redirect to somewhere else.
As per example pointed to by #chunhunghan above in the comments, you need to replace map<Widget> ( (image, url) {..}
with
imgList.map((image) {int index = imgList.indexOf(image); ..}
I was able to get it to work with the above change. Revised code snippet for the build method:
#override
Widget build(BuildContext context) {
return Column(children: [
CarouselSlider(
items: child,
autoPlay: false,
enlargeCenterPage: true,
aspectRatio: 2.0,
onPageChanged: (index) {
setState(() {
_current = index;
print("${_current}");
});
},
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: imgList.map((image) { //these two lines
int index=imgList.indexOf(image); //are changed
return Container(
width: 8.0,
height: 8.0,
margin: EdgeInsets.symmetric(vertical: 10.0, horizontal: 2.0),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: _current == index
? Color.fromRGBO(0, 0, 0, 0.9)
: Color.fromRGBO(0, 0, 0, 0.4)),
);
},
),
),
]);
}
If I understand you clear. with package https://pub.dev/packages/carousel_slider
swipe image to left or right can get current page from onPageChanged event
and use InkWell wrap image, you can navigate to other page. In my demo just print click message
code snippet
final List child = map<Widget>(
imgList,
(index, i) {
return Container(
margin: EdgeInsets.all(5.0),
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(5.0)),
child: Stack(children: <Widget>[
InkWell(
onTap: () { print("you click ${index} "); },
child: Image.network(i, fit: BoxFit.cover, width: 1000.0)),
Positioned(
bottom: 0.0,
left: 0.0,
right: 0.0,
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Color.fromARGB(200, 0, 0, 0), Color.fromARGB(0, 0, 0, 0)],
begin: Alignment.bottomCenter,
end: Alignment.topCenter,
),
),
padding: EdgeInsets.symmetric(vertical: 10.0, horizontal: 20.0),
child: Text(
'No. $index image',
style: TextStyle(
color: Colors.white,
fontSize: 20.0,
fontWeight: FontWeight.bold,
),
),
),
),
]),
),
);
},
).toList();
...
class _CarouselWithIndicatorState extends State<CarouselWithIndicator> {
int _current = 0;
#override
Widget build(BuildContext context) {
return Column(children: [
CarouselSlider(
items: child,
autoPlay: false,
enlargeCenterPage: true,
aspectRatio: 2.0,
onPageChanged: (index) {
setState(() {
_current = index;
print("${_current}");
});
},
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: map<Widget>(
imgList,
(index, url) {
return Container(
width: 8.0,
height: 8.0,
margin: EdgeInsets.symmetric(vertical: 10.0, horizontal: 2.0),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: _current == index
? Color.fromRGBO(0, 0, 0, 0.9)
: Color.fromRGBO(0, 0, 0, 0.4)),
);
},
),
),
]);
}
}
The solution I found, besides change map to use imgList, was to put .toList() at the imgList.map function return as follows:
#override
Widget build(BuildContext context) {
return Column(children: [
CarouselSlider(
items: child,
autoPlay: false,
enlargeCenterPage: true,
aspectRatio: 2.0,
onPageChanged: (index) {
setState(() {
_current = index;
print("${_current}");
});
},
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: imgList.map((image) {
int index=imgList.indexOf(image);
return Container(
width: 8.0,
height: 8.0,
margin: EdgeInsets.symmetric(vertical: 10.0, horizontal: 2.0),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: _current == index
? Color.fromRGBO(0, 0, 0, 0.9)
: Color.fromRGBO(0, 0, 0, 0.4)
),
);
},
).toList(), // this was the part the I had to add
),
]);
}
Vertical Indicators On Slider or Flutter Carousel
class VerticalSlider extends StatefulWidget {
#override
_VerticalSliderState createState() => _VerticalSliderState();
}
class _VerticalSliderState extends State<VerticalSlider> {
List imageSliders=[
//add your items here
];
int _current = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Vertical sliding carousel ')),
body: Stack(
children: [
Container(
child: CarouselSlider(
options: CarouselOptions(
viewportFraction: .6,
aspectRatio: 1.2,
enlargeCenterPage: true,
scrollDirection: Axis.vertical,
autoPlay: true,
onPageChanged: (index, reason) {
setState(() {
_current = index;
});
}
),
items: imageSliders,
)
),
Positioned(
top: 50,
right: 10,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: imgList.map((url) {
int index = imgList.indexOf(url);
return Container(
width: 8.0,
height: 8.0,
margin: EdgeInsets.symmetric(vertical: 4.0, horizontal: 2.0),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: _current == index
? Colors.white60
: Color.fromRGBO(0, 0, 0, 0.4),
),
);
}).toList(),
),
),
],
),
);
}
}
And you may add custom indicators too.
The easiest way is to use CarouselSlider with the AnimatedSmoothIndicator widget
int _current = 0;
#override
Widget build(BuildContext context) {
Column(children: [
CarouselSlider(
options: CarouselOptions(
height: MediaQuery.of(context).size.height / 2,
onPageChanged: (i, r) {
setState(() {
_current = i;
});
}),
items: imageList.map((e) => Container(
child: Image.network(e, fit: BoxFit.cover),
))
.toList(),
),
Container(
margin: EdgeInsets.symmetric(vertical: 10.0, horizontal: 2.0),
child: AnimatedSmoothIndicator(
activeIndex: _current,
count: imageList.length,
effect: ExpandingDotsEffect(
activeDotColor: Color.fromRGBO(0, 0, 0, 0.9),
dotWidth: 8,
dotHeight: 8),
),
)
]);
add auto slider code for flutter like this....
output screen shorts is here
class _ProductDetailsState extends State<ProductDetails> {
List imageSliders = [
'assets/images/man_1.png',
'assets/images/man_2.png',
'assets/images/man_3.png',
'assets/images/woman_1.png',
'assets/images/woman_2.png',
'assets/images/woman_3.png',
'assets/images/woman_4.png',
'assets/images/woman_5.png',
'assets/images/woman_6.png',
'assets/images/woman_7.png',
];
#override
Widget build(BuildContext context) {
SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle(
systemNavigationBarColor: Color(0xFF000000),
systemNavigationBarIconBrightness: Brightness.dark,
systemNavigationBarDividerColor: null,
statusBarColor: Color(0xFFFFFFFF),
statusBarIconBrightness: Brightness.dark,
statusBarBrightness: Brightness.dark,
));
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
elevation: 0,
automaticallyImplyLeading: false,
backgroundColor: Colors.white,
leading: Padding(
padding: const EdgeInsets.only(
left: 20,
top: 10,
),
child: IconButton(
icon: Icon(
Icons.keyboard_backspace_sharp,
size: 35,
color: Colors.grey[600],
),
onPressed: () => Navigator.of(context).pop(),
),
),
actions: [
Padding(
padding: const EdgeInsets.only(
left: 0,
top: 10,
),
child: IconButton(
icon: const Icon(
Icons.search_outlined,
color: Colors.black,
size: 30,
),
onPressed: () {},
),
),
Padding(
padding: const EdgeInsets.only(
left: 0,
top: 10,
right: 20,
),
child: IconButton(
icon: Stack(
children: [
if (_newNotification)
Positioned(
right: 1,
top: 1,
child: Container(
decoration: BoxDecoration(
shape: BoxShape.circle, color: Colors.red),
width: 20.0 / 2.5,
height: 20.0 / 2.5,
),
),
Icon(
Icons.notifications_none_outlined,
color: Colors.black,
size: 30,
)
],
),
onPressed: () {},
),
),
],
),
body: Column(
children: [
Container(
child: CarouselSlider(
options: CarouselOptions(
height: 200,
viewportFraction: .6,
aspectRatio: 1.2,
enlargeCenterPage: true,
scrollDirection: Axis.horizontal,
autoPlay: true,
onPageChanged: (index, reason) {
setState(() {
activeIndex = index;
});
}
),
items: [
for(var item in imageSliders ) Image.asset(item)
],
)
),
Positioned(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: imageSliders.map((url) {
int index = imageSliders.indexOf(url);
return Container(
width: 8.0,
height: 8.0,
margin: EdgeInsets.symmetric(vertical: 4.0, horizontal: 2.0),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: activeIndex == index
? Colors.blue
: Color.fromRGBO(0, 0, 0, 0.4),
),
);
}).toList(),
),
),
],
),
);
}
}