Flutter How to pass a parameter (int) to callbacks? - flutter

How can I pass a parameter wit callback in Flutter?
I have two files main.dart and block.dart. My goal is to add an int (12 for example) to myCallback in block.dart to use it in main.dart in the function whatToDo (instead of print ('Should receive the Value from myCallback');)
Here is the code of the main.dart File:
import 'package:flutter/material.dart';
import 'block.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MainBlock(),
);
}
}
class MainBlock extends StatefulWidget {
#override
_MainBlockState createState() => _MainBlockState();
}
class _MainBlockState extends State<MainBlock> {
void whatToDo() {
print('Should receive the Value from myCallback');
}
#override
Widget build(BuildContext context) {
// print(getraenke.asMap());
// print(getraenke.asMap().keys);
// print(getraenke);
return Scaffold(
body: Container(
margin: EdgeInsets.all(30.0),
color: Color(0xFF122C39),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(
child: Block(
myCallback: whatToDo,
),
),
],
),
),
);
}
}
And here is the Code from block.dart with the callback:
import 'package:flutter/material.dart';
class Block extends StatelessWidget {
final Function myCallback;
Block({this.myCallback});
#override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.all(10.0),
color: Color(0xFF722662),
child: Center(
child: GestureDetector(
onTap: myCallback,
child: Text(
'Button',
style: TextStyle(
color: Color(0xFFFFFFFF),
fontSize: 22.0,
),
),
),
),
);
}
}

If I understood it correctly, You want your function to accept a parameter.
do it like this.
class Block extends StatelessWidget {
final Function(int num) myCallback;
Block({this.myCallback});
and when you call it, you provide it with the parameter
GestureDetector(
onTap:()=> myCallback(12),
child: ...
and finally you can access it from your main
void whatToDo(int num) {
print(num);
}

Simple way without any advanced topic. Better read some articles about state management. Official documentation.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MainBlock(),
);
}
}
class MainBlock extends StatefulWidget {
#override
_MainBlockState createState() => _MainBlockState();
}
class _MainBlockState extends State<MainBlock> {
void whatToDo(int value) {
print('Should receive the Value from myCallback');
print(value);
}
#override
Widget build(BuildContext context) {
// print(getraenke.asMap());
// print(getraenke.asMap().keys);
// print(getraenke);
return Scaffold(
body: Container(
margin: EdgeInsets.all(30.0),
color: Color(0xFF122C39),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(
child: Block(
myCallback: whatToDo,
),
),
],
),
),
);
}
}
class Block extends StatelessWidget {
final void Function(int) myCallback;
Block({required this.myCallback});
#override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.all(10.0),
color: Color(0xFF722662),
child: Center(
child: GestureDetector(
onTap: ()=>myCallback(12),
child: Text(
'Button',
style: TextStyle(
color: Color(0xFFFFFFFF),
fontSize: 22.0,
),
),
),
),
);
}
}

in main.dart:
void whatToDo(int value) {
print('the value is $value');
}
in block.dart:
class Block extends StatelessWidget {
final ValueChanged<int> myCallback;
Block({required this.myCallback});
#override
Widget build(BuildContext context) {
return Container(
margin: const EdgeInsets.all(10.0),
color: const Color(0xFF722662),
child: Center(
child: GestureDetector(
onTap: () => myCallback(100),
child: const Text(
'Button',
style: TextStyle(
color: Color(0xFFFFFFFF),
fontSize: 22.0,
),
),
),
),
);
}
}

I add more info to Ethsan Askari's answer.
You can define your custom callback and reuse it throughout your app.
typedef OnWhatToDoCallback = Function(int value);
class Block extends StatefulWidget {
const Block({
Key? key,
required this.onWhatToDo,
}) : super(key: key);
final OnWhatToDoCallback onWhatToDo;
...
}

Related

How to change variable with getx?

As in the codes I mentioned below, my question is actually simple, but I couldn't find a simple answer on the internet. All the sources I found are going through the same example. There is no simple explanation, but there is good stackoverflow. Let me ask my question without further ado.
I can specify a variable in getx and print that variable on other pages. What I want to do now is I want to change the getx variable in the main file, how can I do that?
I'm posting the wrong version of the code I want to do below for you to understand.
code in getx folder
class numcontroller extends GetxController {
var derece = 20.obs;
}
code is second page
numcontroller deneme = Get.put(numcontroller());
Container(
margin: const EdgeInsets.fromLTRB(27, 10, 0, 0),
child: Row(
children: [
Container(
margin: const EdgeInsets.fromLTRB(5, 0, 0, 0),
child: Text('${deneme.derece.value}',
style: const TextStyle(
fontSize: 45,
fontFamily: 'YesevaOne',
color: Color(0xFF2d4b70)),
),
),
The code I want to run in main.dart
derece = 20
or
derece = 30
When I change the degree manually on main.dart, I want it to change on the second page as well.
EDİTİNG
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:teemapp4/Controller/switch_controller.dart';
import 'routes/app_pages.dart';
import 'routes/app_routes.dart';
import 'themes/app_theme.dart';
//0xFF2d4b70
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return GetMaterialApp(
initialRoute: AppRoutes.DASHBOARD,
getPages: AppPages.list,
debugShowCheckedModeBanner: false,
theme: AppTheme.light,
darkTheme: AppTheme.dark,
themeMode: ThemeMode.system,
);
}
}
this is my main.dart code but i am using a bottombar i made with getx. I'm looking for how to change the data in that file through this code.
I don't think So you need to update your main.dart file.
You can add a button on your first page to update values like:
firstPage.dart
class FirstPage extends StatelessWidget {
FirstPage({Key? key}) : super(key: key);
NumController numController = Get.put(NumController());
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: Column(
children: [
ElevatedButton(
onPressed: () {
numController.updateDerece(30);
},
child: Text(
"Update Value",
),
),
ElevatedButton(
onPressed: () {
Get.to(() => SecondPage());
},
child: Text("Go To Second Screen"),
),
],
),
),
);
}
}
secondPage.dart
class SecondPage extends StatelessWidget {
SecondPage({Key? key}) : super(key: key);
NumController numController = Get.find<NumController>();
#override
Widget build(BuildContext context) {
return Container(
child: Text(
numController.derece.toString(),
),
);
}
}
Or You can directly update the value on your second page like:
secondPage.dart
class SecondPage extends StatelessWidget {
SecondPage({Key? key}) : super(key: key);
NumController numController = Get.put(NumController());
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: Column(
children: [
ElevatedButton(
onPressed: () {
//Any Number You can pass in Function
numController.updateDerece(30);
},
child: Text(
"Update Value",
),
),
Obx(
() => Container(
child: Text(
numController.derece.toString(),
),
),
),
],
),
),
);
}
}
numController.dart
import 'package:get/get.dart';
class NumController extends GetxController {
var _derece = 20.obs;
int get derece => _derece.value;
void updateDerece(int value) {
_derece.value = value;
}
}
Try using this way. And update your derece variable value using updateDerece method.
var _derece = 20.obs;
double get derece => _derece.value;
void updateDerece(double value) {
_derece.value = value;
}
////
Obx(() {
return Container(
margin: const EdgeInsets.fromLTRB(27, 10, 0, 0),
child: Row(
children: [
Container(
margin: const EdgeInsets.fromLTRB(5, 0, 0, 0),
child: Text(
'${deneme.derece}',
style: const TextStyle(
fontSize: 45,
fontFamily: 'YesevaOne',
color: Color(0xFF2d4b70)),
),
),
],
),
);
})

flutter dependOnInheritedWidgetOfExactType() returns null

I am trying to use InheritedWidget approach to share state down the Widget tree. For this, I am making a simple counter app. You can add, subtract, multiply or divide the counter however you like.
It's a small demo so best practices are not followed. The line with code context.dependOnInheritedWidgetOfExactType<MyInheritedWidget>() seem to be null for some reason. When looking at samples and doc, it should find the MyInheritedWidget in the widget tree and return it. However, I am getting complaints from flutter tool that it is null. And, in deed it is null when asserted as well.
What is the reasoning here for failed return here? And, how do I need to do it such that I can receive the instance?
File: main.dart
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Counter(),
);
}
}
class Counter extends StatefulWidget {
const Counter({Key? key}) : super(key: key);
#override
CounterState createState() => CounterState();
}
class CounterState extends State<Counter> {
int counter = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Counter App'),
centerTitle: true,
),
body: MyInheritedWidget(
counterState: this,
child: Builder(
builder: (BuildContext innerContext) {
return CounterViewer(
counterState: MyInheritedWidget.of(context).counterState);
},
),
),
);
}
void addCounter(int value) {
setState(() {
counter++;
});
}
void subtractCounter(int value) {
setState(() {
counter--;
});
}
void multiplyCounter(int value) {
setState(() {
counter *= value;
});
}
void divideCounter(int value) {
setState(() {
counter = (counter / value).toInt();
});
}
}
class MyInheritedWidget extends InheritedWidget {
final CounterState counterState;
const MyInheritedWidget(
{Key? key, required Widget child, required this.counterState})
: super(key: key, child: child);
static MyInheritedWidget of(BuildContext context) {
final MyInheritedWidget? widget =
context.dependOnInheritedWidgetOfExactType<MyInheritedWidget>();
assert(widget != null);
return widget!;
}
#override
bool updateShouldNotify(covariant InheritedWidget oldWidget) {
return true;
}
}
class CounterViewer extends StatelessWidget {
final CounterState counterState;
const CounterViewer({Key? key, required this.counterState}) : super(key: key);
#override
Widget build(BuildContext context) {
return Column(
children: [
Container(
color: Colors.green.shade200,
width: MediaQuery.of(context).size.width,
height: 180,
child: Center(
child: Text(
'220',
style: TextStyle(
color: Colors.grey.shade50,
fontSize: 60,
fontWeight: FontWeight.bold,
),
),
),
),
Container(
color: Colors.grey.shade300,
padding: EdgeInsets.symmetric(vertical: 16),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
onPressed: () {},
child: Text('Add'),
),
ElevatedButton(
onPressed: () {},
child: Text('Subtract'),
),
ElevatedButton(
onPressed: () {},
child: Text('Multiply'),
),
ElevatedButton(
onPressed: () {},
child: Text('Divide'),
),
],
),
)
],
);
}
}
Update: I seem to have passed the wrong context to the dependOnInheritedWidgetOfExactType() method. Changing from context to innerContext fixed the issue.
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Counter App'),
centerTitle: true,
),
body: MyInheritedWidget(
counterState: this,
child: Builder(
builder: (BuildContext innerContext) {
return CounterViewer(
counterState: MyInheritedWidget.of(innerContext).counterState);
},
),
),
);
}

Flutter: How To Change/Refresh State From Another Widget

I am trying to have a global integer that is displayed in a widget and then is updated by something (a button click or something) from another widget. All of the other ways i have tried don't work. What is the best way to do this?
Stack overflow says i have too much code so more text more text more text
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
home: Scaffold(
body: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ScoreDisplay(),
PointButton(),
],
),
),
),
),
);
}
int score = 0;
class ScoreDisplay extends StatefulWidget {
#override
_ScoreDisplayState createState() => _ScoreDisplayState();
}
class _ScoreDisplayState extends State<ScoreDisplay> {
#override
Widget build(BuildContext context) {
return Center(
child: Container(
child: Text(
'Score: $score',
),
),
);
}
}
class PointButton extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Center(
child: Container(
child: RaisedButton(
//onPressed: //increment score,
),
),
);
}
}
You need to implement some kind of State Management for that.
Here are two basic ways to implement such a feature: with a StatefulWidget and with Riverpod.
1. With a StatefulWidget
I extracted your Scaffold as a StatefulWidget maintaining the score of your application.
I then use ScoreDisplay as a pure StatelessWidget receiving the score as a parameter. And your PointButton is also Stateless and call the ScorePage thanks to a simple VoidCallback function.
Full source code:
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
home: ScorePage(),
),
);
}
class ScorePage extends StatefulWidget {
const ScorePage({
Key key,
}) : super(key: key);
#override
_ScorePageState createState() => _ScorePageState();
}
class _ScorePageState extends State<ScorePage> {
int score = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ScoreDisplay(score: score),
PointButton(onIncrement: () => setState(() => score++)),
],
),
),
);
}
}
class ScoreDisplay extends StatelessWidget {
final int score;
const ScoreDisplay({Key key, this.score}) : super(key: key);
#override
Widget build(BuildContext context) {
return Center(
child: Container(
child: Text(
'Score: $score',
),
),
);
}
}
class PointButton extends StatelessWidget {
final VoidCallback onIncrement;
const PointButton({Key key, this.onIncrement}) : super(key: key);
#override
Widget build(BuildContext context) {
return Center(
child: Container(
child: ElevatedButton(
onPressed: () => onIncrement?.call(),
child: Text('CLICK ME'),
),
),
);
}
}
2. With Riverpod
Create a StateProvider:
final scoreProvider = StateProvider<int>((ref) => 0);
Watch the StateProvider:
final score = useProvider(scoreProvider).state;
Update the StateProvider
context.read(scoreProvider).state++
Full Source Code
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
void main() {
runApp(
ProviderScope(
child: MaterialApp(
home: Scaffold(
body: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ScoreDisplay(),
PointButton(),
],
),
),
),
),
),
);
}
int score = 0;
class ScoreDisplay extends HookWidget {
#override
Widget build(BuildContext context) {
final score = useProvider(scoreProvider).state;
return Center(
child: Container(
child: Text(
'Score: $score',
),
),
);
}
}
class PointButton extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Center(
child: Container(
child: ElevatedButton(
onPressed: () => context.read(scoreProvider).state++,
child: Text('CLICK ME'),
),
),
);
}
}
final scoreProvider = StateProvider<int>((ref) => 0);
Check Riverpod Website for more info and more advanced use cases.
But you have many more flavors of State Management available.
The best example is to use "provider" package which can be found on www.pub.dev
It is very easy state management package that can help You solve this problem. Keep in my that provider instead of setState() uses notifyListener()

Get the rack to update after shuffle

