How to draw line between 1 widget to 2nd widget Flutter - flutter

I'm trying to create a comment tree but I don't have any idea how to do that. The package I found on pub.dev is not like what I want. I mesh with codes. No tutorial found related to me.
This is what I want :
I want a tutorial or idea to create design like showing in the image.

You can draw line like this
SizeBox(
height : 2,
width : MediaQuery.of(context).size.width,
child : Container(color:Colors.black)
),

try this
IntrinsicHeight(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Container(width: 2.0, color:Colors.black),//(or use VerticalDivider())
SizedBox(width: 4.0),
YourCommentWidget(),
],
))

In your tree, you can use divider() for clear line, also you can use sizedbox.
firstwidget (
child : secondwidget (child : ..............)
)
simply you can wrap second widget with a padding.

Check this package. https://pub.dev/packages/flutter_fancy_tree_view
#Pradip said in comments.
If that you want, just add in pubspec.yaml file or you want to customize like in image just Copy the code from git repository and paste in your project as separate directory.
Edit as you want.

Finally, I achieve what I want. I think is not an Optimize way. I really like to know your comment on my code. It's litter meshy but the output looks nice.
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
class TestTree extends StatelessWidget {
const TestTree({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('title'),
),
body: ListView(
children: [
commentTreeRoot(
context: context,
image:
'https://www.whatsappprofiledpimages.com/wp-content/uploads/2018/07/beaJKHutiful-girl-profile-p-199x300.jpg',
name: 'User Name',
subtitle: '11111 Comment Text User name Comment Text User name ',
posteDate: Text('20:18'),
content:
Text("""The :expressions will be suitable for girls, guys,\n
married people too. Because in life complications start and\n
ends with girls at the same time happiness comes to girls and only girls. Thus, even a silly waste paper will look bright when it is in the hands of beautiful girls.
The pixels are picture perfect in our website."""),
comments: [
commentTreeChild(
context,
'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcT16eO5W8VPjVFrkvG8n_2FQKjByMcbLtBF4A&usqp=CAU,',
[
commentTreeChild(
context,
'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcT16eO5W8VPjVFrkvG8n_2FQKjByMcbLtBF4A&usqp=CAU',
[],
margin: 40,
last: true)
]),
commentTreeChild(
context,
'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcT16eO5W8VPjVFrkvG8n_2FQKjByMcbLtBF4A&usqp=CAU',
last: true,
[]),
],
)
],
));
}
Widget commentTreeRoot({
required BuildContext context,
required String image,
required String name,
required String subtitle,
required Widget posteDate,
required Widget content,
required List<Widget> comments,
}) {
return Column(
children: [
CustomPaint(
painter: CreateLine(root: true),
child: Column(
// root
children: [
ListTile(
horizontalTitleGap: 0,
leading: CircleAvatar(
backgroundImage: NetworkImage(image),
),
title: Padding(
padding: const EdgeInsets.only(top: 15, left: 8),
child: Text(name),
),
subtitle: Padding(
padding: const EdgeInsets.only(top: 0, left: 8),
child: Text(
subtitle,
overflow: TextOverflow.clip,
style: TextStyle(fontWeight: FontWeight.bold),
),
),
trailing: posteDate,
),
Container(
// Content
margin: EdgeInsets.only(left: 60),
padding: EdgeInsets.all(12),
decoration: BoxDecoration(
color: Color.fromARGB(255, 240, 240, 240),
borderRadius: BorderRadius.all(Radius.circular(10))),
child: content,
),
Column(
children: comments,
),
SizedBox(
height: 10,
),
commentRootTextfield(context),
],
),
)
],
);
}
Widget commentTreeChild(
BuildContext context, String image, List<Widget> commentReply,
{bool last = false, double margin = 60}) {
return Container(
margin: EdgeInsets.only(left: margin, top: 15),
child: CustomPaint(
painter: CreateLine(root: false, last: last),
child: Column(
// child 1
children: [
SizedBox(
width: MediaQuery.of(context).size.width,
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
CircleAvatar(
radius: 15,
backgroundImage: NetworkImage(image),
),
Expanded(
child: Container(
padding: EdgeInsets.all(12),
decoration: BoxDecoration(
color: Color.fromARGB(255, 240, 240, 240),
borderRadius: BorderRadius.all(Radius.circular(10))),
child: Column(
children: [
Row(
children: [
Expanded(
child: Padding(
padding:
const EdgeInsets.symmetric(vertical: 8),
child: Text(
'User Name',
overflow: TextOverflow.ellipsis,
),
),
),
Padding(
padding:
const EdgeInsets.symmetric(horizontal: 8),
child: Text('20:18'),
)
],
),
Text(
"""The expressions will be suitable for girls, guys,
"""),
],
),
),
),
],
),
),
last ? commnetChildTextField(context) : commnetChildReplyButton(),
Column(
children: commentReply,
)
],
), // child root
),
);
}
Widget commnetChildReplyButton() {
return Container(
margin: const EdgeInsets.only(
left: 30,
),
alignment: Alignment.centerLeft,
child: SizedBox(
height: 20,
child: TextButton(
style: ButtonStyle(
padding: MaterialStateProperty.all(EdgeInsets.zero),
),
onPressed: () {},
child: Text('Replay')),
));
}
Widget commnetChildTextField(BuildContext context) {
return FittedBox(
child: Padding(
padding: const EdgeInsets.only(left: 5, right: 8, top: 16),
child: Row(
children: [
CircleAvatar(
backgroundImage: NetworkImage(
'https://img.etimg.com/thumb/msid-69381991,width-650,imgsize-594328,,resizemode-4,quality-100/hacker-1.jpg'),
radius: 15,
),
SizedBox(
width: 10,
),
Container(
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
color: Color.fromARGB(255, 231, 231, 231),
border: Border.all(width: 0.5),
borderRadius: BorderRadius.all(Radius.circular(30))),
child: TextField(
minLines: 1,
maxLines: 3,
decoration: InputDecoration(
hintText: 'Type your message...',
contentPadding:
EdgeInsets.symmetric(horizontal: 16, vertical: 8),
isDense: true,
border: InputBorder.none,
),
style: TextStyle(color: Colors.white, fontSize: 20),
),
)
],
),
),
);
}
Widget commentRootTextfield(BuildContext context) {
return Container(
width: MediaQuery.of(context).size.width,
padding: const EdgeInsets.symmetric(vertical: 5),
decoration: BoxDecoration(
border: Border(
top: BorderSide(width: 3, color: Color.fromARGB(255, 231, 231, 231)),
bottom:
BorderSide(width: 2, color: Color.fromARGB(255, 231, 231, 231)),
),
),
child: FittedBox(
child: Row(
mainAxisSize: MainAxisSize.max,
children: [
IconButton(onPressed: () {}, icon: Icon(FontAwesomeIcons.smile)),
SizedBox(
width: MediaQuery.of(context).size.width,
child: Container(
decoration: BoxDecoration(
color: Color.fromARGB(255, 231, 231, 231),
borderRadius: BorderRadius.all(Radius.circular(30))),
child: TextField(
minLines: 1,
maxLines: 3,
decoration: InputDecoration(
hintText: 'Type your message...',
contentPadding:
EdgeInsets.symmetric(horizontal: 16, vertical: 8),
isDense: true,
border: InputBorder.none,
),
style: TextStyle(color: Colors.white, fontSize: 20),
),
),
),
SizedBox(
width: 30,
child: IconButton(
onPressed: () {},
icon: Icon(
Icons.attach_file,
size: 25,
))),
SizedBox(
width: 40,
child: IconButton(
onPressed: () {},
icon: Icon(
Icons.mic,
size: 30,
)),
),
],
),
),
);
}
}
class CreateLine extends CustomPainter {
CreateLine({required this.root, this.last = false});
final bool root;
final bool last;
#override
void paint(Canvas canvas, Size size) {
final p1 = size.topLeft(root ? Offset(35, 65) : Offset(15, 40));
final p2 = root
? Offset(35, size.height - 53)
: Offset(15, size.height - (last ? 40 : 0));
final paint = Paint()
..color = Colors.black
..strokeWidth = 1;
canvas.drawLine(p1, p2, paint);
// TODO: implement paint
}
#override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
// TODO: implement shouldRepaint
return false;
}
}
Output look like this now

