How to make the phone vibrate on long press with Flutter? - flutter

Is there a way to make the phone vibrates when the onLongPress "timer" is reached?
For example:
1- There is a list of items
2- I push and hold one item for a "long press"
3- When the onLongPress "timer" is reached, I want the phone vibrates just a little.
Doable?
Thanks

You can wrap your widget (item) that you want to long press in an GestureDetector for example, resulting in something like this:
class MyVibrateButton extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Center(
child: GestureDetector(
onLongPress: () => HapticFeedback.vibrate(),
child: Container(
alignment: Alignment.center,
decoration: BoxDecoration(border: Border.all(width: 2.0)),
width: 100.0,
height: 50.0,
child: Text(
'My Item\nPress me',
textAlign: TextAlign.center,
),
),
),
);
}
}
Edit: I just found that you can use the Flutter included services.dart package that contains the HapticFeedback class which allows you to trigger different native haptic feedbacks on both platforms. For this example you can use the vibrate() method. Since you want it to vibrate just a little you may want to also try lightImpact() or mediumImpact()
. I’ve edited my previous answer accordingly.

Related

Flutter app variables reset each time you leave the page

I'm making a flutter app. Each time I leave the page, the variables reset. How do I make it so that the data stays the same, even if you leave the page? I'm using getx for state management. Here is my code:
//Button that leaves the page
Align(
alignment: Alignment.topLeft,
child: IconButton(
onPressed: () => Get.back(),
icon: const Icon(Icons.arrow_back),
),
),
When you click the button, it leaves the page and resets the variable maintasks shown here.
Align(
alignment: Alignment.topLeft,
child: Padding(
padding: const EdgeInsets.only(left: 25.0),
child: Text(
maintasks,
style: const TextStyle(
fontSize: 23,
color: Colors.black,
fontWeight: FontWeight.w800,
),
),
),
),
There is a function which changes the variable maintasks to the user input. However this user input is reset each time you leave the page. I've tried using SetState to save the variable but for some reason it doesn't work.
Sorry if my question is worded badly. If anyone knows how to do this, please tell me. Thanks in advance.
Widget state is reset as soon as the widget is disposed.
For this, using GetX, you could use GetXControllers
Example, let's imagine you need a state that's composed by a username and a password,
class LoginController extends GetxController {//GetxController comes from Getx package
var username = ''.obs;//creates a stream that can be listened from the UI, whose value is a String
var password = ''.obs;//same here
void onUsernameChanged(String newValue) {
username(newValue);//changes username stream last value to newValue's
}
void onPasswordChanged(String newValue) {
password(newValue);//the same
}
}
Now, you must insert an instance of this controller in your widget tree before the widget is built (For example, in initState)
#override
void initState() {
_controller = Get.put<LoginController>(LoginController());
super.initState();
}
Once you know you have this instance in the widget tree, you just listen to its streams using GetX widget
GetX<LoginController>(
builder: (controller)=>Text(controller.username.value)
)//this guy will repaint every time username changes
This is important because the instance of this widget will remain alive in the widget tree until either the app ends or the controller is explicitly deleted

Gesture Detector Precedence

I have a stack containing a GestureDetector (which is the up-most layer and spans across the whole screen) and another widget (under it) that eventually has a ListView. The problem is that the global GestureDetector uses onHorizontalDrag which consumes the touch event. Instead, I want the ListView to consume that event only.
In short, is there a way to make the ListView take precedence over the GestureDetector without keeping some sort of a state? Note, the ListView is not a child/sub-child of the GestureDetector - they are on different branches within the widget tree.
I try out a stack with two GestureDetectors. It gives the highest preference to the GestureDetector which is placed last in the stack.
Example:
#override
Widget build(BuildContext context) {
return Stack(
children: [
GestureDetector(
onTap: () => {
print("gesture detector1 event fired"),
},
child: Container(
color: Colors.red,
height: 600,
width: 400,
),
),
GestureDetector(
onTap: () => {
print("gesture detector2 event fired"),
},
child: Container(
color: Colors.blue,
height: 200,
width: 400,
),
),
],
);
}
When you click on the blue color container "Gesture Detector 2 is fired", you click on the red color container then "Gesture Detector 1 is fired"
Refer this image
try adding behavior: HitTestBehavoir.translucent or HitTestBehavoir.deferToChild to the gestureture detector.

Searching for the name of a specific menu - Flutter

So I'm searching for a Menu often found in a Settings Screen. It's used to select a Setting.
It opens when you press on a ListTile and then it fills the mayority of the Screen, while the borders are transparent. In the menu you have to select one of the options.
An example usecase of that would be to select a Language(onTap of the ListTile opens a Menu where you can select between all the avaliable languages)
It is similar to that of a PopupMenuButton, however as already mentioned it fills most of the screen, and the individual selectable items have a radiobutton in front of the text(probably RadioListTiles)
I hope someone gets what I'm talking about, because for the past 3 hours I'm searching for this widget but just find articles about the PopupMenuButton over and over.
Edit: I finally found an app that uses the feature I'm looking for
: https://imgur.com/a/A9k71io
By clicking on the first ListTile in the first Picture, the dialog in the second picture opens up.
Hopefully this custom widget is something roughly what you want, try to copy and paste it in your project and play with it.
this is made using the Dialog widget, to exit the Dialog you can tap out of it/ press the device back arrow and I added a small back icon on the top left corner.
tell me if it helped :)
class TestPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
final deviceSize = MediaQuery.of(context).size;// the device size
return Scaffold(
body: Center(
child: ListTile(
tileColor: Colors.grey[300],
title: Text(
'Language',
style: TextStyle(fontSize: 25),
),
onTap: () => showDialog(
context: context,
builder: (context) => Dialog(
insetPadding: EdgeInsets.all(20),
child: Container(
color: Colors.white,
height: deviceSize.height,
width: deviceSize.width,
child: Column(
children: [
Row(
children: [
IconButton(
color: Colors.red,
icon: Icon(Icons.arrow_back),
onPressed: () => Navigator.of(context).pop(),
),
],
),
Spacer(),
Text('Pick A Language'),
Spacer(),
],
),
),
),
),
),
),
);
}
}

Flutter ReorderableListView doesn't work with TextFields

The widgets in my ReorderableListView are essentially TextFields. When long pressing on a widget, after the time when the long press should cause the widget to "hover," instead the TextField receives focus. How can I make the drag & drop effect take precedence over the TextField? I would still like a normal tap to activate the TextField.
The code below demonstrates my issue.
I also tried to use this unofficial flutter_reorderable_list package. (To test this one, replace the Text widget on this line of the example code with a TextField.)
I'm willing to use any ugly hacks to get this working, including modifying the Flutter source code!
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
final children = List<Widget>();
for (var i = 0; i < 5; i++) {
children.add(Container(
color: Colors.pink, // Only the pink area activates drag & drop
key: Key("$i"),
height: 50.0,
child: Container(
color: Colors.grey,
margin: EdgeInsets.only(left: 50),
child: TextField(),
),
));
}
return MaterialApp(
home: Scaffold(
body: SafeArea(
child: ReorderableListView(
children: children,
onReorder: (oldIndex, newIndex) => null,
),
),
),
);
}
}
You need to do multiple things in there to fix this.
First disable the default handler in ReorderableListView by setting buildDefaultDragHandles: false in its properties.
Wrap you child widget inside ReorderableDragStartListener widget like this
ReorderableDragStartListener(
index: i,
child: Container(
color: Colors.grey,
margin: EdgeInsets.only(left: 50),
child: TextFormField(initialValue: "Child $i", ),
),
),
Then inside this ReorderableDragStartListener wrap your child in InkWell and AbsorbPointer. Then use FocusNode to focus inner TextField on single tap.
Like this
InkWell(
onTap: () => _focusNode.requestFocus(),
onLongPress: () {
print("long pressed");
},
child: AbsorbPointer(
child: TextFormField(initialValue: "Child $i", focusNode: _focusNode,),
),
),
You need to create multiple FocusNode for all the items in list. You can do this by using List or by simpling creating a new FocusNode inside the loop.
Complete code example here https://dartpad.dev/?id=e75b493dae1287757c5e1d77a0dc73f1

Set fontFamily for all buttons in Flutter

Is there a way to set the fontFamily for all buttons in a Flutter app?
I see I can set my fontFamily for my MaterialApp using theme.fontFamily, but I'd like to use a different fontFamily for all my buttons.
I saw there is also a ButtonThemeData, but it seems to be related to colors and shapes only.
I don't want to set my fontFamily explicitly every time I use a button or having to wrap all types of buttons, is there any way to accomplish this?
Thanks!
You should use themes to customize fonts for whole widgets, including buttons : https://flutter.dev/docs/cookbook/design/fonts
Simplest might be to create a helper method that returns a Button configured as you wish.
I recomend creating a custom button that "extends" Flutter MaterialButton or RawMaterialButton. Remember to add buttonText as a paramater too if you want your button to be reusable. Also remember to add TextStyle(fontFamily: 'Raleway') to the Text widget style.
Another option would be to "extend" the Flutter Text widget in the same way as with the button example below, and add your CustomTextWidget as a child to the Flutter MaterialButton widget. I prefer to use both in a combination. CustomButton together with CustomText widget.
import 'package:flutter/material.dart';
class CustomButton extends StatelessWidget {
CustomButton({#required this.onPressed});
final GestureTapCallback onPressed;
#override
Widget build(BuildContext context) {
return RawMaterialButton(
fillColor: Colors.green,
splashColor: Colors.greenAccent,
child: Padding(
padding: EdgeInsets.all(10.0),
child: Row(
mainAxisSize: MainAxisSize.min,
children: const <Widget>[
Icon(
Icons.face,
color: Colors.amber,
),
SizedBox(
width: 10.0,
),
Text(
"Tap Me",
maxLines: 1,
style: TextStyle(color: Colors.white),
),
],
),
),
onPressed: onPressed,
shape: const StadiumBorder(),
);
}
}
Here is the implementation:
CustomButton(
onPressed: () {
print("Tapped Me");
},
)