I have list of products . While adding them to cart I am doing setstate and updating ui with number of items to the cart. While doing setstate my listview is going to first position. What I want it to be on the same scroll position where I added the item to cart? Any idea how to do this?`
getCart() async {
Result response = await authService.fetchCart();
loading = true;
if (response is SuccessState) {
if (response.value['status'] == true) {
List tempCart = [];
for (var i = 0; i < response.value['data'].length; i ) {
if (response.value['data'][i]['type'] == 'Products') {
tempCart = response.value['data'][i]['data'];
}
}
loading = false;
setState(() {
cart = tempCart;
});
} else {
loading = false;
}
} else {
loading = false;
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Center(
child: Text('Server error please try after some time!!!')),
actions: <Widget>[
Center(
child: InkWell(
onTap: () {
Navigator.pop(context);
},
child: Container(
decoration: BoxDecoration(
color: AppColors.primaryColor,
borderRadius: BorderRadius.all(
Radius.circular(20.0),
)),
margin:
EdgeInsets.symmetric(horizontal: 0, vertical: 20),
child: Padding(
padding: EdgeInsets.only(
left: 40, right: 40, top: 10, bottom: 10),
child: Text('Ok',
style: TextStyle(
fontWeight: FontWeight.w400,
fontSize: AppStyles.SMALL_TEXTSIZE,
color: Colors.white),
textAlign: TextAlign.center),
)),
),
),
],
);
});
}
}`
ListView.builder( key: PageStorageKey(_globalCounter), physics: NeverScrollableScrollPhysics(), scrollDirection: Axis.vertical, shrinkWrap: true, itemCount: products.length, itemBuilder: (context, i) { if (products.length > 0 && i == products.length - 1 && page < total_pages) { print('index equal to length'); loading = true; return _buildProgressIndicator(); } else { return GestureDetector( onTap: () { Navigator.of(context).push( MaterialPageRoute( builder: (context) => ProductDetail( id: products[i]['id'].toString()), ), ); }, child: Container( decoration: BoxDecoration( border: Border.all( color: Colors.grey[100], width: 1), borderRadius: BorderRadius.all( Radius.circular(10.0), ), ), child: Padding( padding: EdgeInsets.only( top: 25, bottom: 10, left: 0, right: 0), child: Row( children: [ Expanded( child: Container( child: // Image.network( // products[i]['image'] != // null // ? products[i] // ['image'] // : '') CachedNetworkImage( imageUrl: products[i]['image'], placeholder: (context, url) => Align( alignment: Alignment.center, child: Loader(), ),
errorWidget: (context, url, error) => Icon(Icons.error),
),
)),
Expanded(
flex: 2,
child: Column(
children: [
Padding(
padding:
EdgeInsets.only(
top: 5,
bottom: 5,
left: 10,
right: 5),
child: Text(
products[i][
'generic_name'],
style: TextStyle(
fontWeight:
FontWeight
.w500,
fontSize:
AppStyles
.SMALL_TEXTSIZE))),
Padding(
padding:
EdgeInsets.only(
top: 2,
bottom: 5,
left: 10,
right: 5),
child: Container(
width: double
.infinity,
child: Wrap(
children: [
Text('MRP ',
style: TextStyle(
fontWeight: FontWeight
.w500,
fontSize: AppStyles
.SMALL_TEXTSIZE,
color: Colors
.deepOrangeAccent,
decoration:
TextDecoration.lineThrough)),
Text(
'Rs. ${products[i]['mrp_amount']} ',
style: TextStyle(
fontWeight: FontWeight
.w500,
fontSize: AppStyles
.SMALL_TEXTSIZE,
color: Colors
.deepOrangeAccent,
decoration:
TextDecoration.lineThrough)),
Text(
' Rs. ${products[i]['chemist_amount']}',
style: TextStyle(
fontWeight: FontWeight
.w500,
fontSize: AppStyles
.SMALL_TEXTSIZE,
color:
Colors.lightGreen))
],
))),
Padding(
padding:
EdgeInsets.only(
top: 2,
bottom: 5,
left: 10,
right: 5),
child: Row(
children: [
Expanded(
child:
Container(
width: double
.infinity,
child: Text(
('${products[i]['package']}' !=
null)
? '${products[i]['package']}'
: '',
style: TextStyle(
fontWeight:
FontWeight
.w500,
fontSize:
AppStyles
.SMALL_TEXTSIZE,
color: Colors
.grey)),
)),
],
)),
if (products[i] != null &&
isProductExistInCart(
products[i]
['id']) !=
null)
Row(
children: [
Expanded(
child: Row(
children: [
Expanded(
flex: 1,
child: Container(
width: double.infinity,
child: RawMaterialButton(
onPressed:
() {
addItemToCart(products[i]['id'],
'remove');
},
elevation:
2.0,
fillColor:
Colors.white,
child: Text(
'-',
style: TextStyle(fontSize: AppStyles.SMALL_TEXTSIZE, fontWeight: FontWeight.bold)),
padding:
EdgeInsets.all(1.0),
shape:
CircleBorder(),
))),
Expanded(
flex: 1,
child: Container(
width: double
.infinity,
child: Text(
getCartCount(products[i][
'id']),
textAlign:
TextAlign.center,
style: TextStyle(fontSize: AppStyles.SMALL_TEXTSIZE, fontWeight: FontWeight.bold)))),
Expanded(
flex: 1,
child:
RawMaterialButton(
onPressed:
() {
//check Stock qty
if (isAvailableInStock(
products[
i])) {
addItemToCart(
products[i]['id'],
'add');
_globalCounter=i;
} else {
final snackBar =
SnackBar(
content: Text("This product is limited with"
products[i]['stock_in']
" items"),
duration:
Duration(seconds: 2),
);
_scaffoldKey
.currentState
.showSnackBar(snackBar);
}
},
elevation:
2.0,
fillColor:
Colors
.white,
child: Text(
' ',
style: TextStyle(
fontSize:
AppStyles.SMALL_TEXTSIZE,
fontWeight: FontWeight.bold)),
padding:
EdgeInsets.all(
1.0),
shape:
CircleBorder(),
),
),
Expanded(
child:
Container())
],
)),
],
),
getBuyNowButton(
products[i])
],
))
],
))));
}
},
)
CodePudding user response:
By far, the easiest solution is to use Scrollable.ensureVisible(context). As it does everything for you and work with any widget size. Fetching the context using GlobalKey.
The problem is that ListView won't render non-visible items. Meaning that your target most likely will not be built at all. Which means your target will have no context ; preventing you from using that method without some more work.
In the end, the easiest solution will be to replace your ListView by a SingleChildScrollView and wrap your children into a Column. Example :
class ScrollView extends StatelessWidget {
final dataKey = new GlobalKey();
@override
Widget build(BuildContext context) {
return new Scaffold(
primary: true,
appBar: new AppBar(
title: const Text('Home'),
),
body: new SingleChildScrollView(
child: new Column(
children: <Widget>[
new SizedBox(height: 160.0, width: double.infinity, child: new Card()),
new SizedBox(height: 160.0, width: double.infinity, child: new Card()),
new SizedBox(height: 160.0, width: double.infinity, child: new Card()),
// destination
new Card(
key: dataKey,
child: new Text("data\n\n\n\n\n\ndata"),
)
],
),
),
bottomNavigationBar: new RaisedButton(
onPressed: () => Scrollable.ensureVisible(dataKey.currentContext),
child: new Text("Scroll to data"),
),
);
}
}
NOTE : While this allows to scroll to the desired item easily, consider this method only for small predefined lists. As for bigger lists you'll get performance problems.
But it's possible to make Scrollable.ensureVisible work with ListView ; although it will require more work.
CodePudding user response:
you can use this library to go to a specific index at anytime
CodePudding user response:
Can you show some code? it seems that maybe you're updating your whole screen, resseting the scroll widget and its value, maybe by creating your own ScrollController in an StatefulWidget you could solve the problem, but again, show some code first so people can understand better your problem....
