I want to make my custom-widget respond to touch, hence I used GestureDetector's onTap method. It's working but it is also changing the dimensions of my custom widget, which I don't want. I am posting some code and screen-shots to make the situation more clear.
What I want is this, just a MALE card (my custom-widget called ReusableCard).
After wrapping my ReusableCard widget in a GestureDetector, what I get is this.
I am sharing my code here. In this code I haven't used GestureDetector yet.
class _InputPageState extends State<InputPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Center(
child: Text('BMI Calculator')
),
),
body: Column(
children: [
Expanded(
child: Row(
children: [
ReusableCard(activeCardColor,
IconContents(FontAwesomeIcons.mars, 'MALE')),
ReusableCard(activeCardColor,
IconContents(FontAwesomeIcons.venus, 'FEMALE')),
],
),
),
Expanded(
child: Row(
children: [
ReusableCard(activeCardColor),
],
),
),
Expanded(
child: Row(
children: [
ReusableCard(activeCardColor),
ReusableCard(activeCardColor),
],
),
),
Container(
color: bottomContainerColor,
width: double.infinity,
margin: EdgeInsets.only(top: 10),
height: bottomContainerHeight,
),
],
),
);
}
}
The real meaty part of the code is in Blockquotes. Meaty Part after adding GestureDetector to MALE ReusableCard.
GestureDetector(
child: ReusableCard(activeCardColor,
IconContents(FontAwesomeIcons.mars, 'MALE')),
),
ReusableCard(activeCardColor,
IconContents(FontAwesomeIcons.venus, 'FEMALE')),
I don't think if it's helpful but I am also sharing my ReusableCard code with you guys.
class ReusableCard extends StatelessWidget {
ReusableCard(this.colour, [this.cardChild]);
final Color colour;
final Widget cardChild;
#override
Widget build(BuildContext context) {
return Expanded(
child: Container(
child: cardChild,
margin: EdgeInsets.all(15),
decoration: BoxDecoration(
color: colour,
borderRadius: BorderRadius.circular(10),
),
),
);
}
}
I have checked the documentation and I seem to be doing everything correctly. What I can infer from this is that I am messing up somewhere with the Expanded widget, but cannot correct it. Any help appreciated folks.
I would suggest adding the GestureDetector inside your ReusableCard, as a child of your Expanded.
class ReusableCard extends StatelessWidget {
ReusableCard(
this.colour, {
required this.cardChild,
required this.onTap,
});
final Color colour;
final Widget cardChild;
final VoidCallback onTap;
#override
Widget build(BuildContext context) {
return Expanded(
child: GestureDetector(
onTap: onTap,
child: Container(
child: cardChild,
margin: EdgeInsets.all(15),
decoration: BoxDecoration(
color: colour,
borderRadius: BorderRadius.circular(10),
),
)),
);
}
}
This way you won't need to wrap your ReusableCard with a GestureDetector breaking the Expanded widget.
I'm new on Flutter so please don't go hard on me! I'm trying to understand how to build screens and navigate back and forth through them bringing values to other screens during navigation.
I wanna build this screen:
Inside lib, I created a models folder which contains the file cats.dart
enum Cat {
black,
white
}
extension CatExtension on Cat {
String get name {
switch (this) {
case Cat.black:
return 'Mr Black Cat';
case Cat.white:
return 'Ms White Cat';
default:
return null;
}
}
}
I thought it would be a good idea to separate the code creating two other folders inside lib which are
lib/screens
lib/widgets
so i created a select_item.dart inside screens and cats_items.dart inside widgets in order to import the widget where needed.
cats_items.dart
class CatsItemsListWidget extends StatelessWidget {
final cat = Cat.white; // I get null error if I don't do like that
#override
Widget build(BuildContext context) {
return Card(
margin: EdgeInsets.fromLTRB(31, 24, 30, 88),
shadowColor: Color(0xFFEDEDEF),
shape: RoundedRectangleBorder(
side: new BorderSide(color: Color(0xFFEDEDEF)),
borderRadius: BorderRadius.circular(10.0)),
child: ListView(
scrollDirection: Axis.vertical,
shrinkWrap: true,
physics: ScrollPhysics(),
children: [
ListTile(
title: Padding(
padding: EdgeInsets.fromLTRB(0, 20, 0, 4),
child: Text('Name:',
subtitle: Padding(
padding: EdgeInsets.fromLTRB(0, 4, 0, 16),
child: Text(
cat.displayValue,
)),
),
],
),
);
}
}
select_item.dart
class SelectItem extends StatelessWidget {
SelectItem();
#override
Widget build(BuildContext context) {
final appBarHeight = MediaQuery.of(context).size.height * 0.10;
return Scaffold(
appBar: AppBar(
toolbarHeight: appBarHeight,
automaticallyImplyLeading: false,
//title: ,
elevation: 0,
backgroundColor: Theme.of(context).backgroundColor,
),
body: SafeArea(
child: Stack(
children: [
SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
CatsItemsListWidget(),
],
),
),
],
),
),
);
}
}
main.dart
class CatsApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'My cats app',
theme: ThemeData(
backgroundColor: PRIMARY_COLOR,
scaffoldBackgroundColor: PRIMARY_COLOR,
),
home: SelectItem(),
);
}
}
This is not working as expected as I get:
I can't understand how to create an item of the list for each element of enum Cat{} and also how to get clickable items in the list in order to switch screen on click. I also have to store a value corrisponding to what the user click, for example if user click on "Ms White Cat" I have to store a value that can be "MWC" and bring this value with me in the other screen.
Is the logic that I'm building correct? If not, why? How can I achieve what I need?
You need to use onTap and Navigator
like:
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => OtherScreen(),
),
);
},
Take a look at the example here
Hey friends on StackOverflow, how are you guys doing today! I am new to Flutter and I'm facing some issues with understanding this language. I am trying to make an overlay of a textfield of a small size when I click on a button. However, I am facing a No material widget found. TextField require a Material widget ancestor Can you guys please help me out with this? Thanks so much!
Happy Coding guys!
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: "text page",
home: FirstPage(),
);
}
}
class FirstPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
var appBar;
return new Scaffold(
appBar: AppBar(
title: Text("page"),
),
body: Center(
child: Container(
child: Text("This is a page blahblah"),
),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.message),
onPressed:(){
showOverlay(context);
},
),
);
}
//void method for overlay text field
void showOverlay(BuildContext context) async {OverlayState overlayState = Overlay.of(context);
OverlayEntry overlayEntry = OverlayEntry(
builder: (context) => Positioned(
top: 200.0,
left: 1.0,
child: TextField(
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Enter text',
),
),
),
);
overlayState.insert(overlayEntry);
}
}```
As flutter said, TextField needs a material widget as parent. You can wrap your TextField in one of these widgets that has Material widget in them: Card , Dialog , Drawer , Scaffold . Or you can directly use Material.
void showOverlay(BuildContext context) async {
OverlayState overlayState = Overlay.of(context);
OverlayEntry overlayEntry = OverlayEntry(
builder: (context) => Material( //Use a Material Widget
child: TextField(
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Enter text',
),
),
),
);
overlayState.insert(overlayEntry);
}
I recommend using Dialog instead of overlay. Dialog don't cover whole screen and contains Material widget in itself. And it is more beautiful :).
I am trying to create a simple To Do App in in flutter with a Floating Action Button in the bottom which when clicked show an Alert Dialog to add items to the list.
Every time I click on the button, the Keyboard pushes the Action Button upward causing overflowing error.
Is there any way to avoid pushing the action button upward when Keyboard is opened?
Here is the snapshot I took:
Snapshot
Below the source code:
import 'package:flutter/material.dart';
import '../model/todo_item.dart';
class ToDoScreen extends StatefulWidget {
#override
_ToDoScreenState createState() => _ToDoScreenState();
}
class _ToDoScreenState extends State<ToDoScreen> {
TextEditingController _textEditingController = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.blueAccent,
body: Column(
children: <Widget>[ToDoItem("Going for a Walk", "12 January, 2019")],
),
floatingActionButton: FloatingActionButton(
tooltip: 'Add Item',
child: Icon(Icons.add),
backgroundColor: Colors.red,
onPressed: _showFormDialog,
),
);
}
void _showFormDialog() {
var alert = AlertDialog(
content: Row(
children: <Widget>[
Expanded(
child: TextField(
controller: _textEditingController,
autofocus: true,
decoration: InputDecoration(
labelText: "Item",
hintText: "eg. Buy Vegetables",
icon: Icon(Icons.note_add)),
),
)
],
),
actions: <Widget>[
FlatButton(
onPressed: () {
// _handleSubmit(_textEditingController.text);
_textEditingController.clear();
},
child: Text("Save ToDo"),
),
FlatButton(
onPressed: () {
Navigator.pop(context);
},
child: Text("Cancel"),
)
],
);
showDialog(context: context, builder: (BuildContext context) => alert);
}
}
I had the same issue, where my Floating Action Button would get pushed up.
I solved this using the property:
resizeToAvoidBottomPadding: false, // fluter 1.x
resizeToAvoidBottomInset: false // fluter 2.x
On the parent Scaffold.
I tested it with your code, it solves the issue as well.
You can check if the keyboard is show up or not, and based on that create the floating button or not.
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: keyboardIsOpened ?
null ://or an empty container
FloatingActionButton(
tooltip: 'Add Item',
child: Icon(Icons.add),
backgroundColor: Colors.red,
onPressed: _showFormDialog,
),
);
}
Inside the build method you can know if the keyboard show up by using MediaQuery.of(context).viewInsets.bottom and save its value on a bool variable keyboardIsOpened like the following code.
#override
Widget build(BuildContext context) {
bool keyboardIsOpened = MediaQuery.of(context).viewInsets.bottom != 0.0;
Used MediaQuery and Visibility
Visibility(
visible: MediaQuery.of(context).viewInsets.bottom == 0.0,
child: FloatingActionButton(
onPressed: () {},
child: Icon(Icons.chat),
),
),
When the keyboard is opened, the bottom will not be zero, which will cause fab to get invisible.
Wrap your complete code in this
new Container(
child: Column(
children: <Widget>[
Expanded(
child: SingleChildScrollView(
child: Stack(
children: <Widget>[
// Your body code
] // Widget
), // Stack
), // SingleChildScrollView
), // Expanded
Container(
alignment: Alignment.bottomCenter,
padding: EdgeInsets.all(10.0),
child :
// button code here
// to make button full width use minWidth: double.infinity,
,
), //Container
], // Widget
), // Column
), // Container
Wrapping the Floating Action Button inside a column together with my bottom navigation, then passing this as the child to my bottom navigation bar solved most of the stated concerns: Also ensure you add mainAxisSize: MainAxisSize.min,to your column.
i try this so good
Visibility(
visible: MediaQuery.of(context).viewInsets.bottom == 0.0,
child: FloatingActionButton(
onPressed: () {},
child: Icon(Icons.chat),
),
),
I'm new to flutter. I've added a form with a text field and when I clicked the textfield and keyboard comes, the textfield goes up.
This is my code :
Widget build(BuildContext context) {
MediaQueryData mediaQuery = MediaQuery.of(context);
return new Scaffold(
body: new Container(
color: Colors.purple,
constraints: new BoxConstraints.expand(),
padding: EdgeInsets.only(top: 10.0,left: 10.0,right: 10.0, bottom: mediaQuery.viewInsets.bottom, ),
child: SingleChildScrollView(
child: Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
SizedBox(height: 12.0),
Text(
'What is your Business Name?',
style: TextStyle(fontSize: 24.0),
),
AppForm(),
],
),
padding: EdgeInsets.only(left: 10.0,right: 10.0, bottom: mediaQuery.viewInsets.bottom),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(30.0)),
color: Colors.white,
),
)
)
),
);
}
This is the result without opening the keyboard:
Image without keyboard
This is the image after opening the keyboard:
Image after opening the keyboard
Here is my flutter doctor output.
Doctor summary (to see all details, run flutter doctor -v): [√] Flutter
(Channel beta, v0.5.1, on Microsoft Windows [Version 10.0.17134.165], locale
en-US) [√] Android toolchain - develop for Android devices (Android SDK
28.0.0) [√] Android Studio (version 3.1) [!] VS Code, 64-bit edition (version
1.25.1) [!] Connected devices ! No devices available ! Doctor found issues in
2 categories.
any idea how to fix this?
new Scaffold(
appBar: new AppBar(
...
resizeToAvoidBottomInset: true,
....
Fixed problem textfield was hidden by keyboard
This answer is not specific the question above but may be useful to those who are still having issues with the keyboard covering the selected text field, no matter what they do. I got to this page while trying to resolve such an issue.
Prior to the problem I had been making some changes to try and improve my splash screen on app startup. As per someone's recommendation, I had included the following line in the <resources><style> section of the styles.xml file in the android/app/src/main/res/values folder
<item name="android:windowFullscreen">true</item>
This had the unexpected effect of stopping any fields scrolling up in the main app when the keyboard is displayed. This might be obvious to some, but it wasn't to me.
Hope this info helps someone.
This was the case with me . You are definitely wrapping a scaffold inside another scaffold . there should be only one scaffold widget inside your flutter app i.e the main layout . Simple remove all the ancestor scaffolds you have and keep only one scaffold . dont wrap a scaffold into another scaffold .inspite of that you can wrap a scaffold inside a container .
Make sure in your main.dart file you are not doing this :-
✖✖
return Scaffold(
body : YourNewFileName(),
);
Inspite of the above code do this:-
✔✔
return YourNewFileName();
You can simply wrap the widget you want to never be hidden by the keyboard inside a padding, like follow :
Padding(
child: YourWidget()
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom));
resizeToAvoidBottomPadding is Deprecated
use instead resizeToAvoidBottomInset: true
<item name="android:windowFullscreen">true</item>
Removing above line from
android/app/src/main/res/values/styles.xml
made my app fixed to input field auto scroll upwards to come in view able on keyboards opens
thanks #GrahamD
You should add SingleChildScroolView into your Scaffold and add reverse: true into your SingleChildScroolView
Scaffold(
body: SingleChildScrollView(
reverse: true,
child: Container()));
Just cut and paste your body code in this -
SingleChildScrollView(
child: Stack(
children: <Widget>[
// your body code
],
),
),
had the same issue got the answer here
If you are using Scaffold than wrap the body with SingleChildScrollView
for Example like this:
...
return Scaffold(
body: SingleChildScrollView(
child: Column(
children: <Widget>[
TextField(),
TextField(),
TextField(),
],
),
),
);
...
this was really a lifesaver for me.
Now the scaffold will become scrollable.
resizeToAvoidBottomInset is true by default.
return Scaffold(
resizeToAvoidBottomInset: false,
);
I set it to false and it worked fine
Consider using scroll padding on the Textfield
return Scaffold(
appBar: AppBar(
title: Text("Demo SoftKeyboard"),
),
body: SingleChildScrollView(
child: Column(
children: [
TextField(
scrollPadding: EdgeInsets.only(bottom:40), // THIS SHOULD SOLVE YOUR PROBLEM
),
],
),
),
);
The fix for me was similar to GrahamD's answer.
I was declaring my own theme using a parent that had .Fullscreen, for example:
<style name="NormalTheme" parent="#android:style/Theme.Black.NoTitleBar.Fullscreen">
<item name="android:windowBackground">#android:color/white</item>
</style>
I've raised an issue with the Flutter team because it should be possible to use a Fullscreen theme and have normal Chat app behaviour.
I resolved the above issue by adding a Stack() as the body of my Scaffold(), this allows the TextField() object to slide up above the soft keyboard. Initially I used SingleChildScrollView() for the body which resulted in the TextField() objects being obscured by the soft keyboard.
Solution that worked for me:
child: Scaffold(
resizeToAvoidBottomInset: true,
body: Stack(
children: <Widget>[]
As per the flutter updates(2021), "resizeToAvoidBottomInset:true" gives a yellow-black strip error when keyboard appears.
This is how I fixed the above issue:
Inside build() method, check if keyboard is open, bool keyboardIsOpen = MediaQuery.of(context).viewInsets.bottom != 0;
Set resizeToAvoidBottomInset:true inside Scaffold
Wrap your widget with a SizedBox() and set height like this: height: keyboardIsOpen
? MediaQuery.of(context).size.height * 0.2
: MediaQuery.of(context).size.width * 0.6,
In Flutter, to prevent from this problem - Flutter Keyboard makes TextField hidden – we can do an easy job. We have to Wrap the TextFields with SingleChildScrollView as a widget for body argument in Scaffold. Only use SingleChildScrollView in that place. If you did not do so, it would not work well. For instance:
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("App"),
),
body: SingleChildScrollView(
child: Column(
// mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Container(
width: double.infinity,
child: Card(
color: Colors.blue,
elevation: 5,
child: Text()
),
),
TextField(),
TextField(),
],
Also, there is another way do this. In the above code, you can replace Column with ListView Widget like the below code:
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("App"),
),
body: Container(
height: 300,
child: ListView(
children: [
Container(
width: double.infinity,
child: Card(
color: Colors.blue,
elevation: 5,
child: Text(),
),
),
TextField(),
TextField(),
],
Here's a complete example which dynamically updates the padding:
import 'dart:ui';
import 'package:flutter/material.dart';
class KeyboardPaddingTest extends StatefulWidget {
const KeyboardPaddingTest({Key? key}) : super(key: key);
#override
_KeyboardPaddingTestState createState() => _KeyboardPaddingTestState();
}
class _KeyboardPaddingTestState extends State<KeyboardPaddingTest> {
EdgeInsets _viewInsets = EdgeInsets.zero;
SingletonFlutterWindow? window;
final _textFieldController = TextEditingController();
#override
void initState() {
super.initState();
window = WidgetsBinding.instance?.window;
window?.onMetricsChanged = () {
setState(() {
final window = this.window;
if (window != null) {
_viewInsets = EdgeInsets.fromWindowPadding(
window.viewInsets,
window.devicePixelRatio,
).add(EdgeInsets.fromWindowPadding(
window.padding,
window.devicePixelRatio,
)) as EdgeInsets;
}
});
};
}
#override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
height: double.infinity,
color: Colors.greenAccent[100],
alignment: Alignment.bottomCenter,
child: Padding(
padding: EdgeInsets.only(bottom: _viewInsets.bottom),
child: Column(
children: [
Expanded(
child: Center(
child: Container(
width: 200.0,
color: Colors.lightBlueAccent[100],
child: TextField(
controller: _textFieldController,
decoration: const InputDecoration(
border: InputBorder.none,
hintText: 'Tap to show keyboard',
),
),
),
),
),
const Text(
'Testing Keyboard',
style: TextStyle(
fontSize: 24.0,
fontWeight: FontWeight.bold,
),
),
],
),
),
);
}
}
Be careful to do not remove those two lines from AndroidManifest.xml
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize"
I did this mistake, all my SingleChildScrollView were not working and the keyboard was hidding the textfield of all my form.
If you use ScreenUtilInit package then maybe setting useInheritedMediaQuery: true in the constructor of ScreenUtilInit will help you. It helped me :)
I also faced with this issue. This's my solution:
1/ Wrap the Column Widget (content of Dialog) inside the Padding Widget with property padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom,)
2/ Wrap all widgets above inside SingleChildScrollView
Below is full code for my Dialog:
Future<T?> showDialogLikeBorrowBook<T>(
BuildContext context, {
bool barrierDismissible = true,
required String labelDialog,
required String labelMainButton,
required Widget contentDialog,
required Function() onTap,
}) async {
return await showGeneralDialog(
context: context,
barrierLabel: "barrierLabel",
barrierDismissible: barrierDismissible,
barrierColor: Colors.black.withOpacity(0.4),
transitionDuration: const Duration(milliseconds: 300),
transitionBuilder: (_, anim1, __, child) {
return ScaleTransition(
scale: Tween<double>(
begin: 0.0,
end: 1.0,
).animate(
CurvedAnimation(
parent: anim1,
curve: Curves.fastOutSlowIn,
),
),
child: child,
);
},
pageBuilder: (_, __, ___) {
return Material(
type: MaterialType.transparency,
child: Align(
alignment: Alignment.center,
child: Padding(
padding: EdgeInsets.symmetric(horizontal: R.dimens.mediumSpacing1)
.copyWith(
top: MediaQuery.of(context).viewPadding.top, // This attribute used to make sure the Dialog widget always show below the AppBar/StatusBar
//if the Dialog widget has size with height large more normal size when the keyboard be shown
),
child: GestureDetector(
onTap: () {
FocusScope.of(context).requestFocus(FocusNode()); // Wrap Dialog widget inside Gesture Detector to every time the user tap outside the TextField widget but still inside scope of Dialog widget,
//the FocusNode of TextField will be unfocus
},
child: Container(
constraints: const BoxConstraints(maxWidth: double.infinity),
decoration: BoxDecoration(
borderRadius:
BorderRadius.all(Radius.circular(R.dimens.smallRadius)),
color: Colors.white,
),
padding: EdgeInsets.all(R.dimens.mediumSpacing),
child: _ShowContentDialog(
labelDialog: labelDialog,
labelMainButton: labelMainButton,
contentDialog: contentDialog,
onTap: onTap,
),
),
),
),
),
);
},
);
}
class _ShowContentDialog extends StatelessWidget {
const _ShowContentDialog();
#override
Widget build(BuildContext context) {
return SingleChildScrollView(
physics: BouncingScrollPhysics(),
child: Padding(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom, // This attribute will auto scale size of Column widget when the keyboard showed
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
_renderLabelDialog(),
... something widget,
CustomTextField(
labelTextField: "Ghi chú",
hintText: "Nhập ghi chú",
textInputType: TextInputType.text,
maxLines: 4,
textController: _editNoteController,
),
_renderButton(context),
],
),
),
);
}
}
Dialog without the keyboard
Dialog with the keyboard when touch on the TextField widget
Wrap the entire widget in a Scaffold, then all other widgets contained in a SingleChildScrollView.
I had same problem i also used SingleChildScrollView but that doesn't solved my problem.
My problem was accruing in this code.
Stack(
childern:[
SingleChildScrollView(),// In scollView i have textFeild when keyboard opens doneButton hide the textFeild.
doneButtonWidget()//this button align with the bottom of the screen.
]
)
To Solve the problem i follow this and it solved my problem.
Column(
childern:[
Expaned(
child:SingleChildScrollView(),// In scollView i have textFeild when keyboard opens doneButton hide the textFeild.
flex:1
),
doneButtonWidget()//this button align with the bottom of the screen.
]
)