How to change the UI if the value of a variable changes? - if-statement

I tried to change the UI if (variable1 == "1"), but I get an error. Can anybody tell me what is wrong with my code or if there is another way to show the user something different if variable1 changes the value? Below is the code I tried. Thanks in advance.
return Scaffold(
body: Container(
if (variable1 == "1") {
child: Center(
child: Text("Test");
),
}
else {
print("test");
}
),
);
}
}

For the small if conditions or like, you can do as suggested by #Random Guru. However, in case you have more complicated logic, then it might be a good idea to get the logic done before returning the widget. e.g.
body:_buildBody()
Widget _buildBody()
{
if (variable1 == "1")
{
return Container(______);
}
else
{
return Text(_____);
}
}

Try this :
Using tenary operator in dart:
return Scaffold(
body: Container(
child: variable1 == "1"
? Center(
child: Text("Variable1 is equals to 1"),
)
: Text("Varibale1 is not 1"),
),
);
I hope this helps.

Related

How can I make my search history not have the same elements repeated many times in flutter/dart?

I'm trying to do a search history using a search delegate but I'm having a problem.
When I perform a search, that element can appear several times in the history and what I want is that it not be repeated.
If I search 3 times for the same person, in the search history it appears 3 times
And I only want it to appear once.
How could I do it?
help would be appreciated.
Code and image::
class MPState extends State<MP>{
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: 3,
child: new Scaffold(
resizeToAvoidBottomInset : false,
appBar: AppBar(
title: Text("App"),
backgroundColor: Colors.redAccent,
elevation: 0,
actions: [
IconButton(
icon: Icon(Icons.search),
onPressed: () async{
final busqueda = await showSearch(
context: context,
delegate: SearchDelegateMP("Buscar...",this.historialMenuPrincipal)
);
if(busqueda != null ) {
if (this.historialMenuPrincipal.length > 0) {
// this.historialMenuPrincipal.add(busqueda);
/*historialMenuPrincipal.removeWhere((item) =>
item.email == busqueda.email); // si elimina*/
for (int i = 0; i < historialMenuPrincipal.length; i++) {
if(historialMenuPrincipal[i].email== busqueda.email){
print(historialMenuPrincipal[i].email);
break;
}else{
this.historialMenuPrincipal.add(busqueda);
break;
}
}
}else{ this.historialMenuPrincipal.add(busqueda);}
}
}
class SearchDelegateMPextends SearchDelegate<SearchDelegateM>{
#override
List<Widget> buildActions(BuildContext context) {
return [
//code
];
}
#override
Widget buildResults(BuildContext context) {
//code
}
Widget buildSuggestions(BuildContext context) {
return StatefulBuilderSuggestions(context,this.historialMenuPrincipal);
}
Widget StatefulBuilderSuggestions(BuildContext context ,List <SearchDelegateM> historialMenuPrincipal){
return Container(
child:StatefulBuilder(
builder:(context,setState)
{
return Container(
child: ListView.builder(
itemCount: historialMenuPrincipal.length,
itemBuilder: (context,i)
{
contentPadding: EdgeInsets.symmetric(vertical: 12,horizontal: 16);
leading:CircleAvatar(
radius: 32,
backgroundImage: NetworkImage(
"https://2.bp.blogspot.com/-3ZzNt8ZsjQk/WR9W4IFn4II/AAAAAAAAAJw/_inTVynhS60V7F5IZ-461-pda7WArTStwCEw/s1600/ANA.jpg"),
);
return
ListTile(
title: Text(historialMenuPrincipal[i].email ),
trailing: IconButton(
icon: Icon(Icons.cancel,color: Colors.black,),
onPressed: () {
setState(() {
historialMenuPrincipal.remove(historialMenuPrincipal[i]);
});
},)
);
}
),
);
}
)
);
}
enter image description here
Empty your list with every new search, before you start adding to it.
this.historialMenuPrincipal.clear();
What is happening is that the result is being added n number of times, even if the result is already there from previous searches.
N = the number of times the search is matched.
List can have repeated elements. You can parse your list to Set as set only contains unique elements.
List <SearchDelegateM> uniqueElementsList = historialMenuPrincipal.toSet().toList();
use this code before showing your elements in Listview.builder() and use uniqueElementsList in your builder.

How can I remove the icon when the validation is null in flutter?

I have a function that receives a list in the function parameter and I am displaying that list.
I have a validation in the Text, when it is null it shows me a message that says "no data" or otherwise it shows me the value of the list.
What I want to remove the cancel icon when it is null and only appear when I have a value to display.
Help would be greatly appreciated.
Code and Image ::
Widget SfuluilderSuggestions(List <SDM> historialMenuPrincipal){
return Container(
child:StatefulBuilder(
builder:(context,setState)
{
return Container(
child: ListView.builder(
itemCount: historialMenuPrincipal.length,
itemBuilder: (context,i)
{
contentPadding: EdgeInsets.symmetric(vertical: 12,horizontal: 16);
leading:CircleAvatar(
radius: 32,
backgroundImage: NetworkImage(
"https://2.bp.blogspot.com/-3ZzNt8ZjQk/WR9W4Fn4II/AAAAAAAJw/_inTVynhS6V75IZ-461-pda7WyrTStwCEw/s1600/A.jpg"),
);
return
ListTile(
title: Text(historialMenuPrincipal[i] == null ? "no data":historialMenuPrincipal[i].email ),
trailing: IconButton(
icon: Icon(Icons.cancel,color: Colors.black,),
onPressed: () {
setState(() {
historialMenuPrincipal.remove(historialMenuPrincipal[i]);
});
},
),
);
}
),
);
}
)
);
}
You can check if the text is null -
trailing: Text(historialMenuPrincipal[i] != null ? IconButton(
icon: Icon(Icons.cancel,color: Colors.black,),
onPressed: () {
setState(() {
historialMenuPrincipal.remove(historialMenuPrincipal[i]);
});
},
) : Padding(padding:EdgeInsets.zero),
While historialMenuPrincipal contains data, you can remove only when data is available. You can pass null on trailing.
trailing:
historialMenuPrincipal.contains(historialMenuPrincipal[i])
? IconButton(...)
: null
If you want to skip the generating ListTile, you can check on return level and provide SizedBox or better filter data while generating the list.

How to change "setState()" when using GetX in Flutter?

I have a login screen code like below that has a text button that changes the state of the Login button to Signup or reverse, and want to rewrite it to use GetX library. But I don't know how?
enum AuthMode { Signup, Login }
class AuthenticationScreen extends StatelessWidget {
const AuthenticationScreen({Key? key}) : super(key: key);
AuthMode _authMode = AuthMode.Login;
#override
Widget build(BuildContext context) {
final GlobalKey<FormState> _formKey = GlobalKey();
void _switchAuthMode() {
if (_authMode == AuthMode.Login) {
setState(() {
_authMode = AuthMode.Signup;
= });
_controller!.forward();
} else {
setState(() {
_authMode = AuthMode.Login;
});
_controller!.reverse();
}
}
return Scaffold(
body: Center(
child: Container(
constraints: const BoxConstraints(maxWidth: 400),
padding: const EdgeInsets.all(24),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
,
TextButton(
child: Text(
'${_authMode == AuthMode.Login ? 'SIGNUP' : 'LOGIN'} '),
onPressed: _switchAuthMode,
style: TextButton.styleFrom(
padding:
const EdgeInsets.symmetric(horizontal: 30.0, vertical: 4),
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
textStyle: TextStyle(color: Theme.of(context).primaryColor),
),
],
),
),
),
);
}
}
I tried some changes like transferring Authmode to the auth_controller file that extends GetxController and add obs after AuthMode _authMode = AuthMode.Login; and try to use obx(()=>) inside the _switchAuthMode() but didn't work.
Try like this:
final authMode= Rx<AuthMode>(AuthMode.Login);
And then on your switchAuthMode method:
authMode.value = AuthMode.Signup; // without setState
And finally, wrap the Text widget with Obx:
Obx(()=> Text('${authMode.value == AuthMode.Login ? 'SIGNUP' : 'LOGIN'} ')
And you can actually make your widget a StatelessWidget.

Remove duplicate widget

My function types() should return a unique list of ExpansionTiles.
In dart combining .toSet().toList() is really efficient in removing duplicates in List and I am trying to do the same here but I'm still rendering duplicates.
In the picture I don't want NISSAN to appear twice, just once as one category.
types() {
return snapshot.data.documents.map((doc) {
if(doc['car']['registryNumber'] != null && doc['car']['category'] ==
'car') {
return ExpansionTile(
title: new Row(
children: <Widget>[
new Text(
doc['car']['type'].split(' ')[0],
style: new TextStyle(
fontSize: 15.0
),
)
],
),
children: <Widget>[
],
);
} else {
return new Text('');
}
}).toSet().toList();
}
Don't forget to add a unique key: to ExpansionTile to avoid any duplicate issues!

image_picker Cancel: Navigation.pop inside Widget builder for Flutter

I have the following issue in my Flutter App:
For the image_picker Cancel-button to work properly, I needed to be able to Navigate.pop() at the moment the user presses the Cancel-button inside the image_picker Plugin.
The main question for this image_picker-Cancel issue is: How can I navigate back (i.e. Navigator.pop(context)) inside a builder of a Widget ?
The following throws an error:
Widget _cancelBtnPressedWidget(BuildContext context) {
Navigator.pop(context);
}
I know a Widget is supposed to return something. Therefore is it possible to pseudo-return something - but actually keep the Navigator.pop() as the main action inside the Widget ??? (and best, automatically invoked without extra user-interaction)...
From the above code, the error sais:
flutter: ══╡ EXCEPTION CAUGHT BY ANIMATION LIBRARY ╞═════════════════════════════════════════════════════════
flutter: The following assertion was thrown while notifying status listeners for AnimationController:
flutter: setState() or markNeedsBuild() called during build.
flutter: This Overlay widget cannot be marked as needing to build because the framework is already in the
flutter: process of building widgets. A widget can be marked as needing to be built during the build phase
flutter: only if one of its ancestors is currently building. This exception is allowed because the framework
flutter: builds parent widgets before children, which means a dirty descendant will always be built.
flutter: Otherwise, the framework might not visit this widget during this build phase.
flutter: The widget on which setState() or markNeedsBuild() was called was:
flutter: Overlay-[LabeledGlobalKey<OverlayState>#b5c98](state: OverlayState#6a872(entries:
flutter: [OverlayEntry#cd1e7(opaque: false; maintainState: false), OverlayEntry#43b81(opaque: false;
flutter: maintainState: true), OverlayEntry#f0b49(opaque: false; maintainState: false),
flutter: OverlayEntry#b9362(opaque: false; maintainState: true)]))
flutter: The widget which was currently being built when the offending call was made was:
flutter: FutureBuilder<File>(dirty, state: _FutureBuilderState<File>#d3cac)
.
Here a more detailed description to where the above requirement comes from :
In fact, I would like to use the Navigator.pop() as soon as the user presses the cancel-Button as for a image_picker Plugin usage.
I realised that the snapshot.hashCode-change is one way to detect the Cancel-Button from being pressed by the user. Therefore if the user presses that Cancel-button, I would like to do no more than navigate.pop back to where I came from ;)... I don't want to show anymore or keep the user inside a Widget, but immediately return back to the view that originally Navigate.pushed.
Here is the image-picker part that does the image-finding - and the Cancel-treatment (i.e. call of _cancelBtnPressedWidget-Widget).
import 'package:flutter/material.dart';
import 'dart:io';
import 'package:image_picker/image_picker.dart';
File _imageFile;
bool _pickImage = true;
int _hashy = 0;
#override
Widget build(BuildContext context) {
if (_pickImage) {
return FutureBuilder<File>(
future: ImagePicker.pickImage(source: ImageSource.camera),
builder: (BuildContext context, AsyncSnapshot<File> snapshot) {
if (snapshot.hasData) {
_pickImage = false;
_imageFile = snapshot.data;
return _showImage(snapshot.data);
} else {
// when cancel is pressed, the hashCode changes...
if ((_hashy != 0) && (snapshot.hashCode != _hashy)) {
// when cancel pressed
return _cancelBtnPressedWidget(context);
}
_hashy = snapshot.hashCode;
return Scaffold(
body: Center(
child: Text('no image picker available'),
),
);
}
},
);
} else {
return _showImage(_imageFile);
}
}
Widget _cancelBtnPressedWidget(BuildContext context) {
// requires a return ..... How to overcome this requirement ????
Navigator.pop(context);
}
Widget _showImage(File imgFile) {
return Scaffold(
body: SafeArea(
child: Stack(
alignment: AlignmentDirectional.topStart,
children: <Widget>[
Positioned(
left: 0.0,
bottom: 0.0,
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: Center(
child: imgFile == null
? Text('No image selected.')
: Image.file(imgFile),
),
),
// more stacks ... not important here....
],
),
),
);
}
Of course, inside pubspec.yaml you add the necessary dependency:
dependencies:
flutter:
sdk: flutter
image_picker: ^0.5.0+3
Add-on:
I tried to add a confirmation-dialog (i.e. to ask the user "Do you really want to cancel").
Now, the above error is gone. However, now the image_picker keeps popping up again and again...overwriting this dialog.
What am I still doing wrong her ??
Widget _cancelBtnPressedWidget(BuildContext context) {
return AlertDialog(
title: Text('Camera Alert'),
content: Text('Are you sure you want to cancel ?'),
actions: <Widget>[
FlatButton(
child: Text('Close'),
onPressed: () {
Navigator.pop(context);
},
)
],
);
}
I finally found an answer:
Indeed, I was able to place a confirmation-dialog and there I was able to place the necessary return Widget.
Now the Cancel for the image_picker is working as expected !
Here is the entire Code:
import 'package:flutter/material.dart';
import 'dart:io';
import 'package:image_picker/image_picker.dart';
class MyImagePickerView extends StatefulWidget {
_MyImagePickerViewState createState() => _MyImagePickerViewState();
}
class _MyImagePickerViewState extends State<MyImagePickerView> {
File _imageFile;
bool _pickImage = true;
int _hashy = 0;
bool _cancelPressed = false;
#override
Widget build(BuildContext context) {
if (_pickImage) {
return FutureBuilder<File>(
future: ImagePicker.pickImage(source: ImageSource.camera),
builder: (BuildContext context, AsyncSnapshot<File> snapshot) {
if (snapshot.hasData) {
_pickImage = false;
_imageFile = snapshot.data;
return _showImage(snapshot.data);
} else {
// when cancel is pressed, the hashCode changes...
if ((_hashy != 0) && (snapshot.hashCode != _hashy)) {
// when cancel pressed
return _cancelBtnPressedWidget(context);
}
_hashy = snapshot.hashCode;
return Scaffold(
body: Center(
child: Text('no image picker available'),
),
);
}
},
);
} else {
if (_cancelPressed) {
return _showAlert();
} else {
return _showImage(_imageFile);
}
}
}
Widget _cancelBtnPressedWidget(BuildContext context) {
_cancelPressed = true;
_pickImage = false;
return Scaffold(
body: Center(
child: Text('Press button to start.'),
),
);
}
Widget _showImage(File imgFile) {
StateContainerState container = StateContainer.of(context);
return Scaffold(
body: SafeArea(
child: Stack(
alignment: AlignmentDirectional.topStart,
children: <Widget>[
Positioned(
left: 0.0,
bottom: 0.0,
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: Center(
child: imgFile == null
? Text('No image selected.')
: Image.file(imgFile),
),
),
// more stacks ... not important here....
],
),
),
);
}
Widget _showAlert() {
return AlertDialog(
title: Text('Camera Alert'),
content: Text('Are you sure you want to cancel the Camera ?'),
actions: <Widget>[
FlatButton(
child: Text('No'),
onPressed: () {
setState(() {
_pickImage = true;
_cancelPressed = false;
});
},
),
FlatButton(
child: Text('Yes'),
onPressed: () {
Navigator.pop(context);
},
),
],
);
}
#override
void dispose() {
_myController.dispose();
super.dispose();
}
}
To me it doesn't seem like you are capturing the click at all. For me I would return a button in the _cancelBtnPressedWidget and in the onPressed call the pop.