Scrollable Column and ListView.builder - flutter

I want to have a Column and ListView.builder to be scrollable using the SingleChildScrollView. I tried wrapping both the Column or the SingleChildScrollView with Expanded but I'm still not winning. I just want the ListView.builder and the Container above it to be scrollable. Please help...
I am getting an error that says : RenderFlex children have non-zero flex but incoming height constraints are unbounded.
import 'package:flutter/material.dart';
import 'package:ionicons/ionicons.dart';
import 'package:provider/provider.dart';
import '../widgets/product_item.dart';
import '../providers/products.dart';
class ProductsOverviewScreen extends StatelessWidget {
const ProductsOverviewScreen({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
final productsData = Provider.of<Products>(context);
final products = productsData.items;
return Scaffold(
appBar: AppBar(
leading: IconButton(
onPressed: () {},
icon: const Icon(
Ionicons.notifications_outline,
),
),
title: SizedBox(
width: MediaQuery.of(context).size.width * 0.3,
height: MediaQuery.of(context).size.height * 0.1,
child: Image.asset(
'assets/logo.png',
fit: BoxFit.contain,
),
),
actions: [
IconButton(
onPressed: () {},
icon: const Icon(
Ionicons.cart_outline,
),
),
],
),
body: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
height: 140,
width: MediaQuery.of(context).size.width * 0.9,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(26.0),
color: Colors.grey[300],
),
),
Row(
children: const [
Padding(
padding: EdgeInsets.only(
left: 15.0,
top: 20.0,
),
child: Text(
'Place Order',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 18.0,
),
),
),
],
),
Expanded(
child: ListView.builder(
scrollDirection: Axis.vertical,
itemCount: products.length,
itemBuilder: (ctx, i) => ProductItem(
products[i].id,
products[i].name,
products[i].size,
products[i].price,
products[i].image,
),
),
)
],
),
),
);
}
}

// The solution to your problem is to make the Listview non using enter code here scrollable and set shrinkwrap to true. Then wrap the first column in SingleChildScrollView. You don't need Expanded or Flexible Widget for this approach.
import 'package:flutter/material.dart';
class ProductsOverviewScreen extends StatelessWidget {
const ProductsOverviewScreen({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
final productsData = Provider.of<Products>(context);
final products = productsData.items;
return Scaffold(
appBar: AppBar(
leading: IconButton(
onPressed: () {},
icon: const Icon(
Icons.info_outline,
),
),
title: SizedBox(
width: MediaQuery.of(context).size.width * 0.3,
height: MediaQuery.of(context).size.height * 0.1,
child: Image.asset(
'assets/logo.png',
fit: BoxFit.contain,
),
),
actions: [
IconButton(
onPressed: () {},
icon: const Icon(
Icons.shopping_cart_outlined,
),
),
],
),
body: SingleChildScrollView(
child: Column(
// mainAxisSize: MainAxisSize.min,
children: [
Container(
height: 140,
width: MediaQuery.of(context).size.width * 0.9,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(26.0),
color: Colors.grey[300],
),
),
Row(
children: const [
Padding(
padding: EdgeInsets.only(
left: 15.0,
top: 20.0,
),
child: Text(
'Place Order',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 18.0,
),
),
),
],
),
ListView.builder(
shrinkWrap: true,
itemCount: 10,
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (ctx, i) => ProductItem(
products[i].id,
products[i].name,
products[i].size,
products[i].price,
products[i].image,
),
)
],
),
),
);
}
}

This is one approach among thousands of solutions, it consists of nesting one listview inside another. If you wish you can make the listview.builder horizontal.
import 'package:flutter/material.dart';
import 'package:ionicons/ionicons.dart';
import 'package:provider/provider.dart';
import '../widgets/product_item.dart';
import '../providers/products.dart';
class ProductsOverviewScreen extends StatelessWidget {
const ProductsOverviewScreen({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
final productsData = Provider.of<Products>(context);
final products = productsData.items;
return Scaffold(
appBar: AppBar(
leading: IconButton(
onPressed: () {},
icon: const Icon(
Ionicons.notifications_outline,
),
),
title: SizedBox(
width: MediaQuery.of(context).size.width * 0.3,
height: MediaQuery.of(context).size.height * 0.1,
child: Image.asset(
'assets/logo.png',
fit: BoxFit.contain,
),
),
actions: [
IconButton(
onPressed: () {},
icon: const Icon(
Ionicons.cart_outline,
),
),
],
),
body: ListView(
scrollDirection: Axis.vertical,
children: [
Container(
height: 140,
width: MediaQuery.of(context).size.width * 0.9,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(26.0),
color: Colors.grey[300],
),
),
Row(
children: const [
Padding(
padding: EdgeInsets.only(
left: 15.0,
top: 20.0,
),
child: Text(
'Place Order',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 18.0,
),
),
),
],
),
ListView.builder(
scrollDirection: Axis.vertical,
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
primary: false,
itemCount: products.length,
itemBuilder: (ctx, i) => ProductItem(
products[i].id,
products[i].name,
products[i].size,
products[i].price,
products[i].image,
),
)
],
),
);
}
}

