ListTile inside ListView is causing an error - flutter

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../providers/weather_provider.dart';
class BottomListView extends StatelessWidget {
const BottomListView({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
final weatherData = Provider.of<WeatherProvider>(context).weatherData;
final isLandscape =
MediaQuery.of(context).orientation == Orientation.landscape;
final height = (MediaQuery.of(context).size.height -
50 -
MediaQuery.of(context).padding.top);
return Container(
decoration: const BoxDecoration(
border: Border(
top: BorderSide(width: 0.3, color: Colors.white),
),
color: Color.fromRGBO(255, 255, 255, 0.2),
),
height: isLandscape ? height * 0.35 : null,
child: Row(
children: [
Expanded(
child: SizedBox(
width: 200,
child: ListView(
scrollDirection: Axis.horizontal,
children: [ListTile(title: Text('Hello'))]),
),
),
],
));
}
}
I want to have horizontal scrollable listView with ListTiles. But without ListTile it works fine . With ListTile it is causing an error.How to solve it? I tried giving it the width but didn't work.
Error:
BoxConstraints forces an infinite width.
These invalid constraints were provided to RenderParagraph's layout() function by the following function, which probably computed the invalid constraints in question:

ListTiles needs to be defined with width params explicitly using SizedBox or Container.
If you dont define width, it will throw infinite width error.
So Wrap your ListTile inside a SizedBox or Container.
Since, ListView's scrollDirection is set to Horizontal, you dont need to place it inside of a row i.e. it will show children horizontally.
If scrollDirection is set to vertical, it will show children in a Column i.e. Vertically
Also you can't do both, Use expanded and give width to a child of a row.
Using Expanded means the child will take maximum size available to it w.r.t to its parent.
Try the below code snippet
Container(
decoration: const BoxDecoration(
border: Border(
top: BorderSide(width: 0.3, color: Colors.white),
),
color: Color.fromRGBO(255, 255, 255, 0.2),
),
// height: isLandscape ? height * 0.35 : null,
height: 100,
child: ListView(
scrollDirection: Axis.horizontal,
children: [
SizedBox(
width: 200,
child: ListTile(
title: Text('Hello'),
),
),
SizedBox(
width: 200,
child: ListTile(
title: Text('Hello'),
),
),
SizedBox(
width: 200,
child: ListTile(
title: Text('Hello'),
),
),
SizedBox(
width: 200,
child: ListTile(
title: Text('Hello'),
),
),
],
),
),

Related

Flutter ListTile leading height

I'd like to have a listtile where the leading widget is simply a half-transparent white container. Let me clarify it with an example
I managed to create the layout above (2 ListTile's). But as you can see, when the title property contains a large text as it is doing in the first (the green) tile, the height of the leading widget is not following as it should. The below code returns a ListTile given a Label which is a class of my own that simply contains text, textcolor and backgroundcolor.
ListTile(
contentPadding: EdgeInsets.zero,
dense: true,
minLeadingWidth: 15,
tileColor: label.bgColor,
textColor: label.textColor,
horizontalTitleGap: 0,
minVerticalPadding: 0,
trailing: getPopUpMenuButton(label),
leading: Container(
height: double.maxFinite,
width: 15,
color: Colors.white54,
),
title: Padding(
padding: EdgeInsets.all(4),
child: Text(
label.title,
),
),
)
So to summarize: how to make the leading height follow the height of the ListTile?
ListTile provide the UI with specific rules. As for leading this Size is defined within the source code as
final BoxConstraints maxIconHeightConstraint = BoxConstraints(
//...
maxHeight: (isDense ? 48.0 : 56.0) + densityAdjustment.dy,
);
final BoxConstraints looseConstraints = constraints.loosen();
final BoxConstraints iconConstraints = looseConstraints.enforce(maxIconHeightConstraint);
final double tileWidth = looseConstraints.maxWidth;
final Size leadingSize = _layoutBox(leading, iconConstraints);
final Size trailingSize = _layoutBox(trailing, iconConstraints);
The height is coming from
maxHeight: (isDense ? 48.0 : 56.0) + densityAdjustment.dy,
We can create the custom widget using rows and column,
body: Center(
child: ListView.builder(
itemCount: 33,
itemBuilder: (context, index) => Padding( //use separate builder to and remove the padding
padding: const EdgeInsets.all(8.0),
child: Container(
width: double.infinity,
decoration: BoxDecoration(
color: Colors.green,
borderRadius:
BorderRadius.circular(defaultBorderRadiusCircular),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(
width: 20,
),
Expanded(
child: Container(
padding: EdgeInsets.all(8.0),
decoration: BoxDecoration(
color: Colors.cyanAccent,
borderRadius: BorderRadius.only(
bottomRight:
Radius.circular(defaultBorderRadiusCircular),
topRight:
Radius.circular(defaultBorderRadiusCircular),
)),
child: Row(
children: [
Expanded(
child: Text(
"I managed to create the layout above (2 ListTile's). But as you can see, when the title property contains a large text as it is doing in the first (the green) tile, the height of the leading widget is not following as it should. The below code returns a ListTile given a Label which is a class of my own that simply contains text, textcolor and backgroundcolor.",
softWrap: true,
maxLines: 13,
style: TextStyle(),
),
),
Icon(Icons.menu),
],
),
),
),
],
),
),
),
),
),

ListView.builder is not overlapping in Stack in Flutter

I have been using ListView.builder in Stack. But the rounded containers are not overlapping each other. How can I overlap them? I have attached the code and screenshot of output as well.
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class Emniii extends StatelessWidget {
const Emniii({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
height: 30,
width: MediaQuery.of(context).size.width,
margin: EdgeInsets.only(top: 10),
child: Center(
child: Stack(
children: [
ListView.builder(
itemCount: 13,
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemBuilder: (_, index) {
return Container(
height: 30,
width: 30,
decoration: BoxDecoration(
color: Colors.black,
borderRadius: BorderRadius.circular(15),
),
);
}),
],
),
),
),
);
}
}
Current Output
what I am expecting
ListView is the most commonly used scrolling widget. It displays its children one after another in the scroll direction. In the cross axis, the children are required to fill the ListView.
In your case you just want to generate 13 Containers, use loop or List.generate and use Positioned widget to align them.
I am using left: index * 15, it is shifting right by container's half width.
child: Stack(
children: [
...List.generate(
13,
(index) => Positioned(
left: index * 15,
child: Container(
height: 30,
width: 30,
decoration: BoxDecoration(
color: index.isEven ? Colors.black : Colors.grey,
borderRadius: BorderRadius.circular(15),
),
),
),
),
],
),
More about ListView and Stack

How can I provide a minimum height to ListView.builder's children which can expand automatically if the children require more space?

I am using ListView.builder. In this, I need to set heights for the individual children. As of now, I'm achieving this using a SizedBox, but this doesn't give me the effect I want.
This is important because some of the children are column widgets like this:
return Column(
children: List.generate( //using List.generate for building the UI
data.length, //I don't know this length beforehand
(int i) => Padding(
padding: EdgeInsets.only(
left: 30.0, right: 30.0, bottom: height * 0.05),
child: EducationMobileCard(
//contents here
),
),
),
);
I want to wrap all widgets like this in a parent ListView.builder. Such that, when the user scrolls, each widget takes up the space that is required to fit its contents. Wrapping the widgets in SizedBox doesn't handle overflows. I've tried ConstrainedBox too. But it doesn't let the other parts of the UI access the vacant screen in case a widget hasn't taken up the entire maxWidth. It just simply keeps the space vacant.
This is the ListView.builder widget I'm currently using:
ListView.builder(
itemCount: 7,
itemBuilder: (context, index) {
return SizedBox(height: height, child: widgetList[index]); //height is the screen height here
}
),
I simply want something that specifies the minimum space to occupy but lets the widget handle the maximum space to take within the ListView.builder.
Edit: This is the EducationMobileCard widget:
import 'package:flutter/material.dart';
import '../custom/text_style.dart';
import '../theme/config.dart';
class EducationMobileCard extends StatefulWidget {
const EducationMobileCard(
{Key? key,
//the required parameters
)
: super(key: key);
final double height, width;
final String insttution, location, years, grades, desc, image;
#override
_EducationMobileCardState createState() => _EducationMobileCardState();
}
class _EducationMobileCardState extends State<EducationMobileCard> {
bool isHover = false;
#override
Widget build(BuildContext context) {
return AnimatedContainer(
decoration: BoxDecoration(
boxShadow: [
//contents
],
),
duration: const Duration(milliseconds: 200),
padding: EdgeInsets.only(
top: isHover ? widget.height * 0.005 : widget.height * 0.01,
bottom: !isHover ? widget.height * 0.005 : widget.height * 0.01),
child: InkWell(
onTap: () {},
onHover: (bool value) {
setState(() {
isHover = value;
});
},
child: Container(
alignment: Alignment.topCenter,
padding: EdgeInsets.only(
top: widget.height * 0.04,
left: widget.width * 0.015,
right: widget.width * 0.015,
bottom: widget.height * 0.04),
width: widget.width,
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color: isHover ? Colors.black12 : Colors.black45,
blurRadius: 10.0,
offset: const Offset(8, 12),
)
],
color: currentTheme.currentTheme == ThemeMode.dark
? Theme.of(context).cardColor
: Theme.of(context).primaryColor,
borderRadius: BorderRadius.circular(
5.0,
),
),
child: SingleChildScrollView(
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(bottom: 5.0),
child: ClipRRect(
borderRadius: BorderRadius.circular(8.0),
child: Image.asset(
'assets/education/${widget.image}',
scale: 1.2,
)),
),
FittedBox(
fit: BoxFit.cover,
child: text(widget.insttution, 25, Colors.white)),
Padding(
padding: const EdgeInsets.only(bottom: 5.0),
child: FittedBox(
fit: BoxFit.cover,
child: text(widget.location, 10, Colors.white)),
),
FittedBox(
fit: BoxFit.cover,
child: Padding(
padding: const EdgeInsets.only(bottom: 11.0),
child: text(
widget.years != ''
? 'Years of study: ${widget.years}'
: '',
12,
Colors.white),
)),
FittedBox(
fit: BoxFit.cover,
child: text(widget.desc, 15, Colors.white)),
FittedBox(
fit: BoxFit.cover,
child: text(
widget.grades != ''
? 'Grades Achieved: ${widget.grades}'
: '',
12,
Colors.white)),
],
),
),
),
),
);
}
}
You can use ConstrainedBox to set the maxmium and minimum hight.
Refer the example below
ConstrainedBox(
constraints: new BoxConstraints(
minHeight: 35.0,
maxHeight: 160.0,
),
child: new ListView(
shrinkWrap: true,
children: <Widget>[
new ListItem(),
new ListItem(),
],
),
)
You can then use the shrinkWrap proper to wrap the unused space like this:-
shrinkWrap: true,
Thank you

