Cupertino Picker content is squished together (see image below) - flutter

I created a Cupertinopicker widget that contains the 7 days of the week, but when you open the picker, they appear very squished together. Not sure why this is as another Cupertinopicker I created works fine.
I've copied exactly the code for the other Cupertinopicker I implemented (obviously changing the necessary components of the code), but it doesn't work in my second implementation.
Widget _buildWeeklyItemPicker() {
return Container(
height: 250,
child: CupertinoPicker(
itemExtent: 7.0,
backgroundColor: CupertinoColors.white,
onSelectedItemChanged: (index1) {
setState(() {
selectedWItemString2 = daysOfTheWeek[index1];
});
},
children: List<Widget>.generate(
daysOfTheWeek.length,
(index1) {
return Center(
child: Text(daysOfTheWeek[index1]),
);
},
),
),
);
}
^^ that's building the CupertinoPicker
List<String> daysOfTheWeek = [
'Monday',
'Tuesday',
'Wednesday',
'Thursday',
'Friday',
'Saturday'
'Sunday'
];
^^ that's my list of items that should appear in the picker
InkWell(
child: Text(
selectedWItemString2 == null ? "_______" : selectedWItemString2),
onTap: () async {
await showModalBottomSheet<int>(
context: context,
builder: (BuildContext context) {
return _buildWeeklyItemPicker();
},
);
},
),
^^ tapping the InkWell above open up the CupertinoPicker
I have attached a picture of what it should look like and what it does look like.

It is because you've set itemExtent: 7.0. Increase the value according to your requirement.

Related

Flutter : Popup for each Listtile

I am working on a flutter project and I want to popup to get generated on clicking a particular tile. This is my code
This is my ListTile generator
Future<Widget> getRecordView() {
print("405 name " + name.toString());
print(nameArr);
var items = List<Record>.generate(int.parse(widget.vcont), (index) => Record(
name: nameArr[index],
type: typeArr[index],
address: addressArr[index],
state: stateArr[index],
phone:phoneArr[index],
city: cityArr[index],
id: idArr[index],
));
print("Started");
var listItems = items;
var listview = ListView.builder(
itemCount: int.parse(widget.vcont),
itemBuilder: (context,index){
return listItems[index] ;
}
);
return Future.value(listview);
}
The Popup I need on tap :
Future <bool> details(BuildContext context,String type) {
return Alert(
context: context,
type: AlertType.success,
title: "Submission",
desc: type, //The parameter
buttons: [
DialogButton(
child: Text(
"OKAY",
style: TextStyle(color: Colors.white, fontSize: 20),
),
onPressed: () => Navigator.pop(context),
color: Color.fromRGBO(0, 179, 134, 1.0),
radius: BorderRadius.circular(0.0),
),
],
).show();
}
I tried to wrap Record with GestureDetector and Inkwell, but I only got errors and Android Studio tells me that Record is not expected in that context. I looked up in the internet and couldnt find anything on this matter. Please help.
Record, as far I can see is just a model, and not a widget. Item Builder requires a widget. You should wrap what you are passing to the item builder with an actual widget like a Container(), ListTile(), .. etc. These widgets can be wrapped with Gesture Detector to perform the pop ups you want.
It would look like this
var listview = ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return GestureDetector(
onTap: () {
// Tap on an item in the list and this will get executed.
},
// Return an actual widget, I'm using a ListTile here, but you can
// use any other type of widget here or a create custom widget.
child: ListTile(
// this will display the record names as list tiles.
title: Text(items[index].name),
),
);
},
);

Flutter Dynamic PopupMenu Content

I'm trying to create a menu that has a 'load more' functionality. From an interface perspective, PopupMenuButton has worked nicely, but I've been unable to dynamically refresh its content.
I'm using redux and I can successfully dispatch the action to fetch more, and the store is updated, but I don't see the change until I close the menu and re-open it, despite wrapping the PopupMenuButton in a StoreConnector. I also have a check for fetchInProgress that should be changing the bottom 'more' item to a spinner while the fetch is in progress, but that state change isn't noticed either.
I'm relatively new to Flutter so I'm wondering if I'm missing something.
Gif of the behavior
#override
Widget build(BuildContext context) {
return StoreConnector<AppState, _ViewModel>(
converter: (store) => _ViewModel.fromStore(store, oneOnOneId),
builder: (ctx, vm) => PopupMenuButton(
onSelected: (callback) => callback(),
icon: Icon(Icons.expand_more),
itemBuilder: (_) =>
[...vm.pastOneOnOnes.map((m) {
return PopupMenuItem(
child: Center(child: Text(DateFormat('MM/dd/yyyy').format(m.meetingDate))),
value: () => {
Navigator.of(context).pushReplacementNamed(routeName,
arguments: {
'meetingId': m.id
})
}
);
}).toList(),
PopupMenuItem(
enabled: false,
child: Container(
height: 40,
width: double.infinity,
child: vm.fetchInProgress ?
Center(child: CircularProgressIndicator()) :
InkWell(
onTap: () => vm.fetchPastOneOnOnes(oneOnOneId, start: vm.pastOneOnOnes.length + 1),
child: Center(
child: Text('More', style: TextStyle(color: Colors.black))
)
),
),
value: null
)
]
),
);
}
}
You need to update the state when you make a change. When you call => vm.fetchPastOneOnOnes wrap it with setState :
onTap: () {
setState(){
vm.fetchPastOneOnOnes(...);}},

Can I use Dismissible without actually dismissing the widget?

I'm trying to make a widget that can be swiped to change the currently playing song in a playlist. I'm trying to mimic how other apps do it by letting the user swipe away the current track and the next one coming in. Dismissible is so close to what I actually want. It has a nice animation and I can easily use the onDismissed function to handle the logic. My issue is that Dismissible actually wants to remove the widget from the tree, which I don't want.
The widget I'm swiping gets updated with a StreamBuilder when the song changes, so being able to swipe away the widget to a new one would be perfect. Can I do this or is there a better widget for my needs?
Here's the widget I'm working on:
class NowPlayingBar extends StatelessWidget {
const NowPlayingBar({
Key key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return StreamBuilder<ScreenState>(
stream: _screenStateStream,
builder: (context, snapshot) {
if (snapshot.hasData) {
final screenState = snapshot.data;
final queue = screenState.queue;
final mediaItem = screenState.mediaItem;
final state = screenState.playbackState;
final processingState =
state?.processingState ?? AudioProcessingState.none;
final playing = state?.playing ?? false;
if (mediaItem != null) {
return Container(
width: MediaQuery.of(context).size.width,
child: Dismissible(
key: Key("NowPlayingBar"),
onDismissed: (direction) {
switch (direction) {
case DismissDirection.startToEnd:
AudioService.skipToNext();
break;
case DismissDirection.endToStart:
AudioService.skipToPrevious();
break;
default:
throw ("Unsupported swipe direction ${direction.toString()} on NowPlayingBar!");
}
},
child: ListTile(
leading: AlbumImage(itemId: mediaItem.id),
title: mediaItem == null ? null : Text(mediaItem.title),
subtitle: mediaItem == null ? null : Text(mediaItem.album),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
if (playing)
IconButton(
onPressed: () => AudioService.pause(),
icon: Icon(Icons.pause))
else
IconButton(
onPressed: () => AudioService.play(),
icon: Icon(Icons.play_arrow)),
],
),
),
),
);
} else {
return Container(
width: MediaQuery.of(context).size.width,
child: ListTile(
title: Text("Nothing playing..."),
));
}
} else {
return Container(
width: MediaQuery.of(context).size.width,
// The child below looks pretty stupid but it's actually genius.
// I wanted the NowPlayingBar to stay the same length when it doesn't have data
// but I didn't want to actually use a ListTile to tell the user that.
// I use a ListTile to create a box with the right height, and put whatever I want on top.
// I could just make a container with the length of a ListTile, but that value could change in the future.
child: Stack(
alignment: Alignment.center,
children: [
ListTile(),
Text(
"Nothing Playing...",
style: TextStyle(color: Colors.grey, fontSize: 18),
)
],
));
}
},
);
}
}
Here's the effect that I'm going for (although I want the whole ListTile to get swiped, not just the song name): https://i.imgur.com/ZapzpJS.mp4
This can be done by using the confirmDismiss callback instead of the onDismiss callback. To make sure that the widget never actually gets dismissed, you need to return false at the end of the function.
Dismissible(
confirmDismiss: (direction) {
...
return false;
}
)

Why do i get a RangeError, if i add something to my List?

