Why flutter UI lag while soft keyboard appearing and disappearing? - flutter

When I click text fields on the main page (main.dart) which is the default dart given by the flutter. I can see a glitch when soft keyboard appears and there is no delay when soft keyboard disappears.I have attached a gif below for this case.
void main() {
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
statusBarColor: primaryColor, //blue
statusBarIconBrightness: Brightness.dark,
));
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.pink,
primaryColor: primaryColor,
primaryColorBrightness: Brightness.dark,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
// This widget is the home page of your application. It is stateful, meaning
// that it has a State object (defined below) that contains fields that affect
// how it looks.
// This class is the configuration for the state. It holds the values (in this
// case the title) provided by the parent (in this case the App widget) and
// used by the build method of the State. Fields in a Widget subclass are
// always marked "final".
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
// setState(() {
// // This call to setState tells the Flutter framework that something has
// // changed in this State, which causes it to rerun the build method below
// // so that the display can reflect the updated values. If we changed
// // _counter without calling setState(), then the build method would not be
// // called again, and so nothing would appear to happen.
// _counter++;
// });
setState(() {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => PhoneAuth()));
});
}
#override
Widget build(BuildContext context) {
// This method is rerun every time setState is called, for instance as done
// by the _incrementCounter method above.
//
// The Flutter framework has been optimized to make rerunning build methods
// fast, so that you can just rebuild anything that needs updating rather
// than having to individually change instances of widgets.
return Scaffold(
backgroundColor: Colors.red,
appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text('hell0000000'),
),
body: Center(
// Center is a layout widget. It takes a single child and positions it
// in the middle of the parent.
child: Container(
color: Colors.white,
child: ListView(
children: [
Column(
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
SizedBox(
height: 200,
),
Align(
alignment: Alignment.bottomCenter,
child: new Container(
child: TextField(
decoration: new InputDecoration(
hintText: 'Chat message',
),
),
),
),
],
),
],
),
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
main.dart glich
Also, When I click text fields on the other page (UserChatView.dart). I can see a glitch when soft keyboard appearing and disappearing. In this dart file, That glitch happening for both actions(Keyboard opening and closing). I have attached a gif below for this case.
class UserChatView extends StatelessWidget{
#override
Widget build(BuildContext context) {
return UserChatViewPage();
}
}
class UserChatViewPage extends StatefulWidget {
UserChatViewPage({Key key}) : super(key: key);
#override
_UserChatViewPageState createState() => _UserChatViewPageState();
}
class _UserChatViewPageState extends State<UserChatViewPage> {
final TextEditingController _textController = new TextEditingController();
#override
Widget build(BuildContext context) {
final focus = FocusNode();
return new Scaffold(
backgroundColor: Colors.red, // Scaffold background Color
appBar: new AppBar(
title: Row(
children: <Widget>[
// new Container(
// child: CircleAvatar(
// backgroundImage: AssetImage("assets/male_icon.png"),
// )
// ),
new SizedBox(
width: 5.00,
),
new Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget> [
new Container(
child: new Text("Alex Marko",
style: TextStyle(color: Colors.white,
fontFamily: 'Roboto_Bold',
letterSpacing: 1.00
),
),
),
new Container(
child: new Text("Online",
style: TextStyle(color: Colors.white,
fontFamily: 'Roboto_Medium',
letterSpacing: 1.00,
fontSize: 12.00,
),
),
),
],
),
],
),
centerTitle: false,
titleSpacing: 0.0,
backgroundColor: primaryColor,
elevation: 0.0,
bottomOpacity: 0.0,
actions: <Widget>[
IconButton(
icon: Icon(
Icons.expand_more_rounded,
color: Colors.white,
),
onPressed: () {
// do something
},
),
],
),
body: Center(
child: new Container(
color: Colors.grey,
child: new Column(
children: <Widget>[
new Expanded(
child: _PageListView(),
),
new Container(
color: Colors.yellow,
padding: new EdgeInsets.all(10.0),
child: _buildTextComposer(),
),
],
),
),
),
);
}
Widget _buildTextComposer() {
return new Container(
color: Colors.yellow,//modified
margin: const EdgeInsets.symmetric(horizontal: 8.0),
child: new Row(
children: <Widget>[
new Flexible(
child: new TextField(
controller: _textController,
onSubmitted: _handleSubmitted,
decoration: new InputDecoration.collapsed(
hintText: "Send a message"),
),
),
new Container(
margin: new EdgeInsets.symmetric(horizontal: 4.0),
child: new IconButton(
icon: new Icon(Icons.send),
onPressed: () => _handleSubmitted(_textController.text)),
),
],
),
);
}
Widget _PageListView(){
return new Container(
child: ListView.builder(
reverse: true,
itemCount: 20,
itemBuilder: (context, position) {
return Card(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Text(position.toString(), style: TextStyle(fontSize: 22.0),),
),
);
},
),
);
}
UserChatView.dart Glich

The reason of this so called Glitch is that the default behaviour of the flutter scaffold widget is to resize it's body when soft keyboard opens up or closes down.
While the flutter scaffold is notified of any of the above two events, it will start resizing the widgets under its body to match the new state. The speed of resizing may differ based on the comlplexity of build process of the widget on screen & processing speed of the device itself.
What you can do is add a flag called resizeToAvoidBottomInset in the scaffold widget in your app, like this:
Scaffold(
...
resizeToAvoidBottomInset: false,
)
What this does is, It notifies the scaffole to not resize the widget under its body on keyboard up or down states.
So, unless you want to explicitely resize the content of the screen on keyboard state, this is a solution to your glitch.
On the other hand, if you want to resize the content, you can choose to modularize/breakdown the widgets that you have on screen to smallest possible combination & make the layout simpler so that the glitch portion of the resizing is taken care of by the speed of rebuild process.

Your keyboard is producing that effect because of the ListView.builder. Add extra properties to your ListView like this
Widget _PageListView(){
return new Container(
child: ListView.builder(
addAutomaticKeepAlives: true, // Add this property
cacheExtent: double.infinity, // And this one
reverse: true,
itemCount: 20,
itemBuilder: (context, position) {
return Card( /* It's better to have here a separated StatefulWidget with AutomaticKeepAliveClientMixin */
// ...
);
},
),
);
}

Related

how to make a dynamic counter?

I'm making a cart on flutter. But, I ran into a problem. As planned, the user can add the quantity of goods from the cart. But, due to the fact that I use one variable, the counter increases / decreases everywhere at once. How to fix it? PS: I can't know how much the product will be, it is added by the user himself
Here is my code - Saving State -
int value = 1;
inc() {
setState(() {
value++;
});
}
dec() {
setState(() {
value--;
});
}
Отображение -
Expanded(
child: ListView.builder(
controller: controller,
padding: EdgeInsets.all(5),
itemCount: HomeBody.shoppingBasketHeader!.length,
itemBuilder: (context, index) {
if (index < HomeBody.shoppingBasketHeader!.length) {
return Container(
padding: EdgeInsets.all(5),
margin: EdgeInsets.all(2),
decoration: const BoxDecoration(
border: Border(bottom: BorderSide(color: Colors.black))
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Column(
children: [
Container(
width: 150,
child: Image.network('http://10.0.2.2:1337${HomeBody.shoppingBasketImage?[index]}'),
)
],
),
Column(
children: [
Container(
width: 200,
child: Column(
children: [
Container(
margin: EdgeInsets.all(5),
child: Text(' ${HomeBody.shoppingBasketHeader?[index]}', style: TextStyle(fontSize: 15),),
),
],
),
),
Container(
width: 200,
child: Column(
children: [
Container(
margin: EdgeInsets.all(5),
child: Text(' ${HomeBody.shoppingBasketPrice?[index]}', style: TextStyle(fontSize: 15),),
),
],
),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
child: IconButton(onPressed: () {inc();}, icon: Icon(Icons.add)),
),
Container(
child: Text('$value'),
),
Container(
child: IconButton(onPressed: () {dec();}, icon: Icon(Icons.remove)),
)
],
)
],
),
],
),
);
} else {
return Padding(padding: EdgeInsets.symmetric(
vertical: 10),
child: Center(
child: Text('Список полностью загружен!'),
),
);
}
}
)
**
Option 1
**
Create a separate widget for the below snippet and declare the count variable (value) locally.
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
child: IconButton(onPressed: () {inc();}, icon: Icon(Icons.add)),
),
Container(
child: Text('$value'),
),
Container(
child: IconButton(onPressed: () {dec();}, icon: Icon(Icons.remove)),
)
],
)
**
Option 2
**
Create a separate class for each row of data and use a List
class CartRow{
int quantity,
double price,
string product,
}
**
Option 3
**
Use option 1 and new class/entity from option 2
-------------------------Option 1 Code -------------------
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class ShoppingCartLine extends StatefulWidget {
const ShoppingCartLine({Key? key}) : super(key: key);
#override
_ShoppingCartLineState createState() => _ShoppingCartLineState();
}
class _ShoppingCartLineState extends State<ShoppingCartLine> {
int? value;
#override
void initState() {
super.initState();
value = 1;
}
#override
Widget build(BuildContext context) {
return _getBody();
}
Widget _getBody(){
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
child: IconButton(onPressed: () {inc();}, icon: Icon(Icons.add)),
),
Container(
child: Text('${value.toString()}'),
),
Container(
child: IconButton(onPressed: () {dec();}, icon: Icon(Icons.remove)),
)
],
);
}
inc() {
setState(() {
value = (value! + 1);
});
}
dec() {
setState(() {
if(value! > 1){
value = (value! - 1);
}
});
}
}
--------------------------------main.dart--------------------------------
import 'package:flutter/material.dart';
import 'features/shopping_cart_line.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
// This widget is the home page of your application. It is stateful, meaning
// that it has a State object (defined below) that contains fields that affect
// how it looks.
// This class is the configuration for the state. It holds the values (in this
// case the title) provided by the parent (in this case the App widget) and
// used by the build method of the State. Fields in a Widget subclass are
// always marked "final".
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
// This call to setState tells the Flutter framework that something has
// changed in this State, which causes it to rerun the build method below
// so that the display can reflect the updated values. If we changed
// _counter without calling setState(), then the build method would not be
// called again, and so nothing would appear to happen.
_counter++;
});
}
#override
Widget build(BuildContext context) {
// This method is rerun every time setState is called, for instance as done
// by the _incrementCounter method above.
//
// The Flutter framework has been optimized to make rerunning build methods
// fast, so that you can just rebuild anything that needs updating rather
// than having to individually change instances of widgets.
return Scaffold(
appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text(widget.title),
),
body: Center(
// Center is a layout widget. It takes a single child and positions it
// in the middle of the parent.
child: Column(
// Column is also a layout widget. It takes a list of children and
// arranges them vertically. By default, it sizes itself to fit its
// children horizontally, and tries to be as tall as its parent.
//
// Invoke "debug painting" (press "p" in the console, choose the
// "Toggle Debug Paint" action from the Flutter Inspector in Android
// Studio, or the "Toggle Debug Paint" command in Visual Studio Code)
// to see the wireframe for each widget.
//
// Column has various properties to control how it sizes itself and
// how it positions its children. Here we use mainAxisAlignment to
// center the children vertically; the main axis here is the vertical
// axis because Columns are vertical (the cross axis would be
// horizontal).
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'You have pushed the button this many times:',
),
Column(
children: [
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
const ShoppingCartLine(),
const ShoppingCartLine(),
],
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
enter code here

Row's Children Must Not Contain Any Null Values Flutter Error

I'm developing a Flutter app, and I am trying to create a reusable button widget to be used in various places throughout my app. I want every button to be required to have text, and an onpressed function, with an option of having an image. Whenever I try to create a button that doesn't have the buttonImage property, I get a "Row's Children must not contain any null values" error, and I'm having issues trying to solve it. Below is code for my ReusableButton Widget and the implementation. Any help is appreciated
import 'package:flutter/material.dart';
class ReusableButton extends StatelessWidget {
ReusableButton({
this.buttonImage,
#required this.buttonText,
#required this.onPressed,
this.buttonColor,
});
final String buttonText;
final Function onPressed;
final Color buttonColor;
final Image buttonImage;
#override
Widget build(BuildContext context) {
return OutlineButton(
onPressed: onPressed,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(40)),
highlightElevation: 0,
borderSide: BorderSide(color: buttonColor),
child: Padding(
padding: const EdgeInsets.fromLTRB(0, 10, 0, 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
buttonImage,
Text(
buttonText,
style: TextStyle(
fontSize: 20,
color: Colors.grey,
),
),
],
),
),
);
}
}
Here is the code in which I am implementing the ReusableButton widget
class LoginPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Center(
child: Container(
child: Center(
child: Column(
children: <Widget>[
ReusableButton(
buttonImage: Image.asset('images/google_logo.png', height: 25.0),
buttonText: 'UserName',
buttonColor: kButtonBorderColor,
onPressed: ()
{
},
),
ReusableButton(
buttonText: 'Password',
buttonColor: kButtonBorderColor,
onPressed: ()
{
},
),
],
),
),
),
),
],
)
);
}
}
You need to return Container() if buttonImage is null
Row widget do not know how to render null
you must tell Row widget to render empty content if it's null
Please see full code and demo below
children: <Widget>[
buttonImage == null ? Container() : buttonImage,
code snippet
class ReusableButton extends StatelessWidget {
ReusableButton({
this.buttonImage,
#required this.buttonText,
#required this.onPressed,
this.buttonColor,
});
final String buttonText;
final Function onPressed;
final Color buttonColor;
final Image buttonImage;
#override
Widget build(BuildContext context) {
return OutlineButton(
onPressed: onPressed,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(40)),
highlightElevation: 0,
borderSide: BorderSide(color: buttonColor),
child: Padding(
padding: const EdgeInsets.fromLTRB(0, 10, 0, 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
buttonImage == null ? Container() : buttonImage,
Text(
buttonText,
style: TextStyle(
fontSize: 20,
color: Colors.grey,
),
),
],
),
),
);
}
}
demo
full code
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class ReusableButton extends StatelessWidget {
ReusableButton({
this.buttonImage,
#required this.buttonText,
#required this.onPressed,
this.buttonColor,
});
final String buttonText;
final Function onPressed;
final Color buttonColor;
final Image buttonImage;
#override
Widget build(BuildContext context) {
return OutlineButton(
onPressed: onPressed,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(40)),
highlightElevation: 0,
borderSide: BorderSide(color: buttonColor),
child: Padding(
padding: const EdgeInsets.fromLTRB(0, 10, 0, 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
buttonImage == null ? Container() : buttonImage,
Text(
buttonText,
style: TextStyle(
fontSize: 20,
color: Colors.grey,
),
),
],
),
),
);
}
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
// This widget is the home page of your application. It is stateful, meaning
// that it has a State object (defined below) that contains fields that affect
// how it looks.
// This class is the configuration for the state. It holds the values (in this
// case the title) provided by the parent (in this case the App widget) and
// used by the build method of the State. Fields in a Widget subclass are
// always marked "final".
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
// This call to setState tells the Flutter framework that something has
// changed in this State, which causes it to rerun the build method below
// so that the display can reflect the updated values. If we changed
// _counter without calling setState(), then the build method would not be
// called again, and so nothing would appear to happen.
_counter++;
});
}
#override
Widget build(BuildContext context) {
// This method is rerun every time setState is called, for instance as done
// by the _incrementCounter method above.
//
// The Flutter framework has been optimized to make rerunning build methods
// fast, so that you can just rebuild anything that needs updating rather
// than having to individually change instances of widgets.
return Scaffold(
appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text(widget.title),
),
body: Center(
// Center is a layout widget. It takes a single child and positions it
// in the middle of the parent.
child: Column(
// Column is also a layout widget. It takes a list of children and
// arranges them vertically. By default, it sizes itself to fit its
// children horizontally, and tries to be as tall as its parent.
//
// Invoke "debug painting" (press "p" in the console, choose the
// "Toggle Debug Paint" action from the Flutter Inspector in Android
// Studio, or the "Toggle Debug Paint" command in Visual Studio Code)
// to see the wireframe for each widget.
//
// Column has various properties to control how it sizes itself and
// how it positions its children. Here we use mainAxisAlignment to
// center the children vertically; the main axis here is the vertical
// axis because Columns are vertical (the cross axis would be
// horizontal).
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ReusableButton(
buttonImage: Image.asset('assets/images/alarm.png', height: 25.0),
buttonText: 'UserName',
buttonColor: Colors.blue,
onPressed: ()
{
},
),
ReusableButton(
buttonText: 'Password',
buttonColor: Colors.blue,
onPressed: ()
{
},
),
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
You're not passing an image to the second button that very much Equal to 'passing a null value'
In constructor check whether the image is null, if it is null set an empty container which should solve the problem
if(this.image==null) this.image = Container(width:0,height:0);
or in short
this.image?? = Container(width:0,height:0);
Or else in build check for whether the image is not null if it is not null then only place it in the row
Or you can use shorthand buttonImage ?? Container() it is equally buttonImage == null ? Container() : buttonImage,
If you ever need to add multiple child items to a Column based on a single "if":
Example:
Column(
children: [
Container(),
if (<some conditional statement>) ...[
Container(),
Container(),
Container(),
Container()
],
] // children
), // Column

Flutter Scaffold.of(context).openDrawer() doesn't work

I want to open a drawer after pushing on the custom button in BottomMenu I have trouble with Scaffold.of(context).openDrawer(), it doesn't work. My BottomMenu is a separate widget class. As I understand, it doesn't work because it's a separate context. How can I get the right context? Or perhaps someone knows another solution.
Here my code reproducer:
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: MyHomePage(title: 'Flutter Drawer'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
bottomNavigationBar: BottomMenu(),
endDrawer: SizedBox(
width: double.infinity,
child: Drawer(
elevation: 16,
child: Container(
color: Colors.black,
child: ListView(
padding: EdgeInsets.zero,
children: <Widget>[
ListTile(
title: Text('Some context here',
style: TextStyle(color: Colors.white))),
ListTile(
title: Text('Some context here',
style: TextStyle(color: Colors.white))),
],
),
),
),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Call Drawer form menu reproducer',
)
],
),
),
);
}
}
class BottomMenu extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 15),
child: Wrap(
alignment: WrapAlignment.center,
children: <Widget>[
Divider(color: Colors.black, height: 1),
Padding(
padding: const EdgeInsets.symmetric(vertical: 2),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
InkWell(
borderRadius: new BorderRadius.circular(20.0),
customBorder: Border.all(color: Colors.black),
child: Container(
padding: EdgeInsets.only(
left: 3, right: 6, bottom: 15, top: 11),
child: Row(
children: <Widget>[
Icon(Icons.menu),
Text('Show menu', style: TextStyle(fontSize: 15, fontWeight: FontWeight.bold)),
],
),
),
onTap: () {
Scaffold.of(context).openDrawer();
},
),
],
),
),
],
),
);
}
}
In my case, this worked.
return Scaffold(
key: _scaffoldKey,
endDrawerEnableOpenDragGesture: false, // This!
appBar: AppBar(
iconTheme: IconThemeData(color: Colors.white),
leading: IconButton(
icon: Icon(Icons.menu, size: 36),
onPressed: () => _scaffoldKey.currentState.openDrawer(), // And this!
),
),
drawer: DrawerHome(),
....
and _scaffoldKey must be initialized as,
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
under the class.
The problem is that you specified endDrawer on Scaffold yet you're calling Scaffold.of(context).openDrawer().
openDrawer() documentation states:
If the scaffold has a non-null Scaffold.drawer, this function will cause the drawer to begin its entrance animation.
Since your drawer is null, nothing happens.
In contrast, openEndDrawer() informs us:
If the scaffold has a non-null Scaffold.endDrawer, this function will cause the end side drawer to begin its entrance animation.
Since your endDrawer is not null you should use openEndDrawer() method. Alternatively, if you don't care which side the drawer slides in from, you can use drawer instead of endDrawer when building Scaffold.
My problem solved that instead of
Scaffold.of(context).openEndDrawer()
I give key to Scaffold and then I call by state like below
_scaffoldkey.currentState.openEndDrawer()
It solved my problem I hope It also works for you
Scaffold.of(context).openEndDrawer()
The Problem
This issue can occur when you do not use the correct BuildContext when calling Scaffold.of(context).openDrawer() (or openEndDrawer()).
Easiest Solution
Simply wrap whatever calls openDrawer() (or openEndDrawer()) with a Builder widget. This will give it a working context.
Minimal Working Example
// your build method
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: Builder(builder: (context) { // this uses the new context to open the drawer properly provided by the Builder
return FloatingActionButton(onPressed: (() => Scaffold.of(context).openDrawer()));
}),
drawer: const Drawer(
child: Text("MY DRAWER"),
),
);
}
Similar problem here. Clicked on button and nothing happened. The problem is I was using the context of the widget that instantiated Scaffold. Not the context of a child of Scaffold.
Here is how I solved it:
// body: Column(
// children: <Widget>[
// Row(
// children: <Widget>[
// IconButton(
// icon: Icon(Icons.filter_list),
// onPressed: () => Scaffold.of(context).openEndDrawer(), (wrong context)
// ),
// ],
// ),
// ],
// )
To:
body: Builder(
builder: (context) => Column(
children: <Widget>[
Row(
children: <Widget>[
IconButton(
icon: Icon(Icons.filter_list),
onPressed: () => Scaffold.of(context).openEndDrawer(),
),
],
),
],
)),
),
Assign Drawer to drawer property in scaffold. Wrap your specific Widget/Button(where you want to open drawer on its click method) with Builder. Use below method on click property:
enter image description here
Scaffold.of(context).openDrawer();
If you have the appbar widget with an action button to launch the drawer and the drawer is never pushed please remember that you need to define after appbar: ... the endDrawer: YOURAppDrawerWIDGET(), or else using the Scaffold.of(context).openEndDrawer() will not work.
Scaffold(
appBar: AppBar(title: Text(_title)),
endDrawer: AppDrawer(), // <-- this is required or else it will not know what is opening
body: SingleChildScrollView(
///...

How to access one class method from another class in flutter?

Hi guys im flutter and dart new-be
i make photoupload function
But I got into trouble while I was making it.
class pictureBox() can't recognize getImage() ,,
Its my whole code :
class writeprofile extends StatefulWidget {
#override
_writeprofileState createState() => _writeprofileState();
}
class _writeprofileState extends State<writeprofile> {
File _image;
#override
Widget build(BuildContext context) {
Future getImage() async{
var image= await ImagePicker.pickImage(source: ImageSource.gallery);
setState(() {
_image = image;
print('Image Path $_image');
});
}
Future uploadPic(BuildContext context) async{
String filName = basename(_image.path);
StorageReference firebaseStorageRef = FirebaseStorage.instance.ref().child(filName);
StorageUploadTask uploadTask = firebaseStorageRef.putFile(_image);
StorageTaskSnapshot taskSnapshot = await uploadTask.onComplete;
setState(() {
print("Profile pic upload !!");
Scaffold.of(context).showSnackBar(SnackBar(content: Text('Profile pic Upload !!')));
});
}
return Scaffold(
body: Builder(
builder: (context)=> Center(
child: Container(
child: Container(
child: Column(
children: <Widget>[
Padding(
padding: EdgeInsets.only(top: 70),
child: Text(
'사진 선택',
style: TextStyle(
fontSize: 30,
fontWeight: FontWeight.w500,
),
),
),
Padding(
padding: EdgeInsets.only(top: 10, bottom: 50),
child: Container(
height: 1,
width: MediaQuery.of(context).size.width / 1.4,
color: Colors.black26,
),
),
Container(
width: MediaQuery.of(context).size.width / 1.5,
height: MediaQuery.of(context).size.height / 15,
alignment: FractionalOffset.center,
decoration: BoxDecoration(
color: const Color.fromRGBO(250, 80, 120, 1),
borderRadius: BorderRadius.all(const Radius.circular(30)),
),
child: Text(
"가이드 라인을 읽어주세요 !",
style: TextStyle(
color: Colors.white,
fontSize: 20,
fontWeight: FontWeight.w300,
letterSpacing: 0.3,
),
),
),
Padding(
padding: const EdgeInsets.only(top: 100),
child: Row(
children: <Widget>[
PictureBox(),
PictureBox(),
PictureBox(),
],
),
),
Padding(
padding: const EdgeInsets.only(top: 10),
child: Row(
children: <Widget>[
PictureBox(),
PictureBox(),
PictureBox(),
],
),
),
InkWell(
onTap: (){uploadPic(context);},
child: Padding(
padding: EdgeInsets.only(top: 50),
child: Container(
width: MediaQuery.of(context).size.width / 3,
height: MediaQuery.of(context).size.height /20,
alignment: FractionalOffset.center,
decoration: BoxDecoration(
color: const Color.fromRGBO(250, 80, 100, 1),
borderRadius: BorderRadius.all(const Radius.circular(30)),
),
child: Text(
"Next",
style: TextStyle(
color: Colors.white,
fontSize: 20,
fontWeight: FontWeight.w500,
letterSpacing: 0.3,
),
),
),
),
),
],
),
),
),
),
),
);
}
}
class PictureBox extends StatefulWidget {
#override
_PictureBoxState createState() => _PictureBoxState();
}
class _PictureBoxState extends State<PictureBox>{
#override
Widget build(BuildContext context) {
return Container(
child: InkWell(
onTap: (){getImage(context);},
child: Padding(
padding: EdgeInsets.only(left: 10),
child:Container(
width: MediaQuery.of(context).size.width / 3.3,
height: MediaQuery.of(context).size.height / 7,
color: Colors.black12,
child: Center(
child: (_image!=null)? Image.file(_image, fit:BoxFit.fill)
:Icon(
Icons.camera_alt,
color: Colors.black26,
),
),
),
),
),
);
}
}
This is my code , i want use to 'Future getImage()' in PictureBox
How to running getImage() in PictureBox?
Additionally how to solve error 'undefined name '_image'' in PictureBox ?
_ means private variable. So remove _ and try.
If you want to call a function inside a StatefulWidget widget
You need to use GlobalKey to keep YourFormState and call function inside YourFormState with key.currentState
The following demo is appbar action call a function inside a form StatefulWidget, so appbar action and form submit button can use same function and snackbar also work fine
code snippet
final key = new GlobalKey<MyCustomFormState>();
...
appBar: AppBar(
title: Text(widget.title),
actions: <Widget>[
// action button
IconButton(
icon: Icon(Icons.access_alarm),
onPressed: () {
key.currentState.validateform();
},
),
]),
...
children: <Widget>[
MyCustomForm(key: key),
...
class MyCustomForm extends StatefulWidget {
MyCustomForm({ Key key }) : super(key: key);
full code
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
final key = new GlobalKey<MyCustomFormState>();
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
// This widget is the home page of your application. It is stateful, meaning
// that it has a State object (defined below) that contains fields that affect
// how it looks.
// This class is the configuration for the state. It holds the values (in this
// case the title) provided by the parent (in this case the App widget) and
// used by the build method of the State. Fields in a Widget subclass are
// always marked "final".
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
var myCustomForm = MyCustomForm();
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
// This call to setState tells the Flutter framework that something has
// changed in this State, which causes it to rerun the build method below
// so that the display can reflect the updated values. If we changed
// _counter without calling setState(), then the build method would not be
// called again, and so nothing would appear to happen.
_counter++;
});
}
#override
Widget build(BuildContext context) {
// This method is rerun every time setState is called, for instance as done
// by the _incrementCounter method above.
//
// The Flutter framework has been optimized to make rerunning build methods
// fast, so that you can just rebuild anything that needs updating rather
// than having to individually change instances of widgets.
return Scaffold(
appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text(widget.title),
actions: <Widget>[
// action button
IconButton(
icon: Icon(Icons.access_alarm),
onPressed: () {
key.currentState.validateform();
},
),
]),
body: Center(
// Center is a layout widget. It takes a single child and positions it
// in the middle of the parent.
child: Column(
// Column is also layout widget. It takes a list of children and
// arranges them vertically. By default, it sizes itself to fit its
// children horizontally, and tries to be as tall as its parent.
//
// Invoke "debug painting" (press "p" in the console, choose the
// "Toggle Debug Paint" action from the Flutter Inspector in Android
// Studio, or the "Toggle Debug Paint" command in Visual Studio Code)
// to see the wireframe for each widget.
//
// Column has various properties to control how it sizes itself and
// how it positions its children. Here we use mainAxisAlignment to
// center the children vertically; the main axis here is the vertical
// axis because Columns are vertical (the cross axis would be
// horizontal).
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
MyCustomForm(key: key),
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
class MyCustomForm extends StatefulWidget {
MyCustomForm({ Key key }) : super(key: key);
#override
MyCustomFormState createState() {
return MyCustomFormState();
}
}
// Create a corresponding State class.
// This class holds data related to the form.
class MyCustomFormState extends State<MyCustomForm> {
// Create a global key that uniquely identifies the Form widget
// and allows validation of the form.
//
// Note: This is a GlobalKey<FormState>,
// not a GlobalKey<MyCustomFormState>.
final _formKey = GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
// Build a Form widget using the _formKey created above.
return Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
TextFormField(
validator: (value) {
if (value.isEmpty) {
return 'Please enter some text';
}
return null;
},
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0),
child: RaisedButton(
onPressed: () {
// Validate returns true if the form is valid, or false
// otherwise.
validateform();
},
child: Text('Submit'),
),
),
],
),
);
}
void validateform() {
// Validate returns true if the form is valid, or false
// otherwise.
if (_formKey.currentState.validate()) {
// If the form is valid, display a Snackbar.
Scaffold.of(context)
.showSnackBar(SnackBar(content: Text('Processing Data')));
}
}
}
#Killer Whale, if you want to call child method from parent and setState() in child, then you can use GlobalKey.
GlobalKey<WriteprofileState> globalKey =new GlobalKey<WriteprofileState>();
_writeprofileState remote private identifier and write as WriteprofileState.
then pass global key from parent to WriteprofileState
like :
Widget build(BuildContext conext){
return Container(
child: Writeprofile(
key:globalKey
)
);
}
and then pass this key to super class, Writeprofile(Key key):super(key:key);
and now from parent class you can access all method of child.
globalKey.currentState.methodName();

Customizing floating action button

I am using sliver list and I want to use both floating action button and sliding_up_panel from pub with the following behaviour: when I scroll down my list, the floating action button disappears; when I scroll up the fab appears. Moreover, the fab should disappear when I slide up (open) the menu.
As you can see above, the floating action button is all on the sliding element, but I want it to be between the sliding element and the scrolling item list.
Also in above picture, the problem is that the floating button is actually visible but I want to hide it with a nice animation when I slide up the sliding menu.
I hope my question is clear!!!
Edit please do it with scroll controller
full code
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',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: SliverExample(
bodyWidgets: Text('Hello Body'),
backgroundWidget: Text('Hello Background'),
),
);
}
}
Widget listItem(Color color, String title) => Container(
height: 100.0,
color: color,
child: Center(
child: Text(
"$title",
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontSize: 14.0,
fontWeight: FontWeight.bold),
),
),
);
class SliverExample extends StatefulWidget {
final Widget backgroundWidget;
final Widget bodyWidgets;
SliverExample({
this.backgroundWidget,
this.bodyWidgets,
});
#override
_SliverExampleState createState() => _SliverExampleState();
}
class _SliverExampleState extends State<SliverExample> {
// I need something like this
// To determine if SliverAppBar is expanded or not.
ScrollController _scrollController;
bool isAppBarExpanded = false;
#override
void initState() {
super.initState();
_scrollController = ScrollController()
..addListener(() => setState(() {
print('Scroll view Listener is called offset ${_scrollController.offset}');
}));
}
bool get _changecolor {
return _scrollController.hasClients
&& _scrollController.offset > (200-kToolbarHeight);
}
bool get _hideFAB {
return _scrollController.hasClients
&& _scrollController.offset > (200-kToolbarHeight);
}
#override
Widget build(BuildContext context) {
// To change the item's color accordingly
// To be used in multiple places in code
//Color itemColor = isAppBarExpanded ? Colors.white : Colors.black;
// In my case PrimaryColor is white,
// and the background widget is dark
return Scaffold(
body: CustomScrollView(
controller: _scrollController,
slivers: <Widget>[
SliverAppBar(
pinned: true,
leading: BackButton(
color: _changecolor? Colors.white: Colors.black, // Here
),
actions: <Widget>[
IconButton(
icon: Icon(
Icons.shopping_cart,
color: _changecolor? Colors.white: Colors.black, // Here
),
onPressed: () {},
),
],
expandedHeight: 200.0,
flexibleSpace: FlexibleSpaceBar(
centerTitle: true,
title: Text(
'title',
style: TextStyle(
fontSize: 18.0,
color: _changecolor? Colors.white: Colors.black, // Here
),
),
// Not affecting the question.
background: widget.backgroundWidget,
),
),
SliverList(
///Use SliverChildListDelegate and provide a list
///of widgets if the count is limited
///
///Lazy building of list
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
/// To convert this infinite list to a list with "n" no of items,
/// uncomment the following line:
/// if (index > n) return null;
return listItem(Colors.grey, "Sliver List item: $index");
},
/// Set childCount to limit no.of items
/// childCount: 100,
),
),
// Not affecting the question.
SliverToBoxAdapter(child: widget.bodyWidgets),
],
),
floatingActionButton: _hideFAB? Container() : FloatingActionButton(
onPressed: () {},
child: Icon(Icons.add,),
),
);
}
}