Using a textfield as a button - flutter

I'm trying to use a textfield as a button so when someone taps it, it takes him to a different page.
I've tried disabling the textfield but then I cannot use the onTap property. But if the textfield is not disabled, when I click it, it gets editing focus and this is something I don't want.
Can anyone help what's the easiest way this could be done?
Thanks

TextField(
readOnly: true,
onTap: () {
// Do something
},
);

You can use a Flatbutton instead. Just put this in your code:
FlatButton(
onPressed: () {
/*...*/
},
child: Text(
"Clickable text!",
),
)
Or else use a GestureDetector:
GestureDetector(
OnTap: () {...},
child: TextField(
// Text...
),
);

you can wrap it with an InkWell, see below:
InkWell(
onTap: () {
},
child: Container(
padding: EdgeInsets.all(4.0),
child: Text('Click me'),
),
);

you can try the following.
GestureDetector(
onTap: () {
// redirect // nav to different screen
},
child: TextField(
enabled: false
),
)
References
TextField
GestureDetector

Related

How to get tap event inside absorb pointer

I have a page containing many widgets which is opened in view only mode. i used AbsorbPointer for ignoring user inputs. but in some cases i have to get onTap event on one button which is inside AbsorbPointer. how can i achieve that ?
I tried using GestureDetector but its not giving onTap event.
any idea??
AbsorbPointer(
absorbing:true,
child: Column(children: [
Text("HELLO"),
Text("HELLO 2"),
GestureDetector(
onTap: () {
showToast("I tried this");
},
child: IconButton(
icon: Icon(
Icons.local_offer,
color: Colors.red,
),
onPressed: () {
print("I need this event");
},
),
)
]),
);
use absorbing: property for your cases... set it to false in the case you want to allow the GestureDetector inside

GetX not showing the updated value

I am trying a simple pop-up that should increment everytime I press the 'Use' button. Using the print command, it is showing the correct current value everytime I press. But for the Text itself, it is just staying a constant value. Any suggestion to fix this? Thanks!
showUsePopup() async {
AwesomeDialog(
context: globalScaffoldKey.currentContext!,
dialogType: DialogType.NO_HEADER,
dismissOnTouchOutside: false,
headerAnimationLoop: false,
animType: AnimType.SCALE,
body: Column(
children: [
Row(
children: [
Text('${controller.numOfItemObs.value}'),
ElevatedButton(
onPressed: () {
controller.numOfItemObs.value++;
print('Current value: ${controller.numOfItemObs.value}');
},
child: const Text('Use'),
),
],
),
],
),
showCloseIcon: false,
btnOkOnPress: () async {},
).show();
}
You need to wrap up the Text widget with Obx. It will update the Text value whenever the changes happen. Here is the example that you can follow.
Obx(
() => Text('${controller.numOfItemObs.value}')')
),

How to make InkWell `onLongPress()` override tap on a TextField inside of it?

I have a TextField inside of an InkWell with an onLongPress() callback. The problem is, despite the fact that even when long pressing on the TextField, I see the ripple effect on InkWell, but the onLongPress() does not run after the long press time passes. It only gets me into editing Text. When pressing on the bottom side of the Card, everything runs fine.
In short: On tap I want to get into TextField editing. On long press I want to trigger the onLongPress(), not the TextField, even if I am pressing on it.
How do I do this? Thank you.
InkWell(
onLongPress: () {
// do stuff
}
child: ListTile(
title: TextField(),
),
),
You can use the AbsorbPointer widget to ignore the TextField gesture recognizer:
InkWell(
onLongPress: () {
print('onLongPress');
},
child: AbsorbPointer(
child: ListTile(
title: TextField(),
),
),
)
To still enabling the editing of TextField when single tapping on it, you can use FocusNode like this:
InkWell(
onLongPress: () {
print('onLongPress');
},
onTap: () => node.requestFocus(),
child: AbsorbPointer(
child: ListTile(
title: TextField(
focusNode: node,
controller: textController,
),
),
),
)
#Bach 's answer helped me to find a solution. Thank you!
InkWell(
onLongPress: () {
// do stuff
},
child: ListTile(
title: GestureDetector(
onTap: () => FocusScope.of(context).requestFocus(_focusNode),
child: AbsorbPointer(
child: TextField(
focusNode: _focusNode,
),
),
),
),
The only problem is now that I started messing with focusNode, multiple input fiels are focusing at the same time. But that is a whole other story ;)
UPD: Just realised, that I can't move text cursor this way. So not useful.
It seems that IntrinsicWidth widget can find the right balance between long press and text editing.
The rationale behind is that IntrinsicWidth will let the TextField shrink to its minimum width, therefore avoiding a gesture collision with the InkWell
So your solution can be like this:
InkWell(
onLongPress: () {
// do stuff
}
child: ListTile(
child: IntrinsicWidth(
title: TextField(
//remember to make some hints here
//because with intrinsicwidth if your textfield is empty it might disappear
),
),
),
),