im trying to create a new Hero Widget by klicking on my FloatingActionButton. Therefore i have created a HeroCover widget, which holds the single Hero widgets.
class HeroCover extends StatelessWidget {
final Widget callPage;
final heroTag;
final coverImageName;
final name;
HeroCover({this.callPage, this.heroTag, this.coverImageName, this.name});
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Hero(
tag: heroTag,
child: GestureDetector(
onTap: () => Navigator.push(
context, MaterialPageRoute(builder: (context) => callPage)),
child: Column(children: <Widget>[
Image(
image: new AssetImage(coverImageName),
height: 100,
width: 100,
),
Text(name),
])),
),
);
}
}
On my HeroPage i now Create those HeroCover widgets depending on the following Lists with mapping
static List<int> matrixID = [0, 1, 2];
static var heroTag = ['matrix1', 'matrix2', 'matrix3'];
static var name = ['Matrix Kitchen', 'DAAANCEFLOR', 'Bath'];
static var matrixIMG = [
'imgs/matrix1.png',
'imgs/matrix2.png',
'imgs/matrix3.png'
];
var matrixCall = [
...matrixID.map((id) {
return MatrixPageOne(
name: name[id],
matrixSize: 20,
heroTag: heroTag[id],
heroImage: matrixIMG[id],
);
}).toList(),
];
Here i map the matrixID in the BuildMethod to return HeroCover Widgets depending on matrixID's length:
body: Column(
children: [
Wrap(children: [
...matrixID.map((id) {
return HeroCover(
heroTag: heroTag[id],
callPage: matrixCall[id],
name: name[id],
coverImageName: matrixIMG[id],
);
}).toList()
] // wrap children
),
],
),
Now if i press my FloatingActionButton, i add one Element to each of the lists:
floatingActionButton: FloatingActionButton(
onPressed: () {
//startAddMatrix(context);
setState(() {
matrixID.add(matrixID.length);
name.add('new Matrix');
matrixIMG.add('imgs/matrix1.png');
heroTag.add(DateTime.now().toString());
});
},
child: Icon(Icons.add),
backgroundColor: color_3,
),
So the .map should find one more element in each list and the next HeroCover Widget should be displayed ( if i add it manually to each list there is no problem), but if i press my FloatingActionButton, this happens:
but if i tap on "Home" in my BottomNavigationBar now and back to "Devices" everything is as it should be:
i just dont understand why .add is causing an RangeError. If anyone knows whats wrong here, id be very Thankful for your help!
your matrixCall init with ...matrixID.map((id) { ,
so it have 3 values 0..2
In your floatingActionButton, did not extend matrixCall, matrixCall still only have 3 values 0..2
when use
Wrap(children: [
...matrixID.map((id) {
return HeroCover(
heroTag: heroTag[id],
callPage: matrixCall[id],
name: name[id],
coverImageName: matrixIMG[id],
);
}).toList()
matrixID have 4 values 0..3,
and matrixCall still have 3 values, matrixCall[3] do not have value.

Button text color change

I'm building simple quiz app as a learning project. I'd like to change only clicked button color. Now it changes colors of all buttons. I've tried to make a list of colors, so every button could take its color from the list.
class _AnwserButtonsState extends State<AnwserButtons> {
Color color = Colors.black;
#override
Widget build(BuildContext context) {
return Container(
height: 200,
child: ListView(
children: widget.anwsers
.map(
(anwser) => RaisedButton(
child: Text(anwser, style: TextStyle(color: color)),
onPressed: () => onPressed(anwser),
),
)
.toList(),
),
);
}
onPressed(anwser) {
setState(
() {
if (anwser == widget.properAnwser) {
color = Colors.green;
} else {
color = Colors.red;
}
},
);
}
}
You need an id value. You could use index when use ListView.builder.
ListView.builder(
itemCount: widget.anwsers.length,
itemBuilder: (BuildContext context, int index) {
return Column(
children: <Widget> [
RaisedButton(
child: Text(widget.anwsers[index], style: TextStyle(color: color)),
onPressed: () => onPressed(widget.anwsers[index], index),
),
)
onPressed(anwser, index) {
setState(
() {
if (anwser == widget.properAnwser[index]) {
color = Colors.green;
} else {
color = Colors.red;
}
},
);
}
}
This could give you an idea. But my opinion is make a class that has answer, correct answer, color and id. Could be much easier and readable when use a class for this example.
You'll be better off using ListView.builder, since you'll be able to control each RaisedButton through its index in the List
Useful Links:
https://api.flutter.dev/flutter/widgets/ListView/ListView.builder.html
https://medium.com/#DakshHub/flutter-displaying-dynamic-contents-using-listview-builder-f2cedb1a19fb