I'm having problems with flex widget with a column inside where the children have a fixed height (constrained to min and max).
I have to build a screen with a column with many rows as children and each row has some column children and this column has widgets with restricted height.
I want each row to fit the maximum height of the inner column and at the same time all rows to fit the full height of the screen.
I mean, I want the children height has priority over his parent.
EDIT: I attached an image and the code to see the problem.
class SecheduleDatatable extends StatelessWidget {
final DateTime initDate;
final int dayTreshold;
final List<ActivityItem> items;
final bool buildHeaders;
SecheduleDatatable({
required this.items,
required this.initDate,
required this.dayTreshold,
this.buildHeaders = false,
});
final double spaceBetween = 64;
final double leftPadding = 32;
double minItemHeight = 100;
double maxItemHeight = 150;
double fontSize = 45;
double headerHeight = 120;
void _initSizes(BuildContext context) {
final screenWidth = MediaQuery.of(context).size.width;
if (screenWidth > 4000) {
fontSize = 100;
minItemHeight = 0;
maxItemHeight = 180;
headerHeight = 180;
} else if (screenWidth > 1920) {
fontSize = 45;
minItemHeight = 60;
maxItemHeight = 120;
headerHeight = 120;
} else {
fontSize = 25;
minItemHeight = 0;
maxItemHeight = 80;
headerHeight = 80;
}
}
#override
Widget build(BuildContext context) {
_initSizes(context);
return Column(
mainAxisSize: MainAxisSize.max,
children: [
Flexible(child: _createColumns()),
..._createRows(),
],
);
}
bool hasToExpand(String time) {
final days = _createDays(true);
days.addAll(_createDays(false));
final groupedByTimeSort = items.groupBy((p0) => p0.dateFormated);
for (DateTime date in days) {
final tempItems = groupedByTimeSort[time]
?.where((element) => element.date.getInitDay() == date.getInitDay())
.toList();
if (tempItems != null && tempItems.length > 1) return false;
}
return true;
}
Widget _createColumns() {
final days = _createDays(true);
days.addAll(_createDays(false));
return IntrinsicHeight(
child: Row(
children: [
Expanded(
child: Row(
children: [
Expanded(child: _clock()),
Expanded(flex: 3, child: _header(days[0].formatHeaderDate())),
Expanded(flex: 3, child: _header(days[1].formatHeaderDate())),
],
)),
/* Spacer(
flex: 1,
), */
Expanded(
child: Row(
children: [
Expanded(child: Container()),
Expanded(flex: 4, child: _header(days[2].formatHeaderDate())),
Expanded(flex: 4, child: _header(days[3].formatHeaderDate())),
Expanded(child: Container())
],
)),
],
),
);
}
List<Widget> _createRows() {
final days = _createDays(true);
days.addAll(_createDays(false));
final groupedByTimeSort = items.groupBy((p0) => p0.dateFormated);
Widget _getItemByDate(String time, DateTime date) {
final maybeItems = groupedByTimeSort[time]
?.where((element) => element.date.getInitDay() == date.getInitDay());
if (maybeItems != null) {
return Column(
mainAxisSize: MainAxisSize.min,
children: maybeItems
.map((e) => hasToExpand(time)
? Flexible(child: _item(e, kSpacing / 2))
: Flexible(child: _item(e, 0)))
.toList());
} else {
return Container();
}
}
Widget _getItem(String time, int pos, int flex) {
return Expanded(flex: flex, child: IntrinsicHeight(child: _getItemByDate(time, days[pos])));
}
final rows = groupedByTimeSort.keys.map((time) {
final row = Flexible(
child: IntrinsicHeight(
child: Row(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(
child: IntrinsicHeight(
child: Row(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(child: _hour(time)),
_getItem(time, 0, 3),
_getItem(time, 1, 3),
],
),
)),
Expanded(
child: IntrinsicHeight(
child: Row(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(child: Container()),
_getItem(time, 2, 4),
_getItem(time, 3, 4),
Expanded(child: Container()),
],
),
))
],
)));
/* final row = IntrinsicHeight(
child: Row(children: [
Expanded(child: _hour(time)),
...days.map((date) => Expanded(flex: 3, child: _getItemByDate(time, date))).toList()
])); */
return row;
}).toList();
return rows;
}
Widget _item(ActivityItem item, double spacing) {
return Container(
width: double.infinity,
margin: EdgeInsets.symmetric(vertical: 2, horizontal: 2),
padding: EdgeInsets.all(spacing),
decoration: BoxDecoration(
color: item.activityModel!.color, borderRadius: BorderRadius.circular(15)),
child: Center(
child: Text(
item.activityModel!.getTitle(),
maxLines: 1,
textAlign: TextAlign.center,
style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: fontSize),
),
));
}
Widget _emptyItem() {
return Container(
// constraints: BoxConstraints(minHeight: minItemHeight, maxHeight: maxItemHeight),
width: double.infinity,
margin: EdgeInsets.symmetric(vertical: 1),
padding: EdgeInsets.all(kSpacing / 2),
child: FittedBox(
fit: BoxFit.scaleDown,
child: Text(
"",
style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: fontSize),
),
));
}
Widget _clock() {
return Container(
padding: EdgeInsets.symmetric(horizontal: kSpacing, vertical: 4),
decoration: BoxDecoration(borderRadius: BorderRadius.circular(15)),
child: FittedBox(
fit: BoxFit.contain,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Icon(
FeatherIcons.clock,
),
),
),
);
}
Widget _hour(String time) {
return Container(
margin: EdgeInsets.all(2),
padding: EdgeInsets.symmetric(horizontal: kSpacing, vertical: 4),
decoration: BoxDecoration(color: Colors.black54, borderRadius: BorderRadius.circular(15)),
child: Align(
alignment: Alignment.topCenter,
child: FittedBox(
fit: BoxFit.contain,
child: Text(
time,
style: TextStyle(color: Colors.white, fontSize: fontSize, fontWeight: FontWeight.bold),
),
),
),
);
}
Widget _header(String text) {
return Container(
height: headerHeight,
margin: EdgeInsets.symmetric(vertical: 2, horizontal: 2),
padding: EdgeInsets.all(kSpacing / 2),
decoration: BoxDecoration(color: Colors.black54, borderRadius: BorderRadius.circular(15)),
child: Align(
alignment: Alignment.center,
child: FittedBox(
child: Text(
text,
textAlign: TextAlign.center,
style:
TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: fontSize),
),
),
));
}
List<DateTime> _createDays(bool first) {
final days = first ? [initDate] : [initDate.add(Duration(days: dayTreshold ~/ 2))];
for (var i = first ? 1 : dayTreshold ~/ 2;
i < (first ? dayTreshold ~/ 2 : dayTreshold - 1);
i++) {
days.add(days.last.add(Duration(days: 1)));
}
return days;
}
}
I want that the parent row take height of column child. Notice the rows are flexible to fit responsiveness to screen changes.
So really, in summarize, I want the rows are responsiveness but its inner columns get max height.
Sorry is not easy to explain it.
I added singlechildscrollview and I set the height of the container for the column items at 320 for four items of 80.
import 'package:flutter/material.dart';
import 'package:flutter/gestures.dart';
class MyCustomScrollBehavior extends MaterialScrollBehavior {
// Override behavior methods and getters like dragDevices
#override
Set<PointerDeviceKind> get dragDevices => {
PointerDeviceKind.touch,
PointerDeviceKind.mouse,
};
}
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
scrollBehavior: MyCustomScrollBehavior(),
debugShowCheckedModeBanner:false,
home: Test_Flexible(),
);
}
}
class Test_Flexible extends StatefulWidget {
Test_Flexible({Key? key}) : super(key: key);
#override
State<Test_Flexible> createState() => _Test_FlexibleState();
}
class _Test_FlexibleState extends State<Test_Flexible> {
#override
Widget build(BuildContext context) {
return Scaffold(appBar: AppBar(title: Text("Test Flexible"),) ,body:
SingleChildScrollView(child:
Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
flex: 1,
child: Container(
height: 100,
color: Colors.orange,
)),
Expanded(
flex: 3,
child: Container(
height: 320,
color: Colors.blue,
child:(Column(children:[
Flexible(
child: Container(
height: 80,
color: Colors.purple,
),
),
Flexible(
child: Container(
height: 80,
color: Colors.green,
),
),
Flexible(
child: Container(
height: 80,
color: Colors.yellow,
),
),
Flexible(
child: Container(
height: 80,
color: Colors.pink,
),
),
]))
)),
Expanded(
flex: 3,
child: Container(
height: 100,
color: Colors.blueGrey,
)),
],)
])
,));
}
}
Related
I am trying to create a horizontal stepper that changes based on a status. It would need a title above, different image (preferably svg) inside the circle and changing color of the divider with the same thickness.
Im trying to achieve this
I tried different approach and other packages, and I cant seem to get to make this, maybe I'm doing something wrong.
Stepper has its title on the side and the circles are checks and numbers only.
IconStepper from im_stepper package only has icons for steps, and no titles, and only dots for the divider.
EnhanceStep from enhance_stepper package has the title below the the icon, and it doesn't have a circle. I tried editing the package and the icon is not aligned with the line anymore.
Custom Widget but it is all UI and no functionality on changing the selected, and changing the index changes the color of the step itself but not the ones before it. Also the text is not aligned along the center of the step, is just aligned using Row's MainAxisAlignment.spaceBetween,
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
class Testing4 extends StatefulWidget {
const Testing4({Key? key}) : super(key: key);
#override
State<Testing4> createState() => _Testing4State();
}
class _Testing4State extends State<Testing4> {
final List<int> steps = [1, 2, 3];
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 30.0),
child: Center(
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisSize: MainAxisSize.max,
children: [
for (var step in steps) Center(child: Text('STEPPER # $step'))
],
),
SizedBox(
width: MediaQuery.of(context).size.width,
height: kToolbarHeight,
child: Stack(
alignment: Alignment.center,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(
width: MediaQuery.of(context).size.width / 3,
child: const Divider(
color: Colors.black,
thickness: 5,
),
),
SizedBox(
width: MediaQuery.of(context).size.width / 3,
child: const Divider(
color: Colors.grey,
thickness: 5,
),
),
],
),
Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
for (var step in steps)
Column(
children: [
Stack(
children: [
Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
color:
step == 2 ? Colors.black : Colors.grey,
),
padding: const EdgeInsets.all(10),
child: Center(
child: SvgPicture.asset("assets/check.svg"),
),
)
],
),
],
)
],
),
)
],
),
),
],
)),
);
}
}
In the end, this one worked for me
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
class CustomStepper extends StatelessWidget {
CustomStepper({
Key? key,
required int currentStep,
required this.steps,
}) : _curStep = currentStep,
assert(currentStep >= 0 == true && currentStep <= steps.length),
super(key: key);
final int _curStep;
final Color _activeColor = Colors.black;
final Color _inactiveColor = Colors.grey.shade300;
final double lineWidth = 5.0;
final List<Map<String, dynamic>> steps;
List<Widget> _iconViews() {
var list = <Widget>[];
steps.asMap().forEach((i, icon) {
Color circleColor =
(i == 0 || _curStep >= i) ? _activeColor : _inactiveColor;
Color lineColor = _curStep > i ? _activeColor : _inactiveColor;
list.add(
Container(
width: 55.0,
height: 55.0,
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: circleColor,
),
child: SvgPicture.asset(
icon['image'],
),
),
);
if (i != steps.length - 1) {
list.add(Expanded(
child: Container(
height: lineWidth,
color: lineColor,
)));
}
});
return list;
}
List<Widget> _titleViews() {
var list = <Widget>[];
steps.asMap().forEach((i, text) {
list.add(Text(text["title"], style: TextStyle(color: _activeColor)));
});
return list;
}
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: _titleViews(),
),
const SizedBox(
height: 10,
),
Row(
children: _iconViews(),
),
],
);
}
}
I would like, in this code, to put the IconButton in the top right corner of each ItemView. The ItemDescription and the ItemTitle centered at the top. I try to put them in the same Row but I can't get them to fit together, either the IconButton sticks to the text or it's in the middle.
I think it is easy but I didn't find a solution.
Here is the code:
import 'package:flutter/material.dart';
import 'package:cached_network_image/cached_network_image.dart';
import '../recyclerview/data.dart';
import 'package:watch/constants.dart';
class ListViewExample extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return new ListViewExampleState(
);
}
}
class ListViewExampleState extends State<ListViewExample>{
List<Container> _buildListItemsFromItems(){
int index = 0;
return item.map((item){
var container = Container(
decoration: index % 2 == 0?
new BoxDecoration(color: const Color(0xFFFFFFFF)):
new BoxDecoration(
color: const Color(0xFFFAFAF5)
),
child: new Row(
children: <Widget>[
new Container(
margin: new EdgeInsets.all(5.0),
child: new CachedNetworkImage(
imageUrl: item.imageURL,
width: 200.0,
height: 100.0,
fit: BoxFit.cover,
),
),
Expanded(
child: Row(
children: <Widget>[
new Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
padding: const EdgeInsets.only(bottom: 75.0 ),
child: Text(
item.title,
style: kItemTitle,
),
),
Container(
padding: const EdgeInsets.only(left: 15.0),
child:Text(
item.description,
style: kItemDescription,
),
),
],
),
new Row(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
child: IconButton(
icon: Icon(Icons.favorite_border, color: Colors.black,),
iconSize: 24.0,
onPressed: null
),
)
],)
]),
),
]),
);
index = index + 1;
return container;
}).toList();
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title: Text('Accueil', style: kAppBarStyle,),
backgroundColor: Colors.white,
elevation: 0,
),
body: ListView(
children: _buildListItemsFromItems(),
),
);
}
}
Update : I have added a Spacer() and put all in the same row, and set CrossAxisAlignment to .center.
Put the Icon in the same row as the title and the description, with a Spacer() in between. That will then give you an overflow error, because the Spacer wants to take up as much space as physically possible, so with no restriction it goes on to infinity. To tell the Spacer that it is only allowed a finite amount of space, you have to set the mainAxisSize of the row to MainAxisSize.min
Here's the code, with a couple alterations so I was able to run it for myself.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: ListViewExample(),
);
}
}
class ListViewExample extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return new ListViewExampleState();
}
}
class ListViewExampleState extends State<ListViewExample> {
var items = [
Item(),
Item(),
Item(),
Item(),
];
List<Container> _buildListItemsFromItems() {
int index = 0;
return items.map(
(item) {
var container = Container(
decoration: index % 2 == 0
? new BoxDecoration(color: const Color(0xFFFFFFFF))
: new BoxDecoration(color: const Color(0xFFFAFAF5)),
child: new Row(
children: <Widget>[
new Container(
margin: new EdgeInsets.all(5.0),
child: new Container(
color: Colors.red,
width: 150.0,
height: 100.0,
),
),
Expanded(
child: new Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(
padding: const EdgeInsets.only(bottom: 75.0),
child: Text(
item.title,
),
),
Container(
padding: const EdgeInsets.only(left: 15.0),
child: Text(
item.description,
),
),
Spacer(),
GestureDetector(
child: Icon(
Icons.favorite_border,
size: 14,
color: Colors.black,
),
onTap: null,
),
],
),
),
],
),
);
index = index + 1;
return container;
},
).toList();
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title: Text('Accueil'),
backgroundColor: Colors.white,
elevation: 0,
),
body: ListView(
children: _buildListItemsFromItems(),
),
);
}
}
class Item {
final String title;
final String description;
Item({this.title = 'FooTitle', this.description = 'BarDescription'});
}
I am trying to show some data from the database and my app must contain UI like this.
But I am encountering this kind of problem.
Problems:
The text is overflowing and not wrapping (I tried to use Flexible and Expanded but it produces more exceptions, mostly of non-zero flex and so on)
The list needs fixed height and width, whereas I need height to match_parent. double.infinity don't work as well.
Here is my code:
class CategoryDetailPage extends StatefulWidget {
final Category category;
CategoryDetailPage({Key key, this.category}) : super(key: key);
#override
_CategoryDetailPageState createState() => _CategoryDetailPageState();
}
class _CategoryDetailPageState extends State<CategoryDetailPage> {
DatabaseProvider databaseProvider = DatabaseProvider.instance;
List<Phrase> phrases;
final List<Color> _itemColors = [
Color(0xff16a085),
Color(0xff2980b9),
Color(0xff8e44ad),
Color(0xff2c3e50),
Color(0xffd35400),
Color(0xffbdc3c7),
Color(0xff27ae60),
Color(0xfff39c12),
Color(0xff7f8c8d),
Color(0xffc0392b),
];
int _colorCounter = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Padding(
padding: EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Row(
children: [
Container(
child: ClipRRect(
borderRadius: BorderRadius.circular(8),
child: Image(
image: AssetImage("assets/images/categories/${widget.category.image}"),
width: 32,
),
),
),
Padding(
padding: const EdgeInsets.only(left: 16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text(
"Say ${widget.category.name}",
style: TextStyle(fontSize: 24, fontFamily: "Pacifico"),
),
Text(
"\"${widget.category.quote}\" --${widget.category.quoteAuthor} aaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
textAlign: TextAlign.left,
style: TextStyle(
color: Colors.grey,
fontStyle: FontStyle.italic
),
),
],
),
),
],
),
Row(
children: <Widget>[
RotatedBox(
quarterTurns: -1,
child: Column(
children: <Widget>[
Text(
"Informal",
style: TextStyle(
fontSize: 32,
color: Colors.grey.withOpacity(0.5),
fontFamily: "AbrilFatFace"),
),
],
),
),
Container(
height: 300,
width: 300,
child: FutureBuilder(
future: databaseProvider
.getPhrasesByCategoryId(widget.category.id),
builder: (context, snapshot) {
return snapshot.hasData
? ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, i) {
return _buildPhraseItem(snapshot.data[i]);
})
: Center(
child: CircularProgressIndicator(),
);
},
),
),
],
),
],
),
),
),
);
}
Widget _buildPhraseItem(Phrase phrase) {
Random random = Random();
int colorIndex = random.nextInt(_itemColors.length - 1);
Color currentColor = _itemColors[colorIndex];
if (_colorCounter >= 10) _colorCounter = 0;
return InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => PhraseDetail(
phraseToShow: phrase.phrase,
color: currentColor,
)));
},
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
height: 80,
decoration: BoxDecoration(
color: currentColor,
borderRadius: BorderRadius.all(Radius.circular(4)),
boxShadow: [
BoxShadow(
blurRadius: 8,
color: Colors.grey.withOpacity(0.5),
offset: Offset(0, 3))
]),
child: Center(
child: Text(
phrase.phrase,
style: TextStyle(color: Colors.white),
)),
),
),
);
}
}
wrap the second child(Padding) of the first Row with Flexible
wrap the second child(Container) of the second Row with Flexible and remove width: 300 from the container parameters.
import 'dart:math';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: CategoryDetailPage(),
);
}
}
Random random = Random();
class CategoryDetailPage extends StatefulWidget {
CategoryDetailPage({
Key key,
}) : super(key: key);
#override
_CategoryDetailPageState createState() => _CategoryDetailPageState();
}
class _CategoryDetailPageState extends State<CategoryDetailPage> {
final List<Color> _itemColors = [
Color(0xff16a085),
Color(0xff2980b9),
Color(0xff8e44ad),
Color(0xff2c3e50),
Color(0xffd35400),
Color(0xffbdc3c7),
Color(0xff27ae60),
Color(0xfff39c12),
Color(0xff7f8c8d),
Color(0xffc0392b),
];
int _colorCounter = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Padding(
padding: EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Row(
mainAxisSize: MainAxisSize.min,
// crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Container(
child: ClipRRect(
borderRadius: BorderRadius.circular(8),
child: Image(
image: NetworkImage(
'https://source.unsplash.com/random',
),
width: 32,
),
),
),
Flexible(
child: Padding(
padding: const EdgeInsets.only(left: 16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text(
'say congratulations',
style:
TextStyle(fontSize: 24, fontFamily: "Pacifico"),
),
Text(
"At every party there are two kinds of people – those who want to go home and those who don’t. The trouble is, they are usually married to each other. - Ann Landers",
textAlign: TextAlign.left,
style: TextStyle(
color: Colors.grey,
fontStyle: FontStyle.italic),
),
],
),
),
),
],
),
Row(
children: <Widget>[
RotatedBox(
quarterTurns: -1,
child: Column(
children: <Widget>[
Text(
"Informal",
style: TextStyle(
fontSize: 32,
color: Colors.grey.withOpacity(0.5),
fontFamily: "AbrilFatFace"),
),
],
),
),
Flexible(
child: Container(
height: 300,
child: ListView(children: [
_buildPhraseItem(),
_buildPhraseItem(),
_buildPhraseItem(),
_buildPhraseItem(),
]),
),
),
],
),
],
),
),
),
);
}
Widget _buildPhraseItem() {
var colorIndex = random.nextInt(_itemColors.length - 1);
var currentColor = _itemColors[colorIndex];
if (_colorCounter >= 10) _colorCounter = 0;
return InkWell(
onTap: () {
print('Navigator.push');
},
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
height: 80,
decoration: BoxDecoration(
color: currentColor,
borderRadius: BorderRadius.all(Radius.circular(4)),
boxShadow: [
BoxShadow(
blurRadius: 8,
color: Colors.grey.withOpacity(0.5),
offset: Offset(0, 3))
]),
child: Center(
child: Text(
'phrase.phrase',
style: TextStyle(color: Colors.white),
)),
),
),
);
}
}
this screenshot of an No Material widget found
I try to add stars RateBar as below code but i got an error no material widget found.
what i need to do is that when i pressed on this flatButton i got a window to rate the order and submit this rate, how can i do that through my code below, or to inform me how to handle it
this is the widget of StarRating
import 'package:flutter/material.dart';
typedef void RatingChangeCallback(double rating);
class StarRating extends StatelessWidget {
final int starCount;
final double rating;
final RatingChangeCallback onRatingchanged;
final Color color;
StarRating({this.starCount=5, this.rating = .0, this.onRatingchanged, this.color});
Widget buildStar(BuildContext context, int index){
Icon icon;
if (index >= rating) {
icon = Icon(
Icons.star_border,
color: Theme.of(context).buttonColor
);
}
else if(index > rating - 1 && index < rating){
icon = Icon(
Icons.star_half,
color: Theme.of(context).primaryColor,
);
}else{
icon = Icon(
Icons.stars,
color: Theme.of(context).primaryColor,
);
}
return InkResponse(
onTap: onRatingchanged==null ? null : ()=> onRatingchanged(index+1.0),
child: icon,
);
}
#override
Widget build(BuildContext context) {
return Row(
children: List.generate(starCount, (index)=>buildStar(context, index)),
);
}
}
and this is the Screen to view the starBar:
import 'package:felsaree/widgets/star.rating.dart';
import 'package:flutter/material.dart';
class StarRatingScreen extends StatefulWidget {
static const routeName = '/starRating';
#override
_StarRatingScreenState createState() => _StarRatingScreenState();
}
class _StarRatingScreenState extends State<StarRatingScreen> {
double rating =3.5;
#override
Widget build(BuildContext context) {
return StarRating(
rating: rating,
onRatingchanged: (rating) => setState(() => this.rating = rating),
);
}
}
and in orderDetails screen through the flatbutton i need to show this Star Rate:
import 'package:felsaree/providers/order_provider.dart';
import 'package:felsaree/screens/star_rating_screen.dart';
import 'package:felsaree/widgets/star.rating.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
class OrderDetails extends StatefulWidget {
static const routeName = '/orderDetails';
#override
_OrderDetailsState createState() => _OrderDetailsState();
}
class _OrderDetailsState extends State<OrderDetails> {
double rating = 3.5;
// Widget ratingChange(double rating){
// return StarRating(
// rating: rating,
// onRatingchanged: (rating)=>this.rating = rating,);
// }
#override
Widget build(BuildContext context) {
final mediaQuery = MediaQuery.of(context).size.height;
final orderId = ModalRoute.of(context).settings.arguments as int;
final orderProvider = Provider.of<OrderProvider>(context, listen: false);
final order = orderProvider.findOrderById(orderId);
AppBar appBar = AppBar(title: Text(order.restaurantName),);
double _totalPrice =orderProvider.totalItemsPrice(order.orderItems);
bool _isAddress = orderProvider.checkUserAdress(order.address);
return Scaffold(
appBar: appBar,
body: Column(
children: <Widget>[
Card(
elevation: 4,
margin: EdgeInsets.all(10),
child: Padding(
padding: EdgeInsets.all(10),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Column(
children: <Widget>[
Text(order.id.toString()),
SizedBox(height: 4,),
Text(order.restaurantName),
SizedBox(height: 4,),
Text(order.branchName),
SizedBox(height: 4,),
],
),
Column(
children: <Widget>[
Text(DateFormat.yMd().format(DateTime.now())),
SizedBox(height: 15,),
Text('InProgress'),
SizedBox(height: 15,)
],
)
],
),),
),
Container(
margin: EdgeInsets.all(10),
padding: EdgeInsets.all(10),
decoration: BoxDecoration(
color: Colors.grey[100],
border: Border.all(width: 2, color: Colors.grey)
) ,
child: Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text('Price'),
Text('${_totalPrice}L.E'),
Text('Total: ${order.price}L.E')
],
),
SizedBox(height: 10,),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text('PC Discount'),
Text('${order.discountValue}L.E'),
Text(''),
],
),
SizedBox(height: 10,),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text('service Tax'),
Text('${order.serviceTax}L.E'),
Text(''),
],
),
SizedBox(height: 10,),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text('Delivery'),
Text('${order.delivery}L.E'),
Text(''),
],
),
SizedBox(height: 10,),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text('Vat'),
Text('${order.vatAmount}L.E'),
Text(''),
],
),
],
),
),
Container(
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(color: Colors.grey),
borderRadius: BorderRadius.circular(10),
),
padding: EdgeInsets.all(10),
margin: EdgeInsets.only(bottom: 20),
height: (mediaQuery
- appBar.preferredSize.height
- MediaQuery.of(context).padding.top)*0.30,
width: MediaQuery.of(context).size.width*.8,
child: ListView.builder(
itemCount: order.orderItems.length,
itemBuilder: (ctx, index){
final item = order.orderItems[index];
if(item.userComments == ''){
String userComment= 'no comment';
item.userComments = userComment;
}
return ListTile(
leading: CircleAvatar(
backgroundImage: NetworkImage(item.image,),
),
title: Text(item.itemName),
subtitle: Text('count: ${item.count}'),
trailing: Text(item.userComments),
);
}
),
),
Container(
width: double.infinity,
margin: EdgeInsets.only(right: 10, left: 10),
padding: EdgeInsets.symmetric(vertical: 5, horizontal: 10),
color: Colors.grey[100],
child: Text('Delivery Address', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),),
),
SizedBox(height: 8),
Container(
width: double.infinity,
padding: EdgeInsets.all(10),
margin: EdgeInsets.all(10),
decoration: BoxDecoration(
border: Border.all(color: Colors.grey[100])
),
child: _isAddress? Text(order.address) : Text('no address found'),
),
FlatButton(
onPressed: ()=>Navigator.of(context).pushNamed(StarRatingScreen.routeName),
child: Text('Rate The Order', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),))
],
),
);
}
}
This can be fixed by ensuring that your main includes MaterialApp() and Scaffold() as ancestors of your widgets as so:
void main() {
runApp(MaterialApp(
home: Scaffold(
appBar: AppBar(),
body: YourWidget(),
),
));
}
If, for whatever reason you don't want to use MaterialApp... you can use Material():
void main() {
runApp(
home: Scaffold(
appBar: AppBar(),
body: Material( child: YourWidget()),
),
);
}
I tried to add carousel along with text. But As far I can only add image carousel, Have no idea on how to add text. Please help me. Totally new.
I expect the output to be like image on above and text on below, but both need to swipe at same time.
I have no idea where to add the text field. I made this carousel with a example in youtube. But no example for carousel images with text. I tried something manually, But it all doesn't ended much well.
Please help me fix it. Thank-you
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(title: 'Slider'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
PageController pageController;
//Images List
List<String> images = [
'',
];
#override
void initState() {
super.initState();
pageController = PageController(initialPage: 1, viewportFraction: 0.6);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: PageView.builder(
controller: pageController,
itemCount: images.length,
itemBuilder: (context, position) {
return imageSlider(position);
}
)
);
}
imageSlider(int index) {
return AnimatedBuilder(
animation: pageController,
builder: (context, widget) {
double value = 1;
if(pageController.position.haveDimensions){
value = pageController.page - index;
value = (1 - (value.abs() * 0.3.clamp(0.0, 1.0)));
}
return Center(
child: SizedBox(
height: Curves.easeInOut.transform(value) * 400.0,
width: Curves.easeInOut.transform(value) * 350.0,
child: widget,
),
);
},
child: Container(
margin: EdgeInsets.all(10.0),
child: Image.asset(images[index],fit: BoxFit.cover),
),
);
}
}
Use column instead of container, so just replace this:
child: Container(
margin: EdgeInsets.all(10.0),
child: Image.asset(images[index],fit: BoxFit.cover),
),
with this:
child: Column(
// To centralize the children.
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
// First child
Container(
margin: EdgeInsets.all(10.0),
child: Image.asset(images[index],fit: BoxFit.cover),
),
// Second child
Text(
'foo',
style: TextStyle(
// Add text's style here
),
),
]
),
OR instead of building your own carousal, you can use a ready to use one, e.g: carousel_slider or flutter_swiper
try this
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text(
heading,
style: TextStyle(
color: Colors.white,
fontSize: 20.0,
fontWeight: FontWeight.bold,
),
),
Padding(
padding: const EdgeInsets.all(10.0),
child: Text(
sub_heading,
style: TextStyle(
color: Colors.white,
fontSize: 15.0,
),
//textAlign: TextAlign.center,
),
),
],
),
PageView with Next and Previous Functionality
Step 1:- Add PageView widget
class _WalkThroughState extends State<WalkThrough> {
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
var height = 0.0;
var width = 0.0;
int mCurrentIndex = -1;
List<Widget> pages=[PageOne(message: "Beauty Trends",),PageTwo(message: "Exclusive Offers",),PageThree(message: "Make your Kit",)];
PageController _controller = new PageController();
static const _kDuration = const Duration(milliseconds: 300);
static const _kCurve = Curves.ease;
#override
void initState() {
super.initState();
_controller = PageController();
}
#override
void dispose() {
_controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
height = MediaQuery.of(context).size.height;
width = MediaQuery.of(context).size.width;
return Scaffold(
extendBodyBehindAppBar: true,
body: Stack(
children: [
Container(
height: height,
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [startColorBackground, endColorBackground])),
),
Column(
children: <Widget>[
Flexible(
child: Container(
child: PageIndicatorContainer(
key: _scaffoldKey,
child: PageView.builder(
controller: _controller,
onPageChanged: _onPageViewChange,
itemBuilder: (context, position) {
mCurrentIndex = position;
return pages[position];
},
itemCount: 3,
),
align: IndicatorAlign.bottom,
length: 3,
indicatorSpace: 10.0,
indicatorColor: Colors.white,
indicatorSelectorColor: Colors.black,
)),
),
Container(
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
// ignore: invalid_use_of_protected_member
mCurrentIndex != 0 ?Padding(
padding: const EdgeInsets.only(left: 30.0, bottom: 30.0),
child: GestureDetector(
onTap: () {
_controller.previousPage(
duration: _kDuration, curve: _kCurve);
},
child: Text('Prev', style: TextStyle(fontSize: 20, fontWeight: FontWeight.w500),)),
) : Container(),
mCurrentIndex != 2 ? Padding(
padding: const EdgeInsets.only(right: 30.0, bottom: 30.0),
child: GestureDetector(
onTap: () {
_controller.nextPage(
duration: _kDuration, curve: _kCurve);
},
child: Text('Next', style: TextStyle(fontSize: 20, fontWeight: FontWeight.w500),)),
) : Container(),
],
),
),
],
),
],
),
);
}
_onPageViewChange(int page) {
/*print("Current Page: " + page.toString());
int previousPage = page;
if(page != 0) previousPage--;
else previousPage = 2;
print("Previous page: $previousPage");*/
setState(() {
mCurrentIndex = page;
print(mCurrentIndex);
});
}
}
Step 2:- Add Pages with data
Page 1
class PageOne extends StatelessWidget {
final String message;
var height = 0.0;
var width = 0.0;
PageOne({Key key, #required this.message}) : super(key: key);
#override
Widget build(BuildContext context) {
height = MediaQuery.of(context).size.height;
width = MediaQuery.of(context).size.width;
return Container(
height: height - 50,
child: Align(alignment: Alignment.center, child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Container(
margin: EdgeInsets.only(top: 16.0),
child: Image(image: AssetImage("assets/images/banner_one.png"),)),
Container(
margin: EdgeInsets.only(bottom: 16.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(message, style: TextStyle(fontSize: 40, fontFamily: 'Playfair', fontWeight: FontWeight.bold),),
SizedBox(height: 30,),
Text("Lorem Ipsum is simply dummy text of the \n printing and typesetting industry.", textAlign: TextAlign.center, style: TextStyle(fontSize: 18),),
],
),
),
],
),),
);
}
}
Page 2
class PageTwo extends StatelessWidget {
final String message;
var height = 0.0;
var width = 0.0;
PageTwo({Key key, #required this.message}) : super(key: key);
#override
Widget build(BuildContext context) {
height = MediaQuery.of(context).size.height;
width = MediaQuery.of(context).size.width;
return Container(
child: Column(
children: [
Expanded(
flex: 2,
child: Container(
width: width,
child: Image(
width: double.infinity,
image: AssetImage("assets/images/banner_two.png"),
fit: BoxFit.cover,)),
),
Expanded(
flex: 1,
child: Container(
margin: EdgeInsets.only(top: 16),
child: Column(
children: [
SizedBox(
height: 40,
),
Text(message, style: TextStyle(fontSize: 40, fontFamily: 'Playfair', fontWeight: FontWeight.bold),),
SizedBox(height: 30,),
Text("Lorem Ipsum is simply dummy text of the \n printing and typesetting industry.", textAlign: TextAlign.center, style: TextStyle(fontSize: 18),),
],
),
),
),
],
),
);
}
}
Page 3
class PageThree extends StatelessWidget {
final String message;
var height = 0.0;
var width = 0.0;
PageThree({Key key, #required this.message}) : super(key: key);
#override
Widget build(BuildContext context) {
height = MediaQuery.of(context).size.height;
width = MediaQuery.of(context).size.width;
return Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
flex: 3,
child: Container(
width: width,
child: Image( width: double.infinity,
image: AssetImage("assets/images/banner_three.png"), fit: BoxFit.fill,)),
),
Expanded(
flex: 1,
child: Container(
child: Column(
children: [
Text(message, style: TextStyle(fontSize: 40, fontFamily: 'Playfair', fontWeight: FontWeight.bold),),
SizedBox(height: 30,),
Text("Lorem Ipsum is simply dummy text of the \n printing and typesetting industry.", textAlign: TextAlign.center, style: TextStyle(fontSize: 18),),
],
),
),
),
],
),
);
}
}
You can add N number of pages. Right now am adding 3 pages with data
Colors.dart
import 'package:flutter/material.dart';
const viewColor = Color(0xFFF5D9CE);
const textPinkColor = Color(0xFFF51678);
const buttonPinkColor = Color(0xFFF5147C);
const pinkColor = Color(0xFFF51479);
const pinkBackground = Color(0xFFF5C3C7);
const startColorBackground = Color(0xFFF5F4F2);
const endColorBackground = Color(0xFFF5EAE6);
This is complete working code with Image on top with text and dots. For this you need to use these two libraries:- " carousel_slider: ^4.1.1 ", "smooth_page_indicator: ^1.0.0+2", update them to the latest.
class MyItem {
String itemName;
String path;
MyItem(this.itemName, this.path);
}
class craouselImage extends StatefulWidget {
#override
_craouselImage createState() => _craouselImage();
}
class _craouselImage extends State<craouselImage> {
int activeIndex = 0;
List<MyItem> items = [
MyItem("item 1", 'assets/images/appiconlogo.png'),
MyItem("item 2", 'assets/images/Mockup4.png'),
];
#override
Widget build(BuildContext context) {
return Container(
child: Column(
children: [
CarouselSlider.builder(
itemCount: items.length,
options: CarouselOptions(
height: 400,
viewportFraction: 1,
autoPlay: true,
enlargeCenterPage: true,
enlargeStrategy: CenterPageEnlargeStrategy.height,
autoPlayInterval: const Duration(seconds: 1),
onPageChanged: (index, reason) {
setState(() {
activeIndex = index;
});
},
),
itemBuilder: (context, index, realIndex) {
final imgList = items[index];
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Expanded(child: buildImage(imgList.path, index)),
const SizedBox(
height: 15,
),
buildText(imgList.itemName, index),
],
);
},
),
const SizedBox(
height: 22,
),
buildIndicator(),
const SizedBox(
height: 22,
),
//buildText(itemName, index),
// buildText(),
],
),
);
}
Widget buildImage(String imgList, int index) => Container(
margin: const EdgeInsets.symmetric(horizontal: 12),
color: Colors.transparent,
child: Align(
alignment: Alignment.center,
child: Image.asset(
imgList,
fit: BoxFit.cover,
),
),
);
buildIndicator() => AnimatedSmoothIndicator(
activeIndex: activeIndex,
count: items.length,
effect: const JumpingDotEffect(
dotColor: Colors.black,
dotHeight: 15,
dotWidth: 15,
activeDotColor: mRed),
);
buildText(String itemName, int index) => Align(
alignment: FractionalOffset.bottomCenter,
child: Text(
itemName,
style: const TextStyle(
fontWeight: FontWeight.w700, fontSize: 23, color: mRed),
));
}