Pixel overflow when using an Image.File in flutter - flutter

I have a column with 2 children, an Image.File and a Row displaying a Flatbutton.Icon. The Image.File causes an overflow, but when I use Expanded on both Image.File and Row the entire body vanishes. How do I avoid both outcomes and just show the intended which is the photo with a flatbutton below it?
Parent
class ProfileHome extends StatefulWidget {
#override
_ProfileHomeState createState() => _ProfileHomeState();
}
class _ProfileHomeState extends State<ProfileHome> {
File _imageFile;
Future<void> _pickImage(ImageSource source) async {
File selected = await ImagePicker.pickImage(source: source);
setState(() {
_imageFile = selected;
});
}
void _clear() {
setState(() => _imageFile = null);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.black,
title: Text(
'My Profile',
style: TextStyle(fontFamily: 'Anton'),
),
centerTitle: true),
drawer: Drawer(
child: DrawerWidget(),
),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
if (_imageFile == null) ...[
ProfileList(
uploadbarvalue: _updateUploadBar,
),
] else ...[
ProfilePhoto(
imageFile: _imageFile,
onImageExit: _clear,
)
]
],
),
bottomNavigationBar: (uploadbar)
? BottomAppBar(
shape: CircularNotchedRectangle(),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
IconButton(
padding: EdgeInsets.all(50.0),
icon: Icon(
Icons.photo_camera,
size: 50.0,
),
onPressed: () {
_pickImage(ImageSource.camera);
uploadbar = false;
},
),
IconButton(
padding: EdgeInsets.all(50.0),
icon: Icon(
Icons.photo_library,
size: 50.0,
),
onPressed: () {
_pickImage(ImageSource.gallery);
uploadbar = false;
}),
],
),
)
: null,
floatingActionButton: (uploadbar)
? FloatingActionButton(
backgroundColor: Colors.black,
child: Icon(Icons.close),
onPressed: () {
setState(() {
uploadbar = false;
});
})
: null,
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
);
}
}
Child
class ProfilePhoto extends StatefulWidget {
File imageFile;
final VoidCallback onImageExit;
final bool uploadbar;
final ValueChanged<bool> uploadbarvalue;
ProfilePhoto(
{Key key,
this.uploadbar,
this.uploadbarvalue,
this.imageFile,
this.onImageExit})
: super(key: key);
#override
_ProfilePhotoState createState() => _ProfilePhotoState();
}
class _ProfilePhotoState extends State<ProfilePhoto> {
#override
Widget build(BuildContext context) {
return Column(children: <Widget>[
if (widget.imageFile != null) ...[
Image(image: FileImage(widget.imageFile)),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
FlatButton.icon(
onPressed: () {
_imageFinished();
},
icon: Icon(Icons.clear),
label: Text('Clear'))
],
),
Uploader(
file: widget.imageFile,
)
]
]);
}
}

Related

widget into List<Widget> does not update into build method even if i call setState

