Does anyone know how to generate a new widget in Flutter when OnTap() is triggered?
In my case, I want to create a new column inside a container, when the column icon is pressed.
The icon is wrapped with an InkWell().
InkWell(
onTap: () {
print("Create Column in another Container");
},
child: Column(
children: const [
Icon(
Icons.view_agenda,
color: iconGreyColor,
size: 20.0,
),
],
),
),
The Goal shut look like this.
Container(child: Column(children:[]),)
Main part:
...widget.widgets -> spread operator .whenever ontap pressed.the array will get new element and set state will update the widget.
InkWell(
onTap: () {
setState(() {
widget.widgets.add(Container(
height: 49,
child: new Column(
children: [
Text(
"hi",
style: TextStyle(fontSize: 40),
)
],
),
));
});
print("Create Column in another Container");
},
child: Column(
children: const [
Icon(
Icons.view_agenda,
size: 20.0,
),
],
),
)
Container(
margin: EdgeInsets.only(
left: 10.0,
right: 10.0,
),
height: MediaQuery.of(context).size.height - 150,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [...widget.widgets],
),
)
sample code
void main() => runApp(MyHomePage());
class MyHomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Page0(),
);
}
}
class Page0 extends StatefulWidget {
final widgets = [];
#override
_Page0State createState() => _Page0State();
}
class _Page0State extends State<Page0> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView(
children: [
SizedBox(
height: 25.0,
),
Center(
child: Text(
"macintosh_app",
style: TextStyle(fontSize: 48),
)),
SizedBox(
height: 50.0,
),
Center(
child: InkWell(
onTap: () {
setState(() {
widget.widgets.add(Container(
height: 49,
child: new Column(
children: [
Text(
"hi",
style: TextStyle(fontSize: 40),
)
],
),
));
});
print("Create Column in another Container");
},
child: Column(
children: const [
Icon(
Icons.view_agenda,
size: 20.0,
),
],
),
),
),
SizedBox(
height: 25.0,
),
Container(
margin: EdgeInsets.only(
left: 10.0,
right: 10.0,
),
height: MediaQuery.of(context).size.height - 150,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [...widget.widgets],
),
),
],
),
);
}
}
You can implement this using StatefulWidget(). Create a List<Widget> outside your build of StatefulWidget() and inside your InkWell() append new Widget() you want to add and call setState((){})
class YellowBird extends StatefulWidget {
const YellowBird({Key? key}) : super(key: key);
#override
State<YellowBird> createState() => _YellowBirdState();
}
class _YellowBirdState extends State<YellowBird> {
List<Widget> myWidgetList = [
Text("hello"),
];
#override
Widget build(BuildContext context) {
return Column(
children: [
InkWell(
onTap: () {
print("Create Column in another Container");
myWidgetList.add(Text("hello 2"));
setState(() {});
},
child: Column(
children: const [
Icon(
Icons.view_agenda,
size: 20.0,
),
],
),
),
Column(
children: myWidgetList,
),
],
);
}
}
You can run same code here Link
Inside OnTap(), you can pass a function that can create a Widget.
e.g.
Widget buildContainer(){ return Container(child: Text("Stack Overflow"))}
Insert this function before your build method and then call it during the OnTap() event. You can, of course, modify the Container according to your exact requirements.
The important thing to understand here is that you can create functions with any permissible return type, even a specific Widget, this is especially useful when you want to create multiple identical widgets, as it reduces redundant code.
Related
I have an Elevated Button which is on of the bottom of the Page and I am a beginner sorry for this silly doubts but i can't figure out how to change the position of the button I dont know how to try positioned widget too. Kindly help me
I tried positioned widget but couldn't do well can anyone help me with this. here is my full code.
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
home: MyApp(),
));
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
children: [
Expanded(
child: PageView.builder(
itemBuilder: (context, index)=> const OnBoardContent(
image: 'assets/splash-1.png',
description: "All under one roof with different approach"),
),
),
SizedBox(
height: 30,
width: 200,
child: ElevatedButton(
onPressed: (){},
child: const Text("Tap to get started"),
),
),
],
)
),
);
}
}
class OnBoardContent extends StatelessWidget {
const OnBoardContent({
Key? key,
required this.image,
required this.description,
}) : super(key: key);
final String image, description;
#override
Widget build(BuildContext context) {
return Column(
children: [
const SizedBox(
height: 160,
),
const Text("Naz-Kearn",
style: TextStyle(
fontSize: 30,
fontWeight: FontWeight.bold
)),
const Text("A simplify learning App",
style: TextStyle(
fontWeight: FontWeight.normal
),
),
Image.asset(image),
const SizedBox(
height: 50,
),
Text(description,
textAlign: TextAlign.center,
style: const TextStyle(fontWeight: FontWeight.normal),
),
],
);
}
}
Output of the above code
You need your widgets in a stack if you want to use Positioned widget on them :
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
home: MyApp(),
));
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Stack( //wrapped the whole column with a stack so that all the other widgets doesn't get disturbed
children: [
Column(
children: [
Expanded(
child: PageView.builder(
itemBuilder: (context, index)=> const OnBoardContent(
image: 'assets/splash-1.png',
description: "All under one roof with different approach"),
),
),
],
),
Positioned(
top: MediaQuery.of(context).size.height*0.7, //change the 0.7 part to any number you like
child: SizedBox(
height: 30,
width: 200,
child: ElevatedButton(
onPressed: (){},
child: const Text("Tap to get started"),
),
),
),
],
)
),
);
}
}
class OnBoardContent extends StatelessWidget {
const OnBoardContent({
Key? key,
required this.image,
required this.description,
}) : super(key: key);
final String image, description;
#override
Widget build(BuildContext context) {
return Column(
children: [
const SizedBox(
height: 160,
),
const Text("Naz-Kearn",
style: TextStyle(
fontSize: 30,
fontWeight: FontWeight.bold
)),
const Text("A simplify learning App",
style: TextStyle(
fontWeight: FontWeight.normal
),
),
Image.asset(image),
const SizedBox(
height: 50,
),
Text(description,
textAlign: TextAlign.center,
style: const TextStyle(fontWeight: FontWeight.normal),
),
],
);
}
}
try this code, you can use alignment property of the Stack widget to center everything.
SafeArea(
child: Stack(
alignment: Alignment.center, //do this
children: [
You can wrap your button with Padding widget which helps you to add padding as you like
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
children: [
Expanded(
child: PageView.builder(
itemBuilder: (context, index)=> const OnBoardContent(
image: 'assets/splash-1.png',
description: "All under one roof with different approach"),
),
),
Padding(
padding: EdgeInsets.all(8),
child: SizedBox(
height: 30,
width: 200,
child: ElevatedButton(
onPressed: (){},
child: const Text("Tap to get started"),
),
),),
],
)
),
);
}
Firstly please mention what precisely the issue you are facing. If you have a problem with the get started button, what is the expected place for the get started button in the design?
Based on the code given, I'm hoping that the get started button should be at the bottom of the screen with some space below. You have already placed the button at the bottom, but you are not able to give space below.
There are some possible ways, you can use it with the get started button component.
Instead of this,
SizedBox(
height: 30,
width: 200,
child: ElevatedButton(
onPressed: (){},
child: const Text("Tap to get started"),
),
),
Option 1
Use container with margin
Container(
height: 30,
width: 200,
margin: EdgeInsets.only(
bottom: 50,
),
child: ElevatedButton(
onPressed: () {},
child: const Text("Tap to get started"),
),
),
Option 2
Wrap existing SizedBox with padding widget
Padding(
padding: EdgeInsets.only(bottom: 50.0),
child: Sizedbox(
height: 30,
width: 200,
child: ElevatedButton(
onPressed: () {},
child: const Text("Tap to get started"),
),
),
),
Even with some more ways to move the button wherever you need, you can try your own with the following widgets Expanded(), Spacer(), SizedBox(), Positioned() and etc.
Can anyone explain me how can I build widget as ListView builder with 2 lines of items. I got an example of this type, you can check out it by the picture below:
An option is to use the Wrap widget with direction set to horizontal.
#override
Widget build(BuildContext context) {
final lorem = [
'accusamus',
'dignissimos',
'ducimus',
'blanditiis',
'praesentium',
'voluptatum'
];
return Container(
height: 100,
width: 250,
child: Wrap(
direction: Axis.horizontal,
children: List.generate(
lorem.length,
(index) => Padding(
padding: const EdgeInsets.all(8.0),
child: Text(lorem[index]),
),
),
),
);
}
This snippet should help you.
You can try it at https://dartpad.dev/028daa76945938f0e5c14aea6a8bf84b?null_safety=true
class MyWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return SizedBox(
width: 500.0,
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: ['English', 'Russian', 'Spanish']
.map((language) => LanguageButton(
language: language,
))
.toList(),
),
SizedBox(height: 20,),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: ['Some really long language', 'French', 'German']
.map((language) => LanguageButton(
language: language,
))
.toList(),
),
],
),
);
}
}
class LanguageButton extends StatelessWidget {
final String language;
const LanguageButton({Key? key, required this.language}) : super(key: key);
#override
Widget build(BuildContext context) {
return OutlinedButton(
style: OutlinedButton.styleFrom(
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(30),
),
),
),
onPressed: () {
// TODO
},
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20.0, vertical: 8.0),
child: Text(language),
),
);
}
}
I used a Column instead of a ListView.builder. Maybe that's good enough for what you need. The gist is to have each line as a Row and set the mainAxisAlignment to spaceBetween.
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'});
}
Hello i am new to Flutter and I want to know if there is a way to add new Widgets with a button click.
I looked into many stack overflow similar Questions. but due to my poor knowledge most of them seems complex to me and hard to grasp. All i need to do is add some containers below old build containers
class MedPreC extends StatefulWidget {
#override
_MedPreCState createState() => _MedPreCState();
}
Widget returnWidget() {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
width: double.infinity,
height: 40,
color: Colors.red,
),
);
}
class _MedPreCState extends State<MedPreC> {
var child2 = Column(
children: [
returnWidget(),
],
);
#override
Widget build(BuildContext context) {
return Container(
child: Column(
children: [
Expanded(
child: Container(
color: Colors.yellow,
height: 400,
width: double.infinity,
child: child2,
),
),
RaisedButton(
child: Text("Add"),
onPressed: () {
setState(() {
//
child2.children.add(returnWidget());
//
});
},
)
],
),
);
}
}
This is the code i have made so far. This whole code will be called inside another class with scafold and stuffs
returnWidget() Returns a red container
child2 is a Column called inside a yellow Container with one red container as one of its children
i need to add more redcontainers on button press
Thank you thats all
Try this
class AddWidget extends StatefulWidget {
#override
_AddWidgetState createState() => _AddWidgetState();
}
class _AddWidgetState extends State<AddWidget> {
List<Widget> containerList = [];
Widget returnWidget() {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
width: double.infinity,
height: 40,
color: Colors.red,
),
);
}
#override
Widget build(BuildContext context) {
return Container(
child: Column(
children: [
Expanded(
child: Container(
color: Colors.yellow,
height: 400,
width: double.infinity,
child: Column(children: containerList),
),
),
RaisedButton(
child: Text("Add"),
onPressed: () {
setState(() {
containerList.add(returnWidget());
});
},
)
],
),
);
}
}
For this you need also check the overflow of widget. So you can check the below code.
import 'package:flutter/material.dart';
class MedPreC extends StatefulWidget {
#override
_MedPreCState createState() => _MedPreCState ();
}
class _MedPreCState extends State<MedPreC > {
List<Widget> data = [];
Widget CustomWidget() {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
width: double.infinity,
height: 40,
color: Colors.red,
),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Container(
color: Colors.yellow,
height: MediaQuery.of(context).size.height - 60,
width: double.infinity,
child: SingleChildScrollView(child: Column(children: data)),
),
],
),
bottomNavigationBar: Container(
height: 60,
width: MediaQuery.of(context).size.width,
color: Colors.white,
child: InkWell(
child: Center(
child: Container(
color: Colors.red,
width: 100,
height: 40,
child: Center(child: Text("Add"))),
),
onTap: () {
setState(() {
data.add(CustomWidget());
});
},
),
),
);
}
}
i'm very new to Flutter.
I have a stateful widget. Every time i click a counter, the whole build function runs and the results are updated.
But is there a way to make it a stateless widget and update only the relevant part somehow so i could avoid rebuilding the screen?
I have a stateful widget. Every time i click a counter, the whole build function runs and the results are updated.
But is there a way to make it a stateless widget and update only the relevant part somehow so i could avoid rebuilding the screen?
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
home:Home(),
));
}
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State {
int long = 0;
void increaseCounter(){
setState(() {
long++;
});
}
void decreaseCounter(){
if(long > 0) {
setState(() {
long--;
});
}
}
Text numberOfDeliveries(){
return Text(
'$long deliveries today',
style: TextStyle(
color:Colors.white,
fontSize: 24.0,
),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title:Text('Deliveries'),
backgroundColor: Colors.green,
),
body: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(
child: Container(
color: Colors.blue,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(
child:Padding(
padding: const EdgeInsets.symmetric(vertical: 32.0, horizontal: 0.0),
child: Text(
'Long',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 32.0,
color: Colors.white,
),
),
),
),
Expanded(
child:
// is it possible to update this without running the whole build again?
numberOfDeliveries(),
),
Expanded(
child: Row(
children: [
Expanded(
child: Container(
padding: EdgeInsets.symmetric(vertical: 32.0, horizontal: 0.0),
color:Colors.blue[100],
child: FlatButton(
onPressed: (){
decreaseCounter();
},
child: Text('-'),
),
),
),
Expanded(
child: Container(
padding: EdgeInsets.symmetric(vertical: 32.0, horizontal: 0.0),
color:Colors.blue[500],
),
),
Expanded(
child: Container(
padding: EdgeInsets.symmetric(vertical: 32.0, horizontal: 0.0),
color:Colors.blue[900],
child: FlatButton(
onPressed: (){
increaseCounter();
},
child: Text('+'),
),
),
),
],
),
),
],
),
),
),
Expanded(
child: Container(
color: Colors.blue[800],
child: Row(
children: [
Text('Bottom'),
],
),
),
),
],
),
);
}
}