Flutter showcase view not working at all without showing errors - android

Am using the showcase_view package and following everything mentioned in the example but it is not working at all not showing the showcase and also not showing an error.
Here is my code :
final _searchShowcase = GlobalKey();
BuildContext myContext;
void initState() {
WidgetsBinding.instance.addPostFrameCallback((_) {
ShowCaseWidget.of(myContext).startShowCase([_searchShowcase]);
super.initState();
}
#override
Widget build(BuildContext context) {
return ShowCaseWidget(
builder: Builder(builder: (context){
myContext =context;
return Scaffold(
body: SingleChildScrollView(
controller: _scrollController,
child: Container(
padding: EdgeInsets.only(bottom: 30, top: 30),
child: StickyHeader(
header: Showcase(
key: _searchShowcase,
title: '${translator.translate("search")}',
description: '${translator.translate("search")}',
child: SearchBarWidget()
),
content:Column(....)
);
);}
And the screen just opens normally without showing the showcase view or even doing any action.. where is the mistake here?

Make sure ShowCaseWidget is as close to root(MaterialApp/CupertinoApp) as possible.
https://stackoverflow.com/a/70879957/18645340 [Check this for more info]
Check the context.
Hope it helps!

Related

Why flutter return me my fallback values?

so I've already have a problem with this code before I ask for some help and I got some.
The help fix my error but I have a new one .
So basically I'm waiting for a variable and this variable is not null because when I print it I can see the value of this variable.
The screen return me the fallback values and I don't know why.
I have two screens one for create my variable and the other for all the graphic stuff.
This is the detail screen:
class DetailScreen extends StatefulWidget {
const DetailScreen({Key? key, required this.mangaImg, required this.mangaTitle, required this.mangalink}) : super(key: key);
final String mangaImg,mangaTitle,mangalink;
#override
_DetailScreenState createState() => _DetailScreenState();
}
class _DetailScreenState extends State<DetailScreen> {
String? mangaGenre,mangaStatus,mangaAuthor,mangaDesc;
List<Map<String,dynamic>>? mangaDetail;
List<Map<String,dynamic>>? mangaDescList;
List<Map<String,dynamic>>? mangaChapters;
Future<void> getMangaInfo() async {
String TempBaseurl = widget.mangalink.split(".com")[0] + ".com";
String TempRoute = widget.mangalink.split(".com")[1];
final webscraper = WebScraper(TempBaseurl);
if (await webscraper.loadWebPage(TempRoute)){
mangaDetail = webscraper.getElement("div.panel-story-info > div.story-info-right > table > tbody > tr > td.table-value", []);
mangaDescList = webscraper.getElement("div.panel-story-info > div.panel-story-info-description", []);
}
mangaGenre = mangaDetail![3]['title'].toString().trim();
mangaStatus = mangaDetail![2]['title'].toString().trim();
mangaAuthor = mangaDetail![1]['title'].toString().trim();
mangaDesc = mangaDescList![0]['title'].toString().trim();
print(mangaDesc);
print(mangaGenre);
print(mangaStatus);
}
#override
Future<void> getMangaInfos()async {
await getMangaInfo();
}
#override
Widget build(BuildContext context) {
Size screensize = MediaQuery.of(context).size;
return Scaffold(
appBar: AppBar(
backgroundColor: Constants.mygreen,
title: Text(widget.mangaTitle),
centerTitle: true,
),
body: Container(
height: screensize.height,
width: screensize.width,
child: SingleChildScrollView(
child: Column(
children: [
MangaInfo(
mangaImg: widget.mangaImg,
mangaStatus: mangaStatus??"Error" ,
mangaAuthor : mangaAuthor??"Error" ,
And this is the graphic screen:
class MangaInfo extends StatelessWidget {
const MangaInfo({Key? key, required this.mangaImg, required this.mangaStatus, required this.mangaAuthor}) : super(key: key);
final String mangaImg, mangaStatus,mangaAuthor;
#override
Widget build(BuildContext context) {
return Container(
height: 300,
width: double.infinity,
child: Column(
children: [
Expanded(child: Center(child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Container(height: 170, width: 130,child: Image.network(mangaImg, fit: BoxFit.cover,)
),
Text("By $mangaAuthor - $mangaStatus"
, style: const TextStyle(
fontFamily: "SFProDisplay",
))
],
))),
const SizedBox(
height: 10,
),
Container(
height: 80,
width: double.infinity,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: const[
MangaInfoBtn(icon:Icons.play_arrow, title: "Read"),
MangaInfoBtn(icon:Icons.library_add_check, title: "Favorites"),
MangaInfoBtn(icon:Icons.list, title: "Chapters"),]
An image of the screen for more details :
So you get the manga information on the method called getMangaInfo, you await said method on the method getMangaInfos But you never call getMangaInfos! you also override it, but I don't think it is a method declared in State class. This leads me to believe that what you actually meant to do was this:
Future<void> initState() async {
await getMangaInfo();
}
The above is NOT POSSIBLE and will result in a compilation error because initstate should never return a future. The next best thing is this:
void initState() {
getMangaInfo();
}
But this means you are not awaiting getMangaInfo
Both initState and build methods are synchronous, which means you can't use the await keyword on them, on the other hand getMangaInfo is asynchronous. Asynchronous methods will be run whenever flutter has some free time, while synchronous methods will run in order always.
So this is the order in which the methods finish running:
initstate -> build -> getMangaInfo
So by the time you build, getMangaInfo is not done.
I propose two solutions:
1. Use setState to tell flutter when to rebuild:
Future<void> getMangaInfo() async {
String TempBaseurl = widget.mangalink.split(".com")[0] + ".com";
String TempRoute = widget.mangalink.split(".com")[1];
final webscraper = WebScraper(TempBaseurl);
if (await webscraper.loadWebPage(TempRoute)){
mangaDetail = webscraper.getElement("div.panel-story-info > div.story-info-right > table > tbody > tr > td.table-value", []);
mangaDescList = webscraper.getElement("div.panel-story-info > div.panel-story-info-description", []);
}
setState(() {
mangaGenre = mangaDetail![3]['title'].toString().trim();
mangaStatus = mangaDetail![2]['title'].toString().trim();
mangaAuthor = mangaDetail![1]['title'].toString().trim();
mangaDesc = mangaDescList![0]['title'].toString().trim();
});
}
With the change above, the new order looks like this:
initstate -> build -> getMangaInfo -> build.
2. Using a future builder:
This method is probably what I would do, but it might be confusing if you don't know what a FutureBuilder is:
Widget build(BuildContext context) {
Size screensize = MediaQuery.of(context).size;
return FutureBuilder(
future: getMangaInfo(),
builder: (context, snapshot) {
return Scaffold(
appBar: AppBar(
backgroundColor: Constants.mygreen,
title: Text(widget.mangaTitle),
centerTitle: true,
),
body: Container(
height: screensize.height,
width: screensize.width,
child: SingleChildScrollView(
child: Column(
children: [
MangaInfo(
mangaImg: widget.mangaImg,
mangaStatus: mangaStatus??"Error" ,
mangaAuthor : mangaAuthor??"Error" ,

How to fix flutter widget flickering?

I'm trying to load an image from firebase storage to my app however I have this weird issue where the profile page(where this image is loading) keeps flickering. The image is loading fine however the whole widget keeps flickering. I have narrowed the issue down to the setState() called within the function getProfilePic() after some debugging, however I do not know if it's the function itself or my call to said function.
P.S there is no issue with the fileURL or picRef.getDownloadURL() as I've tested this with a random internet image as well and got the same flickering.
class profileTab extends StatefulWidget {
#override
_profileTabState createState() => _profileTabState();
}
class _profileTabState extends State<profileTab> {
User user = FirebaseAuth.instance.currentUser;
String _image = "https://picsum.photos/250?image=9";
Reference picRef = FirebaseStorage.instance.ref().child(FirebaseAuth.instance.currentUser.uid);
Future<Widget> getProfilePic() async {
await picRef.getDownloadURL().then((fileURL){
setState(() {
_image = fileURL;
});
});
}
#override
Widget build(BuildContext context) {
getProfilePic();
return StreamBuilder(
stream: FirebaseFirestore.instance.collection('users').doc(user.uid).snapshots(),
builder: (context, snapshot){
if (snapshot.connectionState == ConnectionState.active){
return ListView(
children: <Widget>[
SizedBox(height: 100.0,),
CircleAvatar(
radius: 100.0,
backgroundColor: Colors.lightBlueAccent,
child: ClipOval(
child: SizedBox(
width: 180.0,
height: 180.0,
child: Image.network(_image,fit: BoxFit.fill,),
),
),
),
SizedBox(height: 30.0,),
Center(child: Text("Name: " + snapshot.data.data()['name'],textScaleFactor: 3.0,)),
]
);
}
else {
return CircularProgressIndicator();
}
},
);
}
}
getProfilePic is redrawing widget by calling setState.
setState calls build method which calls getProfilePic.
Therefore, when first time build method is called we call getProfilePic which again updates widget tree.
Fix: Inside getProfilePic add check to call setState if _image is null which will redraw widget only once.
It would be better if you use Image.network. You can refer this
https://www.woolha.com/tutorials/flutter-display-image-from-network-url-show-loading

How to implement a swipe to delete listview to remove data from firestore

Im very new to flutter and dart so this might be a basic question. However, what I would like to know is how to implement a swipe to delete method in a listview to delete data from firestore too.
I tried using the Dissmissible function but i dont understand how to display the list and I cant seem to understand how to remove the selected data as well.
This here is my dart code
Widget build(BuildContext context) {
return new Scaffold(
resizeToAvoidBottomPadding: false,
appBar: new AppBar(
centerTitle: true,
automaticallyImplyLeading: false,
title: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween,children:
<Widget>[
Text("INVENTORY",textAlign: TextAlign.center,) ,new IconButton(
icon: Icon(
Icons.home,
color: Colors.black,
),
onPressed: () {
Navigator.push(
context,
SlideLeftRoute(widget: MyHomePage()),
);
})]),
),body: ListPage(),
);
}
}
class ListPage extends StatefulWidget {
#override
_ListPageState createState() => _ListPageState();
}
class _ListPageState extends State<ListPage> {
Future getPosts() async{
var firestore = Firestore.instance;
QuerySnapshot gn = await
firestore.collection("Inventory").orderBy("Name",descending:
false).getDocuments();
return gn.documents;
}
#override
Widget build(BuildContext context) {
return Container(
child: FutureBuilder(
future: getPosts(),
builder: (_, snapshot){
if(snapshot.connectionState == ConnectionState.waiting){
return Center(
child: Text("Loading"),
);
}else{
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder:(_, index){
return EachList(snapshot.data[index].data["Name"].toString(),
snapshot.data[index].data["Quantity"]);
});
}
}),
);
}
}
class EachList extends StatelessWidget{
final String details;
final String name;
EachList(this.name, this.details);
#override
Widget build(BuildContext context) {
// TODO: implement build
return new Card(
child:new Container(
padding: EdgeInsets.all(8.0),
child: new Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
new Row(
children: <Widget>[
new CircleAvatar(child: new Text(name[0].toUpperCase()),),
new Padding(padding: EdgeInsets.all(10.0)),
new Text(name, style: TextStyle(fontSize: 20.0),),
],
),
new Text(details, style: TextStyle(fontSize: 20.0))
],
),
),
);
}
}
You should use Dismissible widget. I used it for an inbox list retrieved from Firestore. Inside your EachList return something like this
return Dismissible(
direction: DismissDirection.startToEnd,
resizeDuration: Duration(milliseconds: 200),
key: ObjectKey(snapshot.documents.elementAt(index)),
onDismissed: (direction) {
// TODO: implement your delete function and check direction if needed
_deleteMessage(index);
},
background: Container(
padding: EdgeInsets.only(left: 28.0),
alignment: AlignmentDirectional.centerStart,
color: Colors.red,
child: Icon(Icons.delete_forever, color: Colors.white,),
),
// secondaryBackground: ...,
child: ...,
);
});
IMPORTANT: in order to remove the list item you'll need to remove the item from the snapshot list as well, not only from firestore:
_deleteMessage(index){
// TODO: here remove from Firestore, then update your local snapshot list
setState(() {
snapshot.documents.removeAt(index);
});
}
Here the doc: Implement Swipe to Dismiss
And here a video by Flutter team: Widget of the week - Dismissilbe
You can use the flutter_slidable package to achieve the same.
You can also check out my Cricket Team on Github in which I have did the same you want to achieve, using same package.
Example for how to use package are written here.
I'd like to add that when deleting a document from Firestore, no await is needed as the plugin automatically caches the changes and then syncs them up when there is a connection again.
For instance, I used to use this method
Future deleteWatchlistDocument(NotifierModel notifier) async {
final String uid = await _grabUID();
final String notifierID = notifier.documentID;
return await _returnState(users.document(uid).collection(watchlist).document(notifierID).delete());
}
in which I was waiting for the call to go through, however this prevented any other call to go through and only allowed one. Removing this await tag however solved my issue.
Now I can delete documents offline, and the changes will sync up with Firestore when a connection is regained. It's pretty cool to watch in the console.
I'd recommend watching this video about offline use with Firestore

Disabling Flutter Hero reverse animation

Given 2 routes, e.g. parent and a child and a Hero(..) widget with the same tag.
When the user is on the "parent" screen and opens a "child" - the Hero widget is animated. When it goes back (via Navigator.pop) it's also animated.
I'm looking for a way to disable that animation when going back (from child to parent via Navigator.pop).
Is there a kind of handler which will be called on a widget before it's going to be "animated away" ? Then I probably could change Hero tag and problem solved.
Or, when creating a "builder" for a route in parent widget, I could probably remember a reference to a target widget and before calling Navigator.pop notify it about "you are gonna be animated out". That would also require making that widget stateful (I haven't found a way to force rebuild a stateless widget).
Is there an easier way of implementing this?
While there currently isn’t a built-in way to disable Hero animations in any particular direction, though CLucera’s use of FadeTransition with HeroFlightDirection is one creative way, the most direct approach is to break the tag association between the two Hero’s:
When you go from the 2nd Hero back to the 1st Hero, just temporarily change the 1st Hero’s tag to something else, then the Hero won’t animate back. A simplified example:
class _MyHomePageState extends State<MyHomePage> {
String tag1, tag2;
String sharedTag = 'test';
String breakTag = 'notTest';
#override
void initState() {
super.initState();
tag1 = sharedTag;
tag2 = sharedTag;
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Hero(
tag: tag1,
child: RaisedButton(
child: Text("hi"),
onPressed: () {
// restore the tag
if (tag1 != sharedTag) {
setState(() {
tag1 = sharedTag;
});
}
// second route
Navigator.of(context).push(
MaterialPageRoute<void>(
builder: (BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Container(
alignment: Alignment.topLeft,
child: Hero(
tag: tag2,
child: RaisedButton(
child: Text('hello'),
onPressed: () {
// change the tag to disable the reverse anim
setState(() {
tag1 = breakTag;
});
Navigator.of(context).pop();
},
),
)
),
);
}
)
);
},
)
),
),
);
}
}
But if you want to directly modify the animation, then playing around inside the flightShuttleBuilder is the way to do it like CLucera did. You can also check out medium/mastering-hero-animations-in-flutter to further explore that area.
The only approach that I can come up at the moment is to "Animate" the popping Hero in a way that seems not animated, let's check this code:
class SecondRoute extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Hero(
flightShuttleBuilder: (context, anim, direction, fromContext, toContext) {
final Hero toHero = toContext.widget;
if (direction == HeroFlightDirection.pop) {
return FadeTransition(
opacity: AlwaysStoppedAnimation(0),
child: toHero.child,
);
} else {
return toHero.child;
}
},
child: FlatButton(
child: Text("prev 1"),
onPressed: () {
Navigator.of(context).pop();
},
),
tag: "test",
));
}
}
in your SecondRoute (the one that should pop) you have to supply a flightShuttleBuilder parameter to your Hero then you can check the direction and if it is popping, just hide the Widget with an AlwaysStoppedAnimation fade transition
the result is something like this:
I hope that this is something like the expected result, of course, you can completely change the transition inside the flightShuttleBuilder to change the effect! it's up to you :)

Hide On-Screen Keyboard when tapping outside of the Text Field (Anywhere on the screen) in Flutter [duplicate]

I am collecting user input with a TextFormField and when the user presses a FloatingActionButton indicating they are done, I want to dismiss the on screen keyboard.
How do I make the keyboard go away automatically?
import 'package:flutter/material.dart';
class MyHomePage extends StatefulWidget {
MyHomePageState createState() => new MyHomePageState();
}
class MyHomePageState extends State<MyHomePage> {
TextEditingController _controller = new TextEditingController();
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(),
floatingActionButton: new FloatingActionButton(
child: new Icon(Icons.send),
onPressed: () {
setState(() {
// send message
// dismiss on screen keyboard here
_controller.clear();
});
},
),
body: new Container(
alignment: FractionalOffset.center,
padding: new EdgeInsets.all(20.0),
child: new TextFormField(
controller: _controller,
decoration: new InputDecoration(labelText: 'Example Text'),
),
),
);
}
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: new MyHomePage(),
);
}
}
void main() {
runApp(new MyApp());
}
For Flutter version 2 or latest :
Since Flutter 2 with null safety this is the best way:
FocusManager.instance.primaryFocus?.unfocus();
Note: using old ways leads to some problems like keep rebuild states;
For Flutter version < 2 :
As of Flutter v1.7.8+hotfix.2, the way to go is:
FocusScope.of(context).unfocus();
Comment on PR about that:
Now that #31909 (be75fb3) has landed, you should use
FocusScope.of(context).unfocus() instead of
FocusScope.of(context).requestFocus(FocusNode()), since FocusNodes are
ChangeNotifiers, and should be disposed properly.
-> DO NOT use ̶r̶e̶q̶u̶e̶s̶t̶F̶o̶c̶u̶s̶(̶F̶o̶c̶u̶s̶N̶o̶d̶e̶(̶)̶ anymore.
F̶o̶c̶u̶s̶S̶c̶o̶p̶e̶.̶o̶f̶(̶c̶o̶n̶t̶e̶x̶t̶)̶.̶r̶e̶q̶u̶e̶s̶t̶F̶o̶c̶u̶s̶(̶F̶o̶c̶u̶s̶N̶o̶d̶e̶(̶)̶)̶;̶
Read more about the FocusScope class in the flutter docs.
Note: This answer is outdated. See the answer for newer versions of Flutter.
You can dismiss the keyboard by taking away the focus of the TextFormField and giving it to an unused FocusNode:
FocusScope.of(context).requestFocus(FocusNode());
Solution with FocusScope doesn't work for me.
I found another:
import 'package:flutter/services.dart';
SystemChannels.textInput.invokeMethod('TextInput.hide');
It solved my problem.
For Flutter 1.17.3 (stable channel as of June 2020), use
FocusManager.instance.primaryFocus.unfocus();
Following code helped me to hide keyboard
void initState() {
SystemChannels.textInput.invokeMethod('TextInput.hide');
super.initState();
}
To dismiss the keyboard (1.7.8+hotfix.2 and above) just call the method below:
FocusScope.of(context).unfocus();
Once the FocusScope.of(context).unfocus() method already check if there is focus before dismiss the keyboard it's not needed to check it. But in case you need it just call another context method: FocusScope.of(context).hasPrimaryFocus
Looks like different approaches for different version. I am using Flutter v1.17.1 and the below works for me.
onTap: () {
FocusScopeNode currentFocus = FocusScope.of(context);
if (!currentFocus.hasPrimaryFocus && currentFocus.focusedChild != null) {
currentFocus.focusedChild.unfocus();
}
}
GestureDetector(
onTap: () {
FocusScope.of(context).unfocus();
},
child:Container(
alignment: FractionalOffset.center,
padding: new EdgeInsets.all(20.0),
child: new TextFormField(
controller: _controller,
decoration: new InputDecoration(labelText: 'Example Text'),
),
), })
try this on tap gesture
None of the above solutions don't work for me.
Flutter suggests this -
Put your widget inside new GestureDetector() on which tap will hide keyboard and onTap use FocusScope.of(context).requestFocus(new FocusNode())
class Home extends StatelessWidget {
#override
Widget build(BuildContext context) {
var widget = new MaterialApp(
home: new Scaffold(
body: new Container(
height:500.0,
child: new GestureDetector(
onTap: () {
FocusScope.of(context).requestFocus(new FocusNode());
},
child: new Container(
color: Colors.white,
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
new TextField( ),
new Text("Test"),
],
)
)
)
)
),
);
return widget;
}}
For me, the Listener above App widget is the best approach I've found:
Listener(
onPointerUp: (_) {
FocusScopeNode currentFocus = FocusScope.of(context);
if (!currentFocus.hasPrimaryFocus && currentFocus.focusedChild != null) {
currentFocus.focusedChild.unfocus();
}
},
child: MaterialApp(
title: 'Flutter Test App',
theme: theme,
...
),
)
This may simplify the case. Below code will work only if keyboard is open
if(FocusScope.of(context).isFirstFocus) {
FocusScope.of(context).requestFocus(new FocusNode());
}
As in Flutter everything is a widget, I decided to wrap the FocusScope.of(context).unfocus(); approach in a short utility widget.
Just create the KeyboardHider widget:
import 'package:flutter/widgets.dart';
/// A widget that upon tap attempts to hide the keyboard.
class KeyboardHider extends StatelessWidget {
/// Creates a widget that on tap, hides the keyboard.
const KeyboardHider({
required this.child,
Key? key,
}) : super(key: key);
/// The widget below this widget in the tree.
final Widget child;
#override
Widget build(BuildContext context) {
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () => FocusScope.of(context).unfocus(),
child: child,
);
}
}
Now, you can wrap any widget (very convenient when using a good IDE) with the KeyboardHider widget, and then when you tap on something, the keyboard will close automatically. It works well with forms and other tappable areas.
class SimpleWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return KeyboardHider(
/* Here comes a widget tree that eventually opens the keyboard,
* but the widget that opened the keyboard doesn't necessarily
* takes care of hiding it, so we wrap everything in a
* KeyboardHider widget */
child: Container(),
);
}
}
You can use unfocus() method from FocusNode class.
import 'package:flutter/material.dart';
class MyHomePage extends StatefulWidget {
MyHomePageState createState() => new MyHomePageState();
}
class MyHomePageState extends State<MyHomePage> {
TextEditingController _controller = new TextEditingController();
FocusNode _focusNode = new FocusNode(); //1 - declare and initialize variable
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(),
floatingActionButton: new FloatingActionButton(
child: new Icon(Icons.send),
onPressed: () {
_focusNode.unfocus(); //3 - call this method here
},
),
body: new Container(
alignment: FractionalOffset.center,
padding: new EdgeInsets.all(20.0),
child: new TextFormField(
controller: _controller,
focusNode: _focusNode, //2 - assign it to your TextFormField
decoration: new InputDecoration(labelText: 'Example Text'),
),
),
);
}
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: new MyHomePage(),
);
}
}
void main() {
runApp(new MyApp());
}
To summarize, this is a working solution for Flutter 1.17:
Wrap your Widget like this:
GestureDetector(
onTap: FocusScope.of(context).unfocus,
child: YourWidget(),
);
if you use CustomScrollView, just put,
keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag,
You can wrap your widget with "GestureDetector", then assign "FocusScope.of(context).unfocus()" to its onTap function
GestureDetector(
onTap: () => FocusScope.of(context).unfocus(),
child: child,
);
_dismissKeyboard(BuildContext context) {
FocusScope.of(context).requestFocus(new FocusNode());
}
#override
Widget build(BuildContext context) {
return new GestureDetector(
onTap: () {
this._dismissKeyboard(context);
},
child: new Container(
color: Colors.white,
child: new Column(
children: <Widget>[/*...*/],
),
),
);
}
Call this function when you needed
void hideKeyboard(BuildContext context) {
FocusScopeNode currentFocus = FocusScope.of(context);
if (!currentFocus.hasPrimaryFocus && currentFocus.focusedChild != null) {
FocusManager.instance.primaryFocus?.unfocus();
}
}
You can also declare a focusNode for you textfield and when you are done you can just call the unfocus method on that focusNode
and also dispose it
class MyHomePage extends StatefulWidget {
MyHomePageState createState() => new MyHomePageState();
}
class MyHomePageState extends State<MyHomePage> {
TextEditingController _controller = new TextEditingController();
/// declare focus
final FocusNode _titleFocus = FocusNode();
#override
void dispose() {
_titleFocus.dispose();
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(),
floatingActionButton: new FloatingActionButton(
child: new Icon(Icons.send),
onPressed: () {
setState(() {
// send message
// dismiss on screen keyboard here
_titleFocus.unfocus();
_controller.clear();
});
},
),
body: new Container(
alignment: FractionalOffset.center,
padding: new EdgeInsets.all(20.0),
child: new TextFormField(
controller: _controller,
focusNode: _titleFocus,
decoration: new InputDecoration(labelText: 'Example Text'),
),
),
);
}
}
FocusScope.of(context).unfocus() has a downside when using with filtered listView.
Apart from so many details and concisely, use keyboard_dismisser package in https://pub.dev/packages/keyboard_dismisser will solve all the problems.
I have created this function to my base code, so far works well!!
void hideKeyword(BuildContext context) {
FocusScopeNode currentFocus = FocusScope.of(context);
if (!currentFocus.hasPrimaryFocus && currentFocus.focusedChild != null) {
currentFocus.focusedChild.unfocus();
}
}
FocusScope.of(context).unfocus(); doesn't work.
This code works for me at flutter ver 2.2.3 and null safety.
WidgetsBinding.instance?.focusManager.primaryFocus?.unfocus()
Source: https://github.com/flutter/flutter/issues/20227#issuecomment-512860882
For example, put this code in MyAppState to apply hide keyboard when touch outside for whole app.
return GestureDetector(
onTap: () =>
WidgetsBinding.instance?.focusManager.primaryFocus?.unfocus(),
child: MaterialApp(
title: 'Flutter Demo',
theme: getTheme(),
home: _body(),
),
);
Use SystemChannels.textInput.invokeMethod('TextInput.hide');. It will close/dismiss the keyboard when the screen loads.
void initState() {
super.initState();
SystemChannels.textInput.invokeMethod('TextInput.hide');
}
====== Dismiss the keyboard after clicking out of the TextField =======
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () => FocusScope.of(context).unfocus(), //this will dismiss keyboard
child: Scaffold(
body: SafeArea(
.........
====== Dismiss the keyboard when scrolling the screen =======
ListView(
keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag, //this will dismiss
children: [
..........
The SingleChildScrollView widget also have this property.
You can use this one.
FocusScope.of(context).requestFocus(FocusNode());
And you can use this onTap of GestureDetector or InkWell like this.
`GestureDetector(
onTap: () {`
// THIS FOCUS SCOPE WILL CLOSE THE KEYBOARD
FocusScope.of(context).requestFocus(FocusNode());
forgotPasswordAPI(emailController.text);
},``
add this code inside build widget
FocusScope.of(context).requestFocus(FocusNode());
If your keyboard still won't turn off , don't forget add focusNode to TextField. The above information was helpful, but forgetting to add focusNode bothered me a bit. Here an example.
TextField(
focusNode: FocusNode(),
textController: _controller,
autoFocus: false,
textStyle: TextStyle(fontSize: 14),
onFieldSubmitted: (text) {},
onChanged: (text) {},
hint: 'Enter the code',
hintColor: CustomColors.mediumGray,
suffixAsset: _voucherController.text.length == 7
? Assets.ic_approved_voucher
: null,
isIcon: false,
isObscure: false,
maxLength: 7,
)
closeKeyboard(BuildContext context) {
var currentFocus = FocusScope.of(context);
if (!currentFocus.hasPrimaryFocus) {
currentFocus.unfocus();
}
}
#override
Widget build(BuildContext context) {
_keyboardVisible = MediaQuery.of(context).viewInsets.bottom != 0;
size = MediaQuery.of(context).size;
return GestureDetector(
onTap: () {
closeKeyboard(context);
},
child: Scaffold(
backgroundColor: Colors.white,
body: Container(
width: double.maxFinite,
height: double.maxFinite,
child: _buildUI(vm)),
),
);
}
try using a TextEditingController.
at the begining,
final myController = TextEditingController();
#override
void dispose() {
// Clean up the controller when the widget is disposed.
myController.dispose();
super.dispose();
}
and in the on press event,
onPressed: () {
myController.clear();}
this will dismiss the keybord.
If you use TextField(maxLines: null) and just want to show Done button ON the screen keyboard to hide it, the code below works.
TextField(
keyboardType: TextInputType.text,
maxLines: null,
)
Side note: why in the first place doesn't the keyboard show Done button? The reason is found in the implementation of TextField:
keyboardType = keyboardType ?? (maxLines == 1 ? TextInputType.text : TextInputType.multiline),

Categories

Resources