I am using textformfield in flutter. Whenever user types something I give him suggestion. When user taps on suggestion, keyboard is dismissed automatically. I want to stop keyboard from getting dismissed. How to do it? I want user to add suggestion continuously.
Thanks in advance.
From the FocusNode documentation:
FocusNodes are ChangeNotifiers, so a listener can be registered to receive a notification when the focus changes.
final _focusNode = FocusNode();
So you can addListener to it to track changes that happens to it when you assign that FocusNode to the TextFormField:
TextFormField(
focusNode: _focusNode,
// ...
),
You can add the listener, then check if it has focus, which means that you're checking if the TextFormField field is focused, which also means that if the keyboard is shown:
_focusNode.addListener(() {
if(!_focusNode.hasFocus) {
_focusNode.requestFocus();
}
});
by this, it will remain the TextFormField focused, when you're done with it, you can call the removeListener().
Give FocusNode to Textformfield and focus that particular node on tapping of suggestion like this:
//Assign this inputNode to TextFormField
FocusNode inputNode = FocusNode();
//Somewhere on TextFormField
TextFormField(
focusNode:inputNode
)
// to open keyboard call this function;
void openKeyboard(){
FocusScope.of(context).requestFocus(inputNode)
}
You probably have this on
FocusScope.of(context).unfocus();
Or final FocusNode textFieldFocusNode = FocusNode();
TextFormField(
focusNode: textFieldFocusNode,
onTap: () async {
textFieldFocusNode.requestFocus();
},
)
Related
When I push named from the ListTile in Search Delegate, the height of the context is wrong, it seems like the keyboard is still there.
The height of the white space is equal to the height of my keyboard.
(P2)
If I dismiss the keyboard mannually, everything works fine.
(P3)
void showAndNavigate(BuildContext context, title, title2, gameId) {
super.showResults(context);
Navigator.pushNamed(context, RouteName.homeDetail, arguments: {
'data': {
'title': title,
'title2': title2,
'GameId': gameId,
}
});}
ListTile(
title: Text(suggestion),
onTap: () {
query = suggestion;
close(context, null);
showAndNavigate(
context, query, suggestionTitles[index], gameIds[index]);
},
);
resizeToAvoidBottomInset: false,
add this to the page to be pushed
I have added a rive ❤️ heart animation to a iconButton in flutter. when I tap on it, it animates from Unlike > Like and when I tapped again it animates backwards. Which is perfectly working. But the thing is, when I close the page and reopen the same page, Rive animation animates again from the very beginning (the default state of the animation is outline bordered heart icon, which I have to tap on it to make ❤️ filled heart icon). So the problem is if I like an item, close the page and then reopened the page I have to tap on it again, in order to make the item favorite or not. I also created a isFavorite bool to tack the icon button state, the thing is I don't know how to sync the bool with rive animation.
So this is what I want: I need the riveAnimation to stay liked or unliked according to the state of isFavourite bool + Unlike, Dislike transition animation. This may be hard to understand. Please leave a comment what part is that you do not understand.
Rive Animation I Used (go to rive)
class Place with ChangeNotifier {
bool isFavourite;
Place(
{this.isFavourite = false});
void toggleFavouriteStatus() {
isFavourite = !isFavourite;
notifyListeners();
}
}
.
.
.
.
.
.
.
SMIInput<bool>? _heartButtonInput;
Artboard? _heartButtonArtboard;
#override
void initState() {
super.initState();
rootBundle.load('assets/rive/heart.riv').then(
(data) {
final file = RiveFile.import(data);
final artboard = file.mainArtboard;
var controller = StateMachineController.fromArtboard(
artboard,
'state',
);
if (controller != null) {
artboard.addController(controller);
_heartButtonInput = controller.findInput('Like');
}
setState(() => _heartButtonArtboard = artboard);
},
);
}
#override
Widget build(BuildContext context) {
final Fav = Provider.of<Place>(context); // I used provider package to retrieve bool data
void _heartButtonAnimation() {
if (_heartButtonInput?.value == false &&
_heartButtonInput?.controller.isActive == false) {
_heartButtonInput?.value = true;
} else if (_heartButtonInput?.value == true &&
_heartButtonInput?.controller.isActive == false) {
_heartButtonInput?.value = false;
}
}
return Stack(
alignment: Alignment.bottomCenter,
children: [
Positioned(
right: 8,
top: 8,
child: Container(
child: Center(
child: Material(
color: Colors.transparent,
child: _heartButtonArtboard == null
? const SizedBox()
: IconButton(
onPressed: () {
Fav.toggleFavouriteStatus();
_heartButtonAnimation();
},
icon: Rive(
artboard: _heartButtonArtboard!,
fit: BoxFit.cover,
),
),
),
),
),
)
],
);
}
}
I'm not sure if I understood correctly. When your record is already given a heart, then after revisiting it, you want the heart to be displayed in "liked" state without running animating it. Is that it?
If so, IMO the problem is within your state machine not allowing the animation to be started in the desired state of "liked". For the heart to get to the liked state, it needs to pass through the liking animation. This is how your state machine looks now:
You should define two paths from Entry state depending on the value of your Like input. Take a look at a state machine from a checkbox I've imported to Flutter lately. Each of the "idle" timelines have only one keyframe for being checked or unchecked. On entry, there's an intersection where a decision is made based on the initial value of checked input.
This way you can display your heart in the desired state without any animation happening when the widget is built.
this is Antika. I have started learning to code since a few days back, and am only familiar with HTML/CSS/JS, and basics of dart/flutter
Developer Level: Beginner
Project type & language: I'm developing a Simple Notepad App, using flutter.
In my Project,
I want to dynamically add new TextField widgets on the screen, once the user hits enter or clicks the next button ('➡️'), in mobile devices, Just after the TextField in focus, and not to the end of the List.
Outline
User types text >> Clicks Submit >> Keeping in mind TextField in focus >> Add another TextField just after this one. >> The User feels like entering a new line.
For e.g., as is shown in the image below.
You could use a list with initially one TextField widget and onSubmitted adds another TextField to the list.
class MyWidget
extends StatefulWidget {
MyWidget({Key? key}) : super(key: key);
#override
State<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
List<TextField> textFields = [];
#override
void initState(){
super.initState();
textFields.add(_buildTextField());
}
#override
Widget build(BuildContext context) {
return ListView(
children: textFields
);
}
TextField _buildTextField(){
return TextField(
autofocus: true,
onSubmitted: (_){
setState((){
textFields.add(_buildTextField());
});
}
);
}
}
When we set TextField in Flutter via TextEditingController as follows:
textEditingController = TextEditingController();
textEditingController.text = "Some value.";
We know that the text setter here, would set TextSelection to the beginning of the input as seen in the following code:
set text(String newText) {
value = value.copyWith(
text: newText,
selection: const TextSelection.collapsed(offset: -1),
composing: TextRange.empty,
);
}
My problem is that I don't want to set the selection, as after setting the TextField I am shifting focus onto another field.
So, is there any way to either set TextField value without setting selection or remove the set selection after setting the value?
Thanks.
textEditingController.value = TextEditingValue(text: "Some value.");
I am trying to build an Flutter App with a GriView of cards and I want to add a new Card every time I hit the floatingActionButton. But how to update my view? I know the items are added to my list, but the GridView doesn't show the change.
List<Widget> cardsList = [];
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title: Text('Team Kitty'),
),
body: GridView.builder(
itemCount: cardsList.length,
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3),
itemBuilder: (BuildContext context, int index) {
return Container(child: cardsList[index]);
}),
floatingActionButton: new FloatingActionButton(
onPressed: addCard(),
tooltip: 'Add Card',
child: new Icon(Icons.add),
),
);
}
addCard() {
setState(() {
cardsList.add(_RobotCard());
});
}
}
I find it hard to find good Grid documentation, maybe someone has a hint?
Thx Guys
You invoke addCard method while your widget is built instead of passing method's reference as onPressed parameter:
floatingActionButton: new FloatingActionButton(
onPressed: addCard, // pass method reference here
tooltip: 'Add Card',
child: new Icon(Icons.add),
)
Its too late to answer, but this might help someone who came here finding solution to similar problem .
The problem with this is , list will be updated with values , but builder doesn't rebuild the list immediately which is in visible region of the screen. If suppose you have a long list of cards , and if you add a new item to this list, then it wont be rebuild immediately . To see the change ,keep scrolling down the list and then come back up , then you can see that the builder has rebuild the list.
Hence to solve this issue after not finding any relevant answers, I tried this ,May be it might not be the best solution but it works .
The approach is, if you have a list
List CardList =List();
and it initially has 5 items. So builder would have build 5 cards on the screen.
Then , if a new 6th item is added , then even if you do
setState((){
CardList.add(newItem);
})
Builder won't rebuild immediately .
To solve this, use a variable of type Widget, and initialize with empty Text .
Widget WidgetToBeShownInBody = Text("");
Use this under scaffold , as shown :
#override Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title: Text('Team Kitty'),
),
body: WidgetToBeShownInBody,
floatingActionButton: new FloatingActionButton(
onPressed: addCard(),
tooltip: 'Add Card',
child: new Icon(Icons.add),
),
);}
And Modify the onPressed function as this,
So, on every press of the button, empty text is shown in the scaffold for few milliseconds(which is negligible and goes unnoticed) and then the updated list of cards is shown on the screen.
addCard() {
//Show Empty Widget for few milliseconds
setState(() {
WidgetToBeShownInBody=Text("");
});
//update the list with new Item.
cardList.add(SomeNewItem);
//after some milliseconds ,
//use setState to update the variable to list of cards returned by GridViewBuilder
Timer(Duration(milliseconds: 50), () {
setState(() {
WidgetToBeShownInBody=GridView.builder(
itemCount: cardsList.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3),
itemBuilder: (BuildContext context, int index) {
return Container(child: cardsList[index]);
});
});
});
}
The above code is kind of fooling the build function , that now UI only has a simple empty text.
But after few milliseconds , UI is rebuild-ed, as the setState updates the new value of variable "WidgetToBeShownInBody" with list of cards.
When a new item is added, show a empty widget instead of the builder for few milliseconds , and then after some millisecond delay , send the builder list with 6 items.
Hence builder rebuilds the UI with 6 items and "WidgetToBeShownInBody" is updated with new list of cards.
Hope this is clear and useful!!
If someone finds a proper solution for this , please do update .
Thanks!