Flutter: How to add BackdropFilter to SliverAppBar

I want to add a BackdropFilter() to a SliverAppbar().
I want it to look something like the iOS App Library App Bar: https://cln.sh/eP8wfY.
Header sliver not floating over the list in a NestedScrollView does so but only to the header, I want the title and the actions to be visible while the background is blurred.
Thanks!
Edit
What the pages look like: https://cln.sh/vcCY4j.
Github Gist with my code: https://gist.github.com/HadyMash/21e7bd2f7e202de02837505e1c7363e9.
NOTE: getting hard time on color, even after spending hours of time.
you need to change colors
of you find some area problem that maybe because of safeArea or CupertinoNavBar.
you can remove/change color on shadow, i'm giving too much on test purpose.
All you have to play with Colors and LinearGradient
OutPut
Here is my concept:
Stack
- backgroundImage
- Container with white.3
- CustomScrollView
- SliverToBoxAdapter 2x kToolbarHeight for extra height for GridList,
- SliverGrid
- LinearGradient 2xkToolbarHeight for fadeEffect on upper scroll
- our widget TextField or anything
Demo
class Body extends StatelessWidget {
const Body({Key? key}) : super(key: key);
Widget build(BuildContext context) {
return Scaffold(
body: LayoutBuilder(
builder: (context, constraints) => Stack(
children: [
Container(
decoration: BoxDecoration(
// color: Colors.white.withOpacity(.3),
image: DecorationImage(
image: AssetImage("assets/me.jpg"),
fit: BoxFit.cover,
),
),
child: Container(),
),
Container(
decoration: BoxDecoration(
color: Colors.white.withOpacity(.3),
),
child: CustomScrollView(
slivers: [
SliverToBoxAdapter(
child: SizedBox(
height: kToolbarHeight * 2,
),
),
SliverPadding(
padding: EdgeInsets.all(20),
sliver: SliverGrid.count(
crossAxisCount: 2,
mainAxisSpacing: 20,
crossAxisSpacing: 20,
children: [
...List.generate(
12,
(index) => Container(
decoration: BoxDecoration(
color: index % 3 == 0
? Colors.deepPurple
: index % 3 == 1
? Colors.deepOrange
: Colors.amberAccent,
borderRadius: BorderRadius.circular(12),
),
))
],
),
)
],
),
),
Align(
alignment: Alignment.topCenter,
child: Container(
height: kToolbarHeight * 2,
width: constraints.maxWidth,
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Colors.grey,
Colors.white.withOpacity(.7),
],
),
),
child: Text(""),
),
),
Positioned(
top: kTextTabBarHeight * 1.122,
/// need to tweek
left: 20,
right: 20,
child: Container(
height: kToolbarHeight,
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: Colors.white70,
boxShadow: [
BoxShadow(
blurRadius: 12,
spreadRadius: 6,
color: Colors.black54,
offset: Offset(0, 12))
],
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
GestureDetector(
onTap: () {
print("boosm");
},
child: Text("Tap")),
],
),
),
),
],
),
),
);
}
}
TL;DR I fixed the problem by using a normal AppBar() since I didn't need a SliverAppBar(). I made a custom app bar to fix the problem (see code at the end of the question).
I realised I didn't need a SilverAppBar() because it will just stay floating and pinned. This made my life a whole lot easier since I could use an AppBar() and set the extendBodyBehindAppBar to true in the Scaffold(). This made it so that I wouldn't have to make a custom sliver widget as I am not familiar with making them.
My solution was to make a custom AppBar(). I would have a Stack() then put the blur effect and the AppBar() above it.
https://github.com/flutter/flutter/issues/48212 shows that you can't use ShaderMasks() with BackdropFilter()s. To work around this I made a column with a bunch of BackdropFilter()s. They would have decreasing sigma values to create the gradient effect I was looking for. This isn't very performant, however, and in heavier apps wouldn't work well. Making each block have the length of a single logical pixel was too heavy so I made it 2 logical pixels.
It can also be easily expanded, for example, by adding a fade effect as I did.
Here is what the result looks like.
Before: https://cln.sh/vcCY4j
After:
https://cln.sh/vNZVJW (Includes the opacity effect (0.8))
https://cln.sh/jfH7OP (Reduced opacity effect (0.5))
https://cln.sh/nXzPLe (No opacity effect)
Here is the code for the solution:
import 'dart:math';
import 'dart:ui';
import 'package:flutter/material.dart';
class BlurredAppBar extends StatelessWidget implements PreferredSizeWidget {
final String title;
final List<Widget>? actions;
/// An `AppBar()` which has a blur effect behind it which fades in to hide it
/// until content appears behind it. This has a similar effect to the iOS 14
/// App Library app bar. It also has the possibility of having a fade effect to
/// redude the opacity of widgets behind the `BlurredAppBar()` using a `LinearGradient()`.
const BlurredAppBar({required this.title, this.actions, Key? key})
: super(key: key);
/// The height of the `AppBar()`
final double height = 56;
/// Returns a `List<Widget>` of `BackdropFilter()`s which have decreasing blur values.
/// This will create the illusion of a gradient blur effect as if a `ShaderMask()` was used.
List<Widget> _makeBlurGradient(double height, MediaQueryData mediaQuery) {
List<Widget> widgets = [];
double length = height + mediaQuery.padding.top;
for (int i = 1; i <= (length / 2); i++) {
widgets.add(
ClipRRect(
child: BackdropFilter(
filter: ImageFilter.blur(
sigmaX: max(((length / 2) - i.toDouble()) / 2, 0),
sigmaY: min(5, max(((length / 2) - i.toDouble()) / 2, 0)),
),
child: SizedBox(
height: 2,
width: mediaQuery.size.width,
),
),
),
);
}
return widgets;
}
#override
Widget build(BuildContext context) {
final MediaQueryData mediaQuery = MediaQuery.of(context);
return Stack(
children: [
// BackdropFilters
SizedBox(
height: height + mediaQuery.padding.top,
child: Column(
children: _makeBlurGradient(height, mediaQuery),
),
),
// Fade effect.
Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
stops: [0.5, 1],
colors: [
Colors.white.withOpacity(0.8),
Colors.white.withOpacity(0),
],
),
),
),
// AppBar
AppBar(
title: Text(
title,
style: Theme.of(context).textTheme.headline3,
),
automaticallyImplyLeading: false,
actions: actions,
),
],
);
}
#override
Size get preferredSize => Size.fromHeight(height);
}
SliverAppBar(
primary: false,
toolbarHeight: kToolbarHeight * 1.5,
floating: true,
snap: true,
backgroundColor: Colors.black45,
titleSpacing: 0.0,
title: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 36.0, sigmaY: 36.0),
child: SizedBox(
width: MediaQuery.of(context).size.width,
height: kToolbarHeight * 1.5,
),
),
)
You can change toolbarHeight to your liking, but the child of the BackdropFilter must have the same height.

How to set minWidth Container in Expand

I using flutter to build the Web Application,
I have a response problem, I want my window to be as small as 600 dp, and when zoomed horizontally, the middle container will automatically scale, but the smallest is 200 dp.
I tried to write the code as follows, but it doesn't work as I expected. When I shrink to width less than 600, main container keeps automatically shrink and shrink to less than 200 db.
Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: [
Container(
width: 200,
height: 600,
margin: EdgeInsets.only(right: 20),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20)),
),
Expanded(
child: Container(
margin: EdgeInsets.symmetric(horizontal: 20),
constraints: BoxConstraints(minWidth: 300),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.8),
borderRadius: BorderRadius.circular(20)),
child: BlocBuilder<HomeBloc, HomeState>(
builder: (context, state) {
return state.widget;
}),
),
),
Container(
width: 200,
height: 600,
margin: EdgeInsets.only(right: 20),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20)),
),
],
),
Have you tried using ConstrainedBox instead of regular Container?
It has properties minHeigth and minWidth / maxHeight and maxWidth.
I found that ConstrainedBox's minWidth is ignored in Row widget.
So I implemented center widget's dynamic width by using 'MediaQuery' like what you want.
But if you decrease width, the overflow issue is happened.
So I changed Row widget to ListView widget to fix overflow issue.
import 'package:flutter/material.dart';
final Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: MyWidget(),
),
),
);
}
}
class MyWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
double centerWidth = MediaQuery.of(context).size.width - 480;
return ListView(
scrollDirection: Axis.horizontal,
children: [
Container(
width: 200,
height: 600,
margin: EdgeInsets.only(left: 20),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20)),
),
Container(
width: centerWidth < 300 ? 300 : centerWidth,
margin: EdgeInsets.symmetric(horizontal: 20),
constraints: BoxConstraints(minWidth: 150, ),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.8),
borderRadius: BorderRadius.circular(20),
),
child: Text(
'Hello, World!',
style: Theme.of(context).textTheme.headline4,
),
),
Container(
width: 200,
height: 600,
margin: EdgeInsets.only(right: 20),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20)),
),
],
);
}
}