Flutter text fields and keyboard avoidance - flutter

I'm having trouble understanding the keyboard avoidance dynamic.
Could anyone explain the behavior shown in this example below?
I think ultimately, I would like the whole screen to be scrollable, rather than removing the expandable space when the virtual keyboard pops up. (for example, the spacing between "Log in" and the text fields)

To fix this issue you have to warp your widgets with SingleChildScrollView, I've made an example to explain in detail how to implement it. You can try it with your code:
import 'package:flutter/material.dart';
class TestPage extends StatelessWidget {
const TestPage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return SafeArea(
child: SingleChildScrollView(
child: Column(
children: List.generate(
6,
(index) => const Padding(
padding: EdgeInsets.all(8.0),
child: TextField(
decoration: InputDecoration(
border: OutlineInputBorder(),
hintText: 'Example',
),
),
),
)),
),
);
}
}
The above code result would outpot:

Related

Flutter web - shortcuts and action widget is not listening the keyboard events at page level for providing the keyboard shortcuts

In my use case, I have multiple layouts in a particular page. for ex, in a page, i have layout(lets say layout-1) where i get the input data from user using list of textfield and then in the same page, i have another layout (lets say layout-2) in the bottom where table widget is being used to list row by row for the data that we received from user. similarly i have other layouts in the same page. I am trying to provide the keyboard shortcuts for these by using control + D, control + R etc. so the problem that i am facing is, if i focused on the texfield in layout-1 and then i press keyboard keys control + D this is focusing the expected widget correctly. but if i click outside of the texfield (anywhere in the screen on the particular page), then it loose the focus. now if i click the control + D, the shortcuts & action widget not listening the keyboard events.
In order to show this problem i just created simple code here and in this code if i click outside of the text field and if i try to use control + D, its not working.
for example, in the below code i have two textfields and i am focusing in these text fields based on shortcuts (this is just an example to explain the problem). control + R is to focus in textfield1 and control + D is to focus on textfield2. its working fine. but if i click somewhere outside of the text field and then if i try shortcuts, its not listening the keyboard events. it loose the focus.
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class KeyboardShortcutTesting extends StatelessWidget {
KeyboardShortcutTesting({Key? key}) : super(key: key);
final FocusNode textfield1FocusNode = FocusNode();
final FocusNode textfield2FocusNode = FocusNode();
#override
Widget build(BuildContext context) {
return Shortcuts(
shortcuts: {
LogicalKeySet(LogicalKeyboardKey.controlLeft, LogicalKeyboardKey.keyR):
Testfield1ShorcutIntent(),
LogicalKeySet(LogicalKeyboardKey.controlLeft, LogicalKeyboardKey.keyD):
Testfield2ShorcutIntent(),
},
child: Actions(
actions: {
Testfield1ShorcutIntent:
CallbackAction<Testfield1ShorcutIntent>(onInvoke: (intent) {
print('clicked cnrl + D');
return textfield1FocusNode.requestFocus();
}),
Testfield2ShorcutIntent:
CallbackAction<Testfield2ShorcutIntent>(onInvoke: (intent) {
print('clicked cnrl + R');
return textfield2FocusNode.requestFocus();
}),
},
child: Focus(
autofocus: true,
child: Scaffold(
appBar: AppBar(title: const Text('Keyboard shortcut testing')),
body: Center(
child: Card(
color: Colors.amber[50],
child: Padding(
padding: const EdgeInsets.all(16.0),
child: SizedBox(
width: 300,
height: 200,
child: Column(
children: [
TextField(
focusNode: textfield1FocusNode,
decoration: const InputDecoration(
border: OutlineInputBorder(),
),
),
const SizedBox(height: 10),
TextField(
focusNode: textfield2FocusNode,
decoration: const InputDecoration(
border: OutlineInputBorder(),
),
),
],
),
),
),
),
)),
),
),
);
}
}
class Testfield1ShorcutIntent extends Intent {}
class Testfield2ShorcutIntent extends Intent {}
This code i am trying for flutter web. i am also attaching an image to show the problem. here if i focus either on textfield1 or texfield2 and then if i press control + D or control + R then the focus is being switched between the textfields as per the logic but i click outside of the textfield (anywhere in the yellow color card or outside of yellow color card) and then if i press then shortcuts are not working as its not even listening the keys.
Note: I also tried using FocusScope widget instead of Focus widget but FocusScope widget is not allowing to focus outside. for ex. if i use FocusScope widget and if i click outside of the textfield, its not allowing because the focus is not coming out from the textfield. it continuously focusing on the same textfield widget.
Appreciate the response!.
Flutter Docs suggests using Stateful Widget for creating FocusNode
Flutter provide pre-build Intent to request focus -> RequestFocusIntent(focusNode1)
Try out the following code,
class TextFieldShortcut extends StatefulWidget {
const TextFieldShortcut({super.key});
#override
State<TextFieldShortcut> createState() => _TextFieldShortcutState();
}
class _TextFieldShortcutState extends State<TextFieldShortcut> {
late final FocusNode focusNode1, focusNode2;
#override
void initState() {
super.initState();
focusNode1 = FocusNode();
focusNode2 = FocusNode();
}
#override
void dispose() {
focusNode1.dispose();
focusNode2.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Shortcuts(
shortcuts: {
LogicalKeySet(LogicalKeyboardKey.controlLeft, LogicalKeyboardKey.keyM):
RequestFocusIntent(focusNode1),
LogicalKeySet(LogicalKeyboardKey.controlLeft, LogicalKeyboardKey.keyQ):
RequestFocusIntent(focusNode2),
},
child: MaterialApp(
home: Scaffold(
body: Center(
child: Column(
children: [
TextField(
autofocus: true,
focusNode: focusNode1,
),
TextField(
focusNode: focusNode2,
),
],
),
),
),
),
);
}
}

Screen Shift to Left using Flutter Reaction Button Pub

I'm gonna use flutter reaction button plugin on new my app.
But when I put the reaction button, and push the icon, Preview icon box is shown to right side and main view is moved to left site.1
Here is the Item Codes to show pics and reaction button.
class CommunicationItem extends StatefulWidget {
const CommunicationItem({#required this.communication});
final Communication communication;
#override
_CommunicationItemState createState() => _CommunicationItemState();
}
class _CommunicationItemState extends State<CommunicationItem> {
#override
Widget build(BuildContext context) {
return Card(
margin: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
elevation: 2,
child: ClipRRect(
borderRadius: const BorderRadius.all(Radius.circular(5)),
child: Column(
children: [
Image.asset('assets/images/showImage.png'),
spaceH8,
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Row(
children: [
FlutterReactionButtonCheck(
onReactionChanged: (reaction, index, isChecked) {
print('reaction selected index test: $index');
},
reactions: data.reactions,
initialReaction: data.defaultInitialReaction,
selectedReaction: data.reactions[0],
),
I know the other solution like this link.
https://githubmemory.com/repo/GeekAbdelouahed/flutter-reaction-button/issues/22
But I don't know the solution by codes.
Please help it.
V/r,
This happened because the transition of the CupertinoPageRoute, try to set the page transition to none.

Flutter custom widget fails to display

I am a newbie to Flutter and Dart, and am trying to create a clickable container class that is based on the
GestureDetector class. My code for my container is shown below:
class CustomWidget extends GestureDetector
{
final aTitle;
CustomWidget(this.aTitle)
{
onTap() {
print("$aTitle was pressed!");
}
child: new Container(
padding: const EdgeInsets.all(8),
child: Text(aTitle),
color: Colors.blueGrey[200],
);
}
}
I am attempting to display this widget in my main application screen using the following code in the body of my app widget:
body: CustomScrollView(
primary: false,
slivers: <Widget>[
SliverPadding(
padding: const EdgeInsets.all(20),
sliver: SliverGrid.count(
crossAxisSpacing: 10,
mainAxisSpacing: 10,
crossAxisCount: 2,
children: <Widget>[
CustomWidget('Test Display'),
],
),
),
],
),
I seem to have two problems: (1) my development environment is telling me that my onTap() method is "unused", indicating
that it will not capture tap events, and (2) that doesn't seem to matter much because the CustomWidget instance that I am
creating in the app widget is not appearing on my screen.
I am clearly missing something. Can someone help me correct my code so that my custom widget will be displayed and process
onTap events?
Generally speaking, the CustomWidget is a good idea, but inheritance is the wrong implementation. Flutter strongly favors composition over inheritance.
Your custom widget using composition:
class CustomWidget extends StatelessWidget {
final String title;
const CustomWidget(this.title);
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
print("$title was pressed!");
},
child: new Container(
padding: const EdgeInsets.all(8),
child: Text(title),
color: Colors.blueGrey[200],
));
}
}

Flutter: IconButton onPressed responding in console but not in the display

I am new to Flutter and trying to build a responsive web app. So far, the code I have working is when the screen shrinks in width to a certain size, the navigation bar and its items get crunched into a menu icon button (Flutter's IconButton). This works. What doesn't work is when I click the IconButton, the new navigation bar doesn't pop up, even though the console shows I'm clicking on it. DrawerItem() is just a Text Widget wrapped in a Container. After the couple sections of code, you can see the console spitting out a response. I do not get any errors on screen or in the console when I adjust the screen size or when I click the IconButton. I've also tried making the MNavigationBar a stateful widget and adding setState to the onPressed attribute, nothing changes from the current issue and the same thing happens.
class MNavigationBar extends StatelessWidget {
const MNavigationBar({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
height: 80,
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
IconButton(
icon: Icon(
Icons.menu,
),
onPressed: () {
NavigationDrawer();
print('Menu Icon pressed');
},
),
NavBarLogo(),
],
),
);
}
}
class NavigationDrawer extends StatelessWidget {
const NavigationDrawer({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
width: 260,
decoration: BoxDecoration(
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.black,
blurRadius: 16,
),
],
),
child: Column(
children: <Widget>[
NavigationDrawerHeader(),
DrawerItem('Home'),
DrawerItem('Events'),
NavBarMenuDropdown(),
DrawerItem('Store'),
DrawerItem('Partners'),
DrawerItem('About Us'),
],
),
);
}
}
Performing hot restart... 148ms
Restarted application in 149ms.
Menu Icon pressed
Menu Icon pressed
Thank you, Afridi Kayal! I did exactly what you said and it works great! See the answer in the code below...
In my main Scaffold widget, I added this code and also added logic with a ResponsiveBuilder
return ResponsiveBuilder(
builder: (context, sizingInformation) => Scaffold(
drawerEnableOpenDragGesture: false,
drawer: sizingInformation.deviceScreenType == DeviceScreenType.Mobile
? NavigationDrawer()
: null,
In my MNavigationBar, I modified this.
onPressed: () {
Scaffold.of(context).openDrawer();
print('Menu Icon pressed');
},

Flutter Dynamic maxHeight

I build a scrolling textfield like proposed in https://github.com/flutter/flutter/issues/9365. Now I want the maxHeight of the ConstrainedBox change dynamically, according to the shown or not shown keyboard. Is there a way to accomplish this?
Widget _buildTextInput() {
return new Container(
padding: new EdgeInsets.all(7.0),
child: new ConstrainedBox(
constraints: new BoxConstraints(
maxHeight: 150.0 <-- This should be dynamic
),
child: new SingleChildScrollView(
scrollDirection: Axis.vertical,
reverse: true,
// here's the actual text box
child: new TextField(
keyboardType: TextInputType.multiline,
maxLines: null, //grow automatically
decoration: new InputDecoration.collapsed(
hintText: 'Please enter a lot of text',
),
),
),
),
);
}
The red box should be the constrained box with open keyboard.
And like so with a closed keyboard.
EDIT:
I'm trying to build an input field that's kind of like posting on Twitter. I need to combine a CircleAvatar, a TextField and a GridView to display the user's avatar, his post and a few images. Like on Twitter, I want the whole thing to scroll, not only the TextField - both while typing and while reviewing what the user typed or uploaded. Besides, the (multiline) TextField should scroll while typing in the visible area (keeping the open or closed keyboard in mind), so the user can see what he's typing.
Even though the Flutter TextField autoscrolls now, I can't get this whole cluster working. Any idea?
Autoscroll has been supported natively in the textfield widget since I believe the beginning of June (2018) - I think this is the commit that added it. You may need to update to the most recent flutter build for it to work, but that is included in version 5.5.
This simplifies matters a bit - this should be all you need to do to get it to work as you want:
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatefulWidget {
#override
State<StatefulWidget> createState() => new MyAppState();
}
class MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: new Scaffold(
appBar: new AppBar(
title: new Text("Example"),
),
body: new Container(
padding: new EdgeInsets.all(7.0),
child: new TextField(
keyboardType: TextInputType.multiline,
maxLines: null,
decoration: new InputDecoration.collapsed(
hintText: 'Please enter a lot of text',
),
),
),
),
);
}
}
EDIT: To answer the OP's edited question - wanting to have other elements within the same scrolling pane as the textview, I've made this:
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatefulWidget {
#override
State<StatefulWidget> createState() => new MyAppState();
}
class MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: new Scaffold(
appBar: new AppBar(
title: new Text("Example"),
),
body: new SingleChildScrollView(
child: new Container(
padding: new EdgeInsets.all(7.0),
child: new Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
new CircleAvatar(
backgroundColor: Colors.blue,
child: new Text("AB"),
),
new Expanded(
child: new Column(
children: [
new TextField(
keyboardType: TextInputType.multiline,
maxLines: null,
decoration: new InputDecoration.collapsed(
hintText: 'Please enter a lot of text',
),
),
new Container(
height: 300.0,
width: 100.0,
color: Colors.green,
),
],
),
),
],
),
),
),
),
);
}
}
By using a SingleChildScrollView, we're still allowing the children to set the size of the viewport (as opposed to a MultiChildLayoutDelegate etc which has to have that size set). The textview grows as big as it needs to be, but doesn't scroll itself as its height is not constrained. The Expanded is needed within the row to make sure that the right side (with the text & pictures) is as large as it can be horizontally.