i have the following simple full code
import 'dart:developer';
import 'package:flutter/material.dart';
class Test extends StatefulWidget {
const Test({Key? key}) : super(key: key);
#override
State<Test> createState() => _TestState();
}
class _TestState extends State<Test> {
List myListWidget = [];
late bool isColorWhie = false;
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: (){
setState(() {
myListWidget.add(
Container(
width: 50,
height: 50,
color: isColorWhie?Colors.white:Colors.red,
)
);
});
},
child: Scaffold(
backgroundColor: Colors.green,
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
...myListWidget,
TextButton(
onPressed: (){
setState(() {
isColorWhie = !isColorWhie; // here never update
log('done');
});
},
child: const Text('tab to Change color',style: TextStyle(color: Colors.white),)
)
],
),
),
),
);
}
}
i tap on any point on screen to add Container into myListWidget thn call setState(() {}); to update ui.
everything fine now but when i change the isColorWhie to true it should change the color to white but it never update !
i am totally confused why it does not update ? And how could i handle with this ?
For base color change, I am using a separate button, also switching the list value.
One thing variable does update the UI, you need to handle state inside the item(state-management property) or reinitialize the variable to get update state.
class Test extends StatefulWidget {
const Test({Key? key}) : super(key: key);
#override
State<Test> createState() => _TestState();
}
class _TestState extends State<Test> {
List<bool> myListWidgetState = [];
bool isColorWhie = false;
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
setState(
() {
myListWidgetState.add(isColorWhie);
},
);
},
child: Scaffold(
backgroundColor: Colors.green,
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
...myListWidgetState.map(
(e) {
return Container(
width: 50,
height: 50,
color: e ? Colors.white : Colors.red,
);
},
),
TextButton(
onPressed: () {
myListWidgetState = myListWidgetState.map((e) => !e).toList();
setState(() {});
print(isColorWhie);
},
child: const Text(
'tab to Change color',
style: TextStyle(color: Colors.white),
),
),
TextButton(
onPressed: () {
setState(() {
isColorWhie = !isColorWhie;
});
print(isColorWhie);
},
child: const Text(
'tab to Change base color',
style: TextStyle(color: Colors.white),
),
),
],
),
),
),
);
}
}
Since you create a container as an object in GestureDetector and save it to your list, it will not change. It is now permanently saved (of course as long as you do not delete the element) as an entry in your list.
Your logic works exactly as you programmed it. For example, if you were to recompile the app and press the TextButton and then anywhere on your screen, a white container would also appear.
If you want to dynamically change the color of all containers at once, then you can do the following:
class _TestState extends State<Test> {
int containerCounter = 0;
late bool isColorWhie = false;
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
setState(() {
containerCounter++;
});
},
child: Scaffold(
backgroundColor: Colors.green,
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
width: 50,
child: ListView.builder(
shrinkWrap: true,
itemCount: containerCounter,
itemBuilder: ((context, index) {
return Container(
height: 50,
color: isColorWhie ? Colors.white : Colors.red,
);
}),
),
),
TextButton(
onPressed: () {
setState(() {
isColorWhie = !isColorWhie; // here never update
});
},
child: const Text(
'tab to Change color',
style: TextStyle(color: Colors.white),
))
],
),
),
),
);
}
}

Flutter How to cause a new gesture

I have a listview which has Slideable
I want a longPress gesture to activate a Slideable Action.
I can get a longpress message, but I do not know what to do to cause the sliding action to work.
This is a custom Tile Widget I need to edit.
This is what it looks like when I swipe.
I want the same thing to happen when I release the longpress
Code is below:
class BookmarkListTile extends StatelessWidget {
// final BookmarkPageViewModel bookmarkViewmodel;
// final int index;
const BookmarkListTile(
{Key? key, required this.bookmark, this.onTap, this.onDelete})
: super(key: key);
final Bookmark bookmark;
final Function(Bookmark bookmark)? onDelete;
final Function(Bookmark bookmark)? onTap;
#override
Widget build(BuildContext context) {
return GestureDetector(
behavior: HitTestBehavior.translucent,
onLongPressUp: () {
print("longpress");
// add code here to cause the Slidable Action to happen
},
child: Slidable(
actionPane: const SlidableDrawerActionPane(),
secondaryActions: [
IconSlideAction(
icon: Icons.delete,
color: Colors.red,
onTap: () {
if (onDelete != null) onDelete!(bookmark);
},
)
],
child: ListTile(
onTap: () {
if (onTap != null) onTap!(bookmark);
},
title: Text(bookmark.note),
subtitle: Text(PaliScript.getScriptOf(
language:
context.read<ScriptLanguageProvider>().currentLanguage,
romanText: bookmark.bookName!)),
trailing: SizedBox(
width: 100,
child: Row(
children: [
Text('${AppLocalizations.of(context)!.page} -'),
Expanded(
child: Text(
'${bookmark.pageNumber}',
textAlign: TextAlign.end,
)),
],
),
),
),
));
}
}
Try maybe this:
Widget build(BuildContext context) {
return Slidable(
actionPane: const SlidableDrawerActionPane(),
secondaryActions: [
IconSlideAction(
icon: Icons.delete,
color: Colors.red,
onTap: () {
if (onDelete != null) onDelete!(bookmark);
},
)
],
child: Builder(builder: (context) =>
GestureDetector(
behavior: HitTestBehavior.translucent,
onLongPress: () {
openSlidable(context);
},
child: ListTile(
onTap: () {
if (onTap != null) onTap!(bookmark);
},
title: Text(bookmark.note),
subtitle: Text(PaliScript.getScriptOf(
language:
context.read<ScriptLanguageProvider>().currentLanguage,
romanText: bookmark.bookName!)),
trailing: SizedBox(
width: 100,
child: Row(
children: [
Text('${AppLocalizations.of(context)!.page} -'),
Expanded(
child: Text(
'${bookmark.pageNumber}',
textAlign: TextAlign.end,
)),
],
),
),
))));
}
void openSlidable(BuildContext context) {
final slidable = Slidable.of(context);
final isClosed = slidable.renderingMode == SlidableRenderingMode.none;
if (isClosed) {
Future.delayed(Duration.zero, () {
if (slidable.mounted) {
slidable.open(actionType: SlideActionType.secondary);
}
});
}
}
This will automatically open your slidable if it was closed. Child of Slidable should be wrapped in Builder in order to work.

Flutter TabBarView and BottomNavigationBar pages are not refreshing with SetState

I have the following Flutter BottomNavigationBar, I have 3 children page widgets. As soon as the user writes a review and press the submit button, I am calling the void _clear() which resets the values in the textfield widgets. This method is inside and called from the WriteReview widget but is not working, the screen is not refreshing. The data it self is being reset but the UI has not be refreshed. I tried with and without setState(){ _clear()}; but no results.
I have similar issue with the TabBarView. What I would expect as a result would be the selected widget page to be refreshed.
I assume is something different on how the widgets are being handled in the TabBarView and BottomNavigationBar that I am missing.
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class HomeView extends StatefulWidget {
#override
_HomeViewState createState() => _HomeViewState();
}
class _HomeViewState extends State<HomeView> {
final String _writeReviewLabel = 'Write review';
final String _searchLabel = 'Search';
final String _accountLabel = 'Account';
var _currentIndex = 0;
final List<Widget> _bottomBarItems = [
WriteReviewView(),
SearchView(),
UserAccountView()
];
#override
Widget build(BuildContext context) {
final accentColor = Theme.of(context).accentColor;
final primaryColor = Theme.of(context).primaryColor;
return BaseView<HomePresenter>(
createPresenter: () => HomePresenter(),
onInitialize: (presenter) {
_currentIndex = ModalRoute.of(context).settings.arguments;
},
builder: (context, child, presenter) => Scaffold(
bottomNavigationBar: BottomNavigationBar(
backgroundColor: primaryColor,
selectedItemColor: accentColor,
unselectedItemColor: Colors.white,
elevation: 0,
currentIndex: _currentIndex,
onTap: (index) {
onTabTapped(index, presenter);
},
items: [
BottomNavigationBarItem(
activeIcon: Icon(Icons.rate_review),
icon: Icon(Icons.rate_review),
title: Text(_writeReviewLabel),
),
BottomNavigationBarItem(
activeIcon: Icon(Icons.search),
icon: Icon(Icons.search),
title: Text(_searchLabel),
),
BottomNavigationBarItem(
activeIcon: Icon(Icons.person),
icon: Icon(Icons.person),
title: Text(_accountLabel)),
],
),
body: _bottomBarItems[_currentIndex]),
);
}
void onTabTapped(int index, HomePresenter presenter) {
if (index == _currentIndex) {
return;
}
if (presenter.isAuthenticated) {
setState(() {
_currentIndex = index;
});
} else {
presenter.pushNamed(context, Routes.login, arguments: () {
if (presenter.isAuthenticated) {
Future.delayed(const Duration(microseconds: 500), () {
setState(() {
_currentIndex = index;
});
});
}
});
}
}
}
Write Review View
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'base/BaseView.dart';
class WriteReviewView extends StatefulWidget {
#override
_WriteReviewViewState createState() => _WriteReviewViewState();
}
class _WriteReviewViewState extends State<WriteReviewView> {
final String _locationLabel = 'Location';
final String _reviewLabel = 'Review';
#override
Widget build(BuildContext context) {
return BaseView<WriteReviewPresenter>(
createPresenter: () => WriteReviewPresenter(),
onInitialize: (presenter) {
presenter.init();
},
builder: (context, child, presenter) => Container(
color: Theme.of(context).backgroundColor,
child: _body(presenter),
));
}
Widget _body(WriteReviewPresenter presenter) {
final height = MediaQuery.of(context).size.height;
return LayoutBuilder(builder: (context, constraint) {
return SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(minHeight: constraint.maxHeight),
child: IntrinsicHeight(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Card(
margin: EdgeInsets.fromLTRB(4.0, 4.0, 4.0, 8.0),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Padding(
padding: EdgeInsets.only(top: 10, bottom: 20),
child: Row(
children: [
Icon(Icons.location_on,
color: Theme.of(context).cursorColor),
SectionTitle(_locationLabel),
],
),
),
ChooseAddressButton(presenter.addressContainer.address, () {
presenter.navigateNewAddress(context);
}),
SizedBoxes.medium,
],
),
),
),
Card(
margin: EdgeInsets.fromLTRB(4.0, 4.0, 4.0, 8.0),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Column(
children: [
Padding(
padding: EdgeInsets.only(top: 10),
child: Row(
children: [
Icon(Icons.star, color: Theme.of(context).indicatorColor),
SectionTitle(_reviewLabel),
],
),
),
SizedBoxes.medium,
CustomTextFormField(
data: presenter.reviewContainer.review,
showMinimum: true,
characterLimit: 50,
maxLines: 4,
height: 100),
ModifyRatingBar(50.0, presenter.reviewContainer.rating, false),
Padding(
padding: EdgeInsets.symmetric(vertical: 5),
child: Divider(indent: 40, endIndent: 40)),
],
),
),
),
Padding(
padding: EdgeInsets.symmetric(horizontal: 10),
child: Card(
color: Theme.of(context).accentColor,
child: FlatButton(
onPressed: () {
_submit(context, presenter);
},
child: Text('Submit',style:TextStyle(fontWeight: FontWeight.bold,fontSize: 18,color: Colors.white)),
),
),
),
],
),
),
),
);
});
}
void _submit(BuildContext context, WriteReviewPresenter presenter) async {
LoadingPopup.show(context);
final status = await presenter.submit(context);
LoadingPopup.hide(context);
if (status == ReviewStatus.successful) {
PostCompletePopup.show(context);
setState(() {
presenter.clear();
});
} else {
presenter.showError(context, status);
}
}
}
setState() only refreshes the widget that called it, and all the widgets under it.
When calling setState()from WriteReview widget, it will not update the HomeView widget. Try moving the setState()call to the HomeView widget using some sort of callback.

Listview scrolling and selecting Textfield afterwards is freezing my app

I am using the package
country_code_picker: ^1.4.0
https://pub.dev/packages/country_code_picker#-installing-tab-
with flutter 1.17.3
Which is pretty much one of the only country code picker packages. But I have one serious problem an I don't have a clue what it could be.
When I run this code
import 'package:flutter/material.dart';
import 'package:country_code_picker/country_code_picker.dart';
void main() {
runApp(App());
}
class App extends StatelessWidget {
App();
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: TestWidget(),
);
}
}
class TestWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(body: _buildCountryPicker(context));
}
Widget _buildCountryPicker(BuildContext context) {
return Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: Center(
child: CountryCodePicker(
initialSelection: 'NL',
),
),
);
}
}
And I open the dialog to select a country. I scroll in the list and then select the TextField my keyboard opens and when I try to type something my entire app freezes. I can't even hot reload. I don't get a single error.
I am running this on my Huawei P30, but I also experience this on other android devices. I don't know if this is a flutter bug or a country code picker bug.
I think it is probably in this widget somewhere. If anyone could point me in the right direction it would help me alot!
class SelectionDialog extends StatefulWidget {
final List<CountryCode> elements;
final bool showCountryOnly;
final InputDecoration searchDecoration;
final TextStyle searchStyle;
final TextStyle textStyle;
final WidgetBuilder emptySearchBuilder;
final bool showFlag;
final double flagWidth;
final Size size;
final bool hideSearch;
/// elements passed as favorite
final List<CountryCode> favoriteElements;
SelectionDialog(
this.elements,
this.favoriteElements, {
Key key,
this.showCountryOnly,
this.emptySearchBuilder,
InputDecoration searchDecoration = const InputDecoration(),
this.searchStyle,
this.textStyle,
this.showFlag,
this.flagWidth = 32,
this.size,
this.hideSearch = false,
}) : assert(searchDecoration != null, 'searchDecoration must not be null!'),
this.searchDecoration =
searchDecoration.copyWith(prefixIcon: Icon(Icons.search)),
super(key: key);
#override
State<StatefulWidget> createState() => _SelectionDialogState();
}
class _SelectionDialogState extends State<SelectionDialog> {
/// this is useful for filtering purpose
List<CountryCode> filteredElements;
#override
Widget build(BuildContext context) => SimpleDialog(
titlePadding: const EdgeInsets.all(0),
title: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
IconButton(
padding: const EdgeInsets.all(0),
iconSize: 20,
icon: Icon(
Icons.close,
),
onPressed: () => Navigator.pop(context),
),
if (!widget.hideSearch)
Padding(
padding: const EdgeInsets.symmetric(horizontal: 24),
child: TextField(
style: widget.searchStyle,
decoration: widget.searchDecoration,
onChanged: _filterElements,
),
),
],
),
children: [
Container(
width: widget.size?.width ?? MediaQuery.of(context).size.width,
height:
widget.size?.height ?? MediaQuery.of(context).size.height * 0.7,
child: ListView(
children: [
widget.favoriteElements.isEmpty
? const DecoratedBox(decoration: BoxDecoration())
: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
...widget.favoriteElements.map(
(f) => SimpleDialogOption(
child: _buildOption(f),
onPressed: () {
_selectItem(f);
},
),
),
const Divider(),
],
),
if (filteredElements.isEmpty)
_buildEmptySearchWidget(context)
else
...filteredElements.map(
(e) => SimpleDialogOption(
key: Key(e.toLongString()),
child: _buildOption(e),
onPressed: () {
_selectItem(e);
},
),
),
],
),
),
],
);
Widget _buildOption(CountryCode e) {
return Container(
width: 400,
child: Flex(
direction: Axis.horizontal,
children: <Widget>[
if (widget.showFlag)
Flexible(
child: Padding(
padding: const EdgeInsets.only(right: 16.0),
child: Image.asset(
e.flagUri,
package: 'country_code_picker',
width: widget.flagWidth,
),
),
),
Expanded(
flex: 4,
child: Text(
widget.showCountryOnly
? e.toCountryStringOnly()
: e.toLongString(),
overflow: TextOverflow.fade,
style: widget.textStyle,
),
),
],
),
);
}
Widget _buildEmptySearchWidget(BuildContext context) {
if (widget.emptySearchBuilder != null) {
return widget.emptySearchBuilder(context);
}
return Center(
child: Text('No country found'),
);
}
#override
void initState() {
filteredElements = widget.elements;
super.initState();
}
void _filterElements(String s) {
s = s.toUpperCase();
setState(() {
filteredElements = widget.elements
.where((e) =>
e.code.contains(s) ||
e.dialCode.contains(s) ||
e.name.toUpperCase().contains(s))
.toList();
});
}
void _selectItem(CountryCode e) {
Navigator.pop(context, e);
}
}
Also filed an issue on the flutter github https://github.com/flutter/flutter/issues/59886
Edit:
I have a video of it right here
https://www.youtube.com/watch?v=669KitFG9ek&feature=youtu.be
I just had to remove the keys, so there probably was a duplicate key
...filteredElements.map(
(e) => SimpleDialogOption(
//key: Key(e.toLongString()),
child: _buildOption(e),
onPressed: () {
_selectItem(e);
},
),
),

Display different fab depending on active View of TabBarView

If PageA is selected, fabA should be displayed. If PageB is selected, fabB respectively.
Whats the best way to achieve this?
var fabA = FloatingActionButton();
var fabB = FloatingActionButton();
...
Scaffold(
body: TabBarView(children: [
PageA(),
PageB(),
]),
floatingActionButton: fabA,
)
You can copy paste run full code below
You can declare a List<FloatingActionButton> and return based on tabController.index
code snippet
_tabController = TabController(vsync: this, length: choices.length)
..addListener(() {
if (_tabController.indexIsChanging) {
print(
"tab is animating. from active (getting the index) to inactive(getting the index) ");
} else {
setState(() {});
...
floatingActionButton: floatButton[_tabController.index],
...
List<FloatingActionButton> floatButton = [
FloatingActionButton(
onPressed: () {
// Add your onPressed code here!
},
child: Icon(Icons.navigation),
backgroundColor: Colors.green,
),
FloatingActionButton(
onPressed: () {
// Add your onPressed code here!
},
child: Icon(Icons.share),
backgroundColor: Colors.green,
),
working demo
full code
import 'package:flutter/material.dart';
class AppBarBottomSample extends StatefulWidget {
#override
_AppBarBottomSampleState createState() => _AppBarBottomSampleState();
}
class _AppBarBottomSampleState extends State<AppBarBottomSample>
with SingleTickerProviderStateMixin {
TabController _tabController;
#override
void initState() {
super.initState();
_tabController = TabController(vsync: this, length: choices.length)
..addListener(() {
if (_tabController.indexIsChanging) {
print(
"tab is animating. from active (getting the index) to inactive(getting the index) ");
} else {
//tab is finished animating you get the current index
//here you can get your index or run some method once.
print(_tabController.index);
setState(() {});
}
});
}
#override
void dispose() {
_tabController.dispose();
super.dispose();
}
void _nextPage(int delta) {
final int newIndex = _tabController.index + delta;
if (newIndex < 0 || newIndex >= _tabController.length) return;
_tabController.animateTo(newIndex);
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('AppBar Bottom Widget'),
leading: IconButton(
tooltip: 'Previous choice',
icon: const Icon(Icons.arrow_back),
onPressed: () {
_nextPage(-1);
},
),
actions: <Widget>[
IconButton(
icon: const Icon(Icons.arrow_forward),
tooltip: 'Next choice',
onPressed: () {
_nextPage(1);
},
),
],
bottom: PreferredSize(
preferredSize: const Size.fromHeight(48.0),
child: Theme(
data: Theme.of(context).copyWith(accentColor: Colors.white),
child: Container(
height: 48.0,
alignment: Alignment.center,
child: TabPageSelector(controller: _tabController),
),
),
),
),
body: TabBarView(
controller: _tabController,
children: choices.map((Choice choice) {
return Padding(
padding: const EdgeInsets.all(16.0),
child: ChoiceCard(choice: choice),
);
}).toList(),
),
floatingActionButton: floatButton[_tabController.index],
),
);
}
}
List<FloatingActionButton> floatButton = [
FloatingActionButton(
onPressed: () {
// Add your onPressed code here!
},
child: Icon(Icons.navigation),
backgroundColor: Colors.green,
),
FloatingActionButton(
onPressed: () {
// Add your onPressed code here!
},
child: Icon(Icons.share),
backgroundColor: Colors.green,
),
FloatingActionButton(
onPressed: () {
// Add your onPressed code here!
},
child: Icon(Icons.create),
backgroundColor: Colors.green,
),
FloatingActionButton(
onPressed: () {
// Add your onPressed code here!
},
child: Icon(Icons.repeat),
backgroundColor: Colors.green,
),
FloatingActionButton(
onPressed: () {
// Add your onPressed code here!
},
child: Icon(Icons.forward),
backgroundColor: Colors.green,
),
FloatingActionButton(
onPressed: () {
// Add your onPressed code here!
},
child: Icon(Icons.link),
backgroundColor: Colors.green,
)
];
class Choice {
const Choice({this.title, this.icon});
final String title;
final IconData icon;
}
const List<Choice> choices = const <Choice>[
const Choice(title: 'CAR', icon: Icons.directions_car),
const Choice(title: 'BICYCLE', icon: Icons.directions_bike),
const Choice(title: 'BOAT', icon: Icons.directions_boat),
const Choice(title: 'BUS', icon: Icons.directions_bus),
const Choice(title: 'TRAIN', icon: Icons.directions_railway),
const Choice(title: 'WALK', icon: Icons.directions_walk),
];
class ChoiceCard extends StatelessWidget {
const ChoiceCard({Key key, this.choice}) : super(key: key);
final Choice choice;
#override
Widget build(BuildContext context) {
final TextStyle textStyle = Theme.of(context).textTheme.display1;
return Card(
color: Colors.white,
child: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Icon(choice.icon, size: 128.0, color: textStyle.color),
Text(choice.title, style: textStyle),
],
),
),
);
}
}
void main() {
runApp(AppBarBottomSample());
}