Flutter Stack Widget has Whitespace for some unknown reason - flutter

I'm still having trouble with Flutter's approach to laying out widgets.
There's this 'whitespace' that I would remove or cover (see red arrows).
How would I extend the 'image' up to the menu bar?
As you can see in the code below, I'm using a Stack widget.
I don't know what is making the 'whitespace' between the Stack widget and the appbar?? Possibly, it's due to the Crop widget (a third-party package). I'll look into that now, but decided to post this question anyway.
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: I10n.t('Playhouse'),
centerTitle: true,
automaticallyImplyLeading: false,
elevation: 0,
excludeHeaderSemantics: true,
),
endDrawer: const ScrapBookDrawer(),
body: Stack(
children: <Widget>[
Crop(
interactive: false,
backgroundColor: Colors.white,
dimColor: Colors.white,
controller: CropController(),
child: Image.memory(
base64.decode(
con.submodule['image'],
),
),
),
SafeArea(
child: Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Flexible(
child: Text(
widget.subTask['subName'],
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
),
const Flexible(
child: Text(
'Submodule description',
),
),
]),
const Spacer(),
Expanded(
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30),
color: Colors.white),
child: Column(
children: <Widget>[
/// Task Name and Number
Padding(
padding: const EdgeInsets.only(
top: 30,
bottom: 20,
),
child: Text(
widget.subTask['name'],
style: const TextStyle(
fontSize: 26,
fontWeight: FontWeight.bold,
),
),
),
/// Short Description or Title
Padding(
padding: const EdgeInsets.only(
top: 10,
),
child: Text(widget.subTask['short_description']),
),
const SizedBox(height: 30),
Flexible(
child: SingleChildScrollView(
physics: const BouncingScrollPhysics(),
child: Text(widget.subTask['long_description']),
),
),
],
),
),
)
],
),
)
],
),
);
}

It seems it is actually due to Crop widget. It automatically determines the aspect ratio of your picture. You should manually set your aspect ratio by adding the aspectRatio parameter to your CropController, something like this:
Crop(
interactive: false,
backgroundColor: Colors.white,
dimColor: Colors.white,
controller: CropController(aspectRatio: 0.75),
child: Image.memory(
base64.decode(
con.submodule['image'],
),
),
)
In your case it seems that aspect ratio of ~0.75 works the best, play around with this to find your best value.

Related

How use flexible widget to divide my screen into 2

I would like to divide my screen into 2 using the Flexible Widget. The first flexible widget I would like to set is 80% as yellow and blue for the remaining 20%. Is there any way of dividing it using the flexible widget as I would like to have the remaining 20% of empty space in blue colour.
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("BitCoin cryptocurrency ")),
body: SingleChildScrollView(
child: Column(
children: [
Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Padding(
padding: EdgeInsets.all(8.0),
child: Text(
"BitCoin cryptocurrency",
style:
TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
controller: valueEditingController,
keyboardType: TextInputType.number,
decoration: InputDecoration(
hintText: 'Bitcoin Value',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10.0)))),
),
DropdownButton(
itemHeight: 60,
value: selectLoc,
onChanged: (newValue) {
setState(() {
selectLoc = newValue.toString();
});
},
items: locList.map((selectLoc) {
return DropdownMenuItem(
child: Text(
selectLoc,
),
value: selectLoc,
);
}).toList(),
),
ElevatedButton(
onPressed: _loadWeather, child: const Text("Load Value")),
const SizedBox(height: 10),
Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
FittedBox(
child: Text(
// description,
nu,
style: const TextStyle(
fontWeight: FontWeight.bold, fontSize: 25),
),
),
FittedBox(
child: Text(
nu2,
style: const TextStyle(
fontWeight: FontWeight.bold, fontSize: 25),
),
),
FittedBox(
child: Text(
nu3,
style: const TextStyle(
fontWeight: FontWeight.bold, fontSize: 25),
),
),//FittedBox
],
),//Column
),//Padding
],
)),//Cloumn //Centre
],
),//Column
)// SingleChildScrollView
);//Scaffold
}
Sorry for any inconvenience.
You can do it by using the Flexible widget with the flex attribute at flex 8 and flex 2
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Fexible widget'),
), //AppBar
body: CustomScrollView(
slivers: [
SliverFillRemaining(
hasScrollBody: false,
child: Column(
children: <Widget>[
Flexible(
flex: 8,
fit: FlexFit.loose,
child: Container(
color: Colors.yellow,
), //Container
), //Flexible
Flexible(
flex: 2,
fit: FlexFit.loose,
child: Container(
color: Colors.blue,
), //Container
) //Flexible
//Row
//Row
], //<Widget>[]
),
),
],
),
), //Scaffold
debugShowCheckedModeBanner: false,
),
); //MaterialApp
}