Looking at your code, you don't need the SingleChildScrollView widget. Just remove it. The listView is built with a scroll behaviour, you dont need to add it.
Please, let me know if you meant something else and I can help.
If you still have the Renderflex error, then wrap your Column widget inside a Flexible widget
Flexible(child: Column(children:[..

Related

ElevatedButton Position Changing method

I have an Elevated Button which is on of the bottom of the Page and I am a beginner sorry for this silly doubts but i can't figure out how to change the position of the button I dont know how to try positioned widget too. Kindly help me
I tried positioned widget but couldn't do well can anyone help me with this. here is my full code.
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
home: MyApp(),
));
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
children: [
Expanded(
child: PageView.builder(
itemBuilder: (context, index)=> const OnBoardContent(
image: 'assets/splash-1.png',
description: "All under one roof with different approach"),
),
),
SizedBox(
height: 30,
width: 200,
child: ElevatedButton(
onPressed: (){},
child: const Text("Tap to get started"),
),
),
],
)
),
);
}
}
class OnBoardContent extends StatelessWidget {
const OnBoardContent({
Key? key,
required this.image,
required this.description,
}) : super(key: key);
final String image, description;
#override
Widget build(BuildContext context) {
return Column(
children: [
const SizedBox(
height: 160,
),
const Text("Naz-Kearn",
style: TextStyle(
fontSize: 30,
fontWeight: FontWeight.bold
)),
const Text("A simplify learning App",
style: TextStyle(
fontWeight: FontWeight.normal
),
),
Image.asset(image),
const SizedBox(
height: 50,
),
Text(description,
textAlign: TextAlign.center,
style: const TextStyle(fontWeight: FontWeight.normal),
),
],
);
}
}
Output of the above code
You need your widgets in a stack if you want to use Positioned widget on them :
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
home: MyApp(),
));
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Stack( //wrapped the whole column with a stack so that all the other widgets doesn't get disturbed
children: [
Column(
children: [
Expanded(
child: PageView.builder(
itemBuilder: (context, index)=> const OnBoardContent(
image: 'assets/splash-1.png',
description: "All under one roof with different approach"),
),
),
],
),
Positioned(
top: MediaQuery.of(context).size.height*0.7, //change the 0.7 part to any number you like
child: SizedBox(
height: 30,
width: 200,
child: ElevatedButton(
onPressed: (){},
child: const Text("Tap to get started"),
),
),
),
],
)
),
);
}
}
class OnBoardContent extends StatelessWidget {
const OnBoardContent({
Key? key,
required this.image,
required this.description,
}) : super(key: key);
final String image, description;
#override
Widget build(BuildContext context) {
return Column(
children: [
const SizedBox(
height: 160,
),
const Text("Naz-Kearn",
style: TextStyle(
fontSize: 30,
fontWeight: FontWeight.bold
)),
const Text("A simplify learning App",
style: TextStyle(
fontWeight: FontWeight.normal
),
),
Image.asset(image),
const SizedBox(
height: 50,
),
Text(description,
textAlign: TextAlign.center,
style: const TextStyle(fontWeight: FontWeight.normal),
),
],
);
}
}
try this code, you can use alignment property of the Stack widget to center everything.
SafeArea(
child: Stack(
alignment: Alignment.center, //do this
children: [
You can wrap your button with Padding widget which helps you to add padding as you like
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
children: [
Expanded(
child: PageView.builder(
itemBuilder: (context, index)=> const OnBoardContent(
image: 'assets/splash-1.png',
description: "All under one roof with different approach"),
),
),
Padding(
padding: EdgeInsets.all(8),
child: SizedBox(
height: 30,
width: 200,
child: ElevatedButton(
onPressed: (){},
child: const Text("Tap to get started"),
),
),),
],
)
),
);
}
Firstly please mention what precisely the issue you are facing. If you have a problem with the get started button, what is the expected place for the get started button in the design?
Based on the code given, I'm hoping that the get started button should be at the bottom of the screen with some space below. You have already placed the button at the bottom, but you are not able to give space below.
There are some possible ways, you can use it with the get started button component.
Instead of this,
SizedBox(
height: 30,
width: 200,
child: ElevatedButton(
onPressed: (){},
child: const Text("Tap to get started"),
),
),
Option 1
Use container with margin
Container(
height: 30,
width: 200,
margin: EdgeInsets.only(
bottom: 50,
),
child: ElevatedButton(
onPressed: () {},
child: const Text("Tap to get started"),
),
),
Option 2
Wrap existing SizedBox with padding widget
Padding(
padding: EdgeInsets.only(bottom: 50.0),
child: Sizedbox(
height: 30,
width: 200,
child: ElevatedButton(
onPressed: () {},
child: const Text("Tap to get started"),
),
),
),
Even with some more ways to move the button wherever you need, you can try your own with the following widgets Expanded(), Spacer(), SizedBox(), Positioned() and etc.

