Adding dynamic widget with button - android

I am facing a strange bug when I try to add a dynamic widget to my app. When press add button screen turns completely white I can not find why it happens.
I use https://www.youtube.com/watch?v=xPW1vtDDlt4 as resource I am really new at Flutter maybe I forget something to add bu I check many times.
Here is my code,
class DynamicWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
child: new TextField(
decoration: new InputDecoration(hintText: 'Press + to Add Field'),
),
);
}
}
Initialization of the list.
List<DynamicWidget> listDynamic = [];
My function to add widgets to the list.
addDynamic() {
listDynamic.add(new DynamicWidget());
print("addDynamic");
setState(() {});
}
I am not sure but problem might be here,
final testText = Visibility(
child: new Column(
children: <Widget>[
new Flexible(
child: new ListView.builder(
itemCount: listDynamic.length,
itemBuilder: (_, index) => listDynamic[index],
),
),
],
),
);
Here I call my widget which I declare it to variable here.
final body = Container(
child: SingleChildScrollView(
child: Column(
children: <Widget>[
testText,
strPhoto
],
),
),
);
And finally my button.
return Scaffold(
appBar: new AppBar(title: new Text(device_type), centerTitle: true),
drawer: Menu(),
body: body,
floatingActionButton: Column(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
FloatingActionButton(
heroTag: null,
child: Icon(
Icons.add,
color: Colors.white,
),
onPressed: () {
addDynamic();
},
),
],
));
Thanks for helping me.

you must create variable Widget and add to Build Context on Scaffold

In the first step, i created a Widget called CustomTextField
import 'package:flutter/material.dart';
class CustomTextField extends StatelessWidget {
final String hint;
final TextEditingController controllers;
CustomTextField(this.hint, this.controllers);
#override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.only(top: 2.0, left: 6.0, right: 6.0, bottom: 2.0),
child: Column(
children: <Widget>[
TextField(
decoration: InputDecoration(hintText: hint),
controller: controllers),
SizedBox(height: 4.0),
],
),
);
}
}
this widget give me one text for display on hint and one controller for control textfield
And in the next step, I change the homepage class this way
i have list of Custom TextField (my widget) and display on listview using mapping list of build method
import 'package:flutter/material.dart';
import 'CustomTextField.dart';
class PageTutorial extends StatefulWidget {
#override
_PageTutorialState createState() => _PageTutorialState();
}
class _PageTutorialState extends State<PageTutorial> {
List<CustomTextField> widgets = [
CustomTextField("UserName", TextEditingController())
];
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView(
children: widgets.map<Widget>((widget) => widget).toList(),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
setState(() {
widgets.add(CustomTextField("Password", TextEditingController()));
});
},
child: Icon(Icons.add)),
);
}
}
have fun

Related

How to make dart flutter popup box?

