Flutter : How to prevent rebuild of whole Reorderable Listview? - android

Currently I'm using flutter package 'Reorderables' to show a reorderable listview which contains several images.These images can be deleted from listview through a button , everything works fine. But the listview rebuild everytime when I delete an image. I'm using a class called 'ReorderableListviewManager' with ChangeNotifier to update images and Provider.of<ReorderableListviewManager>(context) to get latest images . The problem now is that using Provider.of<ReorderableListviewManager>(context) makes build() called everytime I delete an image , so the listview rebuid. I koow I
can use consumer to only rebuild part of widget tree, but it seems like that there's no place to put consumer in children of this Listview. Is there a way to rebuild only image but not whole ReorderableListview ? Thanks very much!
Below is my code:
class NotePicturesEditScreen extends StatefulWidget {
final List<Page> notePictures;
final NotePicturesEditBloc bloc;
NotePicturesEditScreen({#required this.notePictures, #required this.bloc});
static Widget create(BuildContext context, List<Page> notePictures) {
return Provider<NotePicturesEditBloc>(
create: (context) => NotePicturesEditBloc(),
child: Consumer<NotePicturesEditBloc>(
builder: (context, bloc, _) =>
ChangeNotifierProvider<ReorderableListviewManager>(
create: (context) => ReorderableListviewManager(),
child: NotePicturesEditScreen(
bloc: bloc,
notePictures: notePictures,
),
)),
dispose: (context, bloc) => bloc.dispose(),
);
}
#override
_NotePicturesEditScreenState createState() => _NotePicturesEditScreenState();
}
class _NotePicturesEditScreenState extends State<NotePicturesEditScreen> {
PreloadPageController _pageController;
ScrollController _reorderableScrollController;
List<Page> notePicturesCopy;
int longPressIndex;
List<double> smallImagesWidth;
double scrollOffset = 0;
_reorderableScrollListener() {
scrollOffset = _reorderableScrollController.offset;
}
#override
void initState() {
Provider.of<ReorderableListviewManager>(context, listen: false)
.notePictures = widget.notePictures;
notePicturesCopy = widget.notePictures;
_reorderableScrollController = ScrollController();
_pageController = PreloadPageController();
_reorderableScrollController.addListener(_reorderableScrollListener);
Provider.of<ReorderableListviewManager>(context, listen: false)
.getSmallImagesWidth(notePicturesCopy, context)
.then((imagesWidth) {
smallImagesWidth = imagesWidth;
});
super.initState();
}
#override
void dispose() {
_pageController.dispose();
_reorderableScrollController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
ReorderableListviewManager reorderableManager =
Provider.of<ReorderableListviewManager>(context, listen: false);
return SafeArea(
child: Scaffold(
appBar: AppBar(
backgroundColor: Colors.white,
shape: Border(bottom: BorderSide(color: Colors.black12)),
iconTheme: IconThemeData(color: Colors.black87),
elevation: 0,
automaticallyImplyLeading: false,
titleSpacing: 0,
centerTitle: true,
title: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
child: IconButton(
padding: EdgeInsets.only(left: 20, right: 12),
onPressed: () => Navigator.of(context).pop(),
icon: Icon(Icons.close),
),
),
Text('編輯',
style: TextStyle(color: Colors.black87, fontSize: 18))
],
),
actions: <Widget>[
FlatButton(
onPressed: () {},
child: Text(
'下一步',
),
)
],
),
backgroundColor: Color(0xffeeeeee),
body: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Spacer(),
StreamBuilder<List<Page>>(
initialData: widget.notePictures,
stream: widget.bloc.notePicturesStream,
builder: (context, snapshot) {
notePicturesCopy = snapshot.data;
return Container(
margin: EdgeInsets.symmetric(horizontal: 20),
height: MediaQuery.of(context).size.height * 0.65,
child: PreloadPageView.builder(
preloadPagesCount: snapshot.data.length,
controller: _pageController,
itemCount: snapshot.data.length,
onPageChanged: (index) {
reorderableManager.updateCurrentIndex(index);
reorderableManager.scrollToCenter(
smallImagesWidth,
index,
scrollOffset,
_reorderableScrollController,
context);
},
itemBuilder: (context, index) {
return Container(
child: Image.memory(
File.fromUri(
snapshot.data[index].polygon.isNotEmpty
? snapshot.data[index]
.documentPreviewImageFileUri
: snapshot.data[index]
.originalPreviewImageFileUri)
.readAsBytesSync(),
gaplessPlayback: true,
alignment: Alignment.center,
),
);
}),
);
},
),
Spacer(),
Container(
height: MediaQuery.of(context).size.height * 0.1,
margin: EdgeInsets.symmetric(horizontal: 20),
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: ReorderableRow(
scrollController: _reorderableScrollController,
buildDraggableFeedback: (context, constraints, __) =>
Container(
width: constraints.maxWidth,
height: constraints.maxHeight,
child: Image.memory(File.fromUri(
notePicturesCopy[longPressIndex]
.polygon
.isNotEmpty
? notePicturesCopy[longPressIndex]
.documentPreviewImageFileUri
: notePicturesCopy[longPressIndex]
.originalPreviewImageFileUri)
.readAsBytesSync()),
),
onReorder: (oldIndex, newIndex) async {
List<Page> result = await widget.bloc.reorderPictures(
oldIndex,
newIndex,
reorderableManager.notePictures);
_pageController.jumpToPage(newIndex);
reorderableManager.updateNotePictures(result);
reorderableManager
.getSmallImagesWidth(result, context)
.then((imagesWidth) {
smallImagesWidth = imagesWidth;
});
},
footer: Container(
width: 32,
height: 32,
margin: EdgeInsets.only(left: 16),
child: SizedBox(
child: FloatingActionButton(
backgroundColor: Colors.white,
elevation: 1,
disabledElevation: 0,
highlightElevation: 1,
child: Icon(Icons.add, color: Colors.blueAccent),
onPressed: notePicturesCopy.length >= 20
? () {
Scaffold.of(context)
.showSnackBar(SnackBar(
content: Text('筆記上限為20頁 !'),
));
}
: () async {
List<Page> notePictures =
await widget.bloc.addPicture(
reorderableManager.notePictures);
List<double> imagesWidth =
await reorderableManager
.getSmallImagesWidth(
notePictures, context);
smallImagesWidth = imagesWidth;
reorderableManager.updateCurrentIndex(
notePictures.length - 1);
reorderableManager
.updateNotePictures(notePictures);
_pageController
.jumpToPage(notePictures.length - 1);
},
),
),
),
children: Provider.of<ReorderableListviewManager>(
context)
.notePictures
.asMap()
.map((index, page) {
return MapEntry(
index,
Consumer<ReorderableListviewManager>(
key: ValueKey('value$index'),
builder: (context, manager, _) =>
GestureDetector(
onTapDown: (_) {
longPressIndex = index;
},
onTap: () {
reorderableManager.scrollToCenter(
smallImagesWidth,
index,
scrollOffset,
_reorderableScrollController,
context);
_pageController.jumpToPage(index);
},
child: Container(
margin: EdgeInsets.only(
left: index == 0 ? 0 : 12),
decoration: BoxDecoration(
border: Border.all(
width: 1.5,
color: index ==
manager
.getCurrentIndex
? Colors.blueAccent
: Colors.transparent)),
child: index + 1 <=
manager.notePictures.length
? Image.memory(
File.fromUri(manager
.notePictures[
index]
.polygon
.isNotEmpty
? manager
.notePictures[
index]
.documentPreviewImageFileUri
: manager
.notePictures[
index]
.originalPreviewImageFileUri)
.readAsBytesSync(),
gaplessPlayback: true,
)
: null),
),
));
})
.values
.toList()),
)),
Spacer(),
Container(
decoration: BoxDecoration(
color: Colors.white,
border: Border(top: BorderSide(color: Colors.black12))),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
FlatButton(
onPressed: () async => await widget.bloc
.cropNotePicture(reorderableManager.notePictures,
_pageController.page.round())
.then((notePictures) {
reorderableManager.updateNotePictures(notePictures);
reorderableManager
.getSmallImagesWidth(notePictures, context)
.then((imagesWidth) {
smallImagesWidth = imagesWidth;
});
}),
child: Column(
children: <Widget>[
Icon(
Icons.crop,
color: Colors.blueAccent,
),
Container(
margin: EdgeInsets.only(top: 1),
child: Text(
'裁切',
style: TextStyle(color: Colors.blueAccent),
),
)
],
),
),
FlatButton(
onPressed: () {
int deleteIndex = _pageController.page.round();
widget.bloc
.deletePicture(
reorderableManager.notePictures, deleteIndex)
.then((notePictures) {
if (deleteIndex == notePictures.length) {
reorderableManager
.updateCurrentIndex(notePictures.length - 1);
}
reorderableManager.updateNotePictures(notePictures);
reorderableManager
.getSmallImagesWidth(notePictures, context)
.then((imagesWidth) {
smallImagesWidth = imagesWidth;
});
if (reorderableManager.notePictures.length == 0) {
Navigator.pop(context);
}
});
},
child: Column(
children: <Widget>[
Icon(
Icons.delete_outline,
color: Colors.blueAccent,
),
Container(
margin: EdgeInsets.only(top: 1),
child: Text(
'刪除',
style: TextStyle(color: Colors.blueAccent),
),
),
],
),
)
],
),
)
],
)),
);
}
}

You can't prevent a rebuild on your ReorderableListView widget because it will be rebuild every time there's an update on the Provider. What you can do here is to keep track the current index of all visible ListView items. When new data should be displayed coming from the Provider, you can retain the current indices of previous ListView items, and add the newly added items at the end of the list, or wherever you like.

Related

Updating text value with new discount amount in flutter

I'm making a food ordering app in which I want to provide a discount feature. I've implemented most of the part but I'm getting stuck at a point where I basically want to update the totalAmount with the discountRate.
class CartScreen extends StatefulWidget
{
final String? sellerUID;
const CartScreen({super.key, this.sellerUID});
#override
_CartScreenState createState() => _CartScreenState();
}
class _CartScreenState extends State<CartScreen>
{
List<int>? separateItemQuantityList;
num totalAmount = 0;
final _couponText = TextEditingController();
#override
void initState() {
super.initState();
totalAmount = 0;
Provider.of<TotalAmount>(context, listen: false).displayTotalAmount(0);
separateItemQuantityList = separateItemQuantities();
}
#override
Widget build(BuildContext context) {
var _coupon = Provider.of<CouponProvider>(context);
double discountRate = _coupon.discount/100;
return Scaffold(
appBar: AppBar(
title: const Text("Cart"),
flexibleSpace: Container(decoration: BoxDecoration(color: myColor),),
automaticallyImplyLeading: true,
),
body: CustomScrollView(
slivers: [
//display cart items with quantity number
StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection("items")
.where("itemID", whereIn: separateItemIDs())
.orderBy("publishedDate", descending: true)
.snapshots(),
builder: (context, snapshot)
{
return !snapshot.hasData
? SliverToBoxAdapter(child: Center(child: circularProgress(),),)
: snapshot.data!.docs.isEmpty
? const SliverToBoxAdapter(child: Center(child: Padding(
padding: EdgeInsets.only(top: 300),
child: Text("The cart is empty",style: TextStyle(
fontSize: 24, fontWeight: FontWeight.bold),),
)))
: SliverList(
delegate: SliverChildBuilderDelegate((context, index)
{
Items model = Items.fromJson(
snapshot.data!.docs[index].data()! as Map<String, dynamic>,
);
if(index == 0)
{
totalAmount = 0;
totalAmount = totalAmount + (model.price! * separateItemQuantityList![index]);
}
else
{
totalAmount = totalAmount + (model.price! * separateItemQuantityList![index]);
}
if(snapshot.data!.docs.length - 1 == index)
{
WidgetsBinding.instance.addPostFrameCallback((timeStamp)
{
Provider.of<TotalAmount>(context, listen: false).displayTotalAmount(totalAmount.toDouble());
});
}
return CartItemDesign(
model: model,
context: context,
quanNumber: separateItemQuantityList![index],
);
},
childCount: snapshot.hasData ? snapshot.data!.docs.length : 0,
),
);
},
),
SliverFillRemaining(
hasScrollBody: false,
child: Align(
alignment: Alignment.bottomCenter,
child: Container(
decoration: BoxDecoration(
color: const Color(0xfffb9e5a).withOpacity(0.6),
borderRadius: const BorderRadius.only(topLeft: Radius.circular(20), topRight: Radius.circular(20)),
),
width: double.infinity,
height: 160,
child: Padding(
padding: const EdgeInsets.fromLTRB(8, 12, 8, 6),
child: Column(
children: [
Consumer2<TotalAmount, CartItemCounter>(builder: (context, amountProvider, cartProvider, c){
return Center(
child: cartProvider.count == 0
? const Text("Please add something in the cart", style: TextStyle(fontSize: 18),)
: Column(
children: [
Text("The total amount is ₹${amountProvider.tAmount.toString()}", style: const TextStyle(fontSize: 18)),
const SizedBox(height: 10,),
Container(
height: 50,
width: MediaQuery.of(context).size.width * 8,
decoration: BoxDecoration(
border: Border.all(color: myColor, width: 1,),
borderRadius: const BorderRadius.all(Radius.circular(20)),
color: Colors.white54
//color: Colors.white54
),
child: Row(
children: [
Expanded(
child: Padding(
padding: const EdgeInsets.only(left: 10, right: 15),
child: TextField(
controller: _couponText,
maxLines: 1,
decoration: const InputDecoration.collapsed(
hintText: 'Apply coupon here ...'
),
),
),
),
Padding(
padding: const EdgeInsets.only(right: 10),
child: ElevatedButton(
onPressed: (){
_coupon.getcouponDetails(_couponText.text).then((value) {
if(value.data() == null){
setState(() {
_coupon.discount = 0;
});
showCodeDialog(_couponText.text, 'not valid');
return;
}
if(_coupon.expired==false){
// Code to be done here.
Fluttertoast.showToast(msg: 'Coupon is valid');
// I want to update the totalAmount value with the discountRate here...
}
if(_coupon.expired==true){
setState(() {
_coupon.discount = 0;
});
showCodeDialog(_couponText.text, 'expired');
return;
}
});
},
style: ElevatedButton.styleFrom(
textStyle: const TextStyle(
fontSize: 15,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
)
),
child: const Text('Apply'),
),
),
],
),
),
const SizedBox(height: 10,),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton.icon(
onPressed: (){
clearCartNow(context);
Navigator.pop(context);
Navigator.push(context, MaterialPageRoute(builder: (c) => const HomeScreen()));
Fluttertoast.showToast(msg: "Cart cleared");
},
style: ElevatedButton.styleFrom(
foregroundColor: Colors.black, backgroundColor: myColor
),
icon: const Icon(Icons.clear_all),
label: const Text("Clear")),
ElevatedButton.icon(
onPressed: (){
Navigator.pop(context);
Navigator.push(context, MaterialPageRoute(builder: (c)=> AddressScreen(
totalAmount: totalAmount.toDouble(),
sellerUID: widget.sellerUID,
),
),
);
},
style: ElevatedButton.styleFrom(
foregroundColor: Colors.black,
backgroundColor: myColor,
),
icon: const Icon(Icons.navigate_next),
label: const Text("Proceed")),
],
)
],
),
);
}),
],
),
)
),
),
)
],
),
);
}
showCodeDialog(code, validity){
showCupertinoDialog(
context: context,
builder: (BuildContext context){
return CupertinoAlertDialog(
title: const Text('Apply Coupon'),
content: Text('This discount coupon $code you have entered is $validity'),
actions: [
Padding(
padding: const EdgeInsets.all(8.0),
child: ElevatedButton(
onPressed: (){Navigator.pop(context);},
child: Text('Ok', style: TextStyle(color: Colors.white),),
),
)
],
);
});
}
}
I tried changing the totalAmount, amountProvider.tAmount and their types, but nothing is working for me.
In this image, the total amount is without discount. If I apply a coupon of 10%, the total amount should be subtracted by 10%.
I can add more information if required.

How to use indexwhere

class SearchBar extends SearchDelegate {
final TumUrunlerDeneme _tumUrunlerDeneme = TumUrunlerDeneme();
#override
List<Widget> buildActions(BuildContext context) {
return [
IconButton(
onPressed: () {
query = '';
},
icon: const Icon(Icons.close))
];
}
#override
Widget buildLeading(BuildContext context) {
return IconButton(
icon: const Icon(Icons.arrow_back_ios),
onPressed: () {
Navigator.pop(context);
},
);
}
#override
Widget buildResults(BuildContext context) {
return FutureBuilder<List<Products>>(
future: _tumUrunlerDeneme.getuserList(query: query),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return const Center(
child: CircularProgressIndicator(),
);
}
List<Products> ?data = snapshot.data;
return ListView.builder(
shrinkWrap: true,
//physics: const NeverScrollableScrollPhysics(),
itemCount: data!.length,
itemBuilder: (context, index) {
return Column(
children: [
Flex(
direction: Axis.vertical,
children:[ SingleChildScrollView(
scrollDirection: Axis.vertical,
child: GestureDetector(
onTap: () {
Get.toNamed(RouteHelper.getAllProduct(index));
},
child: Container(
margin: EdgeInsets.only(
left: Dimensions.width20,
right: Dimensions.width10,
bottom: Dimensions.height15),
child: Row(
children: [
//image section
Container(
width: Dimensions.listViewImgSize,
height: Dimensions.listViewImgSize,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(
Dimensions.radius20),
color: Colors.white38,
image: DecorationImage(
fit: BoxFit.cover,
image: CachedNetworkImageProvider(
AppConstans.BASE_URL +
AppConstans.UPLOAD_URL +
data[index]
.img!))),
),
//text section
Expanded(
child: Container(
height: Dimensions.listViewTextContSize,
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topRight: Radius.circular(
Dimensions.radius20),
bottomRight: Radius.circular(
Dimensions.radius20)),
color: Colors.white),
child: Padding(
padding: EdgeInsets.only(
left: Dimensions.width10,
right: Dimensions.width10),
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
mainAxisAlignment:
MainAxisAlignment.center,
children: [
BigText(
text: data[index].name!,
),
SizedBox(
height: Dimensions.height10,
),
ExpandableProductText(
text: data[index]
.description!),
SizedBox(
height: Dimensions.height10,
),
],
),
),
),
)
],
)),
),
),
]),
],
);
});
});
}
#override
Widget buildSuggestions(BuildContext context) {
return const Center(
child: Text('Ürün Arama'),
);
}
}
Here is detail page :
class AllProductDetail extends StatelessWidget {
final int pageId;
const AllProductDetail({Key? key, required this.pageId}) : super(key: key);
#override
Widget build(BuildContext context) {
var product = Get.find<TumUrunlerController>().tumUrunlerList[pageId];
return Scaffold(
backgroundColor: Colors.white,
body: CustomScrollView(
slivers: [
SliverAppBar(
automaticallyImplyLeading: false,
toolbarHeight: 70,
title: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
GestureDetector(onTap: (){
Navigator.of(context).pop(context);
}
,child: const AppIcon(icon: Icons.arrow_back_ios),
),
],
),
bottom: PreferredSize(
preferredSize: const Size.fromHeight(20),
child: Container(
child: Center(
child: BigText(
text: product.name!,
size: Dimensions.font20,
)),
width: double.maxFinite,
padding: const EdgeInsets.only(top: 0, bottom: 0),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(Dimensions.radius20),
topRight: Radius.circular(Dimensions.radius20))),
),
),
backgroundColor: Colors.white,
pinned: true,
expandedHeight: Dimensions.imgsize,
flexibleSpace: FlexibleSpaceBar(
background: Image.network(
AppConstans.BASE_URL+AppConstans.UPLOAD_URL+product.img!,
width: double.maxFinite,
fit: BoxFit.fitWidth,
),
),
),
SliverToBoxAdapter(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
child: ExpandableText(
text: product.description!
),
margin: EdgeInsets.only(
left: Dimensions.width20, right: Dimensions.width20),
),
],
),
)
],
),
);
}
}
here is Controller page:
class TumUrunlerDeneme {
late var data = [];
List<Products> results= [];
String urlList = 'http://mzpdata.com/api/v1/products/allproduct';
Future<List<Products>> getuserList({String? query}) async {
var url = Uri.parse("http://mzpdata.com/api/v1/products/allproduct");
print("got TumUrunlerDeneme 1");
try {
http.Response response = await http.get(url);
if (response.statusCode == 200) {
print("got TumUrunlerDeneme 2");
data = json.decode(response.body)['products'];
print("got TumUrunlerDeneme 3");
results = data.map((e) => Products.fromJson(e)).toList();
print("got TumUrunlerDeneme 4");
if (query != null) {
results = results
.where((element) =>
element.name!.toLowerCase().contains((query.toLowerCase())))
.toList();
print("got TumUrunlerDeneme 5");
}
} else {
print("fetch error");
}
} on Exception catch (e) {
print('error: $e');
}
return results;
}
}
No matter what I search for, the detail opens according to the product order in the whole list.
When I click on the product I am looking for, I reach the details of another product.
How can I search for the product I want and find the details of the product I am looking for?
I appreciate your help.