Flutter Bottom overflowed by xx pixel

I am trying to construct a page with multiple widgets Row, Column, Expanded, ListView, etc...
I am a bit confused. I want a page scrollable with my widgets ThemeList.
I have the error :
A RenderFlex overflowed by 28 pixels on the bottom.
class SettingsViewState extends State<SettingsView> {
#override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
drawer: const NavDrawer(),
appBar: AppBar(
title: Text(AppLocalizations.of(context)!.settingsTitle),
backgroundColor: Theme.of(context).primaryColor,
),
body: CustomScrollView(slivers: [
SliverFillRemaining(
child: Column(
children: const [
ThemeList(),
SizedBox(height: 8),
ThemeList(),
SizedBox(height: 8),
ThemeList(),
],
),
),
]),
);
}
}
class ThemeList extends StatelessWidget {
const ThemeList({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Expanded(
child: Padding(
padding: const EdgeInsets.all(10),
child: Container(
decoration: BoxDecoration(
border: Border.all(color: Theme.of(context).primaryColor, width: 2),
borderRadius: BorderRadius.circular(10),
),
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 5, left: 20),
child: Text(
AppLocalizations.of(context)!.settingsThemeSubTitle,
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 23,
),
),
)
],
),
ListView.builder(
shrinkWrap: true,
padding: const EdgeInsets.all(8),
itemCount: AppTheme.values.length,
itemBuilder: (context, index) {
final itemAppTheme = AppTheme.values[index];
var nameTheme = itemAppTheme.toString()
return Card(
color: appThemeData[itemAppTheme]?.primaryColor,
child: ListTile(
title: Text(
nameTheme,
style: appThemeData[itemAppTheme]?.textTheme.bodyText1,
),
onTap: () {
BlocProvider.of<ThemeBloc>(context).add(
ThemeChanged(theme: itemAppTheme),
);
Preferences.saveTheme(itemAppTheme);
},
),
);
},
)
],
),
),
),
);
}
}
Desired result :
Just wrap the ListView.builder() inside ThemeList with an Expanded and the problem would vanish.
If you want to have all the items inside each ThemeList displayed with a scroll for the whole screen then the easiest why is to do the following:
Change the CustomScrollView in the body of the Scaffold to be SingleChildScrollView with the Column as its child.
Remove the Expanded at the start of ThemeList.
Remove the ListView.builder() inside the ThemeList and replace it with any looping logic to directly render the cards, for example:
...AppTheme.values.map((itemAppTheme) {
var nameTheme = itemAppTheme.toString();
return Card(
color: appThemeData[itemAppTheme]?.primaryColor,
child: ListTile(
title: Text(
nameTheme,
style: appThemeData[itemAppTheme]?.textTheme.bodyText1,
),
onTap: () {
BlocProvider.of<ThemeBloc>(context).add(
ThemeChanged(theme: itemAppTheme),
);
Preferences.saveTheme(itemAppTheme);
},
),
);
}).toList()

large image when clicking - flutter

I have an algorithm working, and I need to click on the image to show it on the entire screen, I have not succeeded, I send all the code, add a comment "// THIS IS THE IMAGE I NEED TO LOOK BIG WHEN I CLICK" which is the image that I want to make it look large when I click it, I have tried in several ways but I have not been able to solve it, and the only thing I am missing is this functionality.
import 'dart:async';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:tienda/models/productos_model.dart';
import 'package:tienda/pages/otra_pagina.dart';
import 'package:tienda/pages/crear_productos.dart';
import 'package:tienda/pages/pedido_lista.dart';
import 'package:tienda/services/firebase_services.dart';
import 'package:tienda/widgets/header.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
//title: 'Flutter Demo',
theme: ThemeData(
//primarySwatch: Colors.yellow,
primaryColor: Colors.yellow[800],
),
home: MyHomePage(title: 'RETO SAN JOSE CHAPARRAL'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<ProductosModel> _productosModel = List<ProductosModel>();
List<ProductosModel> _listaCarro = [];
FirebaseService db = new FirebaseService();
StreamSubscription<QuerySnapshot> productSub;
#override
void initState() {
super.initState();
_productosModel = new List();
productSub?.cancel();
productSub = db.getProductList().listen((QuerySnapshot snapshot) {
final List<ProductosModel> products = snapshot.documents
.map((documentSnapshot) =>
ProductosModel.fromMap(documentSnapshot.data))
.toList();
setState(() {
this._productosModel = products;
});
});
}
#override
void dispose() {
productSub?.cancel();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
actions: <Widget>[
Padding(
padding: const EdgeInsets.only(right: 16.0, top: 8.0),
child: GestureDetector(
child: Stack(
alignment: Alignment.topCenter,
children: <Widget>[
Icon(
Icons.shopping_cart,
size: 38,
),
if (_listaCarro.length > 0)
Padding(
padding: const EdgeInsets.only(left: 2.0),
child: CircleAvatar(
radius: 8.0,
backgroundColor: Colors.red,
foregroundColor: Colors.white,
child: Text(
_listaCarro.length.toString(),
style: TextStyle(
fontWeight: FontWeight.bold, fontSize: 12.0),
),
),
),
],
),
onTap: () {
if (_listaCarro.isNotEmpty)
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => Cart(_listaCarro),
),
);
},
),
)
],
),
drawer: Container(
width: 170.0,
child: Drawer(
child: Container(
width: MediaQuery.of(context).size.width * 0.5,
//color: Colors.black, //color de menu principal
color: Colors.yellow[800],
child: new ListView(
padding: EdgeInsets.only(top: 30.0),
children: <Widget>[
Container(
height: 120,
child: new UserAccountsDrawerHeader(
accountName: new Text(''),
accountEmail: new Text(''),
decoration: new BoxDecoration(
image: new DecorationImage(
fit: BoxFit.fill,
image: AssetImage('assets/images/food1x.png'),
),
),
),
),
new Divider(),
new ListTile(
title: new Text(
'productos',
style: TextStyle(color: Colors.white),
),
trailing: new Icon(
Icons.fastfood,
size: 30.0,
color: Colors.white,
),
onTap: () =>
Navigator.of(context).push(new MaterialPageRoute(
builder: (BuildContext context) => CrearProductos(),
)),
),
new Divider(),
],
),
),
),
),
body: SafeArea(
child: SingleChildScrollView(
child: Container(
child: Column(
children: <Widget>[
Stack(
children: <Widget>[
WaveClip(),
Container(
color: Colors.transparent,
padding: const EdgeInsets.only(left: 24, top: 48),
height: 170,
child: ListView.builder(
itemCount: _productosModel.length,
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
return Row(
children: <Widget>[
Container(
height: 300,
padding: new EdgeInsets.only(
left: 10.0, bottom: 10.0),
child: Card(
elevation: 7.0,
clipBehavior: Clip.antiAlias,
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(24)),
child: AspectRatio(
aspectRatio: 1,
child: CachedNetworkImage(
imageUrl:
'${_productosModel[index].image}' +
'?alt=media',
fit: BoxFit.cover,
placeholder: (_, __) {
return Center(
child:
CupertinoActivityIndicator(
radius: 15,
));
}),
),
),
),
],
);
},
))
],
),
Container(height: 3.0, color: Colors.grey),
SizedBox(
height: 5.0,
),
Container(
color: Colors.grey[300],
height: MediaQuery.of(context).size.height / 1.5,
child: GridView.builder(
padding: const EdgeInsets.all(4.0),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2),
itemCount: _productosModel.length,
itemBuilder: (context, index) {
final String imagen = _productosModel[index].image;
var item = _productosModel[index];
return Card(
elevation: 4.0,
child: Stack(
fit: StackFit.loose,
alignment: Alignment.center,
children: <Widget>[
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Expanded(
child: CachedNetworkImage(
// THIS IS THE IMAGE I NEED TO LOOK BIG WHEN I CLICK
imageUrl:
'${_productosModel[index].image}' +
'?alt=media',
fit: BoxFit.cover,
placeholder: (_, __) {
return Center(
child:
CupertinoActivityIndicator(
radius: 15,
));
}),
),
Text(
'${_productosModel[index].name}',
textAlign: TextAlign.center,
style: TextStyle(fontSize: 20.0),
),
SizedBox(
height: 15,
),
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: <Widget>[
SizedBox(
height: 25,
),
Text(
'${_productosModel[index].price.toString()}COP',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 20.0,
color: Colors.black),
),
Padding(
padding: const EdgeInsets.only(
right: 8.0,
bottom: 8.0,
),
child: Align(
alignment: Alignment.bottomRight,
child: GestureDetector(
child: (!_listaCarro
.contains(item))
? Icon(
Icons.shopping_cart,
color: Colors.yellow[800],
size: 38,
)
: Icon(
Icons.shopping_cart,
color: Colors.red,
size: 38,
),
onTap: () {
setState(() {
if (!_listaCarro
.contains(item))
_listaCarro.add(item);
else
_listaCarro.remove(item);
});
},
),
),
),
],
)
],
),
],
));
},
)),
],
),
)),
));
}
}
Another solution is to show the larger image on the same screen using the dialog below.
InkWell(
onTap: () => showDialog(
builder: (BuildContext context) => AlertDialog(
backgroundColor: Colors.transparent,
insetPadding: EdgeInsets.all(2),
title: Container(
decoration: BoxDecoration(),
width: MediaQuery.of(context).size.width,
child: Expanded(
child: Image.network(
'${_productosModel[index].image}' +
'?alt=media',
fit: BoxFit.fitWidth,
),
),
),
),
context: context),
child: ClipRRect(
borderRadius: BorderRadius.circular(8),
child: Image.network(
BaseUrl.host + posts!.imageUrl!,
fit: BoxFit.cover,
),
),
)
You can create a new page, wrap the image widget in a InkWell widget, and when tapped navigate to the new page showing the image.
EDIT:
Your widget image would become:
// THIS IS THE IMAGE I NEED TO LOOK BIG WHEN I CLICK
return InkWell(
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (BuildContext context) => ImageScreen(
url: '${_productosModel[index].image}' + '?alt=media',
),
),
),
child: Expanded(
child: CachedNetworkImage(
imageUrl: '${_productosModel[index].image}' + '?alt=media',
fit: BoxFit.cover,
placeholder: (_, __) {
return Center(
child: CupertinoActivityIndicator(
radius: 15,
),
);
},
),
),
),
And then you create a new stateless widget which it builds a:
import 'package:flutter/material.dart';
class ImageScreen extends StatelessWidget {
final String? url;
ImageScreen({
Key? key,
#required this.url,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: Expanded(
child: CachedNetworkImage(
imageUrl: '${this.url}',
// Ajust the image changing the box fit attributte
fit: BoxFit.cover,
placeholder: (_, __) {
return Center(
child: CupertinoActivityIndicator(
radius: 15,
),
);
},
),
),
);
}
}
After that when you click the app navigates to a new screen rendering only the image. You can add a back button later.

