How to shrink and expand a Wrap widget in Flutter? - flutter

I would like to shrink and expand my Wrap widget when the size of the parent Container is increased or decreased. The fonts of the individual children should increase or decrease along with the size of the boxes. What is the best way to achieve this?
I have tried FittedBox (scaledDown) which reduces the sizes but then widget doesn't wrap at all (!) and all the children remain on one line.
This is the default behavious (if the Wrap widget is defined in a Container with a specific size).
Here is the code...
Widget _build(BuildContext context) {
var words = ["a", "abc", "de", "ef", "g", "i", "is", "s", "th"];
return new Scaffold(
body: Column(children: <Widget>[
Text('height 100'),
Container(
color: Colors.red,
height: 100.0,
child: Wrap(
alignment: WrapAlignment.spaceEvenly,
children: _buildWordButtons(words),
),
),
Text('height 50'),
Container(
color: Colors.green,
height: 50.0,
child: Wrap(
alignment: WrapAlignment.spaceEvenly,
children: _buildWordButtons(words),
),
),
Text('FittedBox, scaleDown, height 200'),
Container(
color: Colors.blue,
height: 200.0,
child: FittedBox(
fit: BoxFit.scaleDown,
child: Wrap(
alignment: WrapAlignment.spaceEvenly,
children: _buildWordButtons(words),
),
),
),
]),
);
}
List<Widget> _buildWordButtons(List<String> words) {
var buttons = List<Widget>();
for (var word in words) {
buttons.add(Container(
decoration: new BoxDecoration(border: new Border.all(color: Colors.black)),
child: Text(
word,
style: TextStyle(fontSize: 50.0),
),
margin: EdgeInsets.all(5.0),
));
}
return buttons;
}

If you'd like to create a Text widget that will adapt to the size of its parent widget, you may want to look into LayoutBuilder widget. Using this widget should help its child widget determine its parent widget's constraints. Since you've mentioned that having a spacious Container should print long texts in a newline, you can have it set inside the LayoutBuilder.
Here's a sample. I've modified the code snippet provided.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final words = ["a", "abc", "de", "ef", "g", "i", "is", "s", "th"];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Column(children: <Widget>[
Text('height 100'),
Container(
color: Colors.red,
height: 100.0,
child: adaptiveText(),
),
Text('height 50'),
Container(
color: Colors.green,
height: 50.0,
child: adaptiveText(),
),
Text('height 200'),
Container(
alignment: Alignment.center,
color: Colors.blue,
height: 200.0,
child: adaptiveText(),
),
]),
);
}
adaptiveText() {
return LayoutBuilder(
builder: (context, constraints) {
debugPrint('constraint maxHeight: ${constraints.maxHeight}');
// adapt Text widget if parent widget size is <= 100
if (constraints.maxHeight <= 100)
return FittedBox(
fit: BoxFit.scaleDown,
child: Wrap(
alignment: WrapAlignment.spaceEvenly,
children: _buildWordButtons(words),
),
);
else
return Wrap(
alignment: WrapAlignment.spaceEvenly,
children: _buildWordButtons(words),
);
},
);
}
List<Widget> _buildWordButtons(List<String> words) {
var buttons = List<Widget>();
for (var word in words) {
buttons.add(Container(
decoration:
new BoxDecoration(border: new Border.all(color: Colors.black)),
child: Text(
word,
style: TextStyle(fontSize: 50.0),
maxLines: 3,
),
margin: EdgeInsets.all(5.0),
));
}
return buttons;
}
}
Demo

Related

Flutter : Let big image overflow inside stack

I'm trying to let my users increase the size of an image inside a fixed size Stack.
The chosen size can be way above the Stack's size.
This is the result I get for now, even though the image :
Here is the relevant code :
Expanded(
child: AspectRatio(
aspectRatio: myCustomScreen.width / myCustomScreen.height,
child: ClipRRect(
borderRadius: BorderRadius.circular(14),
child: LayoutBuilder(
builder: (context, boxConstraint) {
return Stack(
alignment: Alignment.center,
fit: StackFit.passthrough,
children: [
Container(
color: Colors.blue,
),
//This object doesn't overflow when its width is above the
UnconstrainedBox(
child: Image(
width: (object.width.toDouble() * boxConstraint.biggest.width) / myCustomScreen.width,
image: NetworkImage("www.images.com/image.png", scale: 1)),
),
],
);
},
),
),
),
),
How can I let my users view the real size of the image inside this view without being constrained by the stack ?
Thank you !
Stack has a property called clipBehavior you can use it like this to enable overflow:
Stack(
clipBehavior: Clip.none,
// Your code continues here
Edit: Testing your code I made ti work on dart pad. The steps were, remove the UnconstrainedBox and used the image scale to resize it alongside with the fit property defined as none:
here's the code that I used on darted: https://dartpad.dartlang.org/
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> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
Expanded(
child: AspectRatio(
aspectRatio: 200 / 400,
child: ClipRRect(
borderRadius: BorderRadius.circular(14),
child: LayoutBuilder(
builder: (context, boxConstraint) {
return Stack(
clipBehavior: Clip.none,
alignment: Alignment.center,
fit: StackFit.passthrough,
children: [
Container(
color: Colors.blue,
),
Image(
fit: BoxFit.none,
image: NetworkImage(
"https://images.pexels.com/photos/13406218/pexels-photo-13406218.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2",
scale: 1 / (_counter + 1),
),
),
],
);
},
),
),
),
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}

How to put two containers on the same screen without page scrolling?

I have a search page. I display 2 containers with information on the search page. But I ran into a problem, my bottom station container goes off the screen and I need to scroll the page to see the information. How can I put 2 containers on the screen and not have to scroll the page so that 2 containers fit on the same screen?
1
Widget _addresses(Size size, StationCubit stationCubit) => ConstrainedBox(
constraints: BoxConstraints(
maxHeight: MediaQuery.of(context).size.height / 2,
),
child: SizedBox(
width: size.width,
child: ClipRRect(
borderRadius: BorderRadius.circular(24),
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 8.0, sigmaY: 8.0),
child: Container(
padding: const EdgeInsets.only(left: 20, top: 17),
decoration: BoxDecoration(
color: constants.Colors.greyXDark.withOpacity(0.8),
borderRadius: BorderRadius.circular(24),
),
child: SingleChildScrollView(
controller: _addressesController,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Addresses',
style: constants.Styles.smallBookTextStyleWhite,
),
const SizedBox(height: 25),
2
Widget _station(Size size, StationCubit stationCubit) => ConstrainedBox(
constraints: BoxConstraints(
maxHeight: MediaQuery.of(context).size.height / 2,
),
child: SizedBox(
width: size.width,
child: ClipRRect(
borderRadius: BorderRadius.circular(24),
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 8.0, sigmaY: 8.0),
child: Container(
padding: const EdgeInsets.only(left: 20, top: 17),
decoration: BoxDecoration(
color: constants.Colors.greyXDark.withOpacity(0.8),
borderRadius: BorderRadius.circular(24),
),
child: SingleChildScrollView(
controller: _stationController,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Station',
style: constants.Styles.smallBookTextStyleWhite,
),
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Column(
children: [
Expanded(
child: Container(
color: Colors.deepPurple,
child: ListView.builder(itemBuilder: (c, i) {
return Text("Test $i");
})),
),
Expanded(
child: Container(
color: Colors.deepOrange,
child: ListView.builder(itemBuilder: (c, i) {
return Text("Test $i");
})),
),
],
));
}
}
Try placing both containers in column and wrap both container with flexible/expanded to expand containers in full screen.
Example code:
column(
children: [
Expanded(
child: Container(child: Text("Container 1")
),
Expanded(
child: Container(child: Text("Container 2")
)
]
)
Use 2 Expanded container in single column
column( children: [ Expanded( child: Container(child: Text("Container 1") ), Expanded( child: Container(child: Text("Container 2") ) ] ).
Abdul Rahman Panhyar your answer is right but Max need to show data came from any API so there is a chance of bulk data and just wrapping the container with expanded will disrupt the UI. so what is suggest you can divide your screen in two parts then in each part you can use Listview builder so it will be inner scrollable.

How to solve stack widget problem in flutter pageview?

Im developing a quotes app as a beginner in flutter.I had used a stack widget to use both image and text in the center of my screen.And added "pageview widget" to have multiple page in my app.But the problem im facing is,whenever im trying to swipe the page,image get swiped but the text stayed the same.I mean the fist page "Text", still showing in the middle of 2nd page.Moreover i cant drag to the next page while touching the letter,its only being done via touching above or under the letter.I just wants to have a simple multipage app with text and image. How can i solve this Problem?
class OverviewScreen extends StatefulWidget {
const OverviewScreen({key, Key,}) : super(key: key);
#override
_OverviewScreenState createState() => _OverviewScreenState();
}
class _OverviewScreenState extends State<OverviewScreen> {
PageController pageController =PageController(initialPage: 0);
#override
Widget build(BuildContext context) {
return MaterialApp(
home:Scaffold(
extendBodyBehindAppBar: true,
appBar: AppBar(
title: Text("Hu R Rehman",
style: TextStyle(fontFamily: "MonteCarlo"),),
centerTitle: true,
leading: Icon(Icons.menu),
shape:RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(bottom: Radius.circular(16))
),
backgroundColor: Colors.transparent,
elevation: 0,
),
body:Center(
child: Stack(
alignment: Alignment.center,
children: [
PageView(
controller: pageController,
children: [
Image(
image:AssetImage('Image/soc1.jpg'),
fit:BoxFit.cover,
width: double.infinity,
height: double.infinity,
),
p1()
],
),
const Text('Text'
,style: TextStyle(fontSize: 31.0,
fontFamily:"MonteCarlo",
color: Colors.white,
fontWeight: FontWeight.w700 )
),
],
),
)
),
);
}
}
Here p1() is the second page
class p1 extends StatefulWidget {
#override
_p1State createState() => _p1State();
}
class _p1State extends State<p1> {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
backgroundColor: Colors.blueGrey,
),
);
}
}
If you take a look at widget tree, There are two widgets PageView and Text placed as Stack Children, and according to widget priority render Text widget will be at the top. Also, it is independent from PageView, and there will be no effect on this Text widget by changing Pageview.
let say you wish to part it on 1st child of PageView, you can move it there by wrapping with stack like this
body: Center(
child: Stack(
alignment: Alignment.center,
children: [
PageView(
controller: pageController,
children: [
Stack(
alignment: Alignment.center,
children: [
Image(
image: AssetImage('Image/soc1.jpg'),
fit: BoxFit.cover,
width: double.infinity,
height: double.infinity,
),
const Text(
'Text',
style: TextStyle(
fontSize: 31.0,
fontFamily: "MonteCarlo",
color: Colors.white,
fontWeight: FontWeight.w700,
),
),
],
),
p1()
],
),
],
),
)
Does it solve your issue?
Try putting Stack inside PageView children.
PageView(controller: pageController, children: [
Stack(
alignment: Alignment.center,
children: [
Image(
image: AssetImage('Image/soc1.jpg'),
fit: BoxFit.cover,
width: double.infinity,
height: double.infinity,
),
const Text('Text',
style: TextStyle(
fontSize: 31.0,
fontFamily: "MonteCarlo",
color: Colors.white,
fontWeight: FontWeight.w700)),
],
),
p1(),
],
);

How can I place container on top of other container's border?

How can I place a container on top of other container's border like the image below?
What I'm doing is designing a background image to make it works but I just wonder can I make it without using any image as my background?
You can use Positioned widget inside Stack like this in order make place a Container on top of the other:
Scaffold(
body: SafeArea(
top: true,
child: SingleChildScrollView(
child: Stack(
overflow: Overflow.visible, // TO MAKE SECOND CONTAINER VISIBLE
children: [
Container(
height: 250.0,
color: Colors.green,
child: Center(child: Text("First Container")),
),
Positioned(
bottom: -25.0,
left: (MediaQuery.of(context).size.width/4),
width: 200.0,
height: 50.0,
child: Container(
color: Colors.red,
child: Center(child: Text("Second Container"))
),
)
],
),
),
)
);
I hope this answer will help you.
You can achieve this with Stack & Positioned widget as demonstrated in following code :
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
centerTitle: true,
),
body: Stack(
overflow: Overflow.visible,
children: [
Container(
color: Colors.green,
width: MediaQuery.of(context).size.width,
height: 200,
child: Center(
child: Text("First Container"),
),
),
Positioned(
top: 175,
left: (MediaQuery.of(context).size.width / 2) - 100,
child: Center(
child: Container(
color: Colors.red,
width: 200,
height: 50,
child: Center(
child: Text("Second Container"),
),
),
),
),
],
),
);
}
}