Related

First message in list of messages is overlaped by container

I would like to add a section in my app that has a chat view like the most populars chat apps.
I have been searching examples of UI that could meet my need.
I am testing it at first with hard coded messages to check the layout and to test the functionality of the texfield to write the new messages.
Here you have the code and the initial layout screenshot:
class ChatOtroUsuarioMuro extends StatefulWidget {
const ChatOtroUsuarioMuro({Key key, this.usuario, this.otroUsuario})
: super(key: key);
final Usuario usuario;
final OtroUsuario otroUsuario;
#override
_ChatOtroUsuarioMuroState createState() => _ChatOtroUsuarioMuroState();
}
class _ChatOtroUsuarioMuroState extends State<ChatOtroUsuarioMuro> {
#override
void initState() {
// TODO: implement initState
super.initState();
}
#override
Widget build(BuildContext context) {
final mensajes_chat_provider = Provider.of<MensajesChatProvider>(context);
ScrollController _scrollController;
List<ChatMessage> messages = [
ChatMessage(messageContent: "Hello, Will (first message)", messageType: "receiver"),
ChatMessage(messageContent: "How have you been?(second message)", messageType: "receiver"),
ChatMessage(messageContent: "Hey Kriss, I am doing fine dude. wbu?", messageType: "sender"),
ChatMessage(messageContent: "ehhhh, doing OK.", messageType: "receiver"),
ChatMessage(messageContent: "Is there any thing wrong?", messageType: "sender"),
ChatMessage(messageContent: "Hello, Will", messageType: "receiver"),
ChatMessage(messageContent: "How have you been?", messageType: "receiver"),
ChatMessage(messageContent: "Hey Kriss, I am doing fine dude. wbu?", messageType: "sender"),
ChatMessage(messageContent: "ehhhh, doing OK.", messageType: "receiver"),
ChatMessage(messageContent: "Is there any thing wrong?", messageType: "sender"),
ChatMessage(messageContent: "Last message", messageType: "sender"),
];
void scrollToBottom() {
final bottomOffset = _scrollController.position.maxScrollExtent;
_scrollController.animateTo(
bottomOffset,
duration: Duration(milliseconds: 1000),
curve: Curves.easeInOut,
);
}
return Scaffold(
appBar: AppBar(
elevation: 0,
automaticallyImplyLeading: false,
backgroundColor: Colors.white,
flexibleSpace: SafeArea(
child: Container(
padding: EdgeInsets.only(right: 16),
child: Row(
children: <Widget>[
IconButton(
onPressed: (){
Navigator.pop(context);
},
icon: Icon(Icons.arrow_back,color: Colors.black,),
),
SizedBox(width: 2,),
// CircleAvatar(
// backgroundImage: NetworkImage("<https://randomuser.me/api/portraits/men/5.jpg>"),
// maxRadius: 20,
// ),
SizedBox(width: 12,),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text("Kriss Benwat",style: TextStyle( fontSize: 16 ,fontWeight: FontWeight.w600),),
SizedBox(height: 6,),
Text("Online",style: TextStyle(color: Colors.grey.shade600, fontSize: 13),),
],
),
),
Icon(Icons.settings,color: Colors.black54,),
],
),
),
),
),
body: Stack(
children: <Widget>[
ListView.builder(
itemCount: messages.length,
shrinkWrap: true,
controller: _scrollController,
reverse: true,
padding: EdgeInsets.only(top: 10,bottom: 10),
itemBuilder: (context, index){
return Container(
padding: EdgeInsets.only(left: 14,right: 14,top: 10,bottom: 10),
child: Align(
alignment: (messages[index].messageType == "receiver"?Alignment.topLeft:Alignment.topRight),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: (messages[index].messageType == "receiver"?Colors.grey.shade200:Colors.blue[200]),
),
padding: EdgeInsets.all(10),
child: Text(messages[index].messageContent, style: TextStyle(fontSize: 15),),
),
),
);
},
),
Align(
alignment: Alignment.bottomLeft,
child: Container(
padding: EdgeInsets.only(left: 10,bottom: 10,top: 10),
height: 60,
width: double.infinity,
color: Colors.white,
child: Row(
children: <Widget>[
GestureDetector(
onTap: (){
},
child: Container(
height: 30,
width: 30,
decoration: BoxDecoration(
color: Colors.lightBlue,
borderRadius: BorderRadius.circular(30),
),
child: Icon(Icons.add, color: Colors.white, size: 20, ),
),
),
SizedBox(width: 15,),
Expanded(
child: TextField(
decoration: InputDecoration(
hintText: "Write message...",
hintStyle: TextStyle(color: Colors.black54),
border: InputBorder.none
),
),
),
SizedBox(width: 15,),
FloatingActionButton(
onPressed: (){},
child: Icon(Icons.send,color: Colors.white,size: 18,),
backgroundColor: Colors.blue,
elevation: 0,
),
],
),
),
),
],
),
);
}
}
class ChatMessage{
String messageContent;
String messageType;
ChatMessage({#required this.messageContent, #required this.messageType});
}
As you may see in the screenshot, the first message shown in the list of messages, just above the container with the textfield is not the first message of the list messages, it is the second message. I guess that the first message is hidden behind the container with the textfield.
I have tried to solve the issue, but not solved yet.
What should I take into account to show all messages including the first message?
The reason is that you are using a Stack, which stacks the message input box above the content of the first message. You either need to not use a stack here (for example use a Column) or you need to wrap your ListView in a Container and add margin at the bottom (the same height as the message input box). Like this:
Container(
margin: EdgeInsets.only(bottom: 60),
child: ListView.builder(
itemCount: messages.length,
shrinkWrap: true,
reverse: true,
padding: EdgeInsets.only(top: 10, bottom: 10),
itemBuilder: (context, index) {
return Container(
padding:
EdgeInsets.only(left: 14, right: 14, top: 10, bottom: 10),
child: Align(
alignment: (messages[index].messageType == "receiver"
? Alignment.topLeft
: Alignment.topRight),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: (messages[index].messageType == "receiver"
? Colors.grey.shade200
: Colors.blue[200]),
),
padding: EdgeInsets.all(10),
child: Text(
messages[index].messageContent,
style: TextStyle(fontSize: 15),
),
),
),
);
},
),
),
Here is an example online: https://dartpad.dev/?id=e75b493dae1287757c5e1d77a0dc73f1
(Note that you need to reduce the height of your window if you want to reproduce your original issue).
Perhaps it has something to do with the indexing of your list. Have you tried to add +1 to the index? like so itemCount: messages.length + 1,

remove excess space at the bottom of my pageview.builder widget

I am trying to remove the excess space at the bottom of my widget but have not been able to do so. since I am using a page builder with a lot of text. I have tried adding the height manually but its not enough since i cant predict the size of the text.
import 'package:flutter/material.dart';
import 'package:flutter_lorem/flutter_lorem.dart';
import 'package:blink/core/widgets/widgets.dart';
import 'package:blink/feeds/feeds_details/widgets/widgets.dart';
import 'package:blink/gen/assets.gen.dart';
class FeedsDetailPage extends StatelessWidget {
const FeedsDetailPage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return const FeedsDetailView();
}
}
class FeedsDetailView extends StatelessWidget {
const FeedsDetailView({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
final String text1 = lorem(paragraphs: 2, words: 55);
final String text2 = lorem(paragraphs: 9, words: 500);
final String text3 = lorem(paragraphs: 10, words: 400);
final String text4 = lorem(paragraphs: 8, words: 2000);
final String text5 = lorem(paragraphs: 12, words: 500);
final textList = [
text3,
text4,
text5,
];
return Scaffold(
body: SingleChildScrollView(
child: Column(
children: [
Container(
child: Stack(
children: [
Positioned(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
height: 368,
width: double.infinity,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
//color: Colors.blue,
),
child: Assets.images.nightBuilding.image(
fit: BoxFit.cover,
),
),
),
),
Positioned(
top: 250,
left: 20,
child: Container(
height: 60,
width: 350,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: Theme.of(context)
.backgroundColor
.computeLuminance() >
0.5
? Colors.black
: Colors.white,
),
child: AppMediumText(text: text1),
),
),
Positioned(
top: 334,
right: 33,
child: ElevatedButtonSmall(
onpressed: () {},
text: '',
useIcon: true,
icon: Icons.account_balance,
fizedSize: const Size(50, 50),
radius: 35,
),
),
Positioned(
top: 334,
right: 105,
child: ElevatedButtonSmall(
onpressed: () {},
text: '',
useIcon: true,
icon: Icons.text_fields,
fizedSize: const Size(50, 50),
radius: 35,
),
),
],
),
),
const SizedBox(height: 8),
Divider(
color: Theme.of(context).colorScheme.secondary,
indent: 50,
endIndent: 50,
),
Container(
width: 380,
height: double.maxFinite,
child: PageView.builder(
itemCount: textList.length + 1,
itemBuilder: (context, index) {
if (index == 0) {
return Column(
children: [
const SizedBox(height: 14),
Padding(
padding: const EdgeInsets.only(left: 8, right: 8),
child: SizedBox(
width: 350,
height: double.maxFinite,
child: AppSmallText(
text: text2.replaceFirst(
text2[0],
text2[0].toUpperCase(),
),
),
),
),
],
);
} else {
return Column(
children: [
const SizedBox(height: 14),
Padding(
padding: const EdgeInsets.only(left: 8, right: 8),
child: SizedBox(
width: 350,
height: double.maxFinite,
child: AppSmallText(
text: textList[index - 1].replaceFirst(
textList[0],
textList[0].toUpperCase(),
),
),
),
),
],
);
}
},
),
)
],
),
),
);
}
}
Ignore this line it is just an excess line. I am trying to remove the excess space at the bottom of my widget but have not been able to do so. since I am using a page builder with a lot of text. I have tried adding the height manually but its not enough since i cant predict the size of the text.
You can try mainAxisSize: MainAxisSize.min in your columns and remove height: double.maxFinite:
class FeedsDetailPage extends StatelessWidget {
const FeedsDetailPage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return const FeedsDetailView();
}
}
class FeedsDetailView extends StatelessWidget {
const FeedsDetailView({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
final String text1 = lorem(paragraphs: 2, words: 55);
final String text2 = lorem(paragraphs: 9, words: 500);
final String text3 = lorem(paragraphs: 10, words: 400);
final String text4 = lorem(paragraphs: 8, words: 2000);
final String text5 = lorem(paragraphs: 12, words: 500);
final textList = [
text3,
text4,
text5,
];
return Scaffold(
body: SingleChildScrollView(
child: Column(
children: [
Container(
child: Stack(
children: [
Positioned(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
height: 368,
width: double.infinity,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
//color: Colors.blue,
),
child: Assets.images.nightBuilding.image(
fit: BoxFit.cover,
),
),
),
),
Positioned(
top: 250,
left: 20,
child: Container(
height: 60,
width: 350,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: Theme.of(context)
.backgroundColor
.computeLuminance() >
0.5
? Colors.black
: Colors.white,
),
child: AppMediumText(text: text1),
),
),
Positioned(
top: 334,
right: 33,
child: ElevatedButtonSmall(
onpressed: () {},
text: '',
useIcon: true,
icon: Icons.account_balance,
fizedSize: const Size(50, 50),
radius: 35,
),
),
Positioned(
top: 334,
right: 105,
child: ElevatedButtonSmall(
onpressed: () {},
text: '',
useIcon: true,
icon: Icons.text_fields,
fizedSize: const Size(50, 50),
radius: 35,
),
),
],
),
),
const SizedBox(height: 8),
Divider(
color: Theme.of(context).colorScheme.secondary,
indent: 50,
endIndent: 50,
),
Container(
width: 380,
child: PageView.builder(
itemCount: textList.length + 1,
itemBuilder: (context, index) {
if (index == 0) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
const SizedBox(height: 14),
Padding(
padding: const EdgeInsets.only(left: 8, right: 8),
child: SizedBox(
width: 350,
child: AppSmallText(
text: text2.replaceFirst(
text2[0],
text2[0].toUpperCase(),
),
),
),
),
],
);
} else {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
const SizedBox(height: 14),
Padding(
padding: const EdgeInsets.only(left: 8, right: 8),
child: SizedBox(
width: 350,
child: AppSmallText(
text: textList[index - 1].replaceFirst(
textList[0],
textList[0].toUpperCase(),
),
),
),
),
],
);
}
},
),
)
],
),
),
);
}
}

