Related
I'm currently trying to create a row that consist of maximum 3 column widget with each of them have the property of profile picture, nickname, and status. I wanted each of them to have fixed size so that even when the nickname is long it will still take the same amount of space.
Currently I just make the column to be spaced-evenly and some of the widget still take more space than the other 2. How can I fixed this ? maybe make the nickname turned into dotted (...) when it's too long.
here's my current code:
solverWidgets.add(
Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
BuildRoundedRectProfile(
height: 40,
width: 40,
name: solverTicket[solver]['nickname'],
profileLink: solverTicket[solver]['profile_picture_link'] ?? '',
),
SizedBox(height: 3),
Text(
solverTicket[solver]['nickname'],
style: weight600Style.copyWith(
color: primaryColor,
fontSize: 13,
),
),
if (solversStatus[solver] != null && (povStatus == 'pic' || povStatus == 'pic-client'))
GestureDetector(
onTap: () {
if (solversStatus[solver] == 'Done') {
setState(() {
needToLoadSolverWidgets = true;
isNotExpandedSolverWidgets[solver] = !isNotExpandedSolverWidgets[solver];
});
if (isExpandedSolverWidgetsContent[solver]) {
Future.delayed(Duration(milliseconds: 300), () {
setState(() {
needToLoadSolverWidgets = true;
isExpandedSolverWidgetsContent[solver] = false;
});
});
} else {
setState(() {
needToLoadSolverWidgets = true;
isExpandedSolverWidgetsContent[solver] = true;
});
}
}
},
child: AnimatedContainer(
duration: Duration(milliseconds: 300),
height: isNotExpandedSolverWidgets[solver] ? 20 : 55,
padding: EdgeInsets.only(top: 5, bottom: 5, left: 5, right: 5),
decoration: BoxDecoration(
color: defaultProfileColor.withOpacity(0.2),
borderRadius: BorderRadius.circular(10),
),
child: solversStatus[solver] != 'Done' ?
Text(
solversStatus[solver],
style: primaryColor600Style.copyWith(
fontSize: fontSize9,
),
).tr() : isNotExpandedSolverWidgets[solver] ?
Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
solversStatus[solver],
style: primaryColor600Style.copyWith(
fontSize: fontSize10,
),
).tr(),
Icon(
Icons.arrow_drop_down,
size: fontSize15,
),
],
) : ClipRRect(
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Row(
children: [
Text(
solversStatus[solver],
style: primaryColor600Style
.copyWith(
fontSize: fontSize9,
),
).tr(),
Icon(
Icons.arrow_drop_down,
size: fontSize18,
),
],
),
GestureDetector(
onTap: () {
showDialog(
context: context,
builder: (BuildContext
context) =>
ReusableConfirmationDialog(
titleText: 'changeWorkStatus'.tr(),
contentText: 'rejectWorkStatus'.tr(),
confirmButtonText: 'yes'.tr(),
onConfirm: () async {
await Database.changeWorkStatus(
ticketId: widget.ticketId,
ticketData: ticketData,
targetId: solver as String,
oldWorkStatus: 'done',
workStatus: 'todo');
Navigator.pop(context);
setState(() {
isNotExpandedSolverWidgets[solver] = true;
needToLoadTicket = true;
});
}));
},
child: Container(
padding: EdgeInsets.all(5),
decoration: BoxDecoration(
color: warningColor,
borderRadius:
BorderRadius.circular(5),
),
child: Text(
'disagree',
style: primaryColor600Style
.copyWith(
fontSize: fontSize9,
color: Colors.white,
),
).tr(),
),
)
]),
),
),
),
if(solversStatus[solver] != null && (povStatus != 'pic' && povStatus != 'pic-client'))
Container(
padding: EdgeInsets.all(5),
decoration: BoxDecoration(
color: formBackgroundColor,
borderRadius: BorderRadius.all(
Radius.circular(10))),
child: Text(
solversStatus[solver],
style: weight600Style.copyWith(
color: primaryColor,
fontSize: 9,
),
),
),
],
),
);
use Text overflow
Text(
'You have pushed the button this many times:dfjhejh dskfjkawejfkjadshfkljhaskdfhekjnkjvnkjasdklfjjekjlkj',
maxLines: 1,
overflow: TextOverflow.ellipsis,
)
or You can use https://pub.dev/packages/marquee package, it will scroll your text infinitly. make sure to wrap this marquee widget in a sizedbox with height and width defined.
App was working perfectly before and then I had to make some changes to allow or restrict calling feature in the app based on subscription level of the user, by passing the variable value from one screen to another using provider.
one Screen 1 i am using :
Future<void> _verifyPuchase(String id) async {
PurchaseDetails purchase = _hasPurchased(id);
if (purchase != null && purchase.status == PurchaseStatus.purchased) {
print(purchase.productID);
if (Platform.isIOS) {
await _iap.completePurchase(purchase);
print('Achats antérieurs........$purchase');
isPuchased = true;
}
isPuchased = true;
checkIsPurchsed(isPurchsed: isPuchased);
} else {
isPuchased = false;
checkIsPurchsed(isPurchsed: isPuchased);
}
}
and have i have a class on screen 1:
class checkIsPurchsed with ChangeNotifier{
bool isPurchsed;
checkIsPurchsed({this.isPurchsed});
notifyListeners();
}
and on screen 5 I have:
Consumer<checkIsPurchsed>(
builder: (context,isPurchsed,child){
return isPurchsed.isPurchsed ? IconButton(
icon: Icon(Icons.call), onPressed: () => onJoin("AudioCall"),
):Center(child: Text(
'Sorry you have not subscribe the package',
),);
},
),
Consumer<checkIsPurchsed>(
builder: (context,isPurchsed,child){
return isPurchsed.isPurchsed ? IconButton(
icon: Icon(Icons.video_call), onPressed: () => onJoin("VideoCall"),
):Center(child: Text(
'Sorry you have not subscribe the package',
),);
},
),
on screen 5 when i try to open a chat this is what i am getting :
the icon buttons on which i am checking the purchase status appear when chat is opened , but after adding the above mentioned modifications the chat itself isnt opening and instead i am getting the red screen.
Update 1:
class ChatPage extends StatefulWidget {
final User sender;
final String chatId;
final User second;
ChatPage({this.sender, this.chatId, this.second});
#override
_ChatPageState createState() => _ChatPageState();
}
class _ChatPageState extends State<ChatPage> {
bool isBlocked = false;
final db = Firestore.instance;
CollectionReference chatReference;
final TextEditingController _textController = new TextEditingController();
bool _isWritting = false;
final _scaffoldKey = GlobalKey<ScaffoldState>();
//Ads _ads = new Ads();
#override
void initState() {
//_ads.myInterstitial()
//..load()
//..show();
print("object -${widget.chatId}");
super.initState();
chatReference =
db.collection("chats").document(widget.chatId).collection('messages');
checkblock();
}
var blockedBy;
checkblock() {
chatReference.document('blocked').snapshots().listen((onData) {
if (onData.data != null) {
blockedBy = onData.data['blockedBy'];
if (onData.data['isBlocked']) {
isBlocked = true;
} else {
isBlocked = false;
}
if (mounted) setState(() {});
}
// print(onData.data['blockedBy']);
});
}
List<Widget> generateSenderLayout(DocumentSnapshot documentSnapshot) {
return <Widget>[
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
Container(
child: documentSnapshot.data['image_url'] != ''
? InkWell(
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
new Container(
margin: EdgeInsets.only(
top: 2.0, bottom: 2.0, right: 15),
child: Stack(
children: <Widget>[
CachedNetworkImage(
placeholder: (context, url) => Center(
child: CupertinoActivityIndicator(
radius: 10,
),
),
errorWidget: (context, url, error) =>
Icon(Icons.error),
height:
MediaQuery.of(context).size.height * .65,
width: MediaQuery.of(context).size.width * .9,
imageUrl:
documentSnapshot.data['image_url'] ?? '',
fit: BoxFit.fitWidth,
),
Container(
alignment: Alignment.bottomRight,
child:
documentSnapshot.data['isRead'] == false
? Icon(
Icons.done,
color: secondryColor,
size: 15,
)
: Icon(
Icons.done_all,
color: primaryColor,
size: 15,
),
)
],
),
height: 150,
width: 150.0,
color: secondryColor.withOpacity(.5),
padding: EdgeInsets.all(5),
),
Padding(
padding: const EdgeInsets.only(right: 10),
child: Text(
documentSnapshot.data["time"] != null
? DateFormat.yMMMd()
.add_jm()
.format(documentSnapshot.data["time"]
.toDate())
.toString()
: "",
style: TextStyle(
color: secondryColor,
fontSize: 13.0,
fontWeight: FontWeight.w600,
)),
)
],
),
onTap: () {
Navigator.of(context).push(
CupertinoPageRoute(
builder: (context) => LargeImage(
documentSnapshot.data['image_url'],
),
),
);
},
)
: Container(
padding: EdgeInsets.symmetric(
horizontal: 15.0, vertical: 10.0),
width: MediaQuery.of(context).size.width * 0.65,
margin: EdgeInsets.only(
top: 8.0, bottom: 8.0, left: 80.0, right: 10),
decoration: BoxDecoration(
color: primaryColor.withOpacity(.1),
borderRadius: BorderRadius.circular(20)),
child: Column(
children: <Widget>[
Row(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Expanded(
child: Container(
child: Text(
documentSnapshot.data['text'],
style: TextStyle(
color: Colors.black87,
fontSize: 16.0,
fontWeight: FontWeight.w600,
),
),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Text(
documentSnapshot.data["time"] != null
? DateFormat.MMMd()
.add_jm()
.format(documentSnapshot
.data["time"]
.toDate())
.toString()
: "",
style: TextStyle(
color: secondryColor,
fontSize: 13.0,
fontWeight: FontWeight.w600,
),
),
SizedBox(
width: 5,
),
documentSnapshot.data['isRead'] == false
? Icon(
Icons.done,
color: secondryColor,
size: 15,
)
: Icon(
Icons.done_all,
color: primaryColor,
size: 15,
)
],
),
],
),
],
)),
),
],
),
),
];
}
_messagesIsRead(documentSnapshot) {
return <Widget>[
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
InkWell(
child: CircleAvatar(
backgroundColor: secondryColor,
radius: 25.0,
child: ClipRRect(
borderRadius: BorderRadius.circular(90),
child: CachedNetworkImage(
imageUrl: widget.second.imageUrl[0] ?? '',
useOldImageOnUrlChange: true,
placeholder: (context, url) => CupertinoActivityIndicator(
radius: 15,
),
errorWidget: (context, url, error) => Icon(Icons.error),
),
),
),
onTap: () => showDialog(
barrierDismissible: false,
context: context,
builder: (context) {
return Info(widget.second, widget.sender, null);
}),
),
],
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
child: documentSnapshot.data['image_url'] != ''
? InkWell(
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
new Container(
margin: EdgeInsets.only(
top: 2.0, bottom: 2.0, right: 15),
child: CachedNetworkImage(
placeholder: (context, url) => Center(
child: CupertinoActivityIndicator(
radius: 10,
),
),
errorWidget: (context, url, error) =>
Icon(Icons.error),
height: MediaQuery.of(context).size.height * .65,
width: MediaQuery.of(context).size.width * .9,
imageUrl:
documentSnapshot.data['image_url'] ?? '',
fit: BoxFit.fitWidth,
),
height: 150,
width: 150.0,
color: Color.fromRGBO(0, 0, 0, 0.2),
padding: EdgeInsets.all(5),
),
Padding(
padding: const EdgeInsets.only(right: 10),
child: Text(
documentSnapshot.data["time"] != null
? DateFormat.yMMMd()
.add_jm()
.format(documentSnapshot.data["time"]
.toDate())
.toString()
: "",
style: TextStyle(
color: secondryColor,
fontSize: 13.0,
fontWeight: FontWeight.w600,
)),
)
],
),
onTap: () {
Navigator.of(context).push(CupertinoPageRoute(
builder: (context) => LargeImage(
documentSnapshot.data['image_url'],
),
));
},
)
: Container(
padding: EdgeInsets.symmetric(
horizontal: 15.0, vertical: 10.0),
width: MediaQuery.of(context).size.width * 0.65,
margin: EdgeInsets.only(top: 8.0, bottom: 8.0, right: 10),
decoration: BoxDecoration(
color: secondryColor.withOpacity(.3),
borderRadius: BorderRadius.circular(20)),
child: Column(
children: <Widget>[
Row(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Expanded(
child: Container(
child: Text(
documentSnapshot.data['text'],
style: TextStyle(
color: Colors.black87,
fontSize: 16.0,
fontWeight: FontWeight.w600,
),
),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Text(
documentSnapshot.data["time"] != null
? DateFormat.MMMd()
.add_jm()
.format(documentSnapshot
.data["time"]
.toDate())
.toString()
: "",
style: TextStyle(
color: secondryColor,
fontSize: 13.0,
fontWeight: FontWeight.w600,
),
),
],
),
],
),
],
)),
),
],
),
),
];
}
List<Widget> generateReceiverLayout(DocumentSnapshot documentSnapshot) {
if (!documentSnapshot.data['isRead']) {
chatReference.document(documentSnapshot.documentID).updateData({
'isRead': true,
});
return _messagesIsRead(documentSnapshot);
}
return _messagesIsRead(documentSnapshot);
}
generateMessages(AsyncSnapshot<QuerySnapshot> snapshot) {
return snapshot.data.documents
.map<Widget>((doc) => Container(
margin: const EdgeInsets.symmetric(vertical: 10.0),
child: new Row(
mainAxisAlignment: MainAxisAlignment.center,
children: doc.data['type'] == "Call"
? [
Text(doc.data["time"] != null
? "${doc.data['text']} : " +
DateFormat.yMMMd()
.add_jm()
.format(doc.data["time"].toDate())
.toString() +
" by ${doc.data['sender_id'] == widget.sender.id ? "You" : "${widget.second.name}"}"
: "")
]
: doc.data['sender_id'] != widget.sender.id
? generateReceiverLayout(
doc,
)
: generateSenderLayout(doc)),
))
.toList();
}
#override
Widget build(BuildContext context) {
ChangeNotifierProvider<checkIsPurchsed>(
create: (context)=>checkblock(),
child: Scaffold(
key: _scaffoldKey,
backgroundColor: Colors.white,
appBar: AppBar(
centerTitle: true,
elevation: 0,
title: Text(widget.second.name),
leading: IconButton(
icon: Icon(Icons.arrow_back_ios),
color: Colors.white,
onPressed: () => Navigator.pop(context),
),
actions: <Widget>[
Consumer<checkIsPurchsed>(
builder: (context,isPurchsed,child){
return isPurchsed.isPurchsed ? IconButton(
icon: Icon(Icons.call), onPressed: () => onJoin("AudioCall"),
):Center(child: Text(
'Sorry you have not subscribe the package',
),);
},
),
Consumer<checkIsPurchsed>(
builder: (context,isPurchsed,child){
return isPurchsed.isPurchsed ? IconButton(
icon: Icon(Icons.video_call), onPressed: () => onJoin("VideoCall"),
):Center(child: Text(
'Sorry you have not subscribe the package',
),);
},
),
}
The problematic area is:
#override
Widget build(BuildContext context) {
ChangeNotifierProvider<checkIsPurchsed>(
There's no return in front of ChangeNotifierProvider, so it doesn't return a Widget. Correct would be:
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider<checkIsPurchsed>(
I have a container with a column that have three containers and one listview wrapped with expanded which works perfectly but am trying to add a scrollview to the whole container so that on the three scroll with the listview, please how can I achieve this? Below is what my code looks like.
List<Content> content = [];
_fetchComments() async {
setState(() {
isLoading = true;
_isDealButtonRefresh = true;
});
try {
final result = await InternetAddress.lookup('google.com');
if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) {
print('connected');
String baseURL;
debugPrint("my select:$_mySelection");
if (_mySelection == null && _myFeatureSelection == null) {
baseURL = "myjson link";
} else if (_myFeatureSelection != null) {
baseURL =
"my json link" +
_myFeatureSelection;
debugPrint("feature enter");
_mySelection = null;
} else if (_mySelection != null && _myFeatureSelection == null) {
baseURL = "my json link" +
_mySelection;
}
print("our url:$baseURL");
final response = await http.get(baseURL);
if (response.statusCode == 200) {
print(response.body);
content = (json.decode(response.body) as List)
.map((data) => new Content.fromJson(data))
.toList();
setState(() {
print(response.body);
isLoading = false;
_isDealButtonRefresh = false;
});
} else {
print(response.body);
throw Exception('Failed to load post');
}
}
} on SocketException catch (_) {
print('not connected');
setState(() => isLoading = false);
Navigator.pushReplacement(
context,
new MaterialPageRoute(
builder: (BuildContext context) => NoInternet()));
}
}
initState() {
super.initState();
_fetchComments();
}
body: Container(
child: Column(children: <Widget>[
Container(),
Container(),
Container(),
Expanded(child: ListView.separated(
separatorBuilder:
(context, index) => Divider(
color: Colors.grey,
),
itemCount: content == null
? 0
: _searchResult.length,
itemBuilder:
(context, position) {
final current =
_searchResult[position];
double myrate = double.parse(
_searchResult[position]
.ratings ==
null
? "0"
: _searchResult[position]
.ratings);
debugPrint("rato:$myrate");
return FutureBuilder<String>(
future: getDistance(
current.lat,
current.lng)
.then((value) =>
value.toString()),
builder:
(context, snapshot) {
return Container(
child:
GestureDetector(
onTap: () {
Navigator.push(
context,
CupertinoPageRoute(
builder: (BuildContext ctx) => Maps(_searchResult[position])));
},
child:
Column(
children: <
Widget>[
Row(
children: <
Widget>[
Expanded(
child:Container(
height:150,
width: MediaQuery.of(context).size.width,
child: SizedBox(
child: FadeInImage(image: NetworkImage(_searchResult[position].thumbnail_name), placeholder: AssetImage("assets/640x360.png"),
fit: BoxFit.cover,),
),
)),
],
),
Container(
padding:
const EdgeInsets.all(5.0),
child:
Row(
crossAxisAlignment:
CrossAxisAlignment.start,
children: <Widget>[
Expanded(
child: Column(
children: <Widget>[
Container(
padding: const EdgeInsets.only(bottom: 1.0),
child: Text(
_searchResult[position].title,
style: TextStyle(fontFamily: 'Montserrat', fontSize: 13, fontWeight: FontWeight.bold),
),
),
Container(
padding: const EdgeInsets.only(bottom: 1.0),
child: Text(
_searchResult[position].address,
maxLines: 2,
style: TextStyle(fontFamily: 'Montserrat', fontSize: 10, color: Colors.black54),
),
),
Container(
padding: const EdgeInsets.only(bottom: 1.0),
child: _status != PermissionStatus.denied
? snapshot.hasData
? Text(
snapshot.data + " " + "km",
maxLines: 1,
style: TextStyle(fontFamily: 'Montserrat', fontSize: 10, fontWeight: FontWeight.bold, color: colorBlue),
)
: SizedBox(
child: CircularProgressIndicator(
valueColor: new AlwaysStoppedAnimation<Color>(
colorBlue,
),
strokeWidth: 1,
),
height: 5.0,
width: 5.0,
)
: Icon(
Icons.do_not_disturb,
color: Colors.red,
size: 15,
), ),
SizedBox(
height: 2,
),
Container(
child: Text(
_searchResult[position].price + " " + "USD",
style: TextStyle(
color: colorPink,
fontWeight: FontWeight.bold,
fontSize: 12,
fontFamily: 'Montserrat',
),
),
)
],
crossAxisAlignment: CrossAxisAlignment.start,
),
flex: 9,
),
Column(
children: <Widget>[
Container(
padding: const EdgeInsets.only(bottom: 0),
child: SmoothStarRating(
allowHalfRating: false,
onRatingChanged: (v) {
setState(() {});
},
starCount: 5,
rating: myrate,
size: 12.0,
filledIconData: Icons.star,
halfFilledIconData: Icons.star_half,
color: Colors.orange,
borderColor: Colors.orange,
spacing: 0.0)),
Text(
"(" + myrate.toStringAsFixed(1) + ")",
style: TextStyle(color: Colors.black, fontFamily: 'Montserrat', fontSize: 10, fontWeight: FontWeight.bold, fontStyle: FontStyle.normal),
),
],
)
],
),
)
],
)));
});
}))
])
)
In the above code the listview fetch it data from json rest API.
You could add the 3 inner containers as children of the listview.
Something like this:
Widget getListView(yourListWithData) {
List<Widget> listViewChildren = [
Container(),
Container(),
Container(),
];
listViewChildren.addAll(
yourListWithData
.map(
(e) => Text(e), //text widget as an example, use your own widget
)
.toList(),
);
return ListView(
children: listViewChildren,
);
}
And then you can get rid of the Column and make the listview the only child of the parent container:
Container(
child: getListView(yourListWithData),
);
To solve that:
Add SingleChildScrollView Widget at the beginning with physics: ClampingScrollPhysics() propertie .
Add shrinkWrap: true propertie to your Listview .
SingleChildScrollView(
scrollDirection: Axis.vertical,
physics: ClampingScrollPhysics(),
child: Container(
child: Column( crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(),
Container(),
Container(),
Expanded(child: Listview.builder(shrinkWrap: true,))
])
)
I hope to help you
So finally after many months of research, I was able to resolve this by giving the height of each container. Since I want the height of the listview to cover most of the space in the activity I didn't set the height for the Container with the ListView. First I changed the Expanded() above to Container(), set ListView shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), . Find below my updated code:
body: Container(
child: Column(children: <Widget>[
Container(height: MediaQuery.of(context).size.height * 0.16,
),
Container(height: MediaQuery.of(context).size.height * 0.16,
),
Container(height: MediaQuery.of(context).size.height * 0.16,
),
Container(child: ListView.separated(shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
separatorBuilder:
(context, index) => Divider(
color: Colors.grey,
),
itemCount: content == null
? 0
: _searchResult.length,
itemBuilder:
(context, position) {
final current =
_searchResult[position];
double myrate = double.parse(
_searchResult[position]
.ratings ==
null
? "0"
: _searchResult[position]
.ratings);
debugPrint("rato:$myrate");
return FutureBuilder<String>(
future: getDistance(
current.lat,
current.lng)
.then((value) =>
value.toString()),
builder:
(context, snapshot) {
return Container(
child:
GestureDetector(
onTap: () {
Navigator.push(
context,
CupertinoPageRoute(
builder: (BuildContext ctx) => Maps(_searchResult[position])));
},
child:
Column(
children: <
Widget>[
Row(
children: <
Widget>[
Expanded(
child:Container(
height:150,
width: MediaQuery.of(context).size.width,
child: SizedBox(
child: FadeInImage(image: NetworkImage(_searchResult[position].thumbnail_name), placeholder: AssetImage("assets/640x360.png"),
fit: BoxFit.cover,),
),
)),
],
),
Container(
padding:
const EdgeInsets.all(5.0),
child:
Row(
crossAxisAlignment:
CrossAxisAlignment.start,
children: <Widget>[
Expanded(
child: Column(
children: <Widget>[
Container(
padding: const EdgeInsets.only(bottom: 1.0),
child: Text(
_searchResult[position].title,
style: TextStyle(fontFamily: 'Montserrat', fontSize: 13, fontWeight: FontWeight.bold),
),
),
Container(
padding: const EdgeInsets.only(bottom: 1.0),
child: Text(
_searchResult[position].address,
maxLines: 2,
style: TextStyle(fontFamily: 'Montserrat', fontSize: 10, color: Colors.black54),
),
),
Container(
padding: const EdgeInsets.only(bottom: 1.0),
child: _status != PermissionStatus.denied
? snapshot.hasData
? Text(
snapshot.data + " " + "km",
maxLines: 1,
style: TextStyle(fontFamily: 'Montserrat', fontSize: 10, fontWeight: FontWeight.bold, color: colorBlue),
)
: SizedBox(
child: CircularProgressIndicator(
valueColor: new AlwaysStoppedAnimation<Color>(
colorBlue,
),
strokeWidth: 1,
),
height: 5.0,
width: 5.0,
)
: Icon(
Icons.do_not_disturb,
color: Colors.red,
size: 15,
), ),
SizedBox(
height: 2,
),
Container(
child: Text(
_searchResult[position].price + " " + "USD",
style: TextStyle(
color: colorPink,
fontWeight: FontWeight.bold,
fontSize: 12,
fontFamily: 'Montserrat',
),
),
)
],
crossAxisAlignment: CrossAxisAlignment.start,
),
flex: 9,
),
Column(
children: <Widget>[
Container(
padding: const EdgeInsets.only(bottom: 0),
child: SmoothStarRating(
allowHalfRating: false,
onRatingChanged: (v) {
setState(() {});
},
starCount: 5,
rating: myrate,
size: 12.0,
filledIconData: Icons.star,
halfFilledIconData: Icons.star_half,
color: Colors.orange,
borderColor: Colors.orange,
spacing: 0.0)),
Text(
"(" + myrate.toStringAsFixed(1) + ")",
style: TextStyle(color: Colors.black, fontFamily: 'Montserrat', fontSize: 10, fontWeight: FontWeight.bold, fontStyle: FontStyle.normal),
),
],
)
],
),
)
],
)));
});
}))
])
)
First of all, I created a designed bottom sheet, In which, there are two lists to show numbers(left side) and options(hour, day, week, month) with the help of CupertinoPicker widget,
Numbers will depend on what option I select, If I select the hour, numbers of the left side should be 1-24, and if I select week, numbers should be 1-4, I select the day, numbers should be 1-30 and last I select month number should be 1-12.
Code :
All Lists variable:
List<String> reminderDay = ['hour','day','week','month'];
List<String> reminderHoursVal =['1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16','17','18','19','20','21','22','23','24'];
List<String> reminderDaysVal =['1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16','17','18','19','20','21','22','23','24','25','26','27','28','29','30','31'];
List<String> reminderMonthsVal =['1','2','3','4','5','6','7','8','9','10','11','12'];
List<String> reminderWeeksVal =['1','2','3','4'];
String selectedReminderVal='1';
String selectedReminderDay ='hour';
Code of bottom sheet:
addReminder(){
showModalBottomSheet(
context: context,
builder: (BuildContext context) {
return AnimatedPadding(
padding: MediaQuery.of(context).viewInsets,
duration: const Duration(milliseconds: 100),
curve: Curves.decelerate,
child: Container(
padding: const EdgeInsets.only(top:8,right: 8, left:8,bottom: 8),
height: MediaQuery.of(context).size.height/2,
// color: Colors.transparent,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(30),
topRight: Radius.circular(30)
)
),
child: Container(
child: Column(
// mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(height:10),
Text("Set a reminder",
style: TextStyle(
fontSize:18,
fontWeight:FontWeight.bold,
color: Colors.grey
),
),
SizedBox(height:20),
Container(
margin: const EdgeInsets.only(left: 10, right: 10),
height: MediaQuery.of(context).size.height/4,
decoration: BoxDecoration(
color: Colors.grey[100],
borderRadius: BorderRadius.circular(10)
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Expanded(
child: CupertinoPicker(
scrollController: new FixedExtentScrollController(
initialItem: 0,
),
itemExtent: 30,
backgroundColor: Colors.grey[100],
onSelectedItemChanged: (int val) {
setState(() {
if(selectedReminderDay=='day'){
selectedReminderVal = reminderDaysVal[val];
}else if(selectedReminderDay=='week'){
selectedReminderVal = reminderWeeksVal[val];
}else if(selectedReminderDay=='month'){
selectedReminderVal = reminderMonthsVal[val];
}else{
selectedReminderVal = reminderHoursVal[val];
}
print("selectedReminderVal:$selectedReminderVal");
});
},
children:selectedReminderDay=='day'?reminderDaysVal
:selectedReminderDay=='week'?reminderWeeksVal
:selectedReminderDay=='month'?reminderMonthsVal:reminderHoursVal// ['hour','day','week','month']; reminderHoursVal
.map(
(item) => Center(
child: Text(
item,
style: TextStyle(
fontSize: 16,
// fontWeight:FontWeight.bold,
),
),
),
)
.toList()),
),
Expanded(
child: CupertinoPicker(
scrollController: new FixedExtentScrollController(
initialItem: 0,
),
itemExtent: 30,
backgroundColor: Colors.grey[100],
onSelectedItemChanged: (int val) {
setState(() {
selectedReminderDay = reminderDay[val];
print("selectedReminderDay:$selectedReminderDay");
});
},
children: reminderDay
.map(
(item) => Center(
child: Text(
item,
style: TextStyle(
fontSize: 16,
// fontWeight:FontWeight.bold,
),
),
),
)
.toList()),
),
])
),
SizedBox(height:15),
// selectedVal!=null?Text(selectedVal.toString()):Container()
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text("You'll get the reminder"),
Text('$selectedReminderVal $selectedReminderDay before the event')
],
),
SizedBox(height:25),
Padding(
padding: const EdgeInsets.only(left: 10, right: 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
InkWell(
onTap: (){
Navigator.pop(context);
},
child: Text("Cancel",
style: TextStyle(
fontSize: 18,
color: Colors.blue,
fontWeight: FontWeight.bold
),
),
),
InkWell(
onTap: (){
Navigator.pop(context);
},
child: Container(
alignment: Alignment.center,
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(8)
),
width: MediaQuery.of(context).size.width/5,
height: MediaQuery.of(context).size.height/25 ,
child: Text("Save", style:TextStyle(
color: Colors.white,
fontSize: 19
)),
),
)
],
),
)
],
),
)
),
);
},
);
}
Screenshot:
This is because the state you are setting is different from the state in the modal bottom sheet.
Right now, when you are calling setState, you are actually rebuilding the stateful widget under the modal bottom sheet.
To fix this, just wrap your bottom sheet in a Stateful Builder.
StatefulBuilder(
builder: (context, setState) {
return AnimatedPadding(
padding: MediaQuery.of(context).viewInsets,
duration: const Duration(milliseconds: 100),
curve: Curves.decelerate,
child: Container(
padding: const EdgeInsets.only(top:8,right: 8, left:8,bottom: 8),
height: MediaQuery.of(context).size.height/2,
// color: Colors.transparent,
decoration: BoxDecoration(
color: Colors.white,
....
when we create new context widgets in existing state there states become different, bottomSheets are similar to dialogBox with new context and builder build a completely new widget out of the parent state, to create its own stateful state Wrap it with the stateful builder and user its own setState to change anything in this context not the parent one
eg:
StatefulBuilder(
builder: (context, setStateChild) {
return AnimatedPadding(...
Expanded(
child: CupertinoPicker(
scrollController: new FixedExtentScrollController(
initialItem: 0,
),
itemExtent: 30,
backgroundColor: Colors.grey[100],
onSelectedItemChanged: (int val) {
setStateChild(() {
selectedReminderDay = reminderDay[val];
print("selectedReminderDay:$selectedReminderDay");
});
},);
child: ... ),
}
In my products Screen I have two buttons + and - for quantity,
these two buttons in my ListView it Increment/Decrement the whole list , I want to increment or decrement quantity upon button click for single list item. If I increase or decrease the counter it increment in every list item.
StreamController _event =StreamController<int>.broadcast();
int _counter = 0;
void initState() {
super.initState();
_event.add(0);
}
#override
Widget build(BuildContext context) {
.
.
return Scaffold(
body: allItemsFlowlist(),
);
}
Widget allItemsFlowlist(){
return Container(
child: ListView.builder(
itemCount: items.documents.length,
physics: AlwaysScrollableScrollPhysics(parent: BouncingScrollPhysics()),
itemBuilder: (context, i) {
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Flexible(
flex: 3,
child: Row(
children: <Widget>[
Flexible(
flex: 4,
child: Container(
child: Row(
children: <Widget>[
Container(
width: 35,
height: 35,
decoration: BoxDecoration(
color: colorPallet('vprice_sectionIncrementerBackground'),
borderRadius: BorderRadius.circular(5),
),
child: IconButton(
icon: Icon(Icons.remove),
onPressed: _decrementCounter,
iconSize: 18,
color: colorPallet('vprice_sectionDecrementerBackground')
),
),
Padding(
padding: EdgeInsets.symmetric(horizontal: 16.0),
child: Container(
width: 35,
height: 35,
decoration: BoxDecoration(
border: Border.all(
color: colorPallet('vprice_sectionIncrementerBackground'), //Color(0xFFFFD500),
width: 2,
),
borderRadius: BorderRadius.circular(5),
),
child: Center(
child: StreamBuilder<int>(
stream: _event.stream,
builder: (context, snapshot) {
return Text(
_counter.toString(),
style: TextStyle(
color: colorPallet('vprice_sectionTextTextStyle4'),
fontSize: 16,
fontWeight: FontWeight.w500,
),
);
}),
),
),
),
Container(
width: 35,
height: 35,
decoration: BoxDecoration(
color: colorPallet('vprice_sectionIncrementerBackground'),
borderRadius: BorderRadius.circular(5),
),
child: IconButton(
icon: Icon(Icons.add),
onPressed: _incrementCounter,
iconSize: 18,
color: colorPallet('vprice_sectionDecrementerBackground'),
),
),
],
)),
),
Incrementer:
_incrementCounter() {
_counter++;
_event.add(_counter);
}
Decrementer:
_decrementCounter() {
if (_counter <= 0) {
_counter = 0;
} else {
_counter--;
}
_event.add(_counter);
}
Turn _counter into a list and add an item for each item in your listView.builder to it.
And when changing, change _counter [i];
And so will change that specific item!
List<int> _counter = List();
ListView.builder(
itemCount: items.documents.length,
physics: AlwaysScrollableScrollPhysics(parent: BouncingScrollPhysics()),
itemBuilder: (context, i) {
if(_counter.length < items.documents.length){
_counter.add(0);
}
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Flexible(
[...]
child: IconButton(
icon: Icon(Icons.remove),
onPressed: (){_decrementCounter(i);},
iconSize: 18,
color: colorPallet('vprice_sectionDecrementerBackground')
),
),
[...]
child: IconButton(
icon: Icon(Icons.add),
onPressed: (){_incrementCounter(i);},
iconSize: 18,
color: colorPallet('vprice_sectionDecrementerBackground'),
),
),
],
)),
),
[...]
_incrementCounter(int i) {
_counter[i]++;
_event.add(_counter[i]);
}
_decrementCounter(int i) {
if (_counter[i] <= 0) {
_counter[i] = 0;
} else {
_counter[i]--;
}
_event.add(_counter[i]);
}
Hope this helps!