How to force screen to scroll down upon clicking text field? - flutter

I have this code and when i click on textfield it DOES appear on middle of screen above the keyboard, but it's very tightly fit there and the text below it does not appear. How can i make it so that when I click on the textfield the scrolling is enough to show the text below it as well?
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
SizedBox(height: 600,),
TextField(
),
SizedBox(height: 30,),
Text("I want this text to appear ")
],
),
),
),
);
}
}

There is no exact solution for this, however you can use ScrollController to scroll the rest of the area in your SingleChildScrollView
ScrollController _scrollController = ScrollController();
#override
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
controller: _scrollController,
child: Column(
children: <Widget>[
SizedBox(height: 600),
TextField(
onTap: () {
Timer(Duration(milliseconds: 200), () {
_scrollController.jumpTo(_scrollController.position.maxScrollExtent);
});
},
),
SizedBox(height: 30),
Text("I want this text to appear "),
],
),
),
);
}.

Related

How to copy the value of a Widget Text to another using onPressed property of a button

I need to copy a value of a Text Widget and copy this to another.
I tried to this using keys, but I don't know how to acess the Text Widget in this case.
Is it possible to do in Flutter, using the onPressed property?
import 'package:flutter/material.dart';
class TextWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Value to be copied",
key: Key('text1')
),
RaisedButton(
onPressed: (){
// code here
},
child: Text("Copy value"),
),
SizedBox(height: 40),
Text(
"",
key: Key('text2')
)
],
),
),
);
}
}
Answering your question directly: you can access text inside Text widget using its data property.
Text widget = Text('text value');
String text = widget.data;
print(text); // text value
Next, you can't access widgets by their key properties. At least you shouldn't, because they were designed for different purpose: here's a video and an article about keys in Flutter.
What you can do here is turn your TextWidget from StatelessWidget into StatefulWidget and render contents of your second Text based on the state. Good introduction into what the state is and why you should use it can be found on official Flutter website: Start thinking declaratively.
Then you can save your first Text widget in a variable and then access its contents directly using data property update, then update state of the whole widget.
Example 1 on DartPad
More canonical and in general preferrable approach is to render contents of both buttons based on the state and get desired text from state variable and not from the widget itself, as proposed by Sebastian and MSARKrish.
Example 2 on DartPad
Note that you can't change data attribute of a Text widget imperatively, like you would do in JavaScript DOM API with innerText:
_textWidget.data = "New text"; // Doesn't work
because its data is final. In Flutter you have to think declaratively, and it worth it.
Try this
import 'package:flutter/material.dart';
final Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: MyWidget(),
),
),
);
}
}
class MyWidget extends StatefulWidget {
#override
_MyWidgetState createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
String _text = "Value to be copied";
bool _buttonToggle;
#override
void initState() {
super.initState();
_buttonToggle = false;
}
#override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(_text),
SizedBox(height: 40),
RaisedButton(
onPressed: _toggle,
child: Text("Copy value"),
),
Switch(
value: _buttonToggle,
onChanged: (_) => _toggle(),
),
SizedBox(height: 40),
Text(_buttonToggle ? _text : '')
],
);
}
void _toggle() {
setState(() => _buttonToggle = !_buttonToggle);
}
}
class TextWidget extends StatefulWidget {
#override
_TextWidgetState createState() => _TextWidgetState();
}
class _TextWidgetState extends State<TextWidget> {
String text1Value = "text to be copied";
String text2Value = "";
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
text1Value,
),
RaisedButton(
onPressed: () {
setState(() {
text2Value = text1Value;
});
},
child: Text("Copy value"),
),
SizedBox(height: 40),
Text(
text2Value,
)
],
),
),
);
}
}

how do I listen isDrawerOpen on Flutter?

I want to hide some widgets when the drawer opens. (it's mean when user open drawer then I need to hide some widgets)
Currently, I am using
if(!_scaffoldKey.currentState.isDrawerOpen)
//hide widget
But this is not listen. Is there any way to do listen drawer callbacks?
There is no callback mechanism till now in flutter which gives events for Drawer(), but still we can apply a good solution for it.
I divided the solution using two stateful widgets,
HomeScreen (Main Widget)
MyDrawer (Drawer Widget)
1. HomeScreen:
class HomeScreen extends StatefulWidget {
#override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
bool _isDrawerOpen = false;
void drawerCallback(bool isOpen) {
print('Drawer Status:' + isOpen.toString());
// Based on the bool value set visibility of your widget
WidgetsBinding.instance.addPostFrameCallback((_){
setState(() {
_isDrawerOpen = isOpen;
});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
appBar: AppBar(title: Text('Nav Sample App')),
body: _isDrawerOpen
? Align(alignment: Alignment.centerRight, child: Text('Drawer Open'))
: Align(alignment: Alignment.centerRight, child: Text('Drawr Close')),
drawer: MyDrawer(drawerCallback));
}
}
Above you can see that based on _isDrawerOpen we are setting widgets in the body with the ternary operator.
2. MyDrawer()
class MyDrawer extends StatefulWidget {
final Function _drawerCallback;
MyDrawer(this._drawerCallback);
#override
_MyDrawerState createState() => _MyDrawerState();
}
class _MyDrawerState extends State<MyDrawer> {
#override
void initState() {
super.initState();
widget._drawerCallback(true);
}
#override
void dispose() {
widget._drawerCallback(false);
super.dispose();
}
#override
Widget build(BuildContext context) {
return Drawer(
child: ListView(
children: <Widget>[
DrawerHeader(
child: Text('Drawer Header'),
decoration: BoxDecoration(color: Colors.blue),
),
Text("Drawer Item 1"),
Text("Drawer Item 2"),
],
),
);
}
}
Heart of the logic is applied in initState() and dispose() callbacks where we are returning status.
You can use the onTap() function for drawers using a ListView:
Drawer(
child: ListView(
// Important: Remove any padding from the ListView.
padding: EdgeInsets.zero,
children: <Widget>[
DrawerHeader(
child: Text('Drawers'),
decoration: BoxDecoration(
color: Colors.blue,
),
),
ListTile(
title: Text('Drawer 1'),
onTap: () {
// Insert code to hide or delete your desired widget
// Then close the drawer
Navigator.pop(context);
},
),
],
),
),//drawer

Is there solution for images disapearing in flutter after hot reload?

I'm creating a new flutter app, and i want a solution for the images disappearing problem after flutter hot reload.
import 'package:flutter/material.dart';
class Home extends StatefulWidget {
#override
State <StatefulWidget> createState() {
return HomeState();
}
}
class HomeState extends State<Home> {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
backgroundColor: Colors.redAccent,
title: Text('Login Page '),
),
body: Container(
padding: EdgeInsets.all(33.0),
alignment: Alignment.center,
child: Column(
children: <Widget>[
Image.asset('img/userlogin.png'),
Container(
child: Column(
children: <Widget>[
TextField(
controller: null,
decoration: InputDecoration(
icon: Icon(Icons.person), hintText: 'Yor Name'),
)
],
),
)
],
),
),
);
}
}
You could pre-cache the image using preCacheImage function inside you initState methods
like so:
class HomeState extends State<Home> {
#override
void initState() {
precacheImage(new AssetImage('img/userlogin.png'));
super.initState();
}
#override
Widget build(BuildContext context) {
// Widgets...
}
}

flutter: no refresh indicator when using RefreshIndicator

I added the RefreshIndicator to my page, but there is no indicator visible when pull to refresh. The code is below:
class HomePage extends StatefulWidget {
HomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<HomePage> {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
body: LocalGalleryTab(),
);
}
}
class LocalGalleryTab extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return _LocalGalleryState();
}
}
class _LocalGalleryState extends State<LocalGalleryTab> {
#override
Widget build(BuildContext context) {
return new Container(child: new Center(
child: new RefreshIndicator(
child: Text("Local Gallery"),
onRefresh: _refreshLocalGallery,
),
));
}
Future<Null> _refreshLocalGallery() async{
print('refreshing stocks...');
}
}
How to use the RefreshIndicator? The flutter doc does not give much infomation.
By design, RefreshIndicator works with ListView.
But if you want to use RefreshIndicator with non-scrollable-widgets, you can wrap your widget into Stack with ListView:
RefreshIndicator(
onRefresh: () {},
child: Stack(
children: <Widget>[ListView(), YOUR_CHILD_WIDGET],
),
),
Refresh Indicator by default does not work on a short list so add the following to the ListView.builder
physics: const AlwaysScrollableScrollPhysics(),
You need to add scroll child inside RefreshIndicator
see example below
class HomePage extends StatefulWidget {
HomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<HomePage> {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
body: LocalGalleryTab(),
);
}
}
class LocalGalleryTab extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return _LocalGalleryState();
}
}
class _LocalGalleryState extends State<LocalGalleryTab> {
#override
Widget build(BuildContext context) {
return new Container(child: new Center(
child: new RefreshIndicator(
child: ListView(
children: List.generate(50, (f) => Text("Item $f")),
),
onRefresh: _refreshLocalGallery,
),
));
}
Future<Null> _refreshLocalGallery() async{
print('refreshing stocks...');
}
}
RefreshIndicator(
onRefresh: _onRefresh,
child:SingleChildScrollView(
physics: AlwaysScrollableScrollPhysics(),
child: ListView(
padding: EdgeInsets.all(8.0),
children: _listData.map((i) {
return ListTile(
title: Text("Item $i"),
);
}).toList(),
)
)
);
Add physics in SingleChildScrollView
You can use ListView with SinglchildScrollView widget also.
RefreshIndicator(
onRefresh: () {
//HERE YOUR FUNCTION TO CALL
},
child: Stack(
children: <Widget>[
ListView(
physics: const AlwaysScrollableScrollPhysics(),
children: []
)
],
),
),
In Non-scrollable list view, RefreshIndicator does not work, so you have to wrap your widget with Stack for implementing pull down to refresh.
RefreshIndicator(
onRefresh: () {
// Refresh Functionality
},
child: Stack(
children: [
ListView(
padding: EdgeInsets.zero,
shrinkWrap: true,
children: [
SizedBox(
height: MediaQuery.of(context).size.height,
)
],
),
// Your Widget
],
);
),
I think the best approach by far is to use CustomScrollView with RefreshIndicator. See example below.
class RefreshDemo extends StatelessWidget {
const RefreshDemo({super.key});
#override
Widget build(BuildContext context) {
return RefreshIndicator(
onRefresh: () async {
// Your refresh logic goes here
await Future.delayed(Duration(seconds: 2));
return true;
},
child: CustomScrollView(
slivers: [
// Wrap your widgets with the SliverToBoxAdapter
SliverToBoxAdapter(
child: Container(
child: Column(
children: [
Text('Hello'),
Text('World'),
]
)
),
),
],
),
);
}
}
I got the solution of this after little change from one answer which was already there in current page!
Just need to change position of stack children (main widget first then listview).
updated answer which will work 100%:
RefreshIndicator(
onRefresh: () {},
child: Stack(
children: <Widget>[YOUR_CHILD_WIDGET, ListView()],
),
),
past answer from above answers:
RefreshIndicator(
onRefresh: () {},
child: Stack(
children: <Widget>[ListView(), YOUR_CHILD_WIDGET],
),
),
The most important is to implement in ListView:
physics: const AlwaysScrollableScrollPhysics(),
because otherwise items which are not covering whole screen are stuck and you cannot move/refresh them.
as mentioned above refresh indicator only works with Listview so use it else wrap Listview with Stack

How to implement a right navbar in flutter?

The flutter scaffold shows a right navbar, but I suppose there is no right nav widget. How do I implement a right navbar with scaffold in flutter?
Flutter Scaffold Image
The Scaffold now has a endDrawer property which swipes from right-to-left.
Hope this might help someone.
If you are trying to show a right bar/menu or Drawer in your app, whether it is has a permanent view or a temporary one. I was able to achieve this by building my own custom widget from Allign, Container and Column widgets, and by using setState to show or hide the menu bar based on user interaction, see this simple example.
My custom menu widget looks like the following:
class RightNavigationBar extends StatefulWidget {
#override
_RightNavigationBarState createState() => new _RightNavigationBarState();
}
class _RightNavigationBarState extends State<RightNavigationBar> {
#override
Widget build(BuildContext context) {
return new Align(
alignment: FractionalOffset.centerRight,
child: new Container(
child: new Column(
children: <Widget>[
new Icon(Icons.navigate_next),
new Icon(Icons.close),
new Text ("More items..")
],
),
color: Colors.blueGrey,
height: 700.0,
width: 200.0,
),
);
}
}
Then when the user presses the menu icon, an object of my custom RightNavigationBar widget is created inside setState :
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => new _MyAppState();
}
class _MyAppState extends State<MyApp> {
var _myRightBar = null;
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
actions: [new IconButton(
icon: new Icon (Icons.menu), onPressed: _showRightBar)
],
title: new Text("Right Navigation Bar Example"),
),
body: _myRightBar
);
}
_showRightBar() {
setState(() {
_myRightBar == null
? _myRightBar = new RightNavigationBar()
: _myRightBar = null;
});
}
}
vertical_navigation_bar
How to use it? #
Install
dependencies:
vertical_navigation_bar: ^0.0.1
Run flutter command
flutter pub get
import 'package:flutter/material.dart';
import 'package:vertical_navigation_bar/vertical_navigation_bar.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Abubakr Elghazawy (Software Developer)',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final pageController = PageController(
initialPage: 0,
keepPage: true
);
final navItems = [
SideNavigationItem(icon: FontAwesomeIcons.calendarCheck, title: "New task"),
SideNavigationItem(icon: FontAwesomeIcons.calendarAlt, title: "Personal task"),
SideNavigationItem(icon: FontAwesomeIcons.fileAlt, title: "Personal document"),
SideNavigationItem(icon: FontAwesomeIcons.calendar, title: "Company task"),
SideNavigationItem(icon: FontAwesomeIcons.arrowCircleRight, title: "Options")
];
final initialTab = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Row(
children: <Widget>[
SideNavigation(
navItems: this.navItems,
itemSelected: (index){
pageController.animateToPage(
index,
duration: Duration(milliseconds: 300),
curve: Curves.linear
);
},
initialIndex: 0,
actions: <Widget>[
],
),
Expanded(
child: PageView.builder(
itemCount: 5,
controller: pageController,
scrollDirection: Axis.vertical,
physics: NeverScrollableScrollPhysics(),
itemBuilder: (context, index){
return Container(
color: Colors.blueGrey.withOpacity(0.1),
child: Center(
child: Text("Page " + index.toString()),
)
);
},
),
)
],
),
);
}
}
More Dtailsenter link description here
Use the endDrawer property of the Scaffold like this:
Scaffold(
resizeToAvoidBottomInset: false,
key: _scaffoldKey,
endDrawer: const SideBar(),
body: CustomScrollView(