I have these "cards" with a defined height, but the text can be of different lengths. Basically, there is a title and a body, I want the title to be fully displayed (there is a limit of 50 chars) but here is the issue, the body text isn't taking the whole space and I can't manage to get it to work properly.
Here is how it looks
As you can see on the first card the title text is short so there is space for the body text to expand. On the second card, the title text is longer so if I increase the parent's height of the body text, it would overflow and push the button.
Here is the code
Column(
children: [
Align(
alignment: Alignment.topLeft,
child: Padding(
padding: const EdgeInsets.only(
left: 12, top: 8.0, right: 12),
child: Text(document['titre'],
style: TextStyle(
color: Colors.white,
fontSize: 24)),
),
),
Container(
height: 33,
child: Padding(
padding: const EdgeInsets.only(
left: 15.0, right: 15.0),
child: Column(
children: [
Flexible(
child: Text(document['texte'],
overflow:
TextOverflow.ellipsis,
maxLines: 5,
style: TextStyle(
color: Colors.white)),
),
],
),
),
),
Spacer(),
Padding(
padding: const EdgeInsets.only(
left: 20.0, bottom: 10),
child: Align(
alignment: Alignment.bottomLeft,
child: SizedBox(
height: 30,
width: 120,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
primary: Color.fromRGBO(
255, 64, 0, 1.0),
onPrimary: Colors.white,
shape:
const RoundedRectangleBorder(
borderRadius:
BorderRadius.all(
Radius.circular(10.0))),
),
onPressed: () {
var docid = document.id;
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
Article(id: docid)));
},
child: Text("Lire la suite",
style: TextStyle(
color: Colors.white)),
),
),
),
)
],
)
If I remove the "maxLine" the text is only one line and if I change the container height it works but it pushes the button "Lire la suite" when the text is too long... I'm a bit stuck here
It is not good practice to use fixed sizes in your code so instead try to use MediaQuery of the context which is a very useful feature to avoid pixel overflows and make your UIs look good in different Screen Sizes.
height: MediaQuery.of(context).size.height * 0.9,
width: MediaQuery.of(context).size.width * 0.9,
You can set the a dynamic height and width by multiplying like so
for ex. .9 means 90% of your screen
Related
I have a chat messenger screen which looks like the given screenshot .
As you can see , bottom message is hidden behind the text input area .
The messages are listview , built using streambuilder .
I want the messages above the text input area .
https://i.stack.imgur.com/A82X2.png
return Scaffold(
appBar: AppBarMain(context),
body: Container(
child: Stack(
children: [
chatMessageList(),
Positioned(
bottom: 0,
child: Container(
color: Color(0x54ffffff),
child: Container(
padding: EdgeInsets.symmetric(horizontal: 14, vertical: 20),
width: MediaQuery.of(context).size.width,
child: Row(
children: [
Expanded(
child: TextField(
controller: messageController,
style: TextStyle(color: Colors.white),
decoration: InputDecoration(
hintText: ' Message!...',
hintStyle: TextStyle(color: Colors.white54),
border: InputBorder.none),
),
),
InkWell(
onTap: () {
sendMessage();
},
child: Container(
padding: EdgeInsets.all(9),
height: 40,
width: 40,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
Color(0x36FFFFFF),
Color(0xFFFFFFFF)
],
),
borderRadius: BorderRadius.circular(40)),
child: Image.asset('assets/images/send.png')),
)
],
),
),
),
)
],
),
),
);
}
}
Your structure should be something like
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(
child: chatMessageList(),
),
MessageFieldWidget(),
],
)
This will ensure that your chatMessageList will take up all of the space available in the screen and your Message Field will take up only the space that it needs. You don't need to use Positioned or Padding.
I want a Tinder-like Bio editor, When the user taps on the info, the text field should appear and retrieve the data from the firebase, and display the old bio, if the user taps on the done button on the keyboard or press anywhere on the screen, the data should be submitted. Thanking you in advance
Update: Here is the code I tried, Is there any way I can remove the upper stack and show the text field when the about container is tapped and after the submission the stack to come back and display the about field, and also I want to retrieve the old text from firebase in the text field(when the user is updating).
Widget about(BuildContext context, dynamic snapshot) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Container(
height: MediaQuery
.of(context)
.size
.height * 0.2,
width: MediaQuery
.of(context)
.size
.width,
decoration: BoxDecoration(
color: constantColors.white,
borderRadius: BorderRadius.circular(15),
),
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
Row(
children: [
Padding(
padding: const EdgeInsets.only(
top: 8.0,
left: 10,
),
child: Text(
"About",
style: TextStyle(fontSize: 24),
),
),
Padding(
padding: const EdgeInsets.only(top: 13, left: 6),
child: Icon(
FontAwesome.pencil,
size: 13,
),
)
],
),
Stack(
children: [
Container(
height: MediaQuery
.of(context)
.size
.height * 0.1,
width: MediaQuery
.of(context)
.size
.width,
child: TextField(
onTap: (){
Provider.of<PostFunctions>(context, listen: false).about(context, Provider.of<Authentication>(context, listen: false).getUserUid, {
'about': aboutController.text,
});
},
controller: aboutController,
maxLines: 8,
cursorColor: constantColors.green,
decoration: InputDecoration(
contentPadding: EdgeInsets.all(15),
hintText: 'A little about you',
isDense: true,
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(20),
borderSide: BorderSide.none),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(20),
borderSide: BorderSide.none),
fillColor: constantColors.white,
filled: true,),
),
),
Container(
height: MediaQuery
.of(context)
.size
.height * 0.1,
width: MediaQuery
.of(context)
.size
.width,
color: constantColors.white,
child: Text(snapshot.data.data()['about']),),
],
),
]),
),
);
}
here is the future method of uploading and updating
Future about(BuildContext context, String userID, dynamic data)async{
return FirebaseFirestore.instance.collection('users').doc(userID).update(data);
}
The better approach will be to retrieve the user data ahead of time. Then you can populate the text field using its conntroller with the data if the data exists.
I had a problem with my project, i'm trying make container with box shadow on bottom. below that container i want make to new container but they are some separate space between container, i think its because box shadow. so the question is how to make they connect ith no space but the shadow still visible.
pic
here my code :
return Scaffold(
body: SafeArea(
child: Container(
child: ListView(
physics: BouncingScrollPhysics(),
children: <Widget>[
Container(
child: Padding(
padding: const EdgeInsets.all(0.0),
child: ClipRRect(
borderRadius: BorderRadius.only(
topLeft: Radius.zero,
topRight: Radius.zero,
),
child: Container(
height: 70.0,
margin: const EdgeInsets.only(
bottom: 6.0), //Same as `blurRadius` i guess
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(5.5),
bottomRight: Radius.circular(5.5),
topLeft: Radius.zero,
topRight: Radius.zero,
),
color: kDarkGreenColor,
boxShadow: [
BoxShadow(
color: Colors.grey,
offset: Offset(0.0, 1.0), //(x,y)
blurRadius: 6.0,
),
],
),
child: ListView.builder(
padding: EdgeInsets.only(left: 10, right: 5),
itemCount: planticos.length,
physics: BouncingScrollPhysics(),
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
return Container(
margin: EdgeInsets.only(right: 15, bottom: 6),
height: 40,
width: 70,
decoration: BoxDecoration(
color: kMainColor.withOpacity(0),
image: DecorationImage(
image: AssetImage(planticos[index].image),
),
),
);
}),
),
),
),
),
Container(
margin: EdgeInsets.only(top: 0),
height: 200,
color: kMainColor,
),
],
),
),
),
);
}
use stack.
2nd Container will be visible over 1st Container.
for example...
Stack(
children: <Widget>[
Container(
height: 400,
decoration: BoxDecoration(
color: Colors.green,
),
),
Container(
height: 200,
decoration: BoxDecoration(
color: Colors.green,
boxShadow: [
BoxShadow(
color: Colors.red,
offset: Offset(0.0, 1.0), //(x,y)
blurRadius: 6.0,
),
],
),
),
],
),
You should use the stack widget, see this example:
Stack(
children:[
Container() //which you wanna be under the shadow.
Container() //which you wanna make it's shadow visible.
]
)
Tip: Use Positioned() under the stack to specify the position of containers.
I just started learning Dart and Flutter development and have been playing with BoxShadow.
As you can see in the image below, the shadow for the Bar, Boo and Faz cards are cutoff while that for the text box shows up.
How do I ensure the shadows for the cards show up correctly?
Here's my code:
import 'package:flutter/material.dart';
import 'package:reminder_app/constants.dart';
class Body extends StatelessWidget {
Widget _buildBanner(size) {
return Container(
height: size.height * 0.7,
decoration: BoxDecoration(
color: kPrimaryColor,
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(36),
bottomRight: Radius.circular(36),
),
),
);
}
Widget _buildCard(text) {
return Container(
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(
color: Colors.teal[200],
borderRadius: BorderRadius.circular(15),
boxShadow: [
BoxShadow(
offset: Offset(10, 10),
blurRadius: 25,
color: Colors.black.withOpacity(
0.75,
),
),
],
),
child: Text(text),
);
}
Widget _buildCardGrid() {
return Expanded(
child: GridView.count(
primary: false,
padding: EdgeInsets.symmetric(
vertical: kDefaultPadding * 1.5,
),
crossAxisSpacing: 20,
mainAxisSpacing: 20,
crossAxisCount: 2,
children: <Widget>[
_buildCard("Foo"),
_buildCard("Bar"),
_buildCard("Baz"),
_buildCard("Boo"),
_buildCard("Far"),
_buildCard("Faz"),
],
),
);
}
Widget _buildInputBox() {
return Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(15),
boxShadow: [
BoxShadow(
offset: Offset(10, 10),
blurRadius: 25,
color: Colors.black.withOpacity(
0.75,
),
),
],
),
height: 55,
child: TextField(
decoration: InputDecoration(
hintText: "Text Here",
hintStyle: TextStyle(
color: kPrimaryColor.withOpacity(
0.5,
),
),
enabledBorder: InputBorder.none,
focusedBorder: InputBorder.none,
),
),
);
}
Widget _buildInteractionContainers(size) {
return Positioned(
child: Container(
margin: EdgeInsets.symmetric(
horizontal: kDefaultPadding * 2,
),
width: size.width,
child: Column(
children: [
_buildInputBox(),
_buildCardGrid(),
],
),
),
);
}
Widget _buildBody(size) {
return SingleChildScrollView(
child: Column(
children: <Widget>[
Container(
height: size.height * 0.7,
child: Stack(
children: <Widget>[
_buildBanner(size),
_buildInteractionContainers(size),
],
),
),
],
),
);
}
#override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
return _buildBody(size);
}
}
Bar, Boo and Faz's shadows are cutoff while the shadow for the text box shows up
Edit [Answer]: I was able to fix this by adding clipBehavior: Clip.none to GridView to prevent shadow clipping.
Please try this code, To How to prevent box-shadow from being cut off?
If the box-shadow is muted, make sure that
overflow: visible
Is set to all div tags that contain your element.
I hope this information will be useful to you.
Thank you.
I want to make a Button that looks like the picture above with Flutter.
But I have no idea how to make it... help me, please!
Widget _startButton(BuildContext context) {
return Container(
margin: const EdgeInsets.only(top: 250.0),
child: Stack(
children: <Widget>[
Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
_buildSideButtons(context, Icons.settings, palette.limeYellow,
const EdgeInsets.only(right: 30.0)),
_buildSideButtons(context, Icons.lightbulb_outline,
palette.limeGreen, const EdgeInsets.only(left: 30.0)),
],
),
),
Center(
child: Container(
width: MediaQuery.of(context).size.width * 0.35,
height: MediaQuery.of(context).size.height,
child: DecoratedBox(
decoration: BoxDecoration(
shape: BoxShape.circle,
gradient: LinearGradient(
begin: Alignment.centerLeft,
end: Alignment.centerRight,
colors: [palette.limeYellow, palette.limeGreen])),
))),
Center(
child: Container(
width: MediaQuery.of(context).size.width * 0.275,
height: MediaQuery.of(context).size.height,
child: new RaisedButton(
elevation: 0.0,
color: Colors.white,
child: new Text(
"START",
style: TextStyle(
fontFamily: "Bebas Neue",
fontSize: 25.0,
fontWeight: FontWeight.bold),
),
onPressed: () => Navigator.push(
context,
MaterialPageRoute(
builder: (BuildContext context) => CountDown())),
shape: CircleBorder())))
],
),
);
}
Widget _buildSideButtons(
BuildContext context, IconData icon, Color coverColor, EdgeInsets pad,
{VoidCallback navigate}) {
return Container(
height: MediaQuery.of(context).size.height * 0.07,
child: RaisedButton(
elevation: 5.0,
onPressed: () {},
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(50.0))),
child: Container(
child: Padding(
padding: pad,
child: Icon(icon, color: Colors.black),
),
),
color: coverColor,
textColor: Colors.white,
),
);
}
I used Stack and Raised Buttons and finally made it! Thank you for the advice. I simply need to add boxShadow to make it close to the example picture I uploaded above.
To make a similar compound Button you should use a stack widget, you can see that both the side buttons are same so they are identical buttons in a row with a BorderRadius. they design of the middle button can be done by clipping button border by half of its width and then lay it out at the middle of the row.
You can make use of an IconButton with an asset image which contain a transparent background.
IconButton(
icon: Image.asset('assets/your/transperantBG/icon.png'),
onPressed: (){},
)