How to add a double tap gesture to video player without loosing the focus of controls?

I tried it by wrapping the
return ClipRRect(
borderRadius: BorderRadius.circular(30.0),
child: Chewie(
controller: _chewieController,
)
with
return Stack(
children: [
ClipRRect(
borderRadius: BorderRadius.circular(30.0),
child: Chewie(
controller: _chewieController,
),
),
Positioned.fill(child: GestureDetector(
onDoubleTap: (){
print('its double tapped ');
},
child: Container(
color: Colors.transparent,
height: double.infinity,
width: double.infinity,
),))
],
);
Now I am able to doubleTap, but with a single tap, controllers don't appear, Is there any way I can achieve both things.
With a doubleTap, I can call the like function and with onTap to show the controllers.
the package used above chewie 0.12.0
I don't know how Chewie is built but if there is GestureDetector you could change it to something like this:
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () => setState(() => // show_controls,),
onDoubleTap:() => setState(() => // like behaviour,),
child: VideoWidget // or whatever is there
}
So you can have both listeners on one widget. I think that way onTap will be with some slight delay to check if it is not onDoubleTap. That way you don't have to put overlay on top of your widget.
If for some reason you want to have this overlay... then the interesting attribute here is behaviour as it decides if elements behind will receive events.
https://api.flutter.dev/flutter/rendering/PlatformViewHitTestBehavior-class.html
Update
Try changing into
GestureDetector(
behavior: HitTestBehavior.translucent,
onDoubleTap: (){
print('its double tapped ');
}
OR
In the github project, this line:
https://github.com/flutter/plugins/blob/master/packages/video_player/video_player/example/lib/main.dart#L290
It seems that the controls only show when video is in pause state. Its about this value controller.value.isPlaying.
Why not to control it in your own GestureDetector ?
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () => setState(() => _controller.pause() ,), //changing here
onDoubleTap:() => setState(() => // like behaviour,),
child: VideoWidget // or whatever is there
}
Anyway, hope it you will find answer
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTapDown: (_) {
setState(() {
isMute = !isMute;
_chewieController.setVolume(isMute ? 0 : 1);
});
},
onDoubleTap: (){
print('liked');
},
child: ClipRRect(
borderRadius: BorderRadius.circular(30.0),
child: Chewie(
controller: _chewieController,
),
),
);
on simple onTap on video, it shows the controller, onTap here is not getting override hence
onTapDown is used as an alternative to onTap to mute the video.

How to catch gesture from its child in GestureDetector?

In this part of code only doSthElse() is being called.
GestureDetector(
onTap: doSth,
child: FloatingActionButton(
onPressed: doSthElse,
)
)
If I set null instead of doSthElse, then doSth is called when onTap occurs.
Is there any way to call both methods on the same tap action?
Thanks guys, I figured it out. I merged #Benjamin and #Locked answers and got this:
GestureDetector(
onTap: () {
doSth();
widget.button.onPressed();
},
child: AbsorbPointer(
child: widget.button,
absorbing: true,
),
)
widget is StatefulWidget and code above is in its state build method.