SingleChildScrollView in Column Widget

The SingleChildScrollView is surrounded by the Flexible widget
because there's an overflow error. However, placing the Flexible
then makes the text too small!?
Please, how can I do this in a better way?
#override
Widget build(BuildContext context) {
return Scaffold(
// primary: false,
appBar: AppBar(
title: I10n.t('Playhouse'),
centerTitle: true,
automaticallyImplyLeading: false,
elevation: 0,
excludeHeaderSemantics: true,
),
endDrawer: const ScrapBookDrawer(),
body: SafeArea(
child: Column(
children: [
/// Submodule Name | Short Description
Flexible(
flex: 3,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Padding(
padding: const EdgeInsets.only(top: 4),
child: Text(
widget.subTask['subName'],
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
),
const Flexible(
child: Padding(
padding: EdgeInsets.only(top: 4),
child: Text(
'Submodule description',
),
),
),
],
),
),
Flexible(
flex: 5,
fit: FlexFit.tight,
child: Stack(
alignment: AlignmentDirectional.topCenter,
children: <Widget>[
/// Large Picture
Crop(
interactive: false,
backgroundColor: Colors.white,
dimColor: Colors.white,
controller: CropController(),
child: Image.memory(
base64.decode(
con.submodule['image'],
),
),
),
Positioned(
left: 0,
right: 0,
top: 200,
/// Rounded Container
child: Material(
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(60),
topRight: Radius.circular(60),
),
child: Column(
children: <Widget>[
Container(
height: 225,
child: Column(
children: <Widget>[
/// Task Name and Number
Padding(
padding: const EdgeInsets.only(
top: 30, bottom: 20,),
child: Text(
widget.subTask['name'],
style: const TextStyle(
fontSize: 26,
fontWeight: FontWeight.bold,
),
),
),
/// Short Description or Title
Padding(
padding: const EdgeInsets.only(
top: 10, bottom: 30,),
child:
Text(widget.subTask['short_description']),
),
/// Long Description
Flexible(
child: SingleChildScrollView(
child:
Text(widget.subTask['long_description']),
),
),
],
),
),
],
),
),
),
],
),
),
],
),
),
);
}
In the next version below, I've gotten rid of the Positioned widget, but now (marked with red arrows) I don't see how to get rid of the whitespace?
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: I10n.t('Playhouse'),
centerTitle: true,
automaticallyImplyLeading: false,
elevation: 0,
excludeHeaderSemantics: true,
),
endDrawer: const ScrapBookDrawer(),
body: Stack(
children: <Widget>[
Crop(
interactive: false,
backgroundColor: Colors.white,
dimColor: Colors.white,
controller: CropController(),
child: Image.memory(
base64.decode(
con.submodule['image'],
),
),
),
SafeArea(
child: Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Flexible(
child: Text(
widget.subTask['subName'],
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
),
const Flexible(
child: Text(
'Submodule description',
),
),
]),
const Spacer(),
Expanded(
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30),
color: Colors.white),
child: Column(
children: <Widget>[
/// Task Name and Number
Padding(
padding: const EdgeInsets.only(
top: 30,
bottom: 20,
),
child: Text(
widget.subTask['name'],
style: const TextStyle(
fontSize: 26,
fontWeight: FontWeight.bold,
),
),
),
/// Short Description or Title
Padding(
padding: const EdgeInsets.only(
top: 10,
bottom: 30,
),
child: Text(widget.subTask['short_description']),
),
const SizedBox(height: 30),
Flexible(
child: SingleChildScrollView(
physics: const BouncingScrollPhysics(),
child: Text(widget.subTask['long_description']),
),
),
],
),
),
)
],
),
)
],
),
);
}
Knowing that the second one is the closest to what you need, to remove the whitespace you only need to remove the bottom paddings and the sizedBox, because you are the one controlling the whitespaces with those widgets and set a width size to your container with long and short description, like this:
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: I10n.t('Playhouse'),
centerTitle: true,
automaticallyImplyLeading: false,
elevation: 0,
excludeHeaderSemantics: true,
),
endDrawer: const ScrapBookDrawer(),
body: Stack(
children: <Widget>[
Crop(
interactive: false,
backgroundColor: Colors.white,
dimColor: Colors.white,
controller: CropController(),
child: Image.memory(
base64.decode(
con.submodule['image'],
),
),
),
SafeArea(
child: Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Flexible(
child: Text(
widget.subTask['subName'],
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
),
const Flexible(
child: Text(
'Submodule description',
),
),
]),
const Spacer(),
Expanded(
child: Container(
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30),
color: Colors.white),
child: Column(
children: <Widget>[
/// Task Name and Number
Padding(
padding: const EdgeInsets.only(
top: 30,
bottom: 20,
),
child: Text(
widget.subTask['name'],
style: const TextStyle(
fontSize: 26,
fontWeight: FontWeight.bold,
),
),
),
/// Short Description or Title
Padding(
padding: const EdgeInsets.only(
top: 10,
),
child: Text(widget.subTask['short_description']),
),
Flexible(
child: SingleChildScrollView(
physics: const BouncingScrollPhysics(),
child: Text(widget.subTask['long_description']),
),
),
],
),
),
)
],
),
)
],
),
);
}