How to prevent Row from taking all available width?

I have one problem with my CustomChip :
I need to wrap the card to fit the content only.
However, I have a second requirement: The long text should overflow fade.
When I fixed the second problem, this issue started to occur when I added Expanded to wrap the inner Row
I don't understand why the inner Row also seems to expand although its mainAxisSize is already set to min
Here is the code:
The screen:
import 'package:flutter/material.dart';
import 'package:app/common/custom_chip.dart';
class RowInsideExpanded extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Container(
decoration: BoxDecoration(
border: Border.all(
width: 1.0,
),
),
width: 200.0,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
_buildChip('short'),
_buildChip('looooooooooooooooooooooongg'),
],
),
),
),
);
}
_buildChip(String s) {
return Row(
children: [
Container(
color: Colors.red,
width: 15,
height: 15,
),
Expanded(
child: CustomChip(
elevation: 0.0,
trailing: Container(
decoration: BoxDecoration(
color: Colors.grey,
shape: BoxShape.circle,
),
child: Icon(Icons.close),
),
onTap: () {},
height: 42.0,
backgroundColor: Colors.black12,
title: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Text(
s,
softWrap: false,
overflow: TextOverflow.fade,
style: TextStyle(color: Colors.black, fontWeight: FontWeight.bold, fontSize: 16.0),
),
),
),
),
],
);
}
}
And the CustomChip
import 'package:flutter/material.dart';
class CustomChip extends StatelessWidget {
final Widget leading;
final Widget trailing;
final Widget title;
final double height;
final double elevation;
final Color backgroundColor;
final VoidCallback onTap;
const CustomChip({
Key key,
this.leading,
this.trailing,
this.title,
this.backgroundColor,
this.height: 30.0,
this.elevation = 2.0,
this.onTap,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Card(
elevation: elevation,
color: backgroundColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30.0),
),
child: InkWell(
onTap: onTap,
child: Container(
height: height,
child: Padding(
padding: const EdgeInsets.only(left: 5.0, right: 5.0),
child: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
leading ?? Container(),
SizedBox(
width: 5.0,
),
Flexible(
child: title,
fit: FlexFit.loose,
),
SizedBox(
width: 5.0,
),
trailing ?? Container(),
],
),
),
),
),
);
}
}
Look for "MainAxisSize" property and set to "MainAxisSize.min"
Instead of Expanded, just replace it with a Flexible that's because Expanded inherits Flexible but set the fit proprety to FlexFit.tight
When fit is FlexFit.tight, the box contraints for any Flex widget descendant of a Flexible will get the same box contraints. That's why your Row still expands even though you already set its MainAxisSize to min.
I changed your code to print the box contraints using a the LayoutBuilder widget.
Consider your code with Expanded:
import 'package:flutter/material.dart';
class RowInsideExpanded extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Container(
decoration: BoxDecoration(
border: Border.all(
width: 1.0,
),
),
width: 200.0,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
_buildChip('short'),
SizedBox(
height: 5,
),
_buildChip('looooooooooooooooooooooongg'),
],
),
),
),
);
}
_buildChip(String s) {
return Row(
children: [
Container(
color: Colors.red,
width: 15,
height: 15,
),
Expanded(
child: LayoutBuilder(builder: (BuildContext context, BoxConstraints constraints) {
print("outter $constraints");
return Container(
color: Colors.greenAccent,
child: LayoutBuilder(builder: (BuildContext context, BoxConstraints constraints) {
print("inner $constraints");
return Row(
mainAxisSize: MainAxisSize.min, // this is ignored
children: <Widget>[
SizedBox(
width: 5.0,
),
Flexible(
fit: FlexFit.loose,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Text(
s,
softWrap: false,
overflow: TextOverflow.fade,
style: TextStyle(color: Colors.black, fontWeight: FontWeight.bold, fontSize: 16.0),
),
),
),
SizedBox(
width: 5.0,
),
Container(
decoration: BoxDecoration(
color: Colors.grey,
shape: BoxShape.circle,
),
child: Icon(Icons.close),
),
],
);
}),
);
}),
),
],
);
}
}
It prints
I/flutter ( 7075): outter BoxConstraints(w=183.0, 0.0<=h<=Infinity)
I/flutter ( 7075): inner BoxConstraints(w=183.0, 0.0<=h<=Infinity)
(Look at the width in w, it constrained to be 183.0 for both outter and inner Row)
Now I changed the Expanded to Flexible and check the logs:
I/flutter ( 7075): outter BoxConstraints(0.0<=w<=183.0, 0.0<=h<=Infinity)
I/flutter ( 7075): inner BoxConstraints(0.0<=w<=183.0, 0.0<=h<=Infinity)
(Look at the width in w, it constrained to between zero and 183.0 for both outter and inner Row)
Now your widget is fixed:

