In this screen on top I have button and a text, in second I have a list view.
I want to reduce the gap between first and second layout.
This is the image in which I marked red. That red marked space I want to reduce
I am calling widget's body Column like below.
Widget body = new Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
toplayout,
listScreen,
startButtonlayout
],
);
First layout as below
Widget toplayout = new Container(
width: 70,
height: 70,
color: Colors.red,
child: new Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Builder(builder: (context) => IconButton(
icon: Icon(Icons.arrow_back),
iconSize: 30,
onPressed: () {
// Here i want context
if (Navigator.canPop(context)) {
Navigator.pop(context);
} else {
SystemNavigator.pop();
}
},
),),
new Container(
margin: const EdgeInsets.fromLTRB(20, 0, 0, 0),
child: new Text("Day 1",
style: new TextStyle(
fontSize: 30,
color: Colors.black,
)))
],
),
);
Widget listScreen = new Expanded(
child: new Container(
child: new ListViewExample(),
),
);
class ListViewExample extends StatefulWidget {
#override
State<StatefulWidget> createState() {
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
));
SystemChrome.setEnabledSystemUIOverlays(
[SystemUiOverlay.top, SystemUiOverlay.bottom]);
// TODO: implement createState
return ExerciseListPage();
}
}
This is the list
List<GestureDetector> _buildListItemsfromFlower() {
return flowers.map((flowers) {
var flatbutton = GestureDetector(
child: Card(
elevation: 10.0,
child: new Row(
textBaseline: TextBaseline.alphabetic,
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
new Container(
child: new Column(
children: <Widget>[
new Container(
width: MediaQuery.of(context).size.width * 0.5,
height: MediaQuery.of(context).size.height / 15,)))
As it is taking more gap between the widgets in column i want to reduce it. I have not mentioned any margins.
Related
I want to make this type of UI -
Like this dialog opens when we click on "Other Details" and appears just below it. Is there any package for this? Else I will try to use stack and positioned, and will position it as accurate as I can.
You could use an ExpansionTile.
It does exactly what you are looking for.
Code sample:
Center(
child: ExpansionTile(
iconColor: Colors.red,
title: const Text('More details'),
children: [
ListTile(
title: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: const [
Text('Name'),
Text('Ankit'),
],
)),
ListTile(
title: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: const [
Text('Grade'),
Text('9th'),
],
)),
ListTile(
title: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: const [
Text('Date of birth'),
Text('21-04-2008'),
],
)),
],
),
)
Keep in mind that in the children you could put any widget, even a container, as:
EDIT
After reading your clarifying comment this is what I made:
Obviously it's a basic floating box, but you can customize it.
I used a Stack to overlap widgets and a boolean to check if you need to show or not the infobox.
bool visibile = false;
Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
IconButton(
onPressed: () => setState(() {
visibile = !visibile;
}),
icon: const Icon(Icons.remove_red_eye)),
Stack(
alignment: Alignment.center,
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: const [
ElevatedButton(
onPressed: null,
child: Text("Check In"),
),
TextField()
],
),
),
visibile
? Container(
width: MediaQuery.of(context).size.width * .8,
height: MediaQuery.of(context).size.height * .5,
decoration: BoxDecoration(
color: Colors.white,
boxShadow: [
BoxShadow(
offset: Offset.fromDirection(1, 2),
spreadRadius: 1,
blurRadius: 3,
color: Colors.grey)
],
borderRadius: const BorderRadius.all(Radius.circular(20)),
border: Border.all(
color: Colors.orange,
width: 2,
style: BorderStyle.solid)),
child: Padding(
padding: const EdgeInsets.all(20.0),
child: SingleChildScrollView(
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: const [
Text(
'Academic year',
style: TextStyle(color: Colors.grey),
),
Text('2023'),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: const [
Text(
'Student name',
style: TextStyle(color: Colors.grey),
),
Text('Ankit'),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: const [
Text(
'Grade',
style: TextStyle(color: Colors.grey),
),
Text('9th'),
],
),
],
),
),
),
)
: Container(),
],
),
],
))
Having the button outside the Stack prevents the InfoBox to hide it and makes it so you can click it at any time.
I have no idea why, but someone with enough privileges keeps deleting my comments on this answer.
You could use the native Flutter Widget https://api.flutter.dev/flutter/material/ExpansionPanel-class.html or try a package like https://pub.dev/packages/expandable
If you Want the widget float on the other widgets, you can use OverlayEntry. There is a medium article/guide about this: Click to read.
Abstract:
first you need a global key, an overlay widget and the other variables below:
GlobalKey overlayKey = LabeledGlobalKey("button_icon");
late OverlayEntry overlayEntry;
late Size buttonSize;
late Offset buttonPosition;
bool isMenuOpen = false;
then add the global key to your button's key proprty:
key: context.read<MainViewModel>().overlayKey,
then, find the clicked button using this function:
findButton() {
RenderBox renderBox =
overlayKey.currentContext!.findRenderObject() as RenderBox;
buttonSize = renderBox.size;
buttonPosition = renderBox.localToGlobal(Offset.zero);
}
then, a builder:
OverlayEntry overlayEntryBuilder() {
return OverlayEntry(
builder: (context) {
return Positioned(
top: buttonPosition.dy + buttonSize.height * 4 / 5,
left: buttonPosition.dx - (buttonSize.width / 2) - 32,
// width: buttonSize.width,
child: YourWidgetThatWillOpenWhenYouClickTheButton(),
);
},
);
}
you can play around with the values in the Positioned widget to get the overlay where you want it.
now you can call these functions to open/close the overlay:
void openMenu(BuildContext context) {
findButton();
overlayEntry = overlayEntryBuilder();
Overlay.of(context)!.insert(overlayEntry);
isMenuOpen = !isMenuOpen;
}
void closeMenu() {
overlayEntry.remove();
isMenuOpen = !isMenuOpen;
}
like this:
IconButton(
key: context.read<MainViewModel>().overlayKey,
onPressed: () {
if (!context.read<MainViewModel>().isMenuOpen) {
context.read<MainViewModel>().openMenu(context);
} else {
context.read<MainViewModel>().closeMenu();
}
},
check the medium article for the detailed explanation.
When I press the arrow button on the left using the animation container, I want it to slide down, but the picture is loaded before and it gives an error. How do I synchronize the picture with the container?
here I gave the animated container in the picture. To grow in the picture at the same time as the growth rate of the container, but it did not happen. I tried using the Animation control but didn't understand exactly how to use it in the Animation container.
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import '../models/question_model.dart';
import 'package:date_format/date_format.dart';
class ActiveQuestion extends StatefulWidget {
final Question question;
ActiveQuestion({Key key, this.question}) : super(key: key);
#override
_ActiveQuestionState createState() => _ActiveQuestionState();
}
class _ActiveQuestionState extends State<ActiveQuestion> with SingleTickerProviderStateMixin{
bool tapped = false;
double _margin = 15;
double _height = 120;
Color _color = Colors.white;
#override
Widget build(BuildContext context) {
return AnimatedContainer(
duration: Duration(milliseconds: 100),
margin: EdgeInsets.all(_margin),
width: double.infinity,
height: _height,
decoration: BoxDecoration(
color: _color,
borderRadius: BorderRadius.circular(12),
border: Border.all(color: Colors.black,width: 3.0)
),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (!tapped)
Flexible(
flex: 1,
child: IconButton(
icon: Icon(Icons.arrow_downward),
onPressed: () {
setState(() {
_height +=250;
tapped = tapped ? false : true;
});
},
),
),
if (tapped)
Flexible(
flex: 1,
child: IconButton(
icon: Icon(Icons.arrow_upward),
onPressed: () {
setState(() {
_height -=250;
tapped = tapped ? false : true;
});
},
),
),
Flexible(
flex: 4,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Flexible(child: Text(widget.question.title,style: GoogleFonts.rokkitt(fontSize: 20),)),
],
),
SizedBox(height: 10,),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Icon(Icons.comment),
Text(widget.question.answerCount.toString(),style: GoogleFonts.rokkitt(fontSize: 18),),
],
),
Text("#" + widget.question.name,style: GoogleFonts.rokkitt(fontSize: 18),),
Text('${formatDate(DateTime.parse(widget.question.time),[dd,'.',mm,".",yy," ",HH,":",nn])} ',style: GoogleFonts.rokkitt(fontSize: 18),),
],
),
],
),
),
],
),
if(tapped)
Divider(thickness: 1,),
if (tapped)
AnimatedContainer(
width: double.infinity,
height: _height,
duration: Duration(milliseconds: 1000),
child: SizedBox(
child: Image(
fit: BoxFit.fitWidth,
image: NetworkImage(widget.question.questPath,),
),
),
)
],
),
);
}
}
You should be able to do this by simply wrapping your Image (or SizedBox) in a ClipRect. The linked page includes an example showing how to define the alignment of the child. In your case, I imagine you'll want to align it to the top.
AnimatedContainer(
...
child: Container(
child: Column(
children: [
Row(
children: [
Container(
width:60,
height:50,
color: Colors.black,
),
],
),
Expanded(
child: GestureDetector(
onTap: () {
print('what');
},
child: Container(
height: 50,
child: Column(
children: [
Expanded(
child: Text('asdf'),
),
Expanded(
child: IconButton(
icon: Icon(Icons.ac_unit),
onPressed: () {},
),
I have this AnimatedContainer widget here. My Text() widget and RaisedButton widget are hidden inside the box. They appear as the AnimatedContainer expand. However, my IconButton doesn't.
Also, Icon widget also stays like IconButton widget. How can I make it appear when the AnimatedContainer is stretched like the Text widget?
I've modified your code, hope this is what u want.
class _RowStructureState extends State<RowStructure> {
bool pressed = false;
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
setState(() {
pressed = !pressed;
});
print(pressed);
},
child: Column(children: <Widget>[
AnimatedContainer(
height: pressed ? 120 : 50,
color: Colors.green,
duration: Duration(seconds: 1),
child: Stack(
children: [
Container(
height: 50,
width: 50,
color: Colors.black,
),
Positioned(
bottom:0,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text('asd'),
IconButton(
padding: EdgeInsets.all(0),
icon: Icon(Icons.ac_unit,),
onPressed: pressed?(){}:null,
),
],
),
)
],
),
)
]),
);
}
}
I would like, in this code, to put the IconButton in the top right corner of each ItemView. The ItemDescription and the ItemTitle centered at the top. I try to put them in the same Row but I can't get them to fit together, either the IconButton sticks to the text or it's in the middle.
I think it is easy but I didn't find a solution.
Here is the code:
import 'package:flutter/material.dart';
import 'package:cached_network_image/cached_network_image.dart';
import '../recyclerview/data.dart';
import 'package:watch/constants.dart';
class ListViewExample extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return new ListViewExampleState(
);
}
}
class ListViewExampleState extends State<ListViewExample>{
List<Container> _buildListItemsFromItems(){
int index = 0;
return item.map((item){
var container = Container(
decoration: index % 2 == 0?
new BoxDecoration(color: const Color(0xFFFFFFFF)):
new BoxDecoration(
color: const Color(0xFFFAFAF5)
),
child: new Row(
children: <Widget>[
new Container(
margin: new EdgeInsets.all(5.0),
child: new CachedNetworkImage(
imageUrl: item.imageURL,
width: 200.0,
height: 100.0,
fit: BoxFit.cover,
),
),
Expanded(
child: Row(
children: <Widget>[
new Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
padding: const EdgeInsets.only(bottom: 75.0 ),
child: Text(
item.title,
style: kItemTitle,
),
),
Container(
padding: const EdgeInsets.only(left: 15.0),
child:Text(
item.description,
style: kItemDescription,
),
),
],
),
new Row(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
child: IconButton(
icon: Icon(Icons.favorite_border, color: Colors.black,),
iconSize: 24.0,
onPressed: null
),
)
],)
]),
),
]),
);
index = index + 1;
return container;
}).toList();
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title: Text('Accueil', style: kAppBarStyle,),
backgroundColor: Colors.white,
elevation: 0,
),
body: ListView(
children: _buildListItemsFromItems(),
),
);
}
}
Update : I have added a Spacer() and put all in the same row, and set CrossAxisAlignment to .center.
Put the Icon in the same row as the title and the description, with a Spacer() in between. That will then give you an overflow error, because the Spacer wants to take up as much space as physically possible, so with no restriction it goes on to infinity. To tell the Spacer that it is only allowed a finite amount of space, you have to set the mainAxisSize of the row to MainAxisSize.min
Here's the code, with a couple alterations so I was able to run it for myself.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: ListViewExample(),
);
}
}
class ListViewExample extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return new ListViewExampleState();
}
}
class ListViewExampleState extends State<ListViewExample> {
var items = [
Item(),
Item(),
Item(),
Item(),
];
List<Container> _buildListItemsFromItems() {
int index = 0;
return items.map(
(item) {
var container = Container(
decoration: index % 2 == 0
? new BoxDecoration(color: const Color(0xFFFFFFFF))
: new BoxDecoration(color: const Color(0xFFFAFAF5)),
child: new Row(
children: <Widget>[
new Container(
margin: new EdgeInsets.all(5.0),
child: new Container(
color: Colors.red,
width: 150.0,
height: 100.0,
),
),
Expanded(
child: new Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(
padding: const EdgeInsets.only(bottom: 75.0),
child: Text(
item.title,
),
),
Container(
padding: const EdgeInsets.only(left: 15.0),
child: Text(
item.description,
),
),
Spacer(),
GestureDetector(
child: Icon(
Icons.favorite_border,
size: 14,
color: Colors.black,
),
onTap: null,
),
],
),
),
],
),
);
index = index + 1;
return container;
},
).toList();
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title: Text('Accueil'),
backgroundColor: Colors.white,
elevation: 0,
),
body: ListView(
children: _buildListItemsFromItems(),
),
);
}
}
class Item {
final String title;
final String description;
Item({this.title = 'FooTitle', this.description = 'BarDescription'});
}
I want to position the Button a bit lower and the Widget with the Text and the Image a bit higher, and don't know how to do. MainAxisAlignment.spaceBetween is not a solution, because this would be to high for the Widget and too low for the Button.
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
if (isShown == true) SkillJonglieren(),
Flexible(
flex: 4,
child: Container(
padding: EdgeInsets.only(bottom: 60),
width: 230,
height: 130,
child: RaisedButton(
color: Colors.red,
child: Text('Show Skill',
style: TextStyle(fontSize: 30)),
onPressed: () {
setState(() {
isShown = true;
Next thing: the Text and the Image are one stateless Widget. I want a bit of free space between them, but when I implement the MainAxisAlignment.spaceAround for the Column (in which they are), It somehow doesn't work.
class SkillJonglieren extends StatelessWidget {
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Text(
'Jonglieren',
style: TextStyle(fontSize: 35),
),
Image.asset('images/jonglieren.jpg')
]);
}
}