How to break a Text (placed in a Stack widget) into multiple lines in Flutter? - flutter

I want to implement the following design in Flutter, specifically the rounded rectangle with the Text placed on it.
I have used the Stack widget to position the Text at the bottom left of the Container, but the problem is that the Text goes in one line beyond the Stack boundary, instead of breaking into the second line. For simplicity sake, I have written a simpler code as following:
#override
Widget build(BuildContext context) {
return Center(
child: Stack(
children: [
Container(
width: 150,
height: 150,
color: Colors.teal.shade300,
),
const Positioned(
left: 16,
bottom: 16,
child: Text(
"A very looooooooooooooooong teeeeeeeext",
maxLines: 2,
softWrap: true,
),
),
],
),
);
}
And the result is:
So how can I break the Text into the second line (not by using \n character), in this scenario. Or, if there is another solution other than using Stack, please tell me. Thanks.

You can use align inside the container instead of using stack
#override
Widget build(BuildContext context) {
return Center(
child: Container(
width: 150,
height: 150,
color: Colors.teal.shade300,
child: const Align(
alignment: Alignment.bottomLeft,
child: Text(
"A very looooooooooooooooong teeeeeeeext",
maxLines: 2,
softWrap: true,
),
),
),
);
}

You can use GridView to implement the following design. Like this:
GridView(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
mainAxisSpacing: 16.0,
crossAxisSpacing: 16.0,
),
children: [
Container(
width: 150,
height: 150,
color: Colors.teal.shade300,
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('title1'),
Text('21222222222222222222222222222')
],
),
),
Container(
width: 150,
height: 150,
color: Colors.teal.shade300,
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('title1'),
Text('21222222222222222222222222222')
],
),
),
Container(
width: 150,
height: 150,
color: Colors.teal.shade300,
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('title1'),
Text('21222222222222222222222222222')
],
),
),
Container(
width: 150,
height: 150,
color: Colors.teal.shade300,
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('title1'),
Text('21222222222222222222222222222')
],
),
),
],
)
Or you can use GridView.builder.

Use Expanded Widget
#override
Widget build(BuildContext context) {
return Center(
child: Stack(
children: [
Container(
width: 150,
height: 150,
color: Colors.teal.shade300,
),
const Positioned(
left: 16,
bottom: 16,
child: Expanded(
Text(
"A very looooooooooooooooong teeeeeeeext",
maxLines: 2,
softWrapenter code here: true,
),
),
),
],
),
);
}

Use layout like this for multiple line text on stack.
Stack(
children: [
CustomPaintCurves(),
Positioned(
top: 0.0,
left: 0.0,
right: 0.0,
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: Image.asset(
AppAssets.icon_button_background,
gaplessPlayback: true,
fit: BoxFit.cover,
height: 80,
width: 80),
),
const Padding(
padding: EdgeInsets.all(8.0),
child: Text(
StringManager.appName,
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
),
),
),
const Padding(
padding: EdgeInsets.all(8.0),
child: Text(StringManager.aboutUsDescription),
),
],
),
),
],
),

A sample code snippet
Stack(
children: [
//! other children in this stack
Positioned(
left: 20, //! giving it random position
bottom: 20,
width: MediaQuery.of(context).size.width * 0.80, //! so that the `Text` widget knows where it overflows
child: const Text(
"Some Very Long Text Here .......", //! the long text you want to clip
overflow: TextOverflow.ellipsis, //! type of overflow
softWrap: false,
maxLines: 3, //! max lines before clipping the text
),
),
],
);
Explanation:
Gave random positions to the text widget (bottom left) of its container. Also gave width to the 'Positioned' widget so that the 'Text' widget knows where the text actually overflows and where it needs to apply the overflow properties.
I used 'TextOverflow.ellipsis' so that the overflowed text would go into the next line, but I specified how many lines of text I want to see (i.e. 'maxLines: 3') before the rest of the text is replaced with '...'.

this problem occur because inside stack you not applied any width of Text widget (child widget), so it will not take any width,
so in your case wrap your text widget into SizeBox and applied width , it will work.
watch full code
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
final String title;
const MyHomePage({
Key? key,
required this.title,
}) : super(key: key);
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Stack(
children: [
Container(
width: 150,
height: 150,
color: Colors.teal.shade300,
),
const Positioned(
left: 16,
bottom: 16,
child: SizedBox(
width: 150,
child: Text(
"A very looooooooooooooooong teeeeeeeext",
maxLines: 2,
softWrap: true,
),
),
),
],
),
),
);
}
}
see the result

Related

I can't display 4 Card in middle of page with Flutter

import 'package:flutter/material.dart';
class CardNote extends StatelessWidget {
const CardNote({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.center,
children: const [
Card(
elevation: 3,
color: Colors.amber,
child: SizedBox(
width: 200,
height: 200,
child: Center(
child: Text(
'Card 1',
)),
),
),
Card(
elevation: 3,
color: Colors.amber,
child: SizedBox(
width: 200,
height: 200,
child: Center(
child: Text(
'Card 2',
)),
),
),
],
),
),
),
);
}
}
When I add this widget to the page where I want to show the cards, I can show 2 widgets in a single line. Then when I call the same widget again, I get the following error.
RenderCustomMultiChildLayoutBox object was given an infinite size during layout.This probably means that it is a render object that tries to be as big as possible, but it was put inside another render object that allows its children to pick their own size.
return Scaffold(
body: Container(
child: Row(
children: const [
CardNote(),
SizedBox(
height: 50,
),
CardNote()
],
),
),
);
This is how I add the cards to the page I want to show.
This is how I want to show 4 cards in the middle of the page
This is how it looks on my page. It shows at the top of the page, not in the middle.
You can wrap your CardNote widget with Expanded widget. And use a top level scrollable widget. Also you dont need to us multiple scaffold
home: Scaffold(
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: const [
CardNote(),
SizedBox(
height: 50,
),
CardNote(),
],
),
),
),
While the card is fixed width, you can provide it
class CardNote extends StatelessWidget {
const CardNote({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Center(
child: Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.center,
children: const [
Card(
elevation: 3,
color: Colors.amber,
child: SizedBox(
width: 200,
height: 200,
child: Center(
child: Text(
'Card 1',
)),
),
),
Card(
elevation: 3,
color: Colors.amber,
child: SizedBox(
width: 200,
height: 200,
child: Center(
child: Text(
'Card 2',
)),
),
),
],
),
),
);
}
}
You are trying to add a row which has alignment of spaceEven inside another row. When you added the first set of cards it got aligned evenly. On second set you have 2 set of rows inside a row each one has alignment of spaceEven..
Depending on the layout if you wish to show these cards one below the other set then use a Column widget
return Scaffold(
body: Container(
child: Column(//here
children: const [
CardNote(),
SizedBox(
height: 50,
),
CardNote()
],
),
),
);

how can we place image outside the parent container in flutter

I am trying to implement this kind of UI. But i can't find a way to place image outside the container.(Check the image )
Hey you can use Stack widget to overlap from card, use Positioned to align your widget at particular position.
For - Eg.
Stack(
children: [
Padding(
padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 20),
child: Card(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: MediaQuery.of(context).size.width*0.6,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children:const [
Text("Title Text "),
Text("Body text"),
],
),
),
const Spacer(),
],
),
),
),
),
Positioned(
left: MediaQuery.of(context).size.width*0.65,
top: -10,
bottom: 15,
child: Image.asset("assets/sample.png", fit:BoxFit.fill,), // replace your image with Image.assets here
),
Positioned(
right: 20,
top: 0,
bottom: 0,
child: IconButton(onPressed: (){}, icon: const Icon(Icons.add_circle),),
),
],
)
For more details about Stack
Output will come like this -
You can use Stack widget first put Image widget inside it and then Container widget
import 'package:flutter/material.dart';
const Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(
scaffoldBackgroundColor: darkBlue,
),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: MyWidget(),
),
),
);
}
}
class MyWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Stack(
alignment : Alignment.center,
children :[
Image.network('https://image.shutterstock.com/image-vector/sample-stamp-rubber-style-red-260nw-1811246308.jpg'),
Container( child :const Text('test',style : TextStyle(color: Colors.black ,fontSize: 20.00))),
],
);
}
}

How to display cards on a board (for a card game)?

