Refocusing problem on TextField, cursor doesn't show on right position - flutter

When I unfocus on a TextField with existing Text then refocus on it again, the cursor always shows up at the start position, not at the tapped position. So I apply the logic of unfocusing from flutter_keyboard_visibility package - KeyboardDismissOnTap Widget and it still doesn't work. But when I wrapped my widget with this widget, it works the way I wanted to.
What's the difference if I wrap my widget with this KeyboardDismissOnTap Widget and when I use the same logic of that widget to my widget? I think It's basically the same, but it's not working the same way.
KeyboardDismissOnTap
class KeyboardDismissOnTap extends StatelessWidget {
const KeyboardDismissOnTap({Key? key, required this.child}) : super(key: key);
final Widget child;
void _hideKeyboard(BuildContext context) {
final currentFocus = FocusScope.of(context);
if (!currentFocus.hasPrimaryFocus && currentFocus.hasFocus) {
FocusManager.instance.primaryFocus?.unfocus();
}
}
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () => _hideKeyboard(context),
child: child,
);
}
}
MyPage - copied the logic of KeyboardDismissOnTap. Refocusing not working as intended, cursor still shows at start of existing text
class Mypage extends StatelessWidget {
const Mypage({Key? key}) : super(key: key);
void _hideKeyboard(BuildContext context) {
final currentFocus = FocusScope.of(context);
if (!currentFocus.hasPrimaryFocus && currentFocus.hasFocus) {
FocusManager.instance.primaryFocus?.unfocus();
}
}
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () => _hideKeyboard(context),
child: Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextField(
controller: TextEditingController()..text = 'Existing Text Here',
),
TextButton(
onPressed: () {
//Unfocus function here
}
},
child: Text('Unfocus'))
],
),
),
),
);
}
}
MyPage - wrapped with KeyboardDismissOnTap. Refocusing works correctly, cursor shows at the right position where you tapped it.
class Mypage extends StatelessWidget {
const Mypage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return KeyboardDismissOnTap(
child: Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextField(
controller: TextEditingController()..text = 'Existing Text Here',
),
TextButton(
onPressed: () {
if (!FocusScope.of(context).hasPrimaryFocus && FocusScope.of(context).hasFocus) {
FocusManager.instance.primaryFocus?.unfocus();
}
},
child: Text('Unfocus'))
],
),
),
),
);
}
}

Related

Flutter SnackBar is attached to wrong Scaffold

I have two screens where the second screen is pushed above the first with Navigator.push() and the second screen is partial transparent. I want to display a SnackBar, but it isn't really visible. It looks like the ScaffoldMessenger chooses the wrong of the two Scaffolds to attach the Snackbar. This leads to the effect that the SnackBar collides with the TextInput and it is also not fully visible. But this bad behavior is only the case as long as the soft keyboard is open. If the keyboard is closed, everything works fine. It seems like the open keyboard tells the ScaffoldMessenger to choose the Scaffold from the second screen to display the SnackBar.
How can I achieve that the SnackBar is shown normally in the sense of is attached to the Scaffold of screen 2 while the keyboard is open? The expected behavior is that the Snackbar isn't displayed transparent.
Keyboard open -> SnackBar is attached to Scaffold of screen 1 -> Bad
Keyboard closed -> SnackBar is attached to Scaffold of screen 2 -> Good
GIF showing the complete workflow
My code (fully executable)
import 'dart:io';
import 'package:keyboard_utils/keyboard_listener.dart';
import 'package:keyboard_utils/keyboard_utils.dart';
import 'package:flutter/material.dart' hide KeyboardListener;
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) => const MaterialApp(home: MyHomePage());
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Title')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[const Text('You have pushed the button this many times:'),
Text('$_counter', style: Theme.of(context).textTheme.headline4),
ElevatedButton(
onPressed: () {
Navigator.of(context).push(PageRouteBuilder(
opaque: false, // push route with transparency
pageBuilder: (context, animation, secondaryAnimation) => const Screen2(),
));
},
child: const Text('navigate'),
)
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () => setState(() => _counter++),
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}
class Screen2 extends StatefulWidget {
const Screen2({Key? key}) : super(key: key);
#override
State<Screen2> createState() => _Screen2State();
}
class _Screen2State extends State<Screen2> {
final _keyboardUtils = KeyboardUtils();
late int _idKeyboardListener;
final focusNode = FocusNode();
bool isEmojiKeyboardVisible = false;
bool isKeyboardVisible = false;
double _keyboardHeight = 300;
#override
void initState() {
super.initState();
_idKeyboardListener = _keyboardUtils.add(
listener: KeyboardListener(
willHideKeyboard: () {
if (isKeyboardVisible) {
isKeyboardVisible = false;
isEmojiKeyboardVisible = false;
}
setState(() {}); // show correct Icon in IconButton
},
willShowKeyboard: (double keyboardHeight) async {
if (Platform.isAndroid) {
_keyboardHeight = keyboardHeight + WidgetsBinding.instance.window.viewPadding.top / WidgetsBinding.instance.window.devicePixelRatio;
} else {
_keyboardHeight = keyboardHeight;
}
isKeyboardVisible = true;
isEmojiKeyboardVisible = true;
setState(() {});
},
)
);
}
#override
void dispose() {
_keyboardUtils.unsubscribeListener(subscribingId: _idKeyboardListener);
if (_keyboardUtils.canCallDispose()) {
_keyboardUtils.dispose();
}
focusNode.dispose();
super.dispose();
}
Future<void> onEmojiButtonPressed() async {
if(isEmojiKeyboardVisible){
if(isKeyboardVisible){
FocusManager.instance.primaryFocus?.unfocus();
isKeyboardVisible = false;
} else {
focusNode.unfocus();
await Future<void>.delayed(const Duration(milliseconds: 1));
if(!mounted) return;
FocusScope.of(context).requestFocus(focusNode);
}
} else {
assert(!isKeyboardVisible);
setState(() {
isEmojiKeyboardVisible = true;
});
}
}
#override
Widget build(BuildContext context) {
return Scaffold( // wrapping with ScaffoldMessenger does NOT fix this bug
backgroundColor: Colors.white.withOpacity(0.5),
resizeToAvoidBottomInset: false,
body: SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Expanded(child: SizedBox(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child: Column(
children: [
Expanded(
child: Container(
height: 200,
),
),
Row(
children: [
IconButton(
icon: Icon(isKeyboardVisible || !isEmojiKeyboardVisible ? Icons.emoji_emotions_outlined : Icons.keyboard_rounded),
onPressed: onEmojiButtonPressed,
),
Expanded(
child: TextField(
focusNode: focusNode,
),
),
IconButton(
icon: const Icon(Icons.send),
onPressed: () => ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('A snack!'))),
),
],
),
],
),
),
),
Offstage(
offstage: !isEmojiKeyboardVisible,
child: SizedBox(
height: _keyboardHeight,
child: Container(color: Colors.red),
),
),
],
),
),
);
}
}
Dependencies
keyboard_utils: ^1.3.4
What I've tried
I tried to wrap the Scaffold of Screen2 with a ScaffoldMessenger. This doesn't fix my problem. In that case, no SnackBar was shown at all if the keyboard was open.
Edit: I also created an GitHub issue for that but I don't expect an answer soon: https://github.com/flutter/flutter/issues/105406#issuecomment-1147194647
Edit 2: A workaround for this issue is to use SnackBarBehaviod.floating and a bottom margin, for example:
SnackBar(
content: Text('A snack!'),
margin: EdgeInsets.only(bottom: 350.0),
behavior: SnackBarBehavior.floating,
)
But this is not a satisfying solution.

How do i print the value which is coming from modal bottom sheet to the main scaffold body in dart+flutter

ive created a text and icon button, onpressing that icon
modal bottom sheet gets generated, in that
and ive created a separate dart file with text field and a submit button
when giving an input on text field and after clicking on submit button the given input string will be printed below
atlast i called the function in first dart file
but i want the text to be printed on the main scaffold page.
Below is the main code
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:practice1/StatefulModalbtn.dart';
void main() {
runApp(Modalbtn());
}
class Modalbtn extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Modal Bottom Test'),
),
body: Column(
children: <Widget>[Mymodal()],
),
),
);
}
}
class Mymodal extends StatelessWidget {
const Mymodal({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text(
'Press the icon to select the Tractor model',
style: TextStyle(fontSize: 15),
),
IconButton(
onPressed: () {
showModalBottomSheet(
context: context,
builder: (BuildContext context) {
return Container(
height: 200,
child: Column(
children: <Widget>[StatefulModalbtn()],
),
);
});
},
icon: Icon(Icons.add),
iconSize: 20,
)
],
),
);
}
}
and below code is for creating a text field and submit button
import 'package:flutter/material.dart';
class StatefulModalbtn extends StatefulWidget {
const StatefulModalbtn({Key? key}) : super(key: key);
#override
_StatefulModalbtnState createState() => _StatefulModalbtnState();
}
class _StatefulModalbtnState extends State<StatefulModalbtn> {
TextEditingController textController = TextEditingController();
String displayText = "";
#override
Widget build(BuildContext context) {
return Column(
children: [
TextField(
controller: textController,
maxLines: null,
),
ElevatedButton(
onPressed: () {
setState(() {
displayText = textController.text;
});
},
child: Text('Submit')),
Text(
displayText,
style: TextStyle(fontSize: 20),
),
],
);
}
}
and below is the output link
this is the output im achieving but i want the "Hello World" to be printed on top/main screen, right after the + add icon screen
How should i solve this ??
I just slightly edited your code
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'main1.dart';
void main() {
runApp(MaterialApp(
home: Modalbtn(),
));
}
class Modalbtn extends StatefulWidget {
#override
_ModalbtnState createState() => _ModalbtnState();
}
class _ModalbtnState extends State<Modalbtn> {
String value = "0";
// Pass this method to the child page.
void _update(String newValue) {
setState(() => value = newValue);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
children: [
IconButton(
onPressed: () {
showModalBottomSheet(
context: context,
builder: (BuildContext context) {
return Container(
height: 200,
child: Column(
children: [StatefulModalbtn(update: _update)],
),
);
});
},
icon: Icon(Icons.add),
iconSize: 20,
),
Text(
value,
style: TextStyle(fontSize: 40),
),
],
),
),
);
}
}
and the child class is
import 'package:flutter/material.dart';
class StatefulModalbtn extends StatelessWidget {
final ValueChanged<String> update;
StatefulModalbtn({required this.update});
#override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () => update("100"), // Passing value to the parent widget.
child: Text('Update (in child)'),
);
}
}

where does FocusScope widget exist in the widget tree?

Where does the FocusScope widget create in the tree and we pass every context in it and it can request to any focus nodes. When we pass context to FocusScope it will start looking above the context and we never used the FocusScope widget in the code in the hierarchy where does it create and how does it resolves in the case of scaffold if we pass context that is above in the tree then it throws an exception then we use builder type of thing but in FocusScope why it doesn't throw an error?
Here is the example for the FocusScope
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return const MaterialApp(
title: _title,
home: MyStatefulWidget(),
);
}
}
/// A demonstration pane.
///
/// This is just a separate widget to simplify the example.
class Pane extends StatelessWidget {
const Pane({
Key? key,
required this.focusNode,
this.onPressed,
required this.backgroundColor,
required this.icon,
this.child,
}) : super(key: key);
final FocusNode focusNode;
final VoidCallback? onPressed;
final Color backgroundColor;
final Widget icon;
final Widget? child;
#override
Widget build(BuildContext context) {
return Material(
color: backgroundColor,
child: Stack(
fit: StackFit.expand,
children: <Widget>[
Center(
child: child,
),
Align(
alignment: Alignment.topLeft,
child: IconButton(
autofocus: true,
focusNode: focusNode,
onPressed: onPressed,
icon: icon,
),
),
],
),
);
}
}
class MyStatefulWidget extends StatefulWidget {
const MyStatefulWidget({Key? key}) : super(key: key);
#override
State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
bool backdropIsVisible = false;
FocusNode backdropNode = FocusNode(debugLabel: 'Close Backdrop Button');
FocusNode foregroundNode = FocusNode(debugLabel: 'Option Button');
#override
void dispose() {
super.dispose();
backdropNode.dispose();
foregroundNode.dispose();
}
Widget _buildStack(BuildContext context, BoxConstraints constraints) {
final Size stackSize = constraints.biggest;
return Stack(
fit: StackFit.expand,
// The backdrop is behind the front widget in the Stack, but the widgets
// would still be active and traversable without the FocusScope.
children: <Widget>[
// TRY THIS: Try removing this FocusScope entirely to see how it affects
// the behavior. Without this FocusScope, the "ANOTHER BUTTON TO FOCUS"
// button, and the IconButton in the backdrop Pane would be focusable
// even when the backdrop wasn't visible.
FocusScope(
// TRY THIS: Try commenting out this line. Notice that the focus
// starts on the backdrop and is stuck there? It seems like the app is
// non-responsive, but it actually isn't. This line makes sure that
// this focus scope and its children can't be focused when they're not
// visible. It might help to make the background color of the
// foreground pane semi-transparent to see it clearly.
canRequestFocus: backdropIsVisible,
child: Pane(
icon: const Icon(Icons.close),
focusNode: backdropNode,
backgroundColor: Colors.lightBlue,
onPressed: () => setState(() => backdropIsVisible = false),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
// This button would be not visible, but still focusable from
// the foreground pane without the FocusScope.
ElevatedButton(
onPressed: () => debugPrint('You pressed the other button!'),
child: const Text('ANOTHER BUTTON TO FOCUS'),
),
DefaultTextStyle(
style: Theme.of(context).textTheme.headline2!,
child: const Text('BACKDROP')),
],
),
),
),
AnimatedPositioned(
curve: Curves.easeInOut,
duration: const Duration(milliseconds: 300),
top: backdropIsVisible ? stackSize.height * 0.9 : 0.0,
width: stackSize.width,
height: stackSize.height,
onEnd: () {
if (backdropIsVisible) {
backdropNode.requestFocus();
} else {
foregroundNode.requestFocus();
}
},
child: Pane(
icon: const Icon(Icons.menu),
focusNode: foregroundNode,
// TRY THIS: Try changing this to Colors.green.withOpacity(0.8) to see for
// yourself that the hidden components do/don't get focus.
backgroundColor: Colors.green,
onPressed: backdropIsVisible
? null
: () => setState(() => backdropIsVisible = true),
child: DefaultTextStyle(
style: Theme.of(context).textTheme.headline2!,
child: const Text('FOREGROUND')),
),
),
],
);
}
#override
Widget build(BuildContext context) {
// Use a LayoutBuilder so that we can base the size of the stack on the size
// of its parent.
return LayoutBuilder(builder: _buildStack);
}
}

Flutter - How to Extract Widget with onPressed setState inside?

I want to Extract a Widget with onPressed setState inside but I get the Message "Reference to an enclosing class method cannot be extracted."
Is there a way to do that?
I would like to divide my code into different widgets so that it remains clear. Here is simplified an example of the code:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Calculator(),
);
}
}
class Calculator extends StatefulWidget {
#override
_CalculatorState createState() => _CalculatorState();
}
class _CalculatorState extends State<Calculator> {
var myValue = 0;
void calculate() {
myValue = 12;
}
#override
Widget build(BuildContext context) {
return Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
child: TextButton(
onPressed: () {
setState(() {
calculate();
});
},
child: Text(
'Button 001',
),
),
),
TextOutput(myValue: myValue),
],
),
);
}
}
class TextOutput extends StatelessWidget {
const TextOutput({
Key key,
#required this.myValue,
}) : super(key: key);
final int myValue;
#override
Widget build(BuildContext context) {
return Container(
child: Text(
myValue.toString(),
),
);
}
}
The part I want to extract into a separate widget:
Container(
child: TextButton(
onPressed: () {
setState(() {
calculate();
});
},
child: Text(
'Button 001',
),
),
),
Flutter offers VoidCallback and Function(x) (where x can be a different type) for callback-style events between child and parent widgets.
Simply You can pass Function onPressed; via constructor
Here is your Extracted Container widget:
class ExtractedContainer extends StatelessWidget {
final Function onPressed;
const ExtractedContainer({
Key key, #required this.onPressed,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
child: TextButton(
onPressed: () {
onPressed();
},
child: Text(
'Button 001',
),
),
);
}
}
And Here How to use it:
#override
Widget build(BuildContext context) {
return Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ExtractedContainer(onPressed: calculate,),
TextOutput(myValue: myValue),
],
),
);
}
Your full code example
import 'package:flutter/material.dart';
class MyApp2 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Calculator(),
);
}
}
class Calculator extends StatefulWidget {
#override
_CalculatorState createState() => _CalculatorState();
}
class _CalculatorState extends State<Calculator> {
var myValue = 0;
void calculate() {
myValue = 12;
}
#override
Widget build(BuildContext context) {
return Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ExtractedContainer(onPressed: calculate,),
TextOutput(myValue: myValue),
],
),
);
}
}
class ExtractedContainer extends StatelessWidget {
final Function onPressed;
const ExtractedContainer({
Key key, #required this.onPressed,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
child: TextButton(
onPressed: () {
onPressed();
},
child: Text(
'Button 001',
),
),
);
}
}
class TextOutput extends StatelessWidget {
const TextOutput({
Key key,
#required this.myValue,
}) : super(key: key);
final int myValue;
#override
Widget build(BuildContext context) {
return Container(
child: Text(
myValue.toString(),
),
);
}
}
Setstate is related to the widget you want to refresh its state. If you extract it to another place, then setState refers to the state of the new widget.
In your case, the setState will only change the state of the container encapsulating your widget which you are trying to extract and its children, it doesn't migrate upward.
Unless, you look for the state of the widget you want, using exact type, and then trigger the state there, but this is overkill, a lot harder, requires more code, than what you currently have.
You can use VoidCallback on extract widget to get onPressed event
class MyContainer extends StatelessWidget {
final VoidCallback onTap;
const MyContainer({
Key? key,
required this.onTap,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
child: TextButton(
onPressed: onTap,
child: Text(
'Button 001',
),
),
);
}
}
And use like
MyContainer(
onTap: () {
print("tapped");
setState(() {
calculate();
});
},
),

How to make a floating widget which isn't destroyed when I change screens?

I'm creating a music player and I need the music controls don't reinitialize or disappear on screen changing. If I add the code on another screen it will create another FloatingControls() widget.
I've already tried work with keys but that isn't the case because the Widget is recreated when I change screens.
As you can see my FloatingControls has a Widget called YoutubePlayer when I press play a video starts when I change screens I want that the player doesn't restart.
FloatingControls myFloatingControls = FloatingControls(key: Key("myFloatingControls"),);
class MusicSuggestions extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'MusicSuggestions',
home: new MainScreen(),
);
}
}
class MainScreen extends StatelessWidget {
const MainScreen({
Key key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
FlatButton(
child: Text("Change to Screen A"),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
ScreenA(floatingControls: myFloatingControls),
),
);
},
),
FlatButton(
child: Text("Change to Screen B"),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
ScreenB(floatingControls: myFloatingControls),
),
);
},
),
],
),
myFloatingControls
],
),
),
);
}
}
class ScreenA extends StatefulWidget {
final FloatingControls floatingControls;
const ScreenA({Key key, this.floatingControls}) : super(key: key);
#override
_ScreenAState createState() => _ScreenAState();
}
class _ScreenAState extends State<ScreenA> {
#override
Widget build(BuildContext context) {
return Scaffold(body: Center(child: widget.floatingControls,));
}
}
class ScreenB extends StatefulWidget {
final FloatingControls floatingControls;
const ScreenB({Key key, this.floatingControls}) : super(key: key);
#override
_ScreenBState createState() => _ScreenBState();
}
class _ScreenBState extends State<ScreenB> {
#override
Widget build(BuildContext context) {
return Scaffold(body: Center(child: widget.floatingControls,));
}
}
class FloatingControls extends StatefulWidget {
const FloatingControls({Key key}) : super(key: key);
#override
_FloatingControlsState createState() => _FloatingControlsState();
}
class _FloatingControlsState extends State<FloatingControls> {
VideoPlayerController _videoController;
bool isMute = false;
#override
Widget build(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
ClipOval(
child: Container(
width: 50,
height: 50,
child: YoutubePlayer(
autoPlay: false,
aspectRatio: 1,
width: 50,
context: context,
playerMode: YoutubePlayerMode.NO_CONTROLS,
source: "https://www.youtube.com/watch?v=PodZolu9v30",
quality: YoutubeQuality.LOW,
callbackController: (VideoPlayerController controller) {
_videoController = controller;
},
),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
IconButton(
icon: Icon(Icons.skip_previous),
onPressed: () {},
),
IconButton(
icon: _videoController == null ||
!_videoController.value.isPlaying
? Icon(Icons.play_arrow)
: Icon(Icons.pause),
onPressed: () {
setState(() {
_videoController == null ||
_videoController.value.isPlaying
? _videoController.pause()
: _videoController.play();
});
}),
IconButton(
icon: Icon(Icons.skip_next),
onPressed: () {},
),
Container(
width: 25,
height: 25,
)
],
),
]);
}
}
I expect to see my FloatingControls() in all screens without losing its state when I change pages.
Make sure to add floatingControls to your ScreenA and ScreenB build methods.
Example:
class _ScreenAState extends State<ScreenA> {
#override
Widget build(BuildContext context) {
return widget.floatingControls();
}
}
If you do this for both ScreenA and ScreenB, it should work.
--EDIT--
You should look into the PageStorage and PageStorageBucket classes, which will help you persist state across rebuilds. I don't have a lot of experience with these, so instead of giving you a potentially shoddy code snippet to copy, I will direct you to this tutorial by Tensor Programming (whose tutorials have helped me tremendously) which should help you do what you need to do. They are doing it with navigation bars, but it should extend easily to what you're doing.