Dynamically Adding Widgets in list item on button’s on pressed function in Flutter

i have list item on my screen ... All I want to know is, how to add dynamicaly a list item on pressing a floatingActionbutton....
here is a first screen on which i have a button (for adding one more item like above item)
in this picture after selecting suit id .. i want when i pressed add button a copy of naap widget displays from which i can select 2ndsuit id...
i read a tutorial from medium.com but there he used sijmply two text boxes whixh is very easy..whereas in my situation it is pretty difficult for me.... but the situation is same .. you can also visit https://medium.com/#anilpandey071999/dynamically-adding-widgets-on-buttons-on-pressed-function-in-flutter-4d9f139744c7
following is my code...
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/material.dart';
import 'package:flutter/material.dart';
import 'package:flutter_auth/Screens/Dashboard/DashboardScreen.dart';
import 'package:flutter_auth/Screens/SearchCustomer/SearchCustomerScreen.dart';
import 'package:flutter_auth/components/NavDrawer.dart';
import 'package:flutter_auth/components/bottombar.dart';
import 'package:flutter_auth/components/rounded_button.dart';
import 'package:flutter_auth/components/rounded_input_field.dart';
import 'package:flutter_auth/components/drop_down_list.dart';
import 'package:flutter_auth/Screens/Welcome/welcome_screen.dart';
import '../../constants.dart';
import 'components/inputtextfieldname.dart';
import 'components/inputtextfieldnumber.dart';
class AddCustomerScreen extends StatefulWidget {
#override
_AddCustomerScreenState createState() => _AddCustomerScreenState();
}
class _AddCustomerScreenState extends State<AddCustomerScreen> {
final CategoriesScroller categoriesScroller = CategoriesScroller();
ScrollController controller = ScrollController();
bool closeTopContainer = false;
double topContainer = 0;
List<Widget> itemsData = [];
void getPostsData() {
List<AddCustomerScreen> dynamicList = [];
List<dynamic> responseList = Customer_Data;
List<Widget> listItems = [];
responseList.forEach((post) {
listItems.add(GestureDetector(
onTap: () {
// _navigateAndDisplaySelection(context);
},
child: Container(
height: 200,
margin: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
decoration: BoxDecoration(borderRadius: BorderRadius.all(Radius.circular(20.0)), color: Colors.white, boxShadow: [
BoxShadow(color: Colors.black.withAlpha(100), blurRadius: 10.0),
]),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20.0, vertical: 10),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
post["name"], textAlign: TextAlign.center,
style: const TextStyle( fontSize: 20, fontWeight: FontWeight.bold,color: kPrimaryColor),
),
// Expanded(child: drop_down_list())
],
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding:EdgeInsets.symmetric(horizontal:10.0),
child:Container(
height:2.0,
width:275.0,
color:kPrimaryColor),),
],),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
IconButton(onPressed: (){}, icon: Icon(Icons.camera_alt_rounded), iconSize: 30,color: Color(0XFFc49864)),
IconButton(onPressed: (){}, icon: Icon(Icons.add_photo_alternate_outlined), iconSize: 30,color: Color(0XFFc49864))
],
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Expanded(child: drop_down_list())
])
],),
)),));
});
setState(() {
itemsData = listItems;
});
}
#override
void initState() {
super.initState();
getPostsData();
controller.addListener(() {
setState(() {
});
});
}
#override
Widget build(BuildContext context) {
final Size size = MediaQuery.of(context).size;
final double categoryHeight = size.height*0.30;
return SafeArea(
child: Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
title: Text('Add Customer'),
actions: <Widget>[
IconButton(
icon: Icon(Icons.home,),
onPressed: (){Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return WelcomeScreen();
},
),
);},
)
]
),
drawer: NavDrawer(),
body:Container(
height: size.height,
child: Column(
children: <Widget>[
const SizedBox(
height: 10,
),
AnimatedOpacity(
duration: const Duration(milliseconds: 200),
opacity: closeTopContainer?0:1,
child: AnimatedContainer(
duration: const Duration(milliseconds: 200),
width: size.width,
alignment: Alignment.topCenter,
height: closeTopContainer?0:categoryHeight,
child: categoriesScroller),
),
Expanded(
child: ListView.builder(
controller: controller,
itemCount: itemsData.length,
physics: BouncingScrollPhysics(),
itemBuilder: (context, index) {
return itemsData[index];
})),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
// Add your onPressed code here!
},
child: const Icon(Icons.add),
backgroundColor: Color(0xFF6D4C41),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
),
);
}
}
void _navigateAndDisplaySelection(BuildContext context) async {
// Navigator.push returns a Future that completes after calling
// Navigator.pop on the Selection Screen.
final result = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => SearchCustomerScreen()),
);
}
class CategoriesScroller extends StatelessWidget {
const CategoriesScroller();
#override
Widget build(BuildContext context) {
final double categoryHeight = MediaQuery.of(context).size.height * 0.35 - 50;
return SingleChildScrollView(
physics: BouncingScrollPhysics(),
// scrollDirection: Axis.horizontal,
child: Container(
margin: const EdgeInsets.symmetric(vertical: 25, horizontal: 25),
child: FittedBox(
fit: BoxFit.fill,
alignment: Alignment.topCenter,
child: Row(
children: <Widget>[
Container(
width: 400,
margin: const EdgeInsets.symmetric(horizontal: 10, vertical: 10),
height: categoryHeight,
decoration: BoxDecoration(color: Color(0XFFc49864), borderRadius: BorderRadius.all(Radius.circular(20.0)),boxShadow: [
BoxShadow(color: Colors.black.withAlpha(100), blurRadius: 10.0),]),
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
RoundInputField(
hintText: "Customer Name",
onChanged: (value) {},
),
RoundInputFieldNumber(
hintText: "Phone Number",
icon: Icons.phone,
onChanged: (value) {},
),
],
),
),
),
],
),
),
),
);
}
}
class bottombar extends StatelessWidget {
const bottombar();
#override
Widget build(BuildContext context) {
return Scaffold(
bottomNavigationBar: BottomAppBar(
child: Row(
children: [
IconButton(icon: Icon(Icons.menu), onPressed: () {}),
Spacer(),
IconButton(icon: Icon(Icons.search), onPressed: () {}),
IconButton(icon: Icon(Icons.more_vert), onPressed: () {}),
],
),
),
floatingActionButton:
FloatingActionButton(child: Icon(Icons.add), onPressed: () {}),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
);
}
}
The most straight forward way is imho:
embed the widget to be added with showWidgetA ? WidgetA() : Container();
in your button you toggle the value onPressed: () => showWidgetA = !showWidgetA (showWidgetA being bool)