How do I put a ListView under a scaffold with padding?

I am quite new to flutter and I've been trying to set up a profile page for my app but it seems like I don't quite understand how these flutter widgets come together, I apologize if my question is quite dumb but I've been googling and failing at getting this to work. So basically I have a scaffold which holds a container thats supposed to display profile info (email, name, etc.), under it I'd like to place a listview, but flutter has been boggling my mind, I can't seem to understand how layouts work together, here is my code. When I try to do buildPage(), I get an error that the scaffold has infinite size, using buildBox() alone works. I'm not sure how to go about this. Any Help is appreciated
import 'package:flutter/material.dart';
class ProfileBox extends StatefulWidget {
final String userEmail;
const ProfileBox(this.userEmail);
#override
_ProfileBoxState createState() => _ProfileBoxState();
}
class _ProfileBoxState extends State<ProfileBox> {
#override
Widget build(BuildContext context) {
return _buildPage();
}
Widget _buildBox(){
return Scaffold(
body: Align(
alignment: Alignment.topCenter,
child: LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
return Container(
margin: const EdgeInsets.only(top: 20.0),
decoration: BoxDecoration(
color: Color(0xFF8185E2), border: Border.all(
color: Color(0xFF8185E2),
),
borderRadius: BorderRadius.all(Radius.circular(20))
),
height: constraints.maxHeight / 2.5,
width: MediaQuery.of(context).size.width - (MediaQuery.of(context).size.width * 5)/100,
child: Center(
child: Text(
widget.userEmail,
textAlign: TextAlign.center,
),
),
);
},
),
),
);
}
Widget _buildPage()
{
return Column(children: <Widget>[
_buildBox(),
_buildList(),
],);
}
Widget _buildList()
{
return ListView(
children: <Widget>[
ListTile(
title: Text('Sun'),
),
ListTile(
title: Text('Moon'),
),
ListTile(
title: Text('Star'),
),
],
);
}
}
I just modified your code with Scaffold put the top Widget before the SafeArea, Please check the below code of it.
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
class HomeScreen extends StatefulWidget {
#override
State<StatefulWidget> createState() {
// TODO: implement createState
return _HomeScreen();
}
}
class _HomeScreen extends State<HomeScreen> {
#override
Widget build(BuildContext context) {
return _buildPage();
}
Widget _buildPage() {
return SafeArea(
top: true,
child: Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Container(
margin: const EdgeInsets.only(top: 20.0),
decoration: BoxDecoration(
color: Color(0xFF8185E2),
border: Border.all(
color: Color(0xFF8185E2),
),
borderRadius: BorderRadius.all(Radius.circular(20))),
height: MediaQuery.of(context).size.height / 2.5,
width: MediaQuery.of(context).size.width -
(MediaQuery.of(context).size.width * 5) / 100,
child: Center(
child: Text(
"YOUR_EMAIL",
textAlign: TextAlign.center,
),
),
),
Expanded(
child: _buildList(),
)
],
),
),
);
Column(
children: <Widget>[
// _buildBox(),
_buildList(),
],
);
}
Widget _buildList() {
return ListView(
children: <Widget>[
ListTile(
title: Text('Sun'),
),
ListTile(
title: Text('Moon'),
),
ListTile(
title: Text('Star'),
),
],
);
}
}
And output of the program as follow
Scaffold Widget should be a top Widget that contains the Column widget and all children Widget. I think you can start learning how to layout Widget in Flutter in order to understand more the way how Widget works, and the good place can be: https://flutter.dev/docs/development/ui/layout#lay-out-a-widget
Coming back to your question, you can just fix a bit to make it work:
class _ProfileBoxState extends State<ProfileBox> {
#override
Widget build(BuildContext context) {
return _buildPage();
}
Widget _buildBox() {
return Align(
alignment: Alignment.topCenter,
child: LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
return Container(
margin: const EdgeInsets.only(top: 20.0),
decoration: BoxDecoration(
color: Color(0xFF8185E2),
border: Border.all(
color: Color(0xFF8185E2),
),
borderRadius: BorderRadius.all(Radius.circular(20))),
height: constraints.maxHeight / 2.5,
width: MediaQuery.of(context).size.width -
(MediaQuery.of(context).size.width * 5) / 100,
child: Center(
child: Text(
widget.userEmail,
textAlign: TextAlign.center,
),
),
);
},
),
);
}
Widget _buildPage() {
return Scaffold(
body: Column(
children: <Widget>[
_buildBox(),
_buildList(),
],
),
);
}
Widget _buildList() {
return ListView(
children: <Widget>[
ListTile(
title: Text('Sun'),
),
ListTile(
title: Text('Moon'),
),
ListTile(
title: Text('Star'),
),
],
);
}
}