Flutter SliverList freezes while its loading images

I have a flutter app. One of my screens is loading lots of images from assets. Sometimes my app is freezing while the images are loading.
Here is my solution: I will put a loading animation, this animation needs to end up after the images are finished rendering but how do I understand all the images are finished rendering?
If you have any other solutions you can share with me :)
here is the Widget tree that loads images, in case if you need to know.
final posts = [
Post(
ownerName: "McQueen95",
avatarPath: "images/mcqueen.jpg",
imagePaths: ['images/mcqueen.jpg'],
),
Post(
ownerName: "BugsBunny",
imagePaths: ['images/Bugs_Bunny.png'],
),
Post(
ownerName: "Venom",
imagePaths: ['images/venom.jpg'],
),
Post(
ownerName: "Po",
imagePaths: ["images/kungfu_panda.jpg"],
avatarPath: "images/po.jpg",
),
Post(
ownerName: "Po",
imagePaths: ["images/kai.jpg", "images/oogway.jpg", "images/crane.png"],
avatarPath: "images/po.jpg",
),
];
#override
Widget build(BuildContext context) {
return CustomScrollView(
slivers: [
SliverAppBar(
title: Text("Cossy", style: TextStyle(color: Colors.purple)),
// elevation: 0,
pinned: true,
// expandedHeight: 150.0,
backgroundColor: backgroundColor,
systemOverlayStyle: SystemUiOverlayStyle(
systemNavigationBarColor: backgroundColor,
),
),
SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) => Padding(
child: posts[index],
padding: EdgeInsets.only(
bottom: (index == posts.length - 1) ? 82 : 12,
),
),
childCount: posts.length,
),
)
],
);
}
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter_image_slider/carousel.dart';
class Post extends StatelessWidget {
Post({
Key? key,
this.avatarPath,
required this.ownerName,
required this.imagePaths,
}) : super(key: key);
final String? avatarPath;
final String ownerName;
final List<String> imagePaths;
#override
Widget build(BuildContext context) {
if (imagePaths.length == 0) return Text("no image?");
return Container(
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color: Color(0xFFF2F2F2),
offset: Offset(0.0, 1.0), //(x,y)
blurRadius: 6.0,
),
],
// color: Color(0xFFF2F2F2),
color: Colors.deepOrange,
borderRadius: BorderRadius.all(Radius.circular(10)),
),
child: Column(
children: [
Padding(
padding: const EdgeInsets.all(4.0),
child: Row(
children: [
CircleAvatar(
child: avatarPath == null ? Icon(Icons.person) : null,
backgroundImage:
avatarPath == null ? null : AssetImage(avatarPath ?? ""),
),
SizedBox(width: 10),
Text(ownerName),
Expanded(
child: SizedBox(height: 30),
),
Icon(Icons.settings),
],
),
),
Carousel(
indicatorBarColor: Colors.transparent,
autoScrollDuration: Duration(seconds: 2),
animationPageDuration: Duration(milliseconds: 500),
activateIndicatorColor: Colors.grey.shade200,
animationPageCurve: Curves.bounceInOut,
indicatorBarHeight: 30,
indicatorHeight: 10,
indicatorWidth: 20,
unActivatedIndicatorColor: Colors.grey.shade700,
stopAtEnd: true,
autoScroll: false,
// widgets
items: imagePaths
.map(
(imagePath) => Container(
decoration: BoxDecoration(color: Colors.black),
child: ConstrainedBox(
constraints: new BoxConstraints(
minHeight: 100,
minWidth: 100,
// maxHeight: 500,
maxHeight: MediaQuery.of(context).size.height * 3 / 2,
maxWidth: MediaQuery.of(context).size.width,
),
child: FittedBox(
fit: BoxFit.scaleDown,
alignment: Alignment.center,
child: Image(
image: AssetImage("$imagePath"),
),
),
),
),
)
.toList(),
),
Padding(
padding: const EdgeInsets.only(
left: 16,
right: 16,
top: 4,
),
child: Row(
children: [
TextButton(
onPressed: () {
print(123);
},
child: Icon(
Icons.star_border_outlined,
size: 30,
// color: Colors.grey,
),
),
Expanded(
child: SizedBox(
height: 30,
),
),
Icon(
Icons.send_outlined,
size: 30,
// color: Colors.grey,
),
],
),
),
],
),
);
}
}
I solved the bug by giving certain height and width values to the Widget that contains images. Using ConstrainedBox and FittedBox means it will load images first and then measure all items' height and widths and then give height value to ListView. So, that's why the app freezes, measuring ListView's size takes a lot of time.
I changed this:
Container(
decoration: BoxDecoration(color: Colors.black),
child: ConstrainedBox(
constraints: new BoxConstraints(
minHeight: 100,
minWidth: 100,
maxHeight: MediaQuery.of(context).size.height * 3 / 2,
maxWidth: MediaQuery.of(context).size.width,
),
child: FittedBox(
fit: BoxFit.scaleDown,
alignment: Alignment.center,
child: Image(
image: AssetImage("$imagePath"),
),
),
),
),
To this:
AspectRatio(
aspectRatio: 1 / 1,
child: Container(
decoration: BoxDecoration(color: Colors.black),
width: MediaQuery.of(context).size.width,
alignment: Alignment.center,
child: ClipRRect(
// borderRadius: BorderRadius.circular(10),
child: Image(
image: AssetImage("${imagePaths[0]}"),
),
),
),
),

Bottom container inside stack moves upwards as keyboard opens on textfeild click - Flutter

I have a stack with list of content and custom dialogBox that I created. It contains textfeild. When I click the textfeild, keyboard opens and push dialog box way above the keyboard. There is alot of gap between the bottom of the dialog and the start of the keyboard. How can I keep the bottom of dialog stuck to the top the keyboard in a clean manner.
import 'package:flutter/material.dart';
class CombinedHomeView extends StatefulWidget {
// --- Services Headings
#override
_CombinedHomeViewState createState() => _CombinedHomeViewState();
}
class _CombinedHomeViewState extends State<CombinedHomeView> {
_showGrocOrderReviewDialog(Size _deviceSize) {
return Align(
alignment: Alignment.bottomCenter,
child: Container(
margin: EdgeInsets.all(10),
padding: EdgeInsets.all(10),
width: double.infinity,
height: _deviceSize.height * 0.28,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
"How was your last order?",
style: TextStyle(
fontFamily: fontMontserrat,
color: Colors.black87,
),
),
SizedBox(height: 10),
Expanded(
child: Container(
padding: EdgeInsets.all(5),
decoration: BoxDecoration(
color: Colors.grey.withOpacity(0.2),
borderRadius: BorderRadius.all(
Radius.circular(_deviceSize.height * 0.02),
),
),
child: SingleChildScrollView(
child: TextField(
maxLines: 5,
decoration: InputDecoration(
border: InputBorder.none,
hintText: 'Add additional remarks',
hintStyle: TextStyle(
fontSize: _deviceSize.height * 0.015,
fontFamily: fontMontserrat,
color: Colors.black38,
),
),
),
),
),
),
SizedBox(height: 10),
Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(
child: SmallBtn(
passedText: "Cancel",
passedBorderColor: Colors.green,
passedBGColor: Colors.white,
passedFontColor: Colors.brown,
),
),
SizedBox(width: 10),
Expanded(child: SmallBtn(passedText: "Submit")),
],
),
],
),
),
);
}
#override
Widget build(BuildContext context) {
Size _deviceSize = MediaQuery.of(context).size;
return Stack(
alignment: Alignment.center,
children: [
// ------------ List of content
ListView( // few simple widgets here),
// ------------ Dialog
_showGrocOrderReviewDialog(_deviceSize)
],
);
}
}
You can ignore the below code. It is just a code of SmallBtn incase anyone needs it.
import 'package:flutter/material.dart';
// ignore: must_be_immutable
class SmallBtn extends StatelessWidget {
final String passedText;
IconData passedIcon;
Color passedBGColor;
Color passedFontColor;
Color passedBorderColor;
bool isShadowEnabled;
SmallBtn({
#required this.passedText,
this.passedIcon,
this.passedBGColor,
this.passedFontColor,
this.passedBorderColor,
this.isShadowEnabled,
});
#override
Widget build(BuildContext context) {
isShadowEnabled == null
? isShadowEnabled = false
: isShadowEnabled = isShadowEnabled;
final deviceSize = MediaQuery.of(context).size;
return Container(
// alignment: Alignment.bottomLeft,
// width: deviceSize.width * 0.5 + passedText.length * 3,
padding: EdgeInsets.only(left: 10, right: 10, top: 5, bottom: 5),
height: deviceSize.height * 0.04,
decoration: BoxDecoration(
color: passedBGColor == null ? Colors.brown : passedBGColor,
borderRadius: BorderRadius.all(
Radius.circular(
deviceSize.height * 0.02,
),
),
border: Border.all(
color: passedBorderColor == null
? Colors.transparent
: passedBorderColor,
),
boxShadow: [
isShadowEnabled
? BoxShadow(
color: Colors.brown,
blurRadius: 10.0, // has the effect of softening the shadow
spreadRadius: 1.0, // has the effect of extending the shadow
offset: Offset(
0.0, // horizontal
1.0, // vertical
),
)
: BoxShadow()
],
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
passedIcon != null
? Icon(
passedIcon,
color: Colors.white,
size: deviceSize.height * 0.02,
)
: Container(),
passedIcon != null
? SizedBox(width: deviceSize.width * 0.01)
: SizedBox(),
Text(
passedText,
style: TextStyle(
fontSize: deviceSize.height * 0.018,
fontFamily: "Montserrat",
color: passedFontColor != null ? passedFontColor : Colors.white,
),
),
],
),
);
}
}
Why are you using a stack? If you replace the stack with a column your dialog will not be pushed to the top of the screen.

How to make this screen responsive in Flutter?

I'm kinda confused with how responsive layouts are made with flutter can you guys point me to the right direction or where in my codes will be wrapped in Expanded widget?
I tried wrapping the containers with Extended but It keeps showing an error and I'm getting confused now. I'm still a beginner, to be honest. Thank you very much!
Also, when I searched I found out that I should avoid using hardcoded sizes most of the time. So I want to learn when to apply Extended widget in order to make my screen responsive.
my code is below:
import 'package:flutter/material.dart';
class RegisterPage extends StatefulWidget {
RegisterPage({Key key}) : super(key: key);
#override
_RegisterPageState createState() => _RegisterPageState();
}
class _RegisterPageState extends State<RegisterPage> {
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
backgroundColor: Color(0xff0D192A),
body: Container(
child: ListView(
children: <Widget>[
Column(
children: <Widget>[
Padding(
padding: EdgeInsets.all(10.0),
child: Container(
height: 200,
width: 200,
child: Image(
image: AssetImage("assets/images/vlogo.png"),
),
),
),
Padding(
padding: EdgeInsets.all(40.0),
child: Center(
child: Text("Register an Account",
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 20)),
)),
Padding(
padding: EdgeInsets.fromLTRB(20, 0, 0, 0),
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Text("Email Address",
style: TextStyle(
fontSize: 10.0, color: Colors.grey[400])),
],
),
],
),
),
SizedBox(height:10.0),
Container(
margin: EdgeInsets.fromLTRB(20, 0, 20, 0),
padding: EdgeInsets.all(5.0),
decoration: BoxDecoration(
color: Colors.black,
borderRadius: BorderRadius.circular(10),
),
child: Center(
child: Padding(
padding: EdgeInsets.fromLTRB(20, 0, 0, 0),
child: TextField(
decoration: InputDecoration(
border: InputBorder.none,
hintText: "Enter your email address",
hintStyle: TextStyle(color: Colors.grey[400]),
),
),
),
)
),
SizedBox(height:20.0),
Padding(
padding: EdgeInsets.fromLTRB(20, 0, 0, 0),
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Text("Choose Password",
style: TextStyle(
fontSize: 10.0, color: Colors.grey[400])),
],
),
],
),
),
SizedBox(height:10.0),
Container(
margin: EdgeInsets.fromLTRB(20, 0, 20, 0),
padding: EdgeInsets.all(5.0),
decoration: BoxDecoration(
color: Colors.black,
borderRadius: BorderRadius.circular(10),
),
child: Center(
child: Padding(
padding: EdgeInsets.fromLTRB(20, 0, 0, 0),
child: TextField(
decoration: InputDecoration(
border: InputBorder.none,
hintText: "Enter your email address",
hintStyle: TextStyle(color: Colors.grey[400]),
),
),
),
)
),
SizedBox(height: 50),
Padding(
padding: EdgeInsets.fromLTRB(20, 0, 20, 0),
child: InkWell(
onTap: () {
setState(() {
});
},
child: Container(
height: 50,
decoration: BoxDecoration(
color: Color.fromRGBO(211, 184, 117, 100)
),
child: Center(
child: Text("Login", style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: 20),
),
),
),
),
),
],
),
],
),
),
),
);
}
}
Explore this plugin: This is one of the most effective plugins I have ever used for making responsive design.
https://pub.dev/packages/responsive_screen
Or
Use MediQuery() for getting the screen height and width i.e:-
Example:
#override
Widget build(BuildContext context) {
dynamic screenHeight = MediaQuery.of(context).size.height;
dynamic screenwidth = MediaQuery.of(context).size.width;
//use screenHeight and screenWidth variable for defining the height and
//width of the Widgets.
return Container(
height:screenHeight * .2, //It will take the 20% height of the screen
width: screenwidth * .5, //It will take the 50% width of the screen
//height: screenHeight, //It will take 100% height
child: Image(
image: AssetImage("assets/images/vlogo.png"),
);
}
You can make each screen responsive in flutter by just using MediaQuery or LayoutBuilder Concepts.
For your application, replace all your custom sizes like
width : MediaQuery.of(context).size.width * 0.1
height : MediaQuery.of(context).size.height * 0.3
MediaQuery gives you the sizes and orientation of the screen.
Even your padding, margin and other dimensions also should be calculated using MediaQuery to make it responsive.
Here, MediaQuery.of(context).size.width will give you the width of the current device screen and MediaQuery.of(context).size.height will give you the height of the current device screen.
Also, you can use LayoutBuilder Widget like,
LayoutBuilder(
builder: (context, constraints) {
if(constraints.maxWidth > 500) {
getLandscapeLayout();
} else {
getPortraitLayout();
}
},
)
LayoutBuilder is a widget which provides the dimensions of its parent so we can know how much space we have for the widget and can build it our child accordingly.
So these are two most powerful concepts are available in flutter to make your apps fully responsive.