I got this very simple code, but somehow I get an error when I set scrollDirection to Axis.horizontal
I invoke this widget in Page that has MaterialApp and Scaffold widgets.
What I tried is wrapping ListView.builder with expanded, I removed all widgets besides Container and ListView.builder
Here is code:
class CalendarPage extends StatelessWidget {
List<String> hoursList = ['00:00', '00:30', '01:00'];
#override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(25), topRight: Radius.circular(25))),
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
children: [
TextLabel('Choose preferred date of meeting'),
ListView.builder(
scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemCount: hoursList.length,
itemBuilder: (context, i) {
return Text(hoursList[i]);
})
],
),
),
);
}
}
thank you in advance
Wrap your ListView inside Expanded or Flexible widget. refer below code:
Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(25),
topRight: Radius.circular(25),
),
),
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
children: [
TextLabel('Choose preferred date of meeting'),
Expanded(
child: ListView.builder(
scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemCount: hoursList.length,
itemBuilder: (context, i) {
return Text(
hoursList[i],
);
}),
)
],
),
),
),
Result screen->
You must wrap with a container your Listview and define height value.
class CalendarPage extends StatelessWidget {
List<String> hoursList = ['00:00', '00:30', '01:00'];
#override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(25), topRight: Radius.circular(25))),
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
children: [
TextLabel('Choose preferred date of meeting'),
Container(
height: 300,
child: ListView.builder(
scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemCount: hoursList.length,
itemBuilder: (context, i) {
return Text(hoursList[i]);
}),
)
],
),
),
);
}
}
Related
I have created a list view with images in flutter. it works but the images is wrong size. It looks like this:
But what I want is this:
This is the code I am using:
SizedBox(
height: 300,
child: ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemBuilder: (BuildContext ctx, int index) {
return SizedBox(
width: MediaQuery.of(context).size.width * 0.5,
child: Card(
child: ClipRRect(
borderRadius: BorderRadius.circular(10),
child: Image.file(
File(_imageFileListM[index].path),
fit: BoxFit.fitWidth,
),
),
margin: const EdgeInsets.all(10),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20.0),
),
));
},
itemCount: _imageFileListM.length,
))
What am I doing wrong?
try this:
SizedBox(
height: 300,
child: ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemBuilder: (BuildContext ctx, int index) {
return SizedBox(
width: MediaQuery.of(context).size.width * 0.5,
child: Card(
elevation: 0,
color: Colors.transparent,
surfaceTintColor: Colors.transparent,
child: Align(
alignment: Alignment.center,
child: Container(
clipBehavior: Clip.antiAlias,
decoration: BoxDecoration(
color: Colors.transparent,
borderRadius: BorderRadius.circular(10),
),
child: Image.file(
File(_imageFileListM[index].path),
fit: BoxFit.contain,
),
),
),
margin: const EdgeInsets.all(10),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20.0),
),
));
},
itemCount: _imageFileListM.length,
)),
use container widget Box decoration property
like this may help you
Container(
height: 200.h,
width: double.infinity,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("Enter your path")
),
color: baseColor2,
borderRadius: BorderRadius.only(
bottomLeft:Radius.circular(20.r),
bottomRight:Radius.circular(20.r))),
),
Just wrap your list element with FittedBox like this:
SizedBox(
height: 300,
child: ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemBuilder: (BuildContext ctx, int index) {
return SizedBox(
width: MediaQuery.of(context).size.width * 0.5,
child: FittedBox(
child: Card(
child: ClipRRect(
borderRadius: BorderRadius.circular(20),
child: Image.file(
File(_imageFileListM[index].path),
fit: BoxFit.fitWidth,
),
),
margin: const EdgeInsets.all(10),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20.0),
),
),
));
},
itemCount: _imageFileListM.length,
)))
A simple way to achieve this is to use Stack and position.
Stack allows widgets to overlap each other.
Positioned allows you to render its child at a specific location within the stack.
The stack is pretty much like a column but the widgets are rendered on top of each other therefore you need to specify how they should render.
This would be your main Image Widget:
The image is wrapped in an expanded-sized box to cover the whole space.
positioned is set to bottom 0 will stick the widget to the bottom.
left and right are specified to be 0 so the widget also expands horizontally.
class ImageWidget extends StatelessWidget {
final String url;
const ImageWidget({super.key, required this.url});
#override
Widget build(BuildContext context) {
return ClipRRect(
borderRadius: BorderRadius.circular(16),
child: Stack(
children: [
SizedBox.expand(
child: Image.network(
url,
fit: BoxFit.contain,
),
),
const Positioned(
left: 0,
right: 0,
bottom: 0,
child: ImageChildWidget(),
),
],
),
);
}
}
This would be the bottom part. you can replace this with anything you'd like.
class ImageChildWidget extends StatelessWidget {
const ImageChildWidget({super.key});
#override
Widget build(BuildContext context) {
return const ColoredBox(
color: Color.fromARGB(155, 0, 0, 0),
child: Padding(
padding: EdgeInsets.all(8),
child: Text(
'Some Long Text',
style: TextStyle(
color: Colors.white,
fontSize: 16,
),
),
),
);
}
}
You also have a grid view, it's easy with gridDelegate
crossAxisCount: 2, says that you want 2 elements per row
mainAxisSpacing: 16, says that you want a padding of 16 vertically
crossAxisSpacing: 16, says that you want a padding of 16 horizontally
class GridExample extends StatefulWidget {
const GridExample({super.key});
#override
State<GridExample> createState() => GridExampleState();
}
class GridExampleState extends State<GridExample> {
// Generate a random list of images
List<String> urls = List.generate(
10,
(_) {
int random = Random().nextInt(500) + 250; // 250-500
return 'https://picsum.photos/$random/$random';
},
);
#override
Widget build(BuildContext context) {
return GridView.builder(
key: widget.key,
itemCount: urls.length,
padding: const EdgeInsets.all(16),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
mainAxisSpacing: 16,
crossAxisSpacing: 16,
),
itemBuilder: (context, index) {
return ImageWidget(
key: ValueKey(urls[index]),
url: urls[index],
);
},
);
}
}
Full code sample.
import 'dart:math';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
return const MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: GridExample(
key: ValueKey('grid'),
),
),
),
);
}
}
class GridExample extends StatefulWidget {
const GridExample({super.key});
#override
State<GridExample> createState() => GridExampleState();
}
class GridExampleState extends State<GridExample> {
// Generate a random list of images
List<String> urls = List.generate(
10,
(_) {
int random = Random().nextInt(500) + 250; // 250-500
return 'https://picsum.photos/$random/$random';
},
);
#override
Widget build(BuildContext context) {
return GridView.builder(
key: widget.key,
itemCount: urls.length,
padding: const EdgeInsets.all(16),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
mainAxisSpacing: 16,
crossAxisSpacing: 16,
),
itemBuilder: (context, index) {
return ImageWidget(
key: ValueKey(urls[index]),
url: urls[index],
);
},
);
}
}
class ImageWidget extends StatelessWidget {
final String url;
const ImageWidget({super.key, required this.url});
#override
Widget build(BuildContext context) {
return ClipRRect(
borderRadius: BorderRadius.circular(16),
child: Stack(
children: [
SizedBox.expand(
child: Image.network(
url,
fit: BoxFit.contain,
),
),
const Positioned(
left: 0,
right: 0,
bottom: 0,
child: ImageChildWidget(),
),
],
),
);
}
}
class ImageChildWidget extends StatelessWidget {
const ImageChildWidget({super.key});
#override
Widget build(BuildContext context) {
return const ColoredBox(
color: Color.fromARGB(155, 0, 0, 0),
child: Padding(
padding: EdgeInsets.all(8),
child: Text(
'Some Long Text',
style: TextStyle(
color: Colors.white,
fontSize: 16,
),
),
),
);
}
}
End result:
There are a lot of similar questions, but none of them works in my case. I think it may be connected to my builder widget, but it is just a guess based on that I tried every combination of Expanded, Columns and Flexible I could think of and my Text widget still overflows. I'd my Text widget to wrap for as many lines as needed.
Can you have a look please?
Row messageBubble(String text, bool isMine) {
return Row(
mainAxisAlignment: isMine ? MainAxisAlignment.end : MainAxisAlignment.start,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8),
child: Container(
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.3),
borderRadius: const BorderRadius.all(
Radius.circular(20),
),
),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
child: Text(
text,
style: kSmallText,
),
),
),
),
],
);
}
And more of the code that wraps my message bubble.
SingleChildScrollView(
child: StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection("message${item.id}")
.orderBy("messageCount", descending: false)
.snapshots(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: snapshot.data!.docs.length,
itemBuilder: (context, index) {
DocumentSnapshot doc =
snapshot.data!.docs[index];
lastMessage = doc["messageCount"];
return messageBubble(
doc["message"],
Provider.of<UserProvider>(context,
listen: false)
.userEmail ==
doc["user"]
? true
: false);
});
} else {
return const Center(
child: CircularProgressIndicator());
}
}),
),
Wrap the top level Padding widget with Flexible widget.
Widget messageBubble(String text, bool isMine) {
return Row(
mainAxisAlignment: isMine ? MainAxisAlignment.end : MainAxisAlignment.start,
children: <Widget>[
Flexible(
child: Padding(
padding: const EdgeInsets.all(8),
child: Container(
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.3),
borderRadius: const BorderRadius.all(
Radius.circular(20),
),
),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
child: Text(
text,
// softWrap: true,
),
),
),
),
),
],
);
}
List fu = [
'Packing & Unpacking',
'Cleaning',
'Painting',
'Heavy Lifting',
'Shopping',
'Watching Netflix',
'sadfdsfe eaf',
'ewfsfeagga,' 'gegea',
'gaegaewgv ewaggaa aweegaage',
'safa asdfesadfv esfsdf',
'sadfdsfe eaf',
'ewfsfeagga,' 'gegea',
'awfgraga wsg sfage aegea',
'gaegaewgv ewaggaa aweegaage',
'asdfehtrbfawefa garevaa aewf a'
];
Widget build(BuildContext context) {
return Container(
height: 120,
margin: EdgeInsets.symmetric(horizontal: 3.5.w, vertical: 0.8.h),
child: StaggeredGridView.countBuilder(
crossAxisCount: 2,
staggeredTileBuilder: (index) => const StaggeredTile.fit(1),
shrinkWrap: true,
controller: _controller,
scrollDirection: Axis.horizontal,
// crossAxisSpacing: 0,
mainAxisSpacing: 8,
itemBuilder: (ctx, index) {
return Container(
padding: const EdgeInsets.all(15),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(15)),
child: Text(
fu[index],
maxLines: 1,
),
);
},
itemCount: fu.length,
),
);
}
StaggeredTile.fit(1) didn't work when staggeredGridiew is horizontal.
I also tried using Wrap but I didn't get expected outcome.
Wrap( direction: Axis.vertical, children: fu .map((title) => Container( decoration: BoxDecoration( color: ConstColors.kWhite, borderRadius: BorderRadius.circular(15)), margin: EdgeInsets.all(8), padding: const EdgeInsets.all(8), child: Row( children: [ Text(title), ], ), )) .toList(), )
The result has extra space between containers. It would be great id there was a way to get horizontal container back to back
Try Wrap
Like so:
Wrap(
children: List.generate(
fu.length,
(context){
return Container(
padding: const EdgeInsets.all(15),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(15)),
child: Text(
fu[index],
maxLines: 1,
),
);
})
),
You can use Warp widget to solve this
final items = <String>[
'Packing & Unpacking',
'Cleaning',
'Painting',
'Heavy Lifting',
'Shopping',
'Watching Netflix',
'sadfdsfe eaf',
'ewfsfeagga,' 'gegea',
'gaegaewgv ewaggaa aweegaage',
'safa asdfesadfv esfsdf',
'sadfdsfe eaf',
'ewfsfeagga,' 'gegea',
'awfgraga wsg sfage aegea',
'gaegaewgv ewaggaa aweegaage',
'asdfehtrbfawefa garevaa aewf a'
];
class Screen extends StatelessWidget {
const Screen({
Key? key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: Wrap(
children: [
for (var item in items)
Container(
decoration: BoxDecoration(
color: Colors.white10,
border: Border.all(color: Colors.green),
borderRadius: const BorderRadius.all(Radius.circular(5)),
),
// you can change margin to increase spacing between containers
margin: const EdgeInsets.all(3),
padding: const EdgeInsets.all(5),
child: Text(item),
),
],
),
);
}
}
In slidingUpPanel, I have a ListView widget. When I try to scroll, the ListView slidingUpPanel closes. How do I scroll the ListView without closing the slidingUpPanel?
SlidingUpPanel(
controller: _panelController,
maxHeight: _panelHeightOpen,
minHeight: _panelHeightClosed,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(50),
topRight: Radius.circular(50),
),
boxShadow: [
BoxShadow(
color: secondaryColor,
spreadRadius: 1,
blurRadius: 5,
offset: Offset(0, -10), // changes position of shadow
),
],
panelBuilder: (sc) => _summaryWidget(sc),
),
My _summaryWidget
ListView(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
children: [
Photos(),
],
)
You need to put the sc in the ListView controller also:
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("SlidingUpPanelExample"),
),
body: SlidingUpPanel(
panelBuilder: (ScrollController sc) => _scrollingList(sc),
body: Center(
child: Text("This is the Widget behind the sliding panel"),
),
),
);
}
Widget _scrollingList(ScrollController sc){
return ListView.builder(
controller: sc,
itemCount: 50,
itemBuilder: (BuildContext context, int i){
return Container(
padding: const EdgeInsets.all(12.0),
child: Text("$i"),
);
},
);
}
And after image is loaded, it is taking full container size by overriding the border radius.
This is the out put i was getting Screenshot1
this is the output which i was looking for
ScreenShot2
code:
StaggeredGridView.countBuilder(
padding: EdgeInsets.all(8.0),
crossAxisCount: 4,
itemCount: wallpapersList.length,
itemBuilder: (context, index) {
String imgPath = wallpapersList[index].data['url'];
return Container(
decoration: BoxDecoration(
color: kSecondaryColor,
borderRadius: BorderRadius.all(
Radius.circular(20),
),
),
child: Image.network(imgPath, fit: BoxFit.fitHeight,
loadingBuilder: (BuildContext context, Widget child,
ImageChunkEvent loadingProgress) {
if (loadingProgress == null) return child;
return Center(
child: SpinKitDoubleBounce(
color: Colors.white,
),
);
}));
Images don't follow the border radius of the Container.
So what you'll have to do is use ClipRRect()
Use it like this
Container(
child: ClipRRect(
borderRadius: BorderRadius.circular(20),
child: Image.network(),
),
),
Just add the ClipRRect widget and that should work.