Related
i'm trying to integrate a listView.builder in my UI! First of all, the whole content of the screen is inside a CustomScrollView that has silver widgets inside of it. Everything works pretty fine unless that my listview is not scrolling.
Here is the code:
class _DashboardScreenState extends State<DashboardScreen> {
#override
Widget build(BuildContext context) {
final screenHeight = MediaQuery.of(context).size.height;
return Scaffold(
appBar: CustomAppBar(),
body: CustomScrollView(
physics: ClampingScrollPhysics(),
slivers: <Widget>[
_buildHeader(screenHeight),
_buildBody(screenHeight),
],
),
);
}
}
The _buildBody code:
SliverToBoxAdapter _buildBody(double screenHeight) {
return SliverToBoxAdapter(
child: Column(
children: [
Container(
width: 100,
height: 65,
child: Padding(
padding: const EdgeInsets.only(top: 20),
child: ElevatedButton(
onPressed: () {},
child: Text(
'Add',
style: TextStyle(fontSize: 18),
),
style: ElevatedButton.styleFrom(
shape: StadiumBorder(),
backgroundColor: Palette.primaryColor),
),
),
),
SizedBox(
height: 10,
),
ListView.builder(
scrollDirection: Axis.vertical,
physics: const AlwaysScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: 6,
itemBuilder: ((BuildContext context, int index) {
return Container(
margin: const EdgeInsets.symmetric(
vertical: 10.0,
horizontal: 20.0,
),
padding: const EdgeInsets.all(10.0),
height: screenHeight * 0.15,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Color(0xFFAD9FE4), Palette.primaryColor],
),
borderRadius: BorderRadius.circular(20.0),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Image.asset(
"assets/worker.png",
height: 80,
width: 80,
),
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'Somme: 50 €',
style: const TextStyle(
color: Colors.white,
fontSize: 18.0,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: screenHeight * 0.01),
Text(
'Date: 19 novembre 2022',
style: TextStyle(fontSize: 10, color: Colors.white),
),
SizedBox(height: screenHeight * 0.01),
Text(
'Follow the instructions\nto do your own test.',
style: const TextStyle(
color: Colors.white,
fontSize: 16.0,
),
maxLines: 2,
),
],
)
],
),
);
}))
],
),
);
}
I tried adding shrinkWrap: true as well as the scroll direction. Also tried wrapping it inside a SingleScrollChildView, none of the solutions worked for me. I appreciate any kind of help!
You can use physics: const NeverScrollableScrollPhysics(), on listView, the parent widget is already handling the scroll event. But you can replace listView with Column widget.(we already have on parent, therefor using loop)
SliverToBoxAdapter _buildBody(double screenHeight) {
return SliverToBoxAdapter(
child: Column(
children: [
Container(
width: 100,
height: 65,
child: Padding(
padding: const EdgeInsets.only(top: 20),
child: ElevatedButton(
onPressed: () {},
child: Text(
'Add',
style: TextStyle(fontSize: 18),
),
style: ElevatedButton.styleFrom(
shape: StadiumBorder(),
backgroundColor: Palette.primaryColor),
),
),
),
SizedBox(
height: 10,
),
for (int i = 0; i < 6; i++)
Container(
margin: const EdgeInsets.symmetric(
vertical: 10.0,
horizontal: 20.0,
),
padding: const EdgeInsets.all(10.0),
height: screenHeight * 0.15,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Color(0xFFAD9FE4), Palette.primaryColor],
),
borderRadius: BorderRadius.circular(20.0),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Image.asset(
"assets/worker.png",
height: 80,
width: 80,
),
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'Somme: 50 €',
style: const TextStyle(
color: Colors.white,
fontSize: 18.0,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: screenHeight * 0.01),
Text(
'Date: 19 novembre 2022',
style: TextStyle(fontSize: 10, color: Colors.white),
),
SizedBox(height: screenHeight * 0.01),
Text(
'Follow the instructions\nto do your own test.',
style: const TextStyle(
color: Colors.white,
fontSize: 16.0,
),
maxLines: 2,
),
],
)
],
),
)
],
),
);
}
Instead of using ListView.Builderinside CustomScrollView. It is always better to use Slivers. Therefore, instead of wrapping ListView.builder with SliverToBoxAdapter, use SliverList. Here is the detail code I have refactored below for you. Or you can directly visit this link where you can play with the refactored code.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.light(),
home: const DashboardScreen(),
debugShowCheckedModeBanner: false,
);
}
}
class DashboardScreen extends StatefulWidget {
const DashboardScreen({super.key});
#override
State<DashboardScreen> createState() => _DashboardScreenState();
}
class _DashboardScreenState extends State<DashboardScreen> {
#override
Widget build(BuildContext context) {
final screenHeight = MediaQuery.of(context).size.height;
return Scaffold(
appBar: AppBar(),
body: CustomScrollView(
physics: ClampingScrollPhysics(),
slivers: <Widget>[
// your build header widget
SliverToBoxAdapter(
child: Container(
width: 100,
height: 65,
child: Padding(
padding: const EdgeInsets.only(top: 20),
child: ElevatedButton(
onPressed: () {},
child: Text(
'Add',
style: TextStyle(fontSize: 18),
),
style: ElevatedButton.styleFrom(
shape: StadiumBorder(),
backgroundColor: Colors.red,
),
),
),
),
),
SliverToBoxAdapter(
child: SizedBox(height: 10),
),
SliverList(
delegate: SliverChildBuilderDelegate((context, index) {
return Container(
margin: const EdgeInsets.symmetric(
vertical: 10.0,
horizontal: 20.0,
),
padding: const EdgeInsets.all(10.0),
height: screenHeight * 0.15,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Color(0xFFAD9FE4), Colors.red],
),
borderRadius: BorderRadius.circular(20.0),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
// Image.asset(
// "assets/worker.png",
// height: 80,
// width: 80,
// ),
//
Container(
height: 80,
width: 80,
child: Text("A"),
),
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'Somme: 50 €',
style: const TextStyle(
color: Colors.white,
fontSize: 18.0,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: screenHeight * 0.01),
Text(
'Date: 19 novembre 2022',
style: TextStyle(fontSize: 10, color: Colors.white),
),
SizedBox(height: screenHeight * 0.01),
Text(
'Follow the instructions\nto do your own test.',
style: const TextStyle(
color: Colors.white,
fontSize: 16.0,
),
maxLines: 2,
),
],
)
],
),
);
}),
)
],
),
);
}
}
Why do I get a line the color of the image on the bottom of the stack between Containers x and y? And what can I do to avoid that line?print of the screen
I want to have a Container with the standard background color and another one that has the fade effect and both these Containers are supposed to be on top of the background Image
#override
Widget build(BuildContext context) {
FluxoPermissaoNotificacoes fluxo = ModalRoute.of(context)!.settings.arguments as FluxoPermissaoNotificacoes;
DataPermissaoNotificacoes data = getDataPermissaoNotificacoes(fluxo);
return Scaffold(body: Container(
height: MediaQuery.of(context).size.height,
child: Stack(children: [
Stack(
children: [
Padding(padding: EdgeInsets.only(top: 38, left: 0),
child: Container(child: Image.asset("assets/images/permissao_notificacoes.png")),
),
Positioned(top: MediaQuery.of(context).size.height * 0.3, child: SizedBox(
width: MediaQuery.of(context).size.width,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 46.0),
child: Container(decoration: BoxDecoration(borderRadius: BorderRadius.all(Radius.circular(13)),
color: Color(0xffEBEBEB)), child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
Row(children: [
ClipRRect(borderRadius: BorderRadius.all(Radius.circular(5)), child: Image.asset(F.logoSquare ?? 'assets/applogo/android_logo_acad.png', width: 17,)),
Padding(
padding: const EdgeInsets.only(left: 5.0),
child: Text(F.nomeApp, style: TextStyle(fontFamily: 'SFCompact', color: Colors.black, fontSize: 12, fontWeight: FontWeight.w500)),
),
],),
SizedBox(height: 8,),
Text('A sua próxima aula irá começar em meia hora', style: TextStyle(fontFamily: 'SFCompact', color: Colors.black, fontSize: 12, fontWeight: FontWeight.w400))
],),
),),
),
)),
],
),
Column(mainAxisAlignment: MainAxisAlignment.end,
children: [
//container x
Container(height: MediaQuery.of(context).size.height * 0.29,
decoration: BoxDecoration(
gradient: LinearGradient(
end: Alignment.bottomCenter,
begin: Alignment.topCenter,
colors: GetIt.I.get<ControladorApp>().themeMode == ThemeMode.dark ? [
Colors.black.withOpacity(0.0),
Colors.black.withOpacity(0.2),
Colors.black.withOpacity(0.4),
Colors.black.withOpacity(0.6),
Colors.black.withOpacity(0.8),
Colors.black.withOpacity(1),
Colors.black.withOpacity(1),
] : [
Color(0xffFAFAFA).withOpacity(0.0),
Color(0xffFAFAFA).withOpacity(0.1),
Color(0xffFAFAFA).withOpacity(0.25),
Color(0xffFAFAFA).withOpacity(0.5),
Color(0xffFAFAFA).withOpacity(0.8),
Color(0xffFAFAFA),
Color(0xffFAFAFA),
],
),
),
),
//container y
Container(
color: Theme.of(context).backgroundColor,
child: Column(
children: [
SizedBox(height: 12,),
TextHeader(data.headText, textAlign: TextAlign.center,),
SizedBox(height: 16,),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 24.0),
child: TextBody1(data.bodyText, textAlign: TextAlign.center,),
),
SizedBox(height: 24,),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: BotaoPrimario(onTap: () {}, value: "Permitir Notificações",),
),
SizedBox(height: 8,),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: BotaoPrimario(onTap: () {
_controladorNotificacao.onTapAgoraNao();
}, value: "Agora não", bordered: true, textColor: Theme.of(context).primaryColor, corDefault: Theme.of(context).cardColor),
),
SizedBox(height: 32,),
],
),
),
],
)
],
),
));
}
I wrote a page, at the top everything is fine, as it should be. And at the bottom I have a history of events. The width of my container is determined automatically (depending on the width of the screen), and the height - no, on different devices different heights (indents at the bottom are different). Is it possible to determine the height automatically (to the end of the screen) ?? Also, I'd like to add a scroll bar at the bottom for this container so that when events appear there, I can scroll through them both bottom and top. I will be grateful for your help.
My page:
My code:
Widget build(BuildContext context) {
return Scaffold(
body: Container(
decoration: BoxDecoration(
color:Colors.white12
),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Column(
children: <Widget>[
SizedBox(height: 20.0),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
FlatButton(
textColor: Colors.blueGrey,
color: Colors.transparent,
child: Text('yes',textScaleFactor: 2.5),
onPressed: null,
padding: EdgeInsets.fromLTRB(30.0, 10.0, 30, 10.0),
),
FlatButton(
textColor: Colors.blueGrey,
color: Colors.transparent,
child: Text('no',textScaleFactor: 2.5),
onPressed: null,
padding: EdgeInsets.fromLTRB(30.0, 10.0, 30, 10.0),
)
],
),
SizedBox(height: 15.0),
Container(
child: Text(('20000' == null ? '' : '10000'), style: TextStyle(fontSize: 45.0,color: Colors.blueGrey)),
padding: EdgeInsets.fromLTRB(0, 0.0, 0, 20.0),
),
Container(
child: Text("weight", style: TextStyle(fontSize: 20.0,color: Colors.blueGrey)),
padding: EdgeInsets.only(top: 2, bottom:40, left:0, right:0),
),
Center(
child: Container(
alignment: Alignment.center,
width: double.infinity,
height: 430,
decoration: BoxDecoration(
border: Border.all(
width: 1.5
),
borderRadius: BorderRadius.circular(25)
),
child: new Column(
children: [
Container(
child: Text("history events", style: TextStyle(fontSize: 20.0,color: Colors.blueGrey)),
padding: EdgeInsets.all(2.0)
),
],
),
)//Container
)
]
)
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
setState(() {
_scanQR();
});
},
child: const Icon(Icons.qr_code),
backgroundColor: Colors.pink,
),
);
}
My scrin (after updating the code)
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(children: <Widget>[
SizedBox(height: 20.0),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
FlatButton(
textColor: Colors.blueGrey,
color: Colors.transparent,
child: Text('yes', textScaleFactor: 2.5),
onPressed: null,
padding: EdgeInsets.fromLTRB(30.0, 10.0, 30, 10.0),
),
FlatButton(
textColor: Colors.blueGrey,
color: Colors.transparent,
child: Text('no', textScaleFactor: 2.5),
onPressed: null,
padding: EdgeInsets.fromLTRB(30.0, 10.0, 30, 10.0),
)
],
),
SizedBox(height: 15.0),
Container(
child: Text(('20000' == null ? '' : '10000'), style: TextStyle(fontSize: 45.0, color: Colors.blueGrey)),
padding: EdgeInsets.fromLTRB(0, 0.0, 0, 20.0),
),
Container(
child: Text("weight", style: TextStyle(fontSize: 20.0, color: Colors.blueGrey)),
padding: EdgeInsets.only(top: 2, bottom: 40, left: 0, right: 0),
),
Expanded(
child: Padding(
padding: EdgeInsets.fromLTRB(7, 0, 7, 7),
child: Container(
alignment: Alignment.center,
decoration: BoxDecoration(border: Border.all(width: 1.5), borderRadius: BorderRadius.circular(25)),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
height: 45,
child: Text("history events", style: TextStyle(fontSize: 25.0, color: Colors.blueGrey)),
padding: EdgeInsets.all(2.0)),
Expanded(
child: Scrollbar(
child: new ListView(
shrinkWrap: true,
children: [
Container(
child: Text("Event 1", style: TextStyle(fontSize: 50.0, color: Colors.blueGrey)),
padding: EdgeInsets.all(2.0)),
SizedBox(
height: 200,
),
Container(
child: Text("Event 2", style: TextStyle(fontSize: 50.0, color: Colors.blueGrey)),
padding: EdgeInsets.all(2.0)),
SizedBox(
height: 200,
),
Container(
child: Text("Event 3", style: TextStyle(fontSize: 50.0, color: Colors.blueGrey)),
padding: EdgeInsets.all(2.0)),
SizedBox(
height: 50,
),
],
))),
],
))))
]),
floatingActionButton: FloatingActionButton(
onPressed: () {
setState(() {
// _scanQR();
});
},
child: const Icon(Icons.qr_code),
backgroundColor: Colors.pink,
),
);
}
You can alter the responsive height or width by using Media Query .To do that you need to wrap your Scaffold with Material App or Cupetino App which allows you to use MediaQuery .
void main() {
runApp(MaterialApp(home: MyApp()));
}
To make the list scrollable simply you can use ListView.builder
Center(
child: Container(
margin: new EdgeInsets.only(bottom: 20,right: 15,left: 15),
alignment: Alignment.center,
width: double.infinity,
height: MediaQuery.of(context).size.height/1.5,
decoration: BoxDecoration(
border: Border.all(width: 1.5),
borderRadius: BorderRadius.circular(25)),
child: new Column(
children: [
Container(
child: Text("history events",
style: TextStyle(
fontSize: 20.0, color: Colors.blueGrey)),
padding: EdgeInsets.all(2.0)),
],
),
) //Container
)
I added a little margin to make it looks better.Ofcourse you can also use MediaQuery for margin or padding if you want to.
https://i.stack.imgur.com/W6oXd.png
Im trying to do the layout below with flexible widgets so when the screen size changes the layout stays about the same but when I put a flexible widget around a column anything that I put in the column in not visible. What am I doing wrong?
Wanted Outcome
What I have
My code
class _HomeScreenState extends State<HomeScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black,
appBar: AppBar(
backgroundColor: Colors.black,
),
body: SafeArea(
child: Column(
children: [
Flexible(
flex: 9,
child: Column(
children: [
Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
color: Colors.grey,
),
),
),
Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: Container(),
),
Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: Container(),
),
Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: Container(),
),
],
),
),
Flexible(
flex: 1,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
color: Colors.white),
),
)
],
),
),
);
}
}
Finish your work, you will get the thing you have asked
Provide child on container
Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
color: Colors.grey,
),
child: SizedBox(
height: 50,
width: double.infinity,
),
),
),
I have been trying to replicate these two designs in Flutter using Stack, Positioned, Row, and similar related widgets, however, I've been getting stuck in the same stages again and again. I either can't center the text or cannot position the back button correctly. Also, I am trying not to use fixed sizes/positions as this is supposed to be somewhat adaptable to different screen sizes.
Could someone point me in the right direction, of how to create this or similar layouts, which would be reused in other screens?
Example 1:
Example 2:
For your example numero 1, I came with this solution:
class DetailScreen extends StatefulWidget {
#override
_DetailScreenState createState() => _DetailScreenState();
}
class _DetailScreenState extends State<DetailScreen> {
#override
Widget build(BuildContext context) {
return Material(
color: Colors.white,
child: SafeArea(
child: Stack(
fit: StackFit.expand,
children: [
Container(
margin: const EdgeInsets.all(5),
decoration: BoxDecoration(
color: Color(0xFF0B2746),
borderRadius: BorderRadius.circular(15),
),
child: Container(
margin: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.symmetric(vertical: 18),
child: Text(
'Glossary',
style: TextStyle(
fontWeight: FontWeight.w800,
fontSize: 20,
),
),
)
],
),
),
),
Padding(
padding: const EdgeInsets.only(top: 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Card(
margin: const EdgeInsets.only(left: 0),
child: Padding(
padding: const EdgeInsets.all(12),
child: Icon(Icons.arrow_back_ios),
),
elevation: 6,
),
],
),
)
],
),
),
);
}
}
and the result is the following:
For your second example, I had to add extra logic:
class DetailScreen extends StatefulWidget {
#override
_DetailScreenState createState() => _DetailScreenState();
}
class _DetailScreenState extends State<DetailScreen> {
#override
Widget build(BuildContext context) {
return Material(
color: Colors.white,
child: SafeArea(
child: Stack(
fit: StackFit.expand,
children: [
Container(
margin: const EdgeInsets.all(5),
decoration: BoxDecoration(
color: Color(0xFF0B2746),
borderRadius: BorderRadius.circular(15),
),
child: Column(
children: [
Container(
height: 64.0,
width: double.infinity,
margin: const EdgeInsets.only(left: 54, right: 8, top: 8),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10),
),
child: Row(
children: <Widget>[
SizedBox(width: 20),
Icon(Icons.train, size: 35),
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 18),
child: Text(
'Metro',
textAlign: TextAlign.center,
style: TextStyle(
fontWeight: FontWeight.w800,
fontSize: 20,
),
),
),
),
Icon(Icons.arrow_drop_down, size: 35),
SizedBox(width: 20),
],
),
),
Expanded(
child: Container(
margin: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10),
)),
)
],
),
),
Padding(
padding: const EdgeInsets.only(top: 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Card(
margin: const EdgeInsets.only(left: 0),
child: Padding(
padding: const EdgeInsets.all(12),
child: Icon(Icons.arrow_back_ios),
),
elevation: 6,
),
],
),
)
],
),
),
);
}
}
and the result for this one is the follwing: