flutter change background on click - flutter

I need to change the background color by clicking on the screen to random, I can't figure out how to do it.
import 'package:flutter/widgets.dart';
import 'dart:math';
main() => runApp(
Directionality(
textDirection: TextDirection.ltr,
child: Container(
color: Color((Random().nextDouble() * 0xFFFFFF).toInt()).withOpacity(1.0),
child: MyApp(),
),
),
);
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
child: GestureDetector( // используется как обычный виджет
onTap: () { // одно из свойств GestureDetector
// Этот метод будет вызван, когда дочерний элемент будет нажат
print('You pressed me');
},
),
);
}
}

1. You need to make a StateFulWidget because you want to change the background when tapped.
2. You need to make a list of colors that can be set as the background color.
3. You need to add a variable which holds the current background color's index in the list of colors.
4. You need to change this variable when tapped to set a new background color.
Note: If you want to have random colors you can check the random_color package which is easy to use.
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(title: "Title"),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
MyHomePageState createState() => MyHomePageState();
}
class MyHomePageState extends State<MyHomePage> {
List<Color> _colors = [Colors.blue, Colors.red, Colors.green, Colors.yellow];
var _index = 0;
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: _colors[_index % _colors.length],
body: GestureDetector(
onTap: () {
setState(() {
_index++;
});
},
child: Stack(
children: <Widget>[
Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
color: Colors.transparent,
),
],
)
)
);
}

To do this you want to store the color as part of the state of the widget that you want. Then, when you detect a press, you can change the color and call setState to trigger a rebuild to show the new color. This involves modifying your code to use a StatefulWidget as I have done below.
The following code uses the exact same widgets as your original, with just modifications to make the necessary parts stateful.
import 'package:flutter/widgets.dart';
import 'dart:math';
main() => runApp(
Directionality(
textDirection: TextDirection.ltr,
child: MyApp(),
),
);
class MyApp extends StatefulWidget {//Changed to a `StatefulWidget`
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
//Store the color as a part of your `State`
Color color = Color((Random().nextDouble() * 0xFFFFFF).toInt()).withOpacity(1.0);
#override
Widget build(BuildContext context) {
return Container(
color: color,
child: Container(
child: GestureDetector(
onTap: () {
print('You pressed me');
//`setState` rebuilds your widget to show the new color
//It's not possible to use a `StatelessWidget` here
setState(() {
color = Color((Random().nextDouble() * 0xFFFFFF).toInt()).withOpacity(1.0);
});
},
),
),
);
}
}

Try this
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
debugShowCheckedModeBanner: false,
home: Home(),
);
}
}
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
Color color;
#override
void initState() {
color = Color((Random().nextDouble() * 0xFFFFFF).toInt()).withOpacity(1.0);
super.initState();
}
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
setState(() {
color = Color((Random().nextDouble() * 0xFFFFFF).toInt())
.withOpacity(1.0);
});
},
child: Scaffold(
backgroundColor: color,
),
);
}
}

Related

How to change scaffold colour randomly on clicking separate file's gesturdetector button

I have made two files... one is main.dart and other is homescreen.dart. Homescreen is for scaffold body which is created separately. Now there is a button in home screen for changing colour of scaffold. How to do this?
The main purpose is to know access scaffold from other stateful widget class file...
main.dart
class _MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: SafeArea(child: Scaffold(body: HomeScreen(),)),
);
}
}
homescreen.dart
class _HomeScreenState extends State<HomeScreen> {
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: (){
//My query is to PLACE CODE HERE TO CHANGE SCAFFOLD COLOR ON CLICKING
},
child: Center(
child: Container(
color: Colors.red,
height: 60,
width: 200,
child: Center(child: Text('Change Color',)),
),
),
);
}
}
Try this:
main.dart
import 'package:flutter/material.dart';
import 'home.dart';
import 'dart:math' as math;
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
Color _color = Colors.white;
void changeColor(){
setState(() {
_color = Color((math.Random().nextDouble() * 0xFFFFFF).toInt()).withOpacity(1.0);
});
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: SafeArea(child: Scaffold(
backgroundColor: _color,
body: HomeScreen(changeColor: changeColor,),)),
);
}
}
home.dart
import 'package:flutter/material.dart';
class HomeScreen extends StatelessWidget {
VoidCallback? changeColor;
HomeScreen({Key? key, this.changeColor}) : super(key: key);
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: changeColor,
child: Center(
child: Container(
color: Colors.red,
height: 60,
width: 200,
child: const Center(
child: Text(
'Change Color',
),
),
),
),
);
}
}
You can do it like this :
/// EDIT :
I edit it to get the Color random
import 'dart:math' as math;
class _MyAppState extends State<MyApp> {
Color _newColor = Colors.white; // variable with the color you want to change
final rnd = math.Random(); // random
Color getRandomColor() =>
Color(rnd.nextInt(0xffffffff)); // little function to get the color random
void _changeNewColor() { // function that you are going to send to yout HomeScreen
setState(() {
_newColor = getRandomColor();
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: HomeScreen(change: _changeNewColor), // function
backgroundColor: _newColor, // here the variable
);
}
}
class HomeScreen extends StatelessWidget {
const HomeScreen({
Key? key,
this.change,
}) : super(key: key);
final Function()? change; // instance and get the funct
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: change,
child: Center(
child: Container(
color: Colors.red,
height: 60,
width: 200,
child: const Center(
child: Text(
'Change Color',
)),
),
),
);
}
}

How to scroll the listview or perform any other operation when popupmenu entry appears?

I have created listView which contains 10 container.I trigger the _showCustomMenu() method while longpress the container to show popupmenu.
But could not scroll the listview when popup menu appears.I want to scroll the listview even when popupmenu appears.
This is my code:
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter/rendering.dart';
void main() => runApp(MyApp());
///
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Popup Menu Usage',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Popup Menu Usage'),
);
}
}
///
class MyHomePage extends StatefulWidget {
///
MyHomePage({Key key, this.title}) : super(key: key);
///
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
var _tapPosition;
void _showCustomMenu() {
final RenderBox overlay = Overlay.of(context).context.findRenderObject();
showMenu(
context: context,
items: <PopupMenuEntry<int>>[PopUpMenuEntry()],
position: RelativeRect.fromRect(
_tapPosition &
const Size(40, 40), // smaller rect, the touch area
Offset.zero & overlay.size // Bigger rect, the entire screen
));
}
void _storePosition(TapDownDetails details) {
_tapPosition = details.globalPosition;
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: GestureDetector(
onTapDown:_storePosition,
onLongPress: (){
_showCustomMenu();
},
child:ListView.builder(
itemCount: 10,
itemBuilder: (context,index) {
return Container(height: 500,child: Center(child: Text(index.toString(),style: TextStyle(fontSize: 16),),),);
},
),
),
);
}
}
///
// ignore: must_be_immutable
class PopUpMenuEntry extends PopupMenuEntry<int> {
#override
double height = 100;
// height doesn't matter, as long as we are not giving
// initialValue to showMenu().
#override
bool represents(int n) => n == 1 || n == -1;
#override
PopUpMenuEntryState createState() => PopUpMenuEntryState();
}
///
class PopUpMenuEntryState extends State<PopUpMenuEntry> {
void _onPressed() {
Navigator.pop(context);
}
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
FlatButton(onPressed: _onPressed, child: Text('Copy',style: TextStyle(fontSize: 20),)),
],
);
}
}
This is the Output:
Please help me to solve this or give me suggestion for any other popup widgets to overcome this problem.

How to fix appbar while navigating through pages in flutter?

I want to navigate through screens but I need to change only the content of the body and the appbar stays as it is. I am having 4 files namely main.dart, screen1.dart, screen2.dart, and globals.dart. Screen1 is having a button to goto Screen2 and vice versa. When I clicked the button in screen1 it need to navigate to screen 2 and vice versa, but when I clicked the button nothing is happening. Here is my code:
main.dart
import 'package:demo/globals.dart';
import 'package:demo/screen2.dart';
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
debugShowCheckedModeBanner: false,
home: MyApp(),
),
);
}
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
void initState() {
buildBody = Screen1();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.deepOrange,
title: Text('Fixed AppBar'),
centerTitle: true,
),
body: buildBody,
);
}
}
screen1.dart
import 'package:demo/screen2.dart';
import 'package:flutter/material.dart';
class Screen1 extends StatefulWidget {
#override
_Screen1State createState() => _Screen1State();
}
class _Screen1State extends State<Screen1> {
#override
Widget build(BuildContext context) {
return Container(
color: Colors.green,
child: Center(
child: FlatButton(
child: Text('Goto Screen 2', style: TextStyle(color: Colors.white)),
onPressed: () {
setState(() {
buildBody = Screen2();
});
},
),
),
);
}
}
screen2.dart
import 'package:demo/screen1.dart';
import 'package:flutter/material.dart';
class Screen2 extends StatefulWidget {
#override
_Screen2State createState() => _Screen2State();
}
class _Screen2State extends State<Screen2> {
#override
Widget build(BuildContext context) {
return Container(
color: Colors.brown,
child: Center(
child: FlatButton(
child: Text(
'Goto Screen 1',
style: TextStyle(color: Colors.white),
),
onPressed: () {
setState(() {
buildBody = Screen1();
});
},
),
),
);
}
}
globals.dart
import 'package:flutter/material.dart';
Widget buildBody;
Instead of using Scaffold in main file after MaterialApp
, use it in every separated screen use you custom content and the title you want.
Check out PageView https://api.flutter.dev/flutter/widgets/PageView-class.html
From flutter docs. I think that will work or use Tabs

There are some parts that I don't understand well about Flutter's Key

I practiced after watching a video explaining Flutter's Key.
https://api.flutter.dev/flutter/foundation/Key-class.html
This video shows an example of changing the location of a container with a specific color. (About 1 minute and 50 seconds)
In the video, the statefulwidget says that without a key, the location will not change.
But I wrote the example code myself and confirmed that it worked without giving a key to the stateful widget.
I think I wrote the example code wrong. Below is the code I wrote.
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',
home: KeyPractice(),
);
}
}
class StatefulColorfulTile extends StatefulWidget {
StatefulColorfulTile({#required this.color});
final Color color;
#override
_StatefulColorfulTileState createState() => _StatefulColorfulTileState();
}
class _StatefulColorfulTileState extends State<StatefulColorfulTile> {
#override
Widget build(BuildContext context) {
return Container(
width: 100,
height: 100,
color: widget.color,
);
}
}
class KeyPractice extends StatefulWidget {
#override
_KeyPracticeState createState() => _KeyPracticeState();
}
class _KeyPracticeState extends State<KeyPractice> {
List<Widget> tiles;
#override
void initState() {
super.initState();
tiles = [
StatefulColorfulTile(
color: Colors.blueAccent,
),
StatefulColorfulTile(
color: Colors.amber,
),
];
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Row(
children: tiles,
),
),
floatingActionButton: FloatingActionButton(
child: Icon(
Icons.autorenew,
),
onPressed: () {
setState(() {
tiles.insert(1, tiles.removeAt(0));
});
},
),
);
}
}
The above codes switch positions with each other.
What happens to the example of how the widget does not reposition each other when the stateful widget in the video does not assign keys?
And I understand that the key works only on the Stateful widget, does the Stateless use the key?
And I understood that Key only works with the Stateful widget. I wonder if the Stateless widget uses a key.
If I misunderstood, please teach me.
You're storing the color in the State of KeyPractice. The example they use stores it in the State of the child, in your case: StatefulColorfulTile.
Below is an example of the use of keys to correctly reposition widgets like you're trying to do. My example ended up very similar to what's shown on this medium article. Removing the keys here prevents the widgets from reflecting the color swap, but the use of the keys allows for the intended behavior.
import 'package:flutter/material.dart';
import 'dart:math';
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',
home: KeyPractice(),
);
}
}
class StatefulColorfulTile extends StatefulWidget {
StatefulColorfulTile({Key key}) : super(key: key);
#override
_StatefulColorfulTileState createState() => _StatefulColorfulTileState();
}
class _StatefulColorfulTileState extends State<StatefulColorfulTile> {
final Color myColor = UniqueColorGenerator.getColor();
#override
Widget build(BuildContext context) {
return Container(
width: 100,
height: 100,
color: myColor,
);
}
}
class KeyPractice extends StatefulWidget {
#override
_KeyPracticeState createState() => _KeyPracticeState();
}
class _KeyPracticeState extends State<KeyPractice> {
List<Widget> tiles;
#override
void initState() {
super.initState();
tiles = [
StatefulColorfulTile(key: UniqueKey()),
StatefulColorfulTile(key: UniqueKey()),
];
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Row(
children: tiles,
),
),
floatingActionButton: FloatingActionButton(
child: Icon(
Icons.autorenew,
),
onPressed: () {
setState(() {
tiles.insert(1, tiles.removeAt(0));
});
},
),
);
}
}
class UniqueColorGenerator {
static Random random = new Random();
static Color getColor() {
return Color.fromARGB(255, random.nextInt(255), random.nextInt(255), random.nextInt(255));
}
}

Flutter: Widget State: Is this code safe?

The code below is an example to illustrate this question. The code below works, however the following line:
class WidgetCustom extends StatefulWidget {
has "WidgetCustom" underlined in green in vsCode, and when the cursor is positioned over it, it shows the message:
"This class (or a class this class inherits from) is marked as #immutable, but one or more of its instance fields are not final".
The code works fine.
Is it safe to use this code?
Is there a way to achieve this without the warning?
import 'package:flutter/material.dart';
class WidgetCustom extends StatefulWidget {
_WidgetCustomState _state;
WidgetCustom({#required int iCount}) {
_state = _WidgetCustomState(iCount);
}
#override
State<StatefulWidget> createState() {
return _state;
}
int get getIcount => _state.iCount;
}
class _WidgetCustomState extends State<WidgetCustom> {
int iCount;
_WidgetCustomState(this.iCount);
#override
Widget build(BuildContext context) {
return Container(
child: Row(children: <Widget>[
Column(
children: <Widget>[
RaisedButton(
child: const Text("Please tap me"),
onPressed: () {
setState(() => iCount = iCount + 1);
}),
SizedBox(height: 40),
Text("Tapped $iCount Times")
],
),
]));
}
}
Edited to add main.dart
import 'package:flutter/material.dart';
import 'widgetCustom.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Custom Widget Demo'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
WidgetCustom _widgetCustom;
String _sMessage = "Fab has not been pressed";
#override
void initState() {
super.initState();
_widgetCustom = WidgetCustom(iCount: 99);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Column(children: [
_widgetCustom,
SizedBox(height: 40),
Text(_sMessage),
]),
floatingActionButton: FloatingActionButton(
onPressed: _fabPressed,
tooltip: 'Get Value',
child: Icon(Icons.add),
),
);
}
_fabPressed() {
setState(() => _sMessage =
"Value from last button click = ${_widgetCustom.getIcount}");
}
}
Pass the initial value to the constructor when creating the widget as a final value, and then get it from the State class.
Updated code:
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData.dark(),
home: MyHomePage(title: 'Custom Widget Demo'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
WidgetCustom _widgetCustom;
String _sMessage = "Fab has not been pressed";
int _value = 99;
#override
void initState() {
super.initState();
_widgetCustom = WidgetCustom(iCount: _value, function: _update);
}
void _update(int value) {
setState(() {
_value = value;
_widgetCustom = WidgetCustom(iCount: _value, function: _update);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(widget.title)),
body: Column(
children: [
_widgetCustom,
SizedBox(height: 40),
Text(_sMessage),
],
),
floatingActionButton: FloatingActionButton(
onPressed: _fabPressed,
tooltip: 'Get Value',
child: Icon(Icons.add),
),
);
}
_fabPressed() {
setState(() => _sMessage = "Value from last button click = ${_value}");
}
}
class WidgetCustom extends StatefulWidget {
final int iCount;
final Function function;
WidgetCustom({#required this.iCount, this.function});
#override
State<StatefulWidget> createState() {
return _WidgetCustomState();
}
}
class _WidgetCustomState extends State<WidgetCustom> {
int _iCount;
#override
void initState() {
super.initState();
_iCount = widget.iCount;
}
#override
Widget build(BuildContext context) {
return Container(
child: Row(
children: <Widget>[
Column(
children: <Widget>[
RaisedButton(child: const Text("Please tap me"), onPressed: (){
_iCount = _iCount + 1;
widget.function(_iCount);
}),
SizedBox(height: 40),
Text("Tapped $_iCount Times")
],
),
],
),
);
}
}