In the example below, what is the best construct to use to get the rack to update after a shuffle?
It seems to me that when a StatefulWidget is created, with its corresponding State Object (SO), any method that you can call from elsewhere is a method that's attached to the widget itself (not to the SO).
But, to get the widget to update its display, the SetState() method can only go in the SO's method(s). So how does the method on the widget call a method on its SO?
import 'package:flutter/material.dart';
List<Block> g_blocks = [Block(Colors.red), Block(Colors.green), Block(Colors.blue)];
Rack g_rack = new Rack();
void main() => runApp(MyApp());
// This widget is the root of your application.
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
fontFamily: 'PressStart',
),
home: MyHomeScreen(),
);
}
}
class MyHomeScreen extends StatefulWidget {
MyHomeScreen({Key key}) : super(key: key);
createState() => MyHomeScreenState();
}
class MyHomeScreenState extends State<MyHomeScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Center(child: Text('Thanks for your help')),
backgroundColor: Colors.pink,
),
body: Center(
child: g_rack,
),
bottomNavigationBar: SizedBox(
height: 100.0,
child: BottomNavigationBar(
currentIndex: 0,
iconSize: 48.0,
backgroundColor: Colors.lightBlue[100],
items: [
BottomNavigationBarItem(
label: 'Shuffle',
icon: Icon(Icons.home),
),
BottomNavigationBarItem(
label: 'Shuffle',
icon: Icon(Icons.home),
),
],
onTap: (int indexOfItem) {
setState(() {
g_blocks.shuffle;
rack.updateScreen(); // ** How to get the rack to update? **
});
},
),
),
);
} // build
} // End class MyHomeScreenState
class Rack extends StatefulWidget {
#override
_rackState createState() => _rackState();
}
class _rackState extends State<Rack> {
#override
Widget build(BuildContext context) {
return Container(
height: 150.0,
color: Colors.yellow[200],
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisSize: MainAxisSize.max,
children: g_blocks),
);
}
void updateRack(){
setState(() {
g_blocks.shuffle;
});
}
}
class Block extends StatelessWidget {
final Color color;
Block(this.color);
#override
Widget build(BuildContext context) {
return Container(height:50,width:50, color: color,);
}
}
Here is a solution where I try to decouple the State Management and Business Logic of the application from the User Interface.
I used the following packages:
freezed for the Domain Entities
hooks_riverpod for the State Management
1. Domain Layer: Entities
We need two Entities to model our Racks of Blocks.
Blocks are defined by their color.
Blocks have no business logic.
Racks are ordered lists of Blocks.
Racks can get shuffled.
Racks can be randomly created for a (random or given) number of Blocks
#freezed
abstract class Block with _$Block {
const factory Block({Color color}) = _Block;
}
#freezed
abstract class Rack implements _$Rack {
const factory Rack({List<Block> blocks}) = _Rack;
const Rack._();
static Rack create([int nbBlocks]) => Rack(
blocks: List.generate(
nbBlocks ?? 4 + random.nextInt(6),
(index) => Block(
color: Color(0x66000000 + random.nextInt(0xffffff)),
),
),
);
Rack get shuffled => Rack(blocks: blocks..shuffle());
}
We use the freeze package to have immutability and the precious copyWith method to manage our States.
2. Application Layer: State Management
We use Hooks Riverpod for our State Management. We just need one StateNotifier and its provider.
This StateNotifierProvider gives access to both the Rack State and the core functionalities that are deal() and shuffle().
class RackStateNotifier extends StateNotifier<Rack> {
static final provider =
StateNotifierProvider<RackStateNotifier>((ref) => RackStateNotifier());
RackStateNotifier([Rack state]) : super(state ?? Rack.create());
void shuffle() {
state = state.shuffled;
}
void deal() {
state = Rack.create();
}
}
3. Presentation Layer: User Interface
The User Interface is made of four Widgets:
AppWidget [StatelessWidget]
HomePage [HookWidget]
RackWidget [StatelessWidget]
BlockWidget [StatelessWidget]
As you see, the only Widget that really cares about the State of the Application is the HomePage.
3.1 AppWidget
class AppWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
primaryColor: Colors.amber,
accentColor: Colors.black87,
),
home: HomePage(),
);
}
}
3.2 HomePage
class HomePage extends HookWidget {
#override
Widget build(BuildContext context) {
final rack = useProvider(RackStateNotifier.provider.state);
return Scaffold(
appBar: AppBar(
title: Row(
children: const [
Icon(Icons.casino_outlined),
SizedBox(
width: 8.0,
),
Text('Rack Shuffler'),
],
),
),
body: Center(
child: RackWidget(rack: rack),
),
bottomNavigationBar: BottomAppBar(
color: Theme.of(context).primaryColor,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
IconButton(
icon: Icon(Icons.refresh),
iconSize: 48,
onPressed: () => context.read(RackStateNotifier.provider).deal(),
),
IconButton(
icon: Icon(Icons.shuffle),
iconSize: 48,
onPressed: () =>
context.read(RackStateNotifier.provider).shuffle(),
),
],
),
),
);
}
}
rack is provided by our StateNotifierProvider, in watch mode:
final rack = useProvider(RackStateNotifier.provider.state);
The Racks are dealt and shuffled using the same provider, in read mode:
...
context.read(RackStateNotifier.provider).deal(),
...
context.read(RackStateNotifier.provider).shuffle(),
...
3.3 RackWidget
class RackWidget extends StatelessWidget {
final Rack rack;
const RackWidget({Key key, this.rack}) : super(key: key);
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: LayoutBuilder(
builder: (context, constraints) {
return Row(
children: rack.blocks
.map((block) => BlockWidget(
block: block,
size: constraints.biggest.width / rack.blocks.length))
.toList(),
);
},
),
);
}
}
Basic StatelessWidget. We use a LayoutBuilder to define the size of the BlockWidgets.
3.4 BlockWidget
class BlockWidget extends StatelessWidget {
final Block block;
final double size;
const BlockWidget({
Key key,
this.block,
this.size,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return SizedBox(
width: size,
height: size,
child: Padding(
padding: EdgeInsets.all(size / 10),
child: Container(
decoration: BoxDecoration(
color: block.color,
border: Border.all(color: Colors.black87, width: size / 20),
borderRadius: BorderRadius.circular(size / 15),
),
),
),
);
}
}
Another basic StatelessWidget.
Full Application Code
Just copy-paste the following to try it out.
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
part '66053795.shuffle.freezed.dart';
Random random = Random();
void main() => runApp(ProviderScope(child: AppWidget()));
class AppWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
primaryColor: Colors.amber,
accentColor: Colors.black87,
),
home: HomePage(),
);
}
}
class HomePage extends HookWidget {
#override
Widget build(BuildContext context) {
final rack = useProvider(RackStateNotifier.provider.state);
return Scaffold(
appBar: AppBar(
title: Row(
children: const [
Icon(Icons.casino_outlined),
SizedBox(
width: 8.0,
),
Text('Rack Shuffler'),
],
),
),
body: Center(
child: RackWidget(rack: rack),
),
bottomNavigationBar: BottomAppBar(
color: Theme.of(context).primaryColor,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
IconButton(
icon: Icon(Icons.refresh),
iconSize: 48,
onPressed: () => context.read(RackStateNotifier.provider).deal(),
),
IconButton(
icon: Icon(Icons.shuffle),
iconSize: 48,
onPressed: () =>
context.read(RackStateNotifier.provider).shuffle(),
),
],
),
),
);
}
}
class RackWidget extends StatelessWidget {
final Rack rack;
const RackWidget({Key key, this.rack}) : super(key: key);
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: LayoutBuilder(
builder: (context, constraints) {
return Row(
children: rack.blocks
.map((block) => BlockWidget(
block: block,
size: constraints.biggest.width / rack.blocks.length))
.toList(),
);
},
),
);
}
}
class BlockWidget extends StatelessWidget {
final Block block;
final double size;
const BlockWidget({
Key key,
this.block,
this.size,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return SizedBox(
width: size,
height: size,
child: Padding(
padding: EdgeInsets.all(size / 10),
child: Container(
decoration: BoxDecoration(
color: block.color,
border: Border.all(color: Colors.black87, width: size / 20),
borderRadius: BorderRadius.circular(size / 15),
),
),
),
);
}
}
class RackStateNotifier extends StateNotifier<Rack> {
static final provider =
StateNotifierProvider<RackStateNotifier>((ref) => RackStateNotifier());
RackStateNotifier([Rack state]) : super(state ?? Rack.create());
void shuffle() {
state = state.shuffled;
}
void deal() {
state = Rack.create();
}
}
#freezed
abstract class Block with _$Block {
const factory Block({Color color}) = _Block;
}
#freezed
abstract class Rack implements _$Rack {
const factory Rack({List<Block> blocks}) = _Rack;
const Rack._();
static Rack create([int nbBlocks]) => Rack(
blocks: List.generate(
nbBlocks ?? 4 + random.nextInt(6),
(index) => Block(
color: Color(0x66000000 + random.nextInt(0xffffff)),
),
),
);
Rack get shuffled => Rack(blocks: blocks..shuffle());
}
Here is a solution using a GlobalKey.
It feels pretty inelegant. It surprises me that with the close relationship between the widget and its state object, there's no easy way for a widget's method to call a method on the SO. The "widget.blah" construct provides a way for the SO to access the widget's data, is there a reason for not having a similar "state.myMethod" construct?
Anyway, the following works:
import 'package:flutter/material.dart';
List<Block> g_blocks = [Block(Colors.red), Block(Colors.green),
Block(Colors.blue), Block(Colors.purple)];
GlobalKey g_key = GlobalKey();
Rack g_rack = new Rack(key: g_key);
void main() => runApp(MyApp());
// This widget is the root of your application.
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
fontFamily: 'PressStart',
),
home: MyHomeScreen(),
);
}
}
class MyHomeScreen extends StatefulWidget {
MyHomeScreen({Key key}) : super(key: key);
createState() => MyHomeScreenState();
}
class MyHomeScreenState extends State<MyHomeScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Center(child: Text('Thanks for your help')),
backgroundColor: Colors.pink,
),
body: Center(
child: g_rack,
),
bottomNavigationBar: SizedBox(
height: 100.0,
child: BottomNavigationBar(
currentIndex: 0,
iconSize: 48.0,
backgroundColor: Colors.lightBlue[100],
items: [
BottomNavigationBarItem(
label: 'Shuffle',
icon: Icon(Icons.home),
),
BottomNavigationBarItem(
label: 'Shuffle',
icon: Icon(Icons.home),
),
],
onTap: (int index) {
g_blocks.shuffle();
g_key.currentState.setState(() {
});
}
),
),
);
} // build
} // End class MyHomeScreenState
class Rack extends StatefulWidget {
Rack({Key key}) : super(key: key);
#override
_rackState createState() => _rackState();
}
class _rackState extends State<Rack> {
#override
Widget build(BuildContext context) {
return Container(
height: 150.0,
color: Colors.yellow[200],
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.max,
children: g_blocks),
);
}
void updateRack(){
setState(() {});
}
}
class Block extends StatelessWidget {
final Color color;
Block(this.color);
#override
Widget build(BuildContext context) {
return Container(height:50,width:50, color: color,);
}
}