How do they work? : The Stack Widget and The Position Widget

Please, would you look at the attached screenshot and tell me where that band of off-white is coming from?? (red arrow.)
I want the rounded container to display text right down to the bottom of the screen--any text-overflow will simply be scrolled by the SingleChildScrollView widget, but the container just gets thinner and thinner while that block of grey just stays there??
Been working in Flutter since March of 2018, and Flutter's layout widgets are still a mystery!
Here is the code:
#override
Widget build(BuildContext context) {
return Scaffold(
// primary: false,
appBar: AppBar(
title: I10n.t('Playhouse'),
centerTitle: true,
automaticallyImplyLeading: false,
elevation: 0,
excludeHeaderSemantics: true,
),
endDrawer: const ScrapBookDrawer(),
body: SafeArea(
child: Column(
children: [
/// Submodule Name | Short Description
Row(
children: [
Expanded(
child: Padding(
padding: const EdgeInsets.only(left: 10, top: 4),
child: Text(
'${widget.subTask['subName']} |',
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
),
),
const Expanded(
child: Padding(
padding: EdgeInsets.only(top: 4),
child: Text(
'Submodule description',
),
),
),
],
),
Stack(
alignment: AlignmentDirectional.topCenter,
children: <Widget>[
/// Large Picture
Container(
height: 500, // double.infinity,
child: Crop(
interactive: false,
backgroundColor: Colors.white,
dimColor: Colors.white,
controller: CropController(),
child: Image.memory(
base64.decode(
con.submodule['image'],
),
),
),
),
Positioned(
left: 0,
right: 0,
top: 300,
/// Rounded Container
child: Container(
height: 500,
decoration: const BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(60),
topRight: Radius.circular(60),
),
color: Colors.white,
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
/// Task Name and Number
Padding(
padding: const EdgeInsets.only(top: 30, bottom: 20),
child: Text(
widget.subTask['name'],
style: const TextStyle(
fontWeight: FontWeight.bold,
),
),
),
/// Short Description or Title
Padding(
padding: const EdgeInsets.only(bottom: 20),
child: Text(widget.subTask['short_description']),
),
/// Long Description
Flexible(
flex: 300,
child: SingleChildScrollView(
child: Text(widget.subTask['long_description']),
),
),
],
),
),
)
],
),
],
),
),
);
}
I got rid of the white area by increasing height of the first Container in the Stack. Seems like it is just a default background that's not covered with anything.

Divider in AppBar not appearing

I am struggling to figure out why my divider in my app bar is not appearing. When I increase the height of the divider, I notice my widgets move up. I looked at similar issues and none have worked. My appBar consists of two columns and one row for the user profile information and information on their "Partner". I wanted to use the divider to separate the partner name and username from the win/loss ratio.strong text
Widget build(BuildContext context) {
final user = Provider.of<User>(context);
return Scaffold(
appBar: AppBar(
backgroundColor: Color(0xFF2430346),
bottom: PreferredSize(
preferredSize: const Size.fromHeight(100.0),
child: Row(
children: <Widget>[
Expanded(
child: Padding(
padding: const EdgeInsets.only(left:20.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
_buildUserInfo(user),
Text(
"#username",
style: new TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
color: Colors.white,
)
)
],
),
),
),
Padding(
padding: const EdgeInsets.only(right:70.0),
child: Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
"My Partner",
style: new TextStyle(
fontSize: 24,
fontWeight: FontWeight.w600,
color: Colors.white,
),
),
Text(
"Dorian",
style: new TextStyle(
color: Colors.white,
),
),
Text(
"#Doetheman",
style: new TextStyle(
color: Colors.white,
),
),
// Mfer aint appearing
Padding(
padding: const EdgeInsets.only(left: 16, right: 16, top: 10, bottom: 10),
child: Divider(
height: 2.0,
color: Colors.white,
),
),
],
),
),
),
],
),
),
),
),
Widget _buildUserInfo(User user) {
return Column(
children: [
Avatar(
photoUrl: user.photoUrl,
radius: 40,
borderColor: Colors.black54,
borderWidth: 2.0,
),
const SizedBox(height: 8),
if (user.displayName != null)
Text(
user.displayName,
style: TextStyle(color: Colors.white),
),
const SizedBox(height: 8),
],
);
}
}
What I want it to look in view:
enter image description here
Instead of divider you can use container like this
Container(
alignment: Alignment.center,
width: 250,
height: 1,
color: Colors.black
),
Use IntrinsicWidth widget to wrap Column
IntrinsicWidth(
child: Column(
children: [
// ....
Divider(),
],
),
)

How to implement a SliverAppBar with a collapsable search bar

This is what I'm trying to do, it's a pretty common Widget on iOS. This is my code:
return Scaffold(
backgroundColor: Colors.white,
body: CustomScrollView(
slivers: <Widget>[
SliverAppBar(
automaticallyImplyLeading: false,
pinned: true,
titleSpacing: 0,
backgroundColor: Colors.white,
elevation: 1.0,
title: Container(
width: double.infinity,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceAround,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
CupertinoButton(
padding: EdgeInsets.all(0),
onPressed: () {},
child: AutoSizeText(
'Ordenar',
style: TextStyle(
color: Color(0xff16161F),
fontFamily: 'Brutal',
fontSize: 17.0,
),
),
),
AutoSizeText(
'Equipos 14',
style: TextStyle(
color: Color(0xff16161F),
fontFamily: 'Archia',
fontSize: 22.0,
),
),
CupertinoButton(
padding: EdgeInsets.all(0),
onPressed: () {},
child: AutoSizeText(
'Editar',
style: TextStyle(
color: Color(0xff16161F),
fontFamily: 'Brutal',
fontSize: 17.0,
),
),
),
],
),
),
centerTitle: true,
),
SliverFillRemaining(
child: Center(
child: CupertinoButton(
onPressed: () {
setState(() {
(isBottom) ? isBottom = false : isBottom = true;
});
},
child: Text('YESSS'),
),
),
),
],
),
bottomNavigationBar: (isBottom) ? _toolBar() : _tabBar(),
);
I've tried adding a CupertinoTextField() to the bottom property, but it gets into my Row() and messes up everything. Has anyone done this, or knows how to achieve it?
Thanks.
I managed to solve it. SliverAppBar has a property called flexibleSpace. In here you put a FlexibleSpaceBar, which contains a background property. Now, don't be fooled, this is not limited to a solid color or an image. It can take any Widget you want. In my case, I wanted to add a search bar. And because this property will fill the entire expandedHeight property, you want to add a small blank space so your custom widgets don't get drawn over your SliverAppBar. Here's the relevant piece of code:
flexibleSpace: FlexibleSpaceBar(
background: Column(
children: <Widget>[
SizedBox(height: 90.0),
Padding(
padding: const EdgeInsets.fromLTRB(16.0, 6.0, 16.0, 16.0),
child: Container(
height: 36.0,
width: double.infinity,
child: CupertinoTextField(
keyboardType: TextInputType.text,
placeholder: 'Filtrar por nombre o nombre corto',
placeholderStyle: TextStyle(
color: Color(0xffC4C6CC),
fontSize: 14.0,
fontFamily: 'Brutal',
),
prefix: Padding(
padding:
const EdgeInsets.fromLTRB(9.0, 6.0, 9.0, 6.0),
child: Icon(
Icons.search,
color: Color(0xffC4C6CC),
),
),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8.0),
color: Color(0xffF0F1F5),
),
),
),
),
],
),
),
),
And here is the result. The search bar will disappear when the scroll goes up. Hope this helps anyone wanting to do this.