I want to create a layout like this,
Image
I want to create a flutter app which can scroll vertically and also some content of the app should scroll horizontally as describe in the picture. I used ListView with scroll horizontal inside the SingleChildScrollView but it not work. It hide the content Horizontal listView content and the content below the ListView.
So How to make this layout
Code I used,
body: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 10),
child: CustomizedAppBar(),
),
SizedBox(
height: 30.0,
),
Padding(
padding: const EdgeInsets.only(left: 10,bottom: 5),
child: Text(
'Hello Jessica.',
style: kArtistNamePlayScreen,
),
),
Padding(
padding: const EdgeInsets.only(left: 10,bottom: 40),
child: Text(
'Recommendeddd',
style: kSongNamePlayScreen,
),
),
//TODO Insert Carousel Here
ListView(
children: <Widget>[
Container(
height: 150,
width: 230,
decoration: BoxDecoration(
color: Colors.grey[100],
borderRadius: BorderRadius.circular(20.0),
image: DecorationImage(
image: AssetImage('images/Panini_l.jpg'),
fit: BoxFit.cover,
),
boxShadow: [
new BoxShadow(
color: Colors.grey,
offset: Offset(1.5,1.5),
blurRadius: 3,
),
],
),
),
],
),
Text(
'Popular artists',
style: kSongNamePlayScreen,
),
Container(
child: Row(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(20.0),
child: Container(
width: 60,
height: 75,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(8)),
image: DecorationImage(
image: AssetImage('images/Panini_l.jpg'),
fit: BoxFit.cover,
)
),
),
)
],
),
),
SongList(
songListSongName: 'Beautiful People',
songListArtistName: 'Ed Sheeran',
songListAvatarImage: AssetImage('images/beautiful_people_l.jpg'),
heartClick: (){},
),
SongList(
songListSongName: 'Panini',
songListArtistName: 'Lil Nas X',
songListAvatarImage: AssetImage('images/Panini_l.jpg'),
heartClick: (){},
),
SongList(
songListSongName: 'Do You Sleep',
songListArtistName: 'Sam Samith',
songListAvatarImage: AssetImage('images/Do_you_sleep_l.jpg'),
heartClick: (){},
),
SongList(
songListSongName: 'Bad Guys',
songListArtistName: 'Billie Eilish',
songListAvatarImage: AssetImage('images/Bad_guys_l.jpg'),
heartClick: (){},
)
],
),
)
Instead of ListView, you can use SingleChildScrollView with Row as child. Then give the SingleChildScrollView the scrollDirection: Axis.horizontal Code:
//TODO Insert Carousel Here
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: <Widget>[
Container(
height: 150,
width: 230,
decoration: BoxDecoration(
color: Colors.grey[100],
borderRadius: BorderRadius.circular(20.0),
image: DecorationImage(
image: AssetImage('images/Panini_l.jpg'),
fit: BoxFit.cover,
),
boxShadow: [
new BoxShadow(
color: Colors.grey,
offset: Offset(1.5, 1.5),
blurRadius: 3,
),
],
),
),
],
),
),
You could use a ListView with horizontal scroll, it has to be wrapped inside a Container or SizedBox with a specific height.
Using ListView.builder could be more efficient, here is a quick example:
final _items = List.generate(20, (e) => e);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: SingleChildScrollView(
child: Column(
children: <Widget>[
Text("A"),
SizedBox(
height: 100.0,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: _items.length,
itemBuilder: (context, index) {
print('$index');
return SizedBox(
width: 150.0,
child: Center(child: Text('${_items[index]}')),
);
}),
),
Text("B"),
],
),
),
);
}
You could see the prints in the console, indicating the items are created only when they're scrolled onto the screen.
Related
I am using the Stack widget in my app and it is working great but now I have a problem with wrapping this Stack widget inside ListView Widget.
I am getting error
RenderBox was not laid out: RenderPointerListener#20d10 relayoutBoundary=up7 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
'package:flutter/src/rendering/box.dart':
Failed assertion: line 1979 pos 12: 'hasSize'
My Stack Widget is
Widget? stackW() {
return Stack(
alignment: Alignment.center,
children: <Widget>[
Positioned(
top: 70,
width: MediaQuery.of(context).size.width * .9,
height: 150,
child: Center(
child: Container(
width: MediaQuery.of(context).size.width * .9,
decoration: BoxDecoration(
color: Colors.grey[200],
borderRadius: BorderRadius.circular(15)),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
"Product Designer",
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
const SizedBox(
height: 10,
),
],
),
),
),
),
Positioned(
top: 30,
left: MediaQuery.of(context).size.width / 2.5,
width: 80,
height: 80,
child: CircleAvatar(
backgroundColor: Colors.white,
child: CircleAvatar(
backgroundColor: Colors.green[100],
radius: 35,
child: const FaIcon(
FontAwesomeIcons.apple,
size: 30,
color: Colors.black,
),
),
),
),
],
);
}
When I am passing stackWidget directly in body then it is working fine but after wrapping inside ListView, it is creating problem.
so Please guide me to achieve my listview data with Stack Widget.
body: stackW()!, //working
body: ListView(
scrollDirection: Axis.vertical,
children: [
stackW()!,
],
),
``` //not working
Both widgets are getting infinite height, you can wrap stackW() with SizedBox widget.
body: LayoutBuilder(
builder: (context, constraints) => ListView(
scrollDirection: Axis.vertical,
children: [
SizedBox(
height: constraints.maxHeight,
width: constraints.maxWidth,
child: stackW()!,
)
],
),
),
I made an application like this:
I want to add a little info text on top of this gridView structure. How can I do it? I'm a beginner and I just couldn't do it.
Codes:
body: Container(
padding: EdgeInsets.all(7),
child: GridView.builder(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 10,
mainAxisSpacing: 10,
),
itemCount: subjects.length,
itemBuilder: (BuildContext context, int index) {
return Padding(
padding: const EdgeInsets.all(2.0),
child: Container(
child: InkWell(
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
border: Border.all(color: Colors.black),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset(subjects[index].subjectImage, fit: BoxFit.cover, height: 50, width: 50,),
SizedBox(height: 15,),
Text(subjects[index].subjectName, style: TextStyle(fontSize: 20, fontWeight: FontWeight.w500),),
],
),
),
onTap: () {},
),
),
);
},
),
How can I do it? Thanks in advance.
Try below code. I have added text like Text("1234567890")
body: Container(
padding: EdgeInsets.all(7),
child: Column(
children: [
Text("1234567890"), //<------------
Expanded(
child: GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 10,
mainAxisSpacing: 10,
),
itemCount: subjects.length,
itemBuilder: (BuildContext context, int index) {
return Padding(
padding: const EdgeInsets.all(2.0),
child: Container(
child: InkWell(
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
border: Border.all(color: Colors.black),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset(
subjects[index].subjectImage,
fit: BoxFit.cover,
height: 50,
width: 50,
),
SizedBox(
height: 15,
),
Text(
subjects[index].subjectName,
style: TextStyle(
fontSize: 20, fontWeight: FontWeight.w500),
),
],
),
),
onTap: () {},
),
),
);
},
),
),
],
),
);
You can use #DholaHardik's answer. Just need to wrap the Grid View Builder to a Sized Box and give it a height let's say height = MediaQuery.of(context).size.height and if the error says Overyflow by say 45 pixels.. You can change height to MediaQuery.of(context).size.height - 45;
I have three tab. One of the tab is for edit photo page (retrieve image which already have in API, edit and return capture image to API with Update button in that page). All is work and fine. But after capture image with camera, and change to other tab and return back to this tab (in this state not save), Already capture image not show and only API image show. I capture again to save. I want to remain the capture image in container although I don't save to API and change tab.
This is picture of my app contain tab bar view which contain edit image tab bar
This is my tab bar view dart file.
var width = MediaQuery.of(context).size.width;
final tabText = TextStyle(fontSize: width * 0.03);
return Scaffold(
appBar: new AppBar(
title: new Text(
'EDIT CLIENT',
style: new TextStyle(color: accentColor, fontFamily: 'Dosis'),
),
bottom: PreferredSize(
preferredSize: Size(40, 40),
child: Container(
height: getScreenHeightRation(40.0),
decoration: BoxDecoration(
color: Color(0xFFF0C185),
border: Border.all(color: Colors.grey[600]),
//0xFFF0C185
),
child: TabBar(
indicatorPadding: EdgeInsets.symmetric(horizontal: 40),
//isScrollable: true,
//change here
labelPadding: EdgeInsets.only(left: 10),
indicatorSize: TabBarIndicatorSize.tab,
indicatorColor: Colors.transparent,
indicator: BoxDecoration(
color: Color(0xFFD2A368),
),
tabs: [
Container(
decoration: BoxDecoration(
border: Border(right: BorderSide(color: Colors.grey))),
child: Tab(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ImageIcon(
AssetImage('assets/images/icon_ext/menu.png'),
size: 12,
),
SizedBox(
width: 5.0,
),
Text('Customer Data',style: tabText, ),
],
),
),
),
Container(
decoration: BoxDecoration(
border: Border(right: BorderSide(color: Colors.grey))),
child: Tab(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ImageIcon(
AssetImage('assets/images/icon_ext/image.png'),
size: 12,
),
SizedBox(
width: 5.0,
),
Text('Profile',style: tabText, )
],
),
),
),
Container(
child: Tab(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ImageIcon(
AssetImage('assets/images/icon_ext/placeholder.png'),
size: 12,
),
SizedBox(
width: 5.0,
),
Text('Location',style: tabText, )
],
),
),
)
],
controller: tabController,
),
),
),
iconTheme: new IconThemeData(color: accentColor),
centerTitle: true,
),
body: TabBarView(
controller: tabController,
children: [
EditClientInformation(
customerNo: widget.customerNo,
branchId: _branchId,
defaultBranchId: _defaultBranchId,
userId: _userId,
systemFormatDate: _systemFormatDate,
),
EditClientProfile(
customerNo: widget.customerNo,
branchId: _branchId,
defaultBranchId: _defaultBranchId,
userId: _userId,
systemFormatDate: _systemFormatDate,
),
EditClientMap(
customerNo: widget.customerNo,
branchId: _branchId,
defaultBranchId: _defaultBranchId,
userId: _userId,
systemFormatDate: _systemFormatDate,
),
],
),
);
}
This is capture image tab.
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Stack(
children: [
Container(
width: 300.0,
height: 170.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(20)),
border:
Border.all(width: 1, style: BorderStyle.solid),
),
child: Center(
child: Container(
width: 170.0,
height: double.infinity,
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topRight: Radius.circular(20),
topLeft: Radius.circular(10),
bottomLeft: Radius.circular(10),
bottomRight: Radius.circular(10)),
//border: Border.all(width: 1, style: BorderStyle.solid),
image: DecorationImage(
image: _profileCaptImg == ""
? NetworkImage(_profileImg)
: FileImage(profile),
fit: BoxFit.cover,
),
),
),
),
),
Positioned(
right: 62.0,
top: 0.0,
child: _profileCaptImg != ''
? GestureDetector(
onTap: () {
setState(() {
profile = null;
_profileCaptImg = '';
});
},
child: Container(
width: 20.0,
height: 20.0,
child: Icon(
Icons.close,
color: Colors.white,
size: 20.0,
),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.black,
),
),
)
: Container(),
),
],
),
Container(
width: 50.0,
height: 50.0,
child: FloatingActionButton(
onPressed: profileImgPicker,
heroTag: null,
child: new Icon(Icons.camera_alt),
)),
],
),
Try this solution:
/// Add with AutomaticKeepAliveClientMixin:
class _YourWidgetState extends State<YourWidget> with AutomaticKeepAliveClientMixin {
/// Add these 2 lines:
#override
bool get wantKeepAlive => true;
/// Add super.build(context) to your build method
#override
Widget build(BuildContext context) {
super.build(context);
return YourWidgets();
}
}
I'm coding a layout like homepage from Linkedin, Twitter, etc (example here) with Flutter for Web, but the Profile Tab it's not fixing on top of layout. I need something like gravity property (Android), I tried usign Align class, CrossAxisAlignment, MainAxisAlignment but it didn't work. Also I tried to set a margin/padding subtracting the height of the context with container, but it didn't work either
return SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Padding(
padding: EdgeInsets.only(top: 30, left: 50, right: 50),
child: Row(children: [
Expanded(
flex: 1,
child: Column(
children: [
Container(
margin: EdgeInsets.only(right: 50),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(15),
),
child: Center(child: Text('Trend Stories')))
],
),
),
Expanded(
flex: 2,
child: Column(
children: [
Container(
margin: EdgeInsets.only(right: 50),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(15),
),
height: MediaQuery.of(context).size.height,
child: Center(child: Text('Trend Stories')))
],
),
),
Expanded(
flex: 1,
child: Column(
children: [
Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(15),
),
height: MediaQuery.of(context).size.height,
child: Center(child: Text('Trend Stories')))
],
),
),
])));
code
I was trying to recreate a design concept from this guy(https://dribbble.com/shots/3812962-iPhone-X-Todo-Concept) but I'm getting some troubles with the ListView alignment or so I think.
What I'm trying to do is moving the List to the right without cutting the edges of the cards when I swipe.
I already tried with margin and padding but none of this applied to the container produces the results I want to obtain.Edges are cutted off when I swipe.
I leave here the Container with the ListView inside it.
Screenshoots of the actual app:
https://imgur.com/a/hJ96sEv
Container(
height: 350.0,
child: ListView.builder(
physics: NeverScrollableScrollPhysics(),
itemCount: 3,
controller: scrollController,
scrollDirection: Axis.horizontal,
itemBuilder: (context, position) {
return GestureDetector(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Card(
child: Container(
width: 250.0,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: <Widget>[
Icon(
cardsList[position].icon,
color: appColors[position],
),
Icon(
Icons.more_vert,
color: Colors.grey,
)
],
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 8.0, vertical: 4.0),
child: Text(
"${cardsList[position].tasksRemaining} Tasks",
style:
TextStyle(color: Colors.grey),
),
),
Padding(
padding:
const EdgeInsets.symmetric(
horizontal: 8.0,
vertical: 4.0),
child: Text(
"${cardsList[position].cardTitle}",
style:
TextStyle(fontSize: 28.0),
)),
Padding(
padding: const EdgeInsets.all(8.0),
child: LinearProgressIndicator(
value: cardsList[position]
.taskCompletion,
),
)
],
),
),
],
),
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0)),
),
),
onHorizontalDragEnd: (details) {
animationController = AnimationController(
vsync: this,
duration: Duration(milliseconds: 450));
curvedAnimation = CurvedAnimation(
parent: animationController,
curve: Curves.fastOutSlowIn);
animationController.addListener(() {
setState(() {
currentColor =
colorTween.evaluate(curvedAnimation);
});
});
if (details.velocity.pixelsPerSecond.dx > 0) {
if (cardIndex > 0) {
cardIndex--;
colorTween = ColorTween(
begin: currentColor,
end: appColors[cardIndex]);
}
} else {
if (cardIndex < 2) {
cardIndex++;
colorTween = ColorTween(
begin: currentColor,
end: appColors[cardIndex]);
}
}
setState(() {
scrollController.animateTo((cardIndex) * 256.0,
duration: Duration(milliseconds: 450),
curve: Curves.fastOutSlowIn);
});
colorTween.animate(curvedAnimation);
animationController.forward();
});
},
),
),
What I'm trying to do is moving the List to the right without cutting the edges of the cards when I swipe.
To achieve that goal you need a PageView instead of a ListView, that way you can swipe and "snap" the views when you reach and specific position:
PageView.builder(
itemCount: tasks.length,
controller: PageController(initialPage: 0, viewportFraction: 0.8),
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 10),
child: Container(
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color: Color(0x40000000),
blurRadius: 10,
offset: Offset(0, 12),
),
],
),
child: Card(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10),
),
color: Colors.white,
child: Padding(
padding: const EdgeInsets.all(15),
child: Column(
children: <Widget>[
IntrinsicHeight(
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Icon(tasks[index].icon),
Expanded(
child: Container(
child: Align(
alignment: Alignment.topRight,
child: Icon(Icons.menu),
),
),
),
],
),
),
Expanded(
child: Container(
width: double.infinity,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Text(
"${tasks[index].tasks} tasks",
style: TextStyle(
color: Color(0xD0000000),
fontSize: 15,
),
),
SizedBox(height: 10),
Text(
"${tasks[index].title}",
style: TextStyle(
color: Color(0xD0000000),
fontSize: 24,
),
),
SizedBox(height: 10),
LinearProgressIndicator(
value: tasks[index].percentage,
backgroundColor: Color(0x300000FF),
)
],
),
),
),
],
),
),
),
),
);
},
)
The result of this implementation is something like this:
If you want to change the offset of the cards, you need to modify the value viewportFraction: 0.8 to anything you'd like. 1.0 is the value without offset.
You can find my full implementation over this Gist Github