flutter: How to detect keyboard?

I want detect Keyboard. And want to show it other text when keyboard is visible or unvisible.
But my code is not working.
This is my code.
class Search extends StatefulWidget {
#override
_SearchState createState() => _SearchState();
}
class _SearchState extends State<Search> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
color: Colors.white,
child: Column(
children: [
Expanded(
flex: 1,
child: ListView(
children: [
MediaQuery.of(context).viewInsets.bottom !=0 ? Center(child: Text("true"),) : Center(child: Text("false"),)
],
),
)
],
),
),
);
}
}
As #Anas Mohammed mentioned, you can do it with the keyboard_visibility package. Here is a total example:
import 'package:flutter/material.dart';
import 'package:keyboard_visibility/keyboard_visibility.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Keyboard visibility example',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: KeyboardVisibilityExample(),
);
}
}
class KeyboardVisibilityExample extends StatefulWidget {
KeyboardVisibilityExample({Key key}) : super(key: key);
#override
_KeyboardVisibilityExampleState createState() => _KeyboardVisibilityExampleState();
}
class _KeyboardVisibilityExampleState extends State<KeyboardVisibilityExample> {
KeyboardVisibilityNotification _keyboardVisibility = new KeyboardVisibilityNotification();
int _keyboardVisibilitySubscriberId;
bool _keyboardState;
#protected
void initState() {
super.initState();
_keyboardState = _keyboardVisibility.isKeyboardVisible;
_keyboardVisibilitySubscriberId = _keyboardVisibility.addNewListener(
onChange: (bool visible) {
setState(() {
_keyboardState = visible;
});
},
);
}
#override
void dispose() {
_keyboardVisibility.removeListener(_keyboardVisibilitySubscriberId);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Keyboard visibility example'),
),
body: Center(
child: Padding(
padding: EdgeInsets.all(24.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextField(
keyboardType: TextInputType.text,
decoration: InputDecoration(
labelText: 'Input box for keyboard test',
),
),
Container(height: 60.0),
Text(
'The current state of the keyboard is: ' + (_keyboardState ? 'VISIBLE' : 'NOT VISIBLE'),
),
],
)
),
),
);
}
}
for to visible keyboard this code:
FocusScope.of(context).requestFocus();
for to unvisible keyboard this code:
FocusScope.of(context).unfocus();
for check visiblity of keyboard :
FocusScope.of(context).hasFocus
your provided code:
class Search extends StatefulWidget {
#override
_SearchState createState() => _SearchState();
}
class _SearchState extends State<Search> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
color: Colors.white,
child: Column(
children: [
Expanded(
flex: 1,
child: ListView(
children: [
FocusScope.of(context).hasFocus ? Center(child: Text("true"),) : Center(child: Text("false"),)
],
),
)
],
),
),
);
}
}
Accepted answer contains old library not support null safety, you can use this one flutter_keyboard_visibility which support null safety.