"NoSuchMethodError: The method '>=' " Flutter

i have the NoSuchMethodError by simulation my App.
NoSuchMethodError (NoSuchMethodError: The method '>=' was called on null.
Receiver: null
Tried calling: >=(55))
The Error is schowing when I simulation my app.
Can someone help me?
my full code in this file:
class GameEN extends StatefulWidget {
//Game({Key key}) : super(key: key);
#override
_GameENState createState() => _GameENState();
}
class _GameENState extends State<GameEN> {
int _counterK;
int _pktK;
#override
void initState() {
_subscription =
super.initState();
_loadCounterK();
}
#override
void dispose() {
_subscription.cancel();
super.dispose();
}
//Loading counter value on start (load)
_loadCounterK() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
setState(() {
_counterK = (prefs.getInt('counterK') ?? 1);
_pktK = (prefs.getInt('pktK') ?? 0);
print(Text("Load number is: $_counterK"));
print(Text("Load pkt is: $_pktK"));
});
}
#override
Widget build(BuildContext context) {
return new WillPopScope(
onWillPop: () async => false,
child: Scaffold(
appBar: AppBar(
backgroundColor: Colors.white,
centerTitle: true,
title: Text(
'ToolQuiz',
style: TextStyle(
fontStyle: FontStyle.italic,
color: Colors.black,
),
),
actions: <Widget>[
Padding(
padding: EdgeInsets.only(right: 15.0),
child: IconButton(
padding: EdgeInsets.all(0),
icon: Icon(
Icons.settings,
color: Colors.black,
),
onPressed: () {
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1, animation2) {
return Einstellungen();
},
),
);
}),
)
],
),
body: Center(
child: Container(
decoration: BoxDecoration(),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
//Küchenutensilien
GestureDetector(
onTap: () {
_interstitialAd.show();
_interstitialAd.dispose();
// _incrementCounterRightAnsK();
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1, animation2) {
if (56 <= _counterK)
return KuechenutensilienEnd();
else
return KuechenutensilienStart();
},
transitionsBuilder:
(context, animation1, animation2, child) {
return FadeTransition(
opacity: animation1,
child: child,
);
},
transitionDuration: Duration(milliseconds: 500),
),
);
},
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
Colors.brown[600],
Colors.brown[700]
],
begin: Alignment.bottomLeft,
end: Alignment.topRight,
),
border:
Border.all(width: 2, color: Colors.black54),
borderRadius: const BorderRadius.all(
const Radius.circular(20))),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Container(
child: Column(
children: <Widget>[
Container(
alignment: Alignment.center,
child: Text('Küchenutensilien',
style: Theme.of(context)
.textTheme
.headline5
.copyWith(color: Colors.black)),
),
Container(
alignment: Alignment.center,
child: Text(
_pktK.toString() + ' ' + 'Punkte',
),
),
Container(
alignment: Alignment.center,
child: Text(() {
if (_counterK >= 55) {
return 'Level ' + '55' + '/55';
}
return 'Level ' +
_counterK.toString() +
'/55';
}()),
),
],
),
),
],
))),
],
),
),
))));
}
}
The error is showing me by all: if....>=
I dont find my problem :(
Thanks for your help
Please make sure that _counterK is properly initialized, do so by initializing it when declaring it
Int _counterK = 0
I solve the problem by changing to the flutter stable channel

Keyboard getting dismissed on click of TextField

I have a TextField on the tap of which keyboard opens and dismiss immediately. This is my code for TextField:
class DataItem extends StatefulWidget {
Data data;
List<Menu> menuList;
int quantity;
String price;
String title;
var id;
DataItem(
{this.data,
this.menuList,
this.id,
this.quantity,
this.price,
this.title});
#override
_DataItemState createState() => _DataItemState();
}
class _DataItemState extends State<DataItem> {
String selectedType = 'Select Type';
String comments = 'No';
#override
Widget build(BuildContext context) {
return Dismissible(
key: UniqueKey(),
background: Container(
color: Theme.of(context).errorColor,
child: Icon(
Icons.delete,
color: Colors.white,
size: 40,
),
alignment: Alignment.centerRight,
padding: EdgeInsets.only(right: 20),
margin: EdgeInsets.symmetric(
horizontal: 15,
vertical: 4,
),
),
direction: DismissDirection.endToStart,
confirmDismiss: (direction) {
return showDialog(
context: context,
builder: (ctx) => AlertDialog(
title: Text('Are you sure?'),
content: Text('Do you want to remove?'),
actions: <Widget>[
FlatButton(
child: Text('No'),
onPressed: () {
Navigator.of(ctx).pop(false);
},
),
FlatButton(
child: Text('Yes'),
onPressed: () {
Navigator.of(ctx).pop(true);
},
)
],
),
);
},
onDismissed: (direction) {
//Delete Functionality
},
child: Card(
margin: EdgeInsets.symmetric(
horizontal: 15,
vertical: 4,
),
child: Padding(
padding: EdgeInsets.all(8),
child: Column(
children: <Widget>[
ListTile(
leading: CircleAvatar(
backgroundColor:Colors.purple,
child: Padding(
padding: EdgeInsets.all(5),
child: FittedBox(
child: Text(
widget.price,
style: TextStyle(color: Colors.white),
),
),
),
),
title: Text(widget.title),
subtitle: Text(
'Total: 0',
),
trailing: Text(widget.quantity.toString() + ' x'),
),
Padding(
padding: const EdgeInsets.only(
left: 15, right: 5, top: 5, bottom: 5),
child: Container(
width: double.infinity,
decoration: (BoxDecoration(
borderRadius: BorderRadius.circular(7),
border: Border.all(color:Colors.red))),
child: DropdownButton<String>(
items:
<String>['Type1 ', 'Type2'].map((String value) {
return new DropdownMenuItem<String>(
value: value,
child: new Text(
value,
style: TextStyle(color: Colors.black),
),
);
}).toList(),
hint: Padding(
padding: const EdgeInsets.only(left: 16),
child: Text(selectedType),
),
onChanged: (String val) {
setState(() {
selectedType = val;
selectedType);
});
},
),
),
),
Padding(
padding: const EdgeInsets.only(
left: 32, right: 5, top: 10, bottom: 5),
child: GestureDetector(
onTap: () {
var focusNode = new FocusNode();
// var textField = new TextField(focusNode: focusNode);
FocusScope.of(context).requestFocus(focusNode);
},
child: TextField(
decoration:
new InputDecoration.collapsed(hintText: 'Add Comments'),
),
)
],
),
),
),
);
}
This is the code of the DataItem class. On tap of TextField the keyboard opens and dismiss immediately. Please Help. I have tried using GestureDetector, request focus and onChanged as well but nothing works.
You should put your focus node outside your build method. Tested example added.
var focusNode = new FocusNode(); // This should be here and not inside the build method
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding:
const EdgeInsets.only(left: 32, right: 5, top: 10, bottom: 5),
child: GestureDetector(
onTap: () {
FocusScope.of(context).requestFocus(focusNode);
},
child: TextField(
decoration:
InputDecoration.collapsed(hintText: 'Add Comments'),
),
),
),
],
),
),
);
DartPad Example
I have resolved this issue using TextFormField instead of TextField.

Categories

Resources