Flutter - material design 2 semi transparent appbar

I want to get effect like this - when scrolled up, appbar is transparent with listview visible below it:
And scrolled down, only white color - first item below appbar:
My window layout:
return Container(
color: AppTheme.nearlyWhite,
child: SafeArea(
top: false,
bottom: false,
child: Scaffold(
backgroundColor: AppTheme.nearlyWhite,
body: Stack(
children: <Widget>[
DrawerUserController(
screenIndex: _drawerIndex,
drawerWidth: MediaQuery.of(context).size.width * 0.75,
animationController: (AnimationController animationController) => _sliderAnimationController = animationController,
onDrawerCall: (DrawerIndex drawerIndexdata) => _onDrawerCall(drawerIndexdata, _forceRefresh),
onDrawerTap:(DrawerIndex drawerIndexdata) => _onDrawerTap(drawerIndexdata),
screenView: Column(
children: <Widget>[
Padding(
padding: EdgeInsets.fromLTRB(8, MediaQuery.of(context).padding.top + 8, 8, 8),
child: _createAppBar(),
),
Expanded(
child:
Container(
color: Colors.white,
child: _screenView,
)
),
],
),
),
new FabDialer(_fabMiniMenuItemList, Colors.blue, new Icon(Icons.add))
],
),
),
),
);
}
_screenView is simple Listview().builder() and it shows InkWell widget for each item. My appbar is custom, defined like this:
_createAppBar() {
return SizedBox(
height: AppBar().preferredSize.height,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 8, left: 8),
child: Container(
width: AppBar().preferredSize.height - 8,
height: AppBar().preferredSize.height - 8,
),
),
Expanded(
child: Center(
child: Padding(
padding: const EdgeInsets.only(top: 4),
child: Column(
children: <Widget>[
Text(
_menuSelected,
style: TextStyle(
fontSize: 22,
color: AppTheme.darkText,
fontWeight: FontWeight.w400,
),
),
Text(
globals.cityName,
style: TextStyle(
fontSize: 15,
color: AppTheme.darkerText,
fontWeight: FontWeight.w400,
),
),
],
),
),
),
),
Padding(
padding: const EdgeInsets.only(top: 8, right: 8),
child: Container(
width: AppBar().preferredSize.height - 8,
height: AppBar().preferredSize.height - 8,
color: Colors.white,
child: Material(
color: Colors.transparent,
child: InkWell(
borderRadius:
BorderRadius.circular(AppBar().preferredSize.height),
child: Icon(Icons.refresh, color: AppTheme.dark_grey,),
onTap: () => setState(() => _forceRefresh = true),
),
),
),
),
],
),
);
}
That's how it looks now with first list item visible:
So, almost there, but when scrolled down, appbar won't be transparent:
I tried to mess around with setting my appbar backround to color with transparency, without success. Also I need to get my widgets actually overlapped (ListView needs to overlap my appbar) and it generates error messages from Flutter.
Any ideas how to do that properly?
set extendBodyBehindAppBar: true in Scaffold widget. Then use Opacity widget like this,
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(home: Home()));
}
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
#override
Widget build(BuildContext context) {
return Scaffold(
extendBodyBehindAppBar: true,
appBar: PreferredSize(
preferredSize: const Size.fromHeight(kToolbarHeight),
child: Opacity( //Wrap your `AppBar`
opacity: 0.8,
child: AppBar(
title: Text("Demo"),
),
),
),
body: ListView.builder(
itemCount: 30,
itemBuilder: (context, index) {
return ListTile(
title: Text("Tile: $index"),
);
},
),
);
}
}
#override
Widget build(BuildContext context) {
return Container(
child: Stack(
children:[
Container(
color:Colors.white,
padding:EdgeInsets.all(10),
child:ListView.builder(
itemCount:25+1,
//length + 1 is beacause to show 1st item at the beginning
shrinkWrap:true,
itemBuilder:(con,ind){
return ind==0 ?
Container(height:70)
:ListTile(
title:Text('Item $ind',
style:TextStyle(color:Colors.black,))
);
}
)
),
Container(
height:70,
color:Colors.transparent,
child:Card(
color:Colors.white.withAlpha(80),
child: Row(
children:[
Expanded(
flex:1,
child: IconButton(
icon:Icon(Icons.list,color:Colors.black,size:25),
onPressed:(){
//todo
}
),
),
Expanded(
flex:3,
child: Text('Title',
style:TextStyle(color:Colors.black,)),
),
Expanded(
flex:1,
child: IconButton(
icon:Icon(Icons.search,color:Colors.black,size:25),
onPressed:(){
//todo
}
),
),
Expanded(
flex:1,
child: IconButton(
icon:Icon(Icons.more_vert,color:Colors.black,size:25),
onPressed:(){
//todo
}
),
)
]
),
)
)
]
)
);
}