I have an application like this:
My aim is that when I press the eye icon next to the text "Hello", I want a box to open just below the text and write the German version of "Hello". So it will say "Hallo".
My purpose is to show the meaning of the word.
When I press the eye, I want to show the German of the word. How can I make a white box under the word Hello, that is, the box in which the German language will be written?
Codes:
import 'package:flutter/material.dart';
import 'package:carousel_slider/carousel_slider.dart';
class selamlasmaLearn extends StatelessWidget {
List <wordAndMeaning> wordsList = [wordAndMeaning("Hello", "Hallo"), wordAndMeaning("Go", "Gehen")];
#override
Widget build(BuildContext context) {
return Scaffold(
body: Builder(
builder: (context) {
final double height = MediaQuery.of(context).size.height;
return CarouselSlider(
options: CarouselOptions(
height: height,
viewportFraction: 1.0,
enlargeCenterPage: false,
),
items: wordsList.map((wordAndMeaning word) {
return Builder(
builder: (BuildContext context) {
return Container(
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(color: Colors.amber),
child: Center(
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
word.word,
style: TextStyle(fontSize: 45, color: Colors.white),
),
SizedBox(width: 10,),
Icon(Icons.remove_red_eye_sharp, color: Colors.white, size: 25,), // <<<<<<<<<
],
),
),
);
},
);
}).toList(),
);
}
),
);
}
}
class wordAndMeaning {
String word;
String meaning;
wordAndMeaning(this.word, this.meaning);
}
I keep the word and its German in a list called wordsList.
Thanks for the help in advance.
You can convert the widget to StatefulWidget or use a ValueNotifier to control the preserve/notify the state visibility.
You can use Visibility widget or just if to show and hide German text.
class selamlasmaLearn extends StatefulWidget {
#override
State<selamlasmaLearn> createState() => _selamlasmaLearnState();
}
class _selamlasmaLearnState extends State<selamlasmaLearn> {
bool _showGerman = false;
List<wordAndMeaning> wordsList = [
wordAndMeaning("Hello", "Hallo"),
wordAndMeaning("Go", "Gehen")
];
#override
Widget build(BuildContext context) {
return Scaffold(
body: Builder(builder: (context) {
final double height = MediaQuery.of(context).size.height;
return CarouselSlider(
options: CarouselOptions(
height: height,
viewportFraction: 1.0,
enlargeCenterPage: false,
),
items: wordsList.map((wordAndMeaning word) {
return Builder(
builder: (BuildContext context) {
return Container(
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(color: Colors.amber),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(word.word,
style:
TextStyle(fontSize: 45, color: Colors.white)),
if (_showGerman) Text(word.meaning), //modify the way you want
],
),
const SizedBox(
width: 10,
),
IconButton(
icon: Icon(Icons.remove_red_eye_sharp),
color: Colors.white,
iconSize: 25,
onPressed: () {
setState(() {
_showGerman = !_showGerman;
});
},
),
],
),
);
},
);
}).toList(),
);
}),
);
}
}
Use the Tooltip widget
I'm emphasizing on the popup part in your question title. When using a Tooltip you ensure that your widgets do not shift position or jump when the Tooltip widget appear, as the example below illustrates.
Example code:
import 'package:flutter/material.dart';
class TooltipExample extends StatelessWidget {
const TooltipExample({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Tooltip(
// Set the tooltip to trigger on a single tap, tapping outside the
// widget will make the tooltip disappear.
triggerMode: TooltipTriggerMode.tap,
// The message shown when the tooltip appears.
message: "Tooltip showing!",
// Consider adjusting this to your needs.
showDuration: const Duration(days: 1),
// The widget that must be clicked to show the tooltip.
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisSize: MainAxisSize.min,
children: const [
Text("Hello"),
SizedBox(
width: 8,
),
Icon(Icons.visibility),
],
),
),
),
const Padding(
padding: EdgeInsets.all(8.0),
child: Text("Cover me!"),
)
],
),
);
}
}
// Some code to run the above example, note the theme part that turns the
// tooltip white.
class App extends StatelessWidget {
const App({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
// Style the overall design of tooltips in the app in one place,
// or provide in each tooltip individually.
theme: ThemeData(
tooltipTheme: const TooltipThemeData(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(
Radius.circular(4),
),
),
textStyle: TextStyle(
backgroundColor: Colors.white,
color: Colors.black,
),
),
),
home: const Scaffold(
backgroundColor: Colors.amber,
body: TooltipExample(),
),
);
}
}
void main() => runApp(const App());
Here is how it looks:
Note that the Tooltip widget overlays whatever is below it. (instead of pushing it further down - like toggling the visibility of a normal widget in a row or column would have done)

Why do I need to wrap the list items in a Column in order to dynamically add items using a button to ListView Flutter?

For the past day, I had a hard time coming up with a simple piece of code just to add some items to a ListView using a button. I wanted to create a list in my app and add items to this list simply by clicking a FloatingActionButton.
The problem was that when I clicked the button, nothing happened. But then when I HotReloaded the app, items magically appeared in the list (code block 1).
After some research, I found a simple solution that worked perfectly. I just wrapped the items in a Column widget and everything worked fine. But I cannot explain why. How is this working? What part of my initial code was wrong? Is this related to how the setState() method works? How does setState() work exactly??
My initial code:
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
List<Widget> items = [
Text('initial txt'),
];
void _incrementCounter() {
setState(() {
items.add(Text('NewText'));
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
child: ListView(
children: this.items,
),
width: 100,
height: 400,
alignment: Alignment.center,
)
],
),
alignment: Alignment.center,
// padding: EdgeInsets.fromLTRB(40, 10, 20, 10),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
Second Code: Just created a temp list in _incrementCounter() function and assigned it to the old list in setState() (Why should I do it like this?) and wrapped the items in a Column widget.
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
List<Widget> items = [
Text('initial txt'),
];
void _incrementCounter() {
List<Widget> ls_tmp = this.items;
ls_tmp.add(Text('New Text $_counter'));
setState(() {
_counter++;
this.items = ls_tmp;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
child: ListView(
children: [
Column(
children: this.items,
),
],
),
width: 100,
height: 400,
alignment: Alignment.center,
)
],
),
alignment: Alignment.center,
// padding: EdgeInsets.fromLTRB(40, 10, 20, 10),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
And last but not least, any other solution for this?
It's kind of buried in the documentation, but you can find it here:
https://api.flutter.dev/flutter/widgets/ListView/ListView.html
Like other widgets in the framework, this widget expects that the children list will not be mutated after it has been passed in here. See the documentation at SliverChildListDelegate.children for more details.
In Android Studio, if you hover over children:, then it will show this same documentation.
Instead, you need to use a ListView.builder:
child: ListView.builder(
itemCount: items.length,
itemBuilder: (BuildContext context, int index) {
return items[index];
},
),

How can I stop flip cards that have already been flipped from flipping back when user scrolls down and then scrolls back up again?

My issue is what the title says - I have a gridview of flip cards. When I flip a few over, scroll past them and then scroll back up the cards have flipped back. I don't really want that to happen because it's supposed to be that every time the user flips a card a point is added to a total, and then when they flip it back a point is taken away from the total. I've tried "AutomaticKeepAliveClientMixin", which works to preserve the state when I have another tab, but it doesn't seem to help keep the cards flipped when I scroll.
Apologies in advance if an obvious solution exists here and I've missed it. I did try to find a solution online.
Here is the code from the dart file I'm working with:
import 'package:flutter/material.dart';
import 'package:flip_card/flip_card.dart';
import 'statenames.dart';
import 'globalVariables.dart';
StateNames stateObject = new StateNames();
class GridOne extends StatefulWidget {
final Function updateCounter;
final Function decreaseCount;
GridOne(this.updateCounter, this.decreaseCount);
#override
_GridOneState createState() => _GridOneState();
}
class _GridOneState extends State<GridOne>
with AutomaticKeepAliveClientMixin {
#override
bool get wantKeepAlive => true;
int points = 0;
#override
Widget build(BuildContext context) {
return new Scaffold(
body: GridView.count(
crossAxisCount: 4,
children: List.generate(52, (index){
return Card(
elevation: 0.0,
margin: EdgeInsets.only(left: 3.0, right: 3.0, top: 9.0, bottom: 0.0),
color: Color(0x00000000),
child: FlipCard(
direction: FlipDirection.HORIZONTAL,
speed: 1000,
onFlipDone: (status) {
setState(() {
(status)
? widget.decreaseCount()
: widget.updateCounter();
});
print(counter);
},
front: Container(
decoration: BoxDecoration(
color: Color(0xFF006666),
borderRadius: BorderRadius.all(Radius.circular(8.0)),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
FittedBox(fit:BoxFit.fitWidth,
child: Text(stateObject.stateNames[index], style: TextStyle(fontFamily: 'Architects Daughter', color: Colors.white), )
),
Text('',
style: Theme.of(context).textTheme.body1),
],
),
),
back: Container(
decoration: BoxDecoration(
color: Color(0xFF006666),
borderRadius: BorderRadius.all(Radius.circular(8.0)),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Image(image: AssetImage(stateObject.licensePlatePaths[index])),
],
),
),
),
);
})
),
);
}
}
Thank you so much for reading.
I did hit trial to achieve what you wanted and i think it's only possible if you use column. I even tried using simple ListView but still the the card will return to front face
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Test(),
);
}
}
class Test extends StatefulWidget{
#override
_Test createState() => _Test();
}
class _Test extends State<Test>{
List<Widget> list = [];
_Test(){
list = new List.filled(30, flipCards());
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
child: Column(
children: list,
),
)
);
}
Widget flipCards(){
return Container(
height: 70,
child: FlipCard(
flipOnTouch: true,
front: Card(
child: Container(
alignment: Alignment.center,
child: Text('Toggle'),
),
),
back: Card(
child: Container(
alignment: Alignment.center,
child: Text('Back'),
),
),
)
);
}
}
You need to use the AutomaticKeepAliveClientMixin on the children of the GridView
So make a new stateful widget for your cards and use the keepalive there.
Also for the AutomaticKeepAliveClientMixin you need to call super.build(context); in your build method

Flutter Expanded widget error even if theres a Flex parent

Hi can you guys help me with this, I know that the Expanded widget requires a Flex parent. but for some reason, mine gives an error:
my code are:
import 'package:flutter/material.dart';
class InputPage extends StatefulWidget {
#override
_InputPageState createState() => _InputPageState();
}
class _InputPageState extends State<InputPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Center(child: Text('BMI CALCULATOR')),
),
body: Column(
children: <Widget>[
Expanded(
child: Container(
child: ReusableCard(colour: Color(0xFF141A3C)),
),
),
],
),
);
}
}
class ReusableCard extends StatelessWidget {
//CUSTOM CONSTRUCTOR
//the color from the Stateful Widget from above is passed in to the INPUT of ReusableCard({PASSED IN HERE}),
ReusableCard({this.colour});
Color colour;
#override
Widget build(BuildContext context) {
return Expanded(
child: Container(
margin: EdgeInsets.all(15.0),
// height: 200.0,
// width: 170.0,
decoration: BoxDecoration(
color: colour,
borderRadius: BorderRadius.circular(10.0),
),
),
);
}
}
UPDATE
Ive tried adding another Extended widget AS A CHILD of Column() but the error reappears
class _InputPageState extends State<InputPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Center(child: Text('BMI CALCULATOR')),
),
body: Column(
children: <Widget>[
Expanded(
child: Row(
// <------ change this Container to a Row or Column
children: <Widget>[
ReusableCard(colour: Color(0xFF141A3C)),
ReusableCard(colour: Color(0xFF141A3C)),
],
),
),
Expanded(
child: ReusableCard(
colour: Color(0xFF141A3C),
),
)
],
),
);
}
}
Your ReusableCard (which returns an Expanded widget) is wrapped within a Container class. This is what's giving you the error. To fix this, you can simply change your Container class to a Row or Column:
class _InputPageState extends State<InputPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Center(child: Text('BMI CALCULATOR')),
),
body: Column(
children: <Widget>[
Expanded(
child: Container( // <------ change this Container to a Row or Column
child: ReusableCard(colour: Color(0xFF141A3C)
),
),
),
],
),
);
}
}

Flutter DropdownButton not updated by setState

I have this flutter code.
When I select new item from dropdown list, the value of _selectedCurrency is updated, but the dropdown button itself not updated. The item shown is always USD.
import 'package:flutter/material.dart';
import 'coin_data.dart' as coinData;
class PriceScreen extends StatefulWidget {
#override
_PriceScreenState createState() => _PriceScreenState();
}
class _PriceScreenState extends State<PriceScreen> {
String _selectedCurrency = "USD";
DropdownButton _currencyDropdownButton;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Coin Ticker'),
),
body: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Container(
height: 150.0,
alignment: Alignment.center,
padding: EdgeInsets.only(bottom: 30.0),
color: Colors.lightBlue,
child: _currencyDropdownButton,
),
],
),
);
}
#override
void initState() {
super.initState();
_currencyDropdownButton = DropdownButton<String>(
value: _selectedCurrency,
items:
coinData.currenciesList.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
onChanged: (value) {
setState(() {
_selectedCurrency = value;
});
},
);
}
}
But if I created the DropdownButton widget inside build() then everything works fine, like this
import 'package:flutter/material.dart';
import 'coin_data.dart' as coinData;
class PriceScreen extends StatefulWidget {
#override
_PriceScreenState createState() => _PriceScreenState();
}
class _PriceScreenState extends State<PriceScreen> {
String _selectedCurrency = "USD";
DropdownButton _currencyDropdownButton;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Coin Ticker'),
),
body: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Container(
height: 150.0,
alignment: Alignment.center,
padding: EdgeInsets.only(bottom: 30.0),
color: Colors.lightBlue,
child: DropdownButton<String>(
value: _selectedCurrency,
items: coinData.currenciesList
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
onChanged: (value) {
setState(() {
_selectedCurrency = value;
});
},
),
),
],
),
);
}
}
I'm trying to make my code neat, by not create everything on build().
Is creating the widget on initState() is correct way in flutter?
Thanks
why would you want to put your widget inside initState()? in rebuild progress, only widgets inside build() will get updated but you created an immutable widget inside init.
I offer you using the provider package. create a new StatelessWidget class and use ChangeNotifierProvider<String>() in root
to rebuild your widget on every change.
No initState is called only once, while building, you can not change if you declare inside, it might possible with GlobalKey only.try with GlobalKey.
and when setState(); , is called build method get update. so we have to put widget inside build method only.

Categories

Resources