I'm implementing a phone app for playing UNO using flutter (and dart), and I'm stuck with how I should display the cards on the board.
This is what I would like my code to look like
and this is what my code result looks like.
import 'package:flutter/material.dart';
import 'card.dart';
class Partida extends StatefulWidget {
const Partida({ Key? key }) : super(key: key);
#override
State<Partida> createState() => _PartidaState();
}
class _PartidaState extends State<Partida> {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color.fromARGB(255, 19, 107, 22),
body: Center(
child: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
MyCard(),
MyCard(),
],
),
// MyCard(),
// Row(
// mainAxisAlignment: MainAxisAlignment.center,
// children: [
// // MyCard(),
// MyCard(),
// ]
// ),
],
),
),
),
);
}
}
Thanks in advance.
You can use the Stack() widget to achieve this. Start by giving clipBehaviour:Clip.none which will help overflow the cards when u stack multiple of them.
Then use the Positioned() widget to make them shift to left using property called left: 50 (or whatever your preferred number). This will shift the cards to left.
class MyWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Stack(
clipBehavior: Clip.none,
alignment: AlignmentDirectional.bottomCenter,
children: const [
ColoredBox(
color: Colors.red,
child: SizedBox(
height: 100,
width: 80,
),
),
Positioned(
left: 50,
bottom: 0,
child: ColoredBox(
color: Colors.green,
child: SizedBox(
height: 100,
width: 80,
),
),
),
Positioned(
left: 100,
bottom: 0,
child: ColoredBox(
color: Colors.blue,
child: SizedBox(
height: 100,
width: 80,
),
),
),
Positioned(
left: 150,
bottom: 0,
child: ColoredBox(
color: Colors.yellow,
child: SizedBox(
height: 100,
width: 80,
),
),
),
],
);
}
}
Output

Flutter - How 2 Give different width to different container enclosed in a single column?

I'm trying to develop a clone of an App idea from dribble, which can be found here.
Can you please tell me is the code I'm trying to write is correct or not??
As I've tried to wrap a Column with two text Widgets Enclosed in Container ( separate ) and when I'm trying to change the width of one container It changes the margin of the other also.
My Code is :-
class HomeScreen extends StatelessWidget {
const HomeScreen({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
children: [
Container(
margin: const EdgeInsets.only(top: 30, left: 20),
child: const Text(
'Find Intrested Events to Join',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 30.0,
wordSpacing: 2,
),
),
width: 200,
),
// -----------------------------------------------------------------
Container(
margin: EdgeInsets.only(left: 20, top: 20),
width: 220,
child: Text(
'We share all events like Charity, workshop, Blood drive, etc.',
style: TextStyle(wordSpacing: 2, height: 1.4),
),
)
],
),
),
);
Can you tell me How to achieve that stage that I can change the Containers' width without affecting the margin of others.
It will be better to use Stack for this case while it contains background image, Also learn more about Stack, Align, Positioned and LayoutBuilder from flutter.dev
Play with this widget ,
class HomeScreen extends StatelessWidget {
const HomeScreen({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(child: LayoutBuilder(
builder: (context, constraints) {
return Stack(
children: [
Container(
color: Colors.amber.withOpacity(.4),
), //background image
Positioned(
left: 20,
top: 30,
child: SizedBox(
width: constraints.maxWidth * .5, // 50% of width
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const Text(
'Find Intrested Events to Join',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 30.0,
wordSpacing: 2,
),
),
SizedBox(
height: 20,
), //spaces between text
Text(
'We share all events like Charity, workshop, Blood drive, etc.',
style: TextStyle(wordSpacing: 2, height: 1.4),
),
],
),
),
),
Align(
// also Postisioned can be use
alignment: Alignment.bottomCenter,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text("hereh"),
ElevatedButton(onPressed: () {}, child: Text("Button"))
],
),
)
],
);
},
)),
);
}
}

Custom dialog widget that scales height dynamically to child content

I want to build a custom dialog whose child is a widget displaying the HTML content. I'm struggling with making the dialog's height size to its child. Currently, I'm giving the container a fixed height as otherwise it would crash due to unbounded height for Column. The package i use to display HTML content: Easy Web View.
My code:
class CustomContentDialog extends StatelessWidget {
CustomContentDialog({required this.content});
final String content;
#override
Widget build(BuildContext context) {
return Center(
child: Material(
child: Container(
width: MediaQuery.of(context).size.width * 0.3,
height: MediaQuery.of(context).size.height * 0.8,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Padding(
padding:
const EdgeInsets.only(left: 24, bottom: 16, top: 16),
child: Text(
'Title',
),
),
IconButton(
onPressed: () {
Navigator.of(context).pop();
},
icon: const Icon(
Icons.close,
color: Colors.grey,
size: 20,
),
)
],
),
const Divider(
indent: 10,
endIndent: 10,
color: Color(0xFFE9E9E9),
),
Flexible(
fit: FlexFit.loose,
child: Padding(
padding: const EdgeInsets.only(left: 24.0),
child: EasyWebView(
src: src,
onLoaded: () {},
isHtml: true,
isMarkdown: false,
convertToWidgets: false,
key: const Key('HTML'),
),
),
),
],
),
),
),
);
}
}
What I've achieved so far: