For color, I can use dialogBackgroundColor property to give AlertDialog background my own color.
I was looking to use Gradient as my background. How can I use that? DecoratedBox is something that will be needed, but I don't know what to wrap in what. Can anyone give me idea or link for the same?
You can add a Container inside which will be decorated with gradient. For example:
class GradientDialog extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return new _GradientDialogState();
}
}
class _GradientDialogState extends State<GradientDialog> {
#override
Widget build(BuildContext context) {
return AlertDialog(
content: Container(
padding: const EdgeInsets.all(8.0),
decoration: new BoxDecoration(
gradient: new LinearGradient(
colors: AppColors.BG_GRADIENT,
begin: Alignment.topCenter,
end: Alignment.bottomCenter)),
child: YourContentInside(),
),
contentPadding: EdgeInsets.all(0.0),
);
}
}
Open it with
showDialog(
context: context,
barrierDismissible: true,
builder: (BuildContext context) {
return GradientDialog();
});
In build method of AlertDialog there is return Dialog(child: dialogChild, shape: shape);. In Dialog.build() - it returns Material(color: _getColor(context), .... There is no way to set gradient background for AlertDialog without customization.
I can add example if it'll be needed.
P.S. Or you can call showDialog and send another widget instead of AlertDialog.
Related
Is there a way to use setState with StatelessWidget?
I know that I could be used with StatefulWidget and using a State, but I don't know if there's a way to use it with StatelessWidget.
I think that's a direct question and it doesn't need code to be shown.
If you could help me, I will appreciate it.
here is an example of code that makes it possible for a StatelessWidget to update itself, its from an article of Didier Boelens.
https://www.didierboelens.com/2019/09/flutter-internals/
The following useless code makes possible for a StatelessWidget to
update itself (as if it was a StatefulWidget but without using any
setState()), by using the BuildContext …
void main(){
runApp(MaterialApp(home: TestPage(),));
}
class TestPage extends StatelessWidget {
// final because a Widget is immutable (remember?)
final bag = {"first": true};
#override
Widget build(BuildContext context){
return Scaffold(
appBar: AppBar(title: Text('Stateless ??')),
body: Container(
child: Center(
child: GestureDetector(
child: Container(
width: 50.0,`enter code here`
height: 50.0,
color: bag["first"] ? Colors.red : Colors.blue,
),
onTap: (){
bag["first"] = !bag["first"];
//
// This is the trick
//
(context as Element).markNeedsBuild();
}
),
),
),
);
}
}
Between us, when you are invoking the setState() method, the latter
ends up doing the very same thing: _element.markNeedsBuild().
No. That's the whole point of StatelessWidget: It doesn't have a state.
Only StatefulWidget has a state, and therefore only it has a setState.
I have a TextFormField that reloads the current screen when I tap on it to enter text. When I tap on the formfield the software keyboard is displayed briefly before the entire screen reloads and renders all the widgets again. I am running the app on an Android device.
Container(
child: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
TextFormField(
validator: (value) {
if (value.isEmpty) {
return 'Your input cannot be empty';
}
},
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0),
child: RaisedButton(
onPressed: () {
if (_formKey.currentState.validate()) {
print('validated');
}
},
child: Text('Save'),
),
),
],
),
),
margin: EdgeInsets.only(top:8.0),
),
The problem is that the controller of the TextFormField is rebuild when you click on the field, and that's the reason of your issue.
So to solve that, did you try to create a Statefull widget and then creating a TextEditingController in the State of this widget and passing it as an argument to the TextFormField ?
I had the same Problem. this was my code
class MainPage extends StatefulWidget {
#override
_MainPageState createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
Model model = Model();
#override
Widget build(BuildContext context) {
GlobalKey<FormState> _formKey = GlobalKey<FormState>();
var mediaWidth = MediaQuery.of(context).size.width / 2.0;
return Scaffold(
...
and I solved this problem by declaring the _formKey outside of build method. and this worked for me.
class MainPage extends StatefulWidget {
#override
_MainPageState createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
Model model = Model();
GlobalKey<FormState> _formKey = GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
var mediaWidth = MediaQuery.of(context).size.width / 2.0;
return Scaffold(
...
hope it will help you
Yes, that happens because when the keyboard appears, the flutter scaffold gets resize to the current available screen size. So, we can easily handle this by preventing the scaffold size change. I suggest to set scaffold resizeToAvoidBottomInset property false. If it's true the body and the scaffolds floating widgets should size themselves to avoid the onscreen keyboard whose height is defined by the ambient MediaQuery's, MediaQueryData,viewInsets bottom property.
Solution:
resizeToAvoidBottomInset: false,
Complete example:
#override
Widget build(BuildContext context) {
setDisplayData();
return Scaffold(
resizeToAvoidBottomInset: false,
appBar: getAppBar(),
body: OrientationBuilder(
builder: (context, orientation) {
return orientation == Orientation.portrait
? _buildVerticalLayout()
: _buildHorizontalLayout();
},
),
);
Check if you are using MediaQueries wrongly in your project, I had similar issue and it stopped when I changed the MediaQuery
in my case:
Size _size = MediaQuery.of(context).size;
removing this piece of code fixed my app.
When TextFormField focused the size of screen will changed because of the appearance of keyboard, that cause rebuild of state, you cant prevent re-build of state.
Instead of trying prevent re-build state, you need to solve problems which happen when state do re-build, one of common problem is declaration and initialization variables inside build(BuildContext context){ ... }' function.
The main problem, when you need to get some data related of context (like size of screen), in this case I prefer to pass this value from parent Widget...
For example this code will cause problem when re-build state:
#override
Widget build(BuildContext context) {
double? _screenHeight = MediaQuery.of(context).size.height;
return Container();
}
To solve problem get _screenHeight from parent, to know how to do that look at https://stackoverflow.com/a/50289032/2877427
I would like to create a new widget class with a container size of 250x500 with the rest of the class/widget 0.5 opacity - allowing the prior widget - we launched from - to be partially visible.
Is this possible ? if so how ?
-Thanks
Below is the Stateful class I am calling
class ShowMyTitles extends StatefulWidget {
#override
_ShowMyTitlesState createState() => _ShowMyTitlesState();
}
class _ShowMyTitlesState extends State<ShowMyTitles> {
List<Map<String, bool>> myListOfMapTitles;
Map<String, bool> valuesHeaders;
int trueCount = 0;
#override
void initState() {
// TODO: implement initState
super.initState();
SettingsForMap SFM = new SettingsForMap();
myListOfMapTitles = SFM.myListOfMapTitles;
valuesHeaders = SFM.valuesHeaders;
}
#override
Widget build(BuildContext context) {
List myTitles = [];
return new WillPopScope(
onWillPop: (){
myListOfMapTitles.forEach((valuesAll) {
valuesAll.forEach((s,b){
if(b == true) {
myTitles.add(s);
print('My Selecteed titles are = ' + s.toString());
}
});
});
Navigator.pop(context, myTitles);
},
child: new Container(
child: new GestureDetector(
onTap: (){
myListOfMapTitles.forEach((valuesAll) {
valuesAll.forEach((s,b){
if(b == true) {
myTitles.add(s);
print('My Selecteed titles are = ' + s.toString());
}
});
});
Navigator.pop(context, myTitles);
},
child: _titlesDialog(context, 'Select 2 Titles (Max)'),
),
),
);
}
There is an Opacity widget. Wrap the widget you want to be transparent within it.
Opacity(child:MyTransparentWidget(),opacity:0.45)
You can use Stack widget for that.
Surround the widget which you want to change the opacity and the container with Stack widget.
Then wrap the widget which you want to change the opacity with Opacity widget and mention required opacity.
Make sure you put the container after the widget which you want to change the opacity then only it will sit above the transparent widget
To make any widget transparent, you make that widget a child of a parent Theme() widget. e.g
class TransparentWidget extends StatelessWidget {
#override Widget build(BuildContext context) {
return Theme(
data: Theme.of(context).copyWith(
// Set the transparency here
canvasColor: Colors.white70, //or any other color you want. e.g Colors.blue.withOpacity(0.5)
),
child: Container(
height: 250.0,
width: 250.0,
child: Text("Hello World")
)
);
}
}
OR
Simply make the main container background decoration an opaque color.
Container(
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.7),
)
);
To implement a color picker, I want to draw a rectangle with a gradient of colors inside. I tried to use a container with a DecoratedBox but it didn't quite work, as I had to give it a width, and I wanted it to fill its parent.
What is the best way to draw a Gradient in flutter?
It sounds like you already know how to draw a gradient and your question is more about how to make a DecoratedBox as big as possible.
If your DecoratedBox appears in a Column or Row, consider wrapping it in an Expanded and setting the crossAxisAlignment to CrossAxisAlignment.stretch.
If your DecoratedBox is a child of a widget that doesn't provide a size to its child (e.g. Center), try wrapping it in a ConstrainedBox with a constraints of new BoxConstraints.expand(). Here's an example:
import 'package:flutter/material.dart';
void main() {
runApp(new MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Gradient Example',
home: new MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Gradient Example'),
),
body: new Center(
child: new ConstrainedBox(
constraints: new BoxConstraints.expand(),
child: new DecoratedBox(
decoration: new BoxDecoration(
gradient: new LinearGradient(
colors: <Color>[Colors.red, Colors.blue]
),
),
),
),
),
);
}
}
I am trying to change the color of the element the user clicked on using a GestureDetector:
new GestureDetector(
onTap: (){
// Change the color of the container beneath
},
child: new Container(
width: 80.0,
height: 80.0,
margin: new EdgeInsets.all(10.0),
color: Colors.orange,
),
),
The problem is that I can't use setState inside of onTap. Otherwise I would have created a color variable. Any suggestions?
You can use setState() inside of onTap. In fact, that's exactly the right thing to do in this situation. If you are having trouble calling setState(), make sure your widget is stateful (see the interactivity tutorial).
You might also want to check out FlatButton or InkWell as more material-y ways to capture touches. If you really want a GestureDetector, read up on HitTestBehavior to make sure you're configuring it correctly.
Here's an example that changes to a random color every time it's clicked.
import 'dart:math';
import 'package:flutter/material.dart';
void main() {
runApp(new MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
home: new MyHome(),
);
}
}
class MyHome extends StatefulWidget {
#override
State createState() => new _MyHomeState();
}
class _MyHomeState extends State<MyHome> {
final Random _random = new Random();
Color _color = Colors.orange;
#override
Widget build(BuildContext context) {
return new Scaffold(
body: new Center(
child: new GestureDetector(
onTap: () {
// Change the color of the container beneath
setState(() {
_color = new Color.fromRGBO(
_random.nextInt(256),
_random.nextInt(256),
_random.nextInt(256),
1.0
);
});
},
child: new Container(
width: 80.0,
height: 80.0,
margin: new EdgeInsets.all(10.0),
color: _color,
),
),
),
);
}
}