How to restrict dragging some elements in Flutter's RerderableListView - flutter

I'd like some elements in RerderableListView to be non-draggable. I know I can do nothing in the onReorder function, but I want to deny start dragging.
How to achieve that?

You can wrap the elements with AbsorbPointer or IgnorePointer.
AbsorbPointer class
A widget that absorbs pointers during hit testing.
When absorbing is true, this widget prevents its subtree from
receiving pointer events by terminating hit testing at itself. It
still consumes space during layout and paints its child as usual. It
just prevents its children from being the target of located events,
because it returns true from RenderBox.hitTest.
IgnorePointer class
A widget that is invisible during hit testing.
When ignoring is true, this widget (and its subtree) is invisible to
hit testing. It still consumes space during layout and paints its
child as usual. It just cannot be the target of located events,
because it returns false from RenderBox.hitTest.

I have wrapped widgets I want to be non-draggable with GestureDetector and set empty handler onLongPress: (){}.

Related

Flutter how to requestFocus for a FocusNode?

I'm trying to give focus to a FocusNode on a tap. I can do this with a GestureDetector's onTap callback but I am running into an issue of propagation in nested GestureDetectors as noted in the documents:
Given a parent GestureDetector with an onTap callback, and a child GestureDetector that also defines an onTap callback, when the inner GestureDetector is tapped, both GestureDetectors send a GestureRecognizer into the gesture arena. This is because the pointer coordinates are within the bounds of both GestureDetectors. The child GestureDetector wins in this scenario because it was the first to enter the arena, resolving as first come, first served. The child onTap is called, and the parent's is not as the gesture has been consumed.
This causes an issue for me if I have a deep section of a window to be considered "in focus" such as a row in a DataTable that will listen for certain shortcuts, like the delete key, but I also want other widgets which are higher up in the window to listen for a ESC or Enter key.
If I use a GestureDetector to request focus then it is consumed. Is there some other way to requestFocus() instead of a GestureDector so that I'm not trapping myself?

Flutter AnimatedSlide breaks hitbox

I have an AnimatedSlide widget as a child of a column. Depending on a simple condition, it should slide between its initial and a destination position. This works just fine.
The problem is that the AnimatedSlide widget has an InkWell as one of its children. The InkWell's onTap callback works as intended if the AnimatedSlide widget is in is initial position. However, in the destination position, nothing happens when tapping the InkWell.
It seems like the hitbox disappeared completely because even tapping the initial position doesn't do anything.
Is there any way to get this working or is AnimatedSlide simply not meant to be used with InkWells, Buttons, etc.?

Is there a way to disable GestureArena in flutter?

I want to disable GestureArena which decides the preference of gestures,
is there any possible way to do this?
About Gesture disambiguation
you can try an IgnorePointer widget or an AbsorbPointer widget.
IgnorePointer prevents its children from receiving pointer events but is itself invisible to hit testing.
AbsorbPointer prevents its subtree from receiving pointer events by terminating hit testing at itself.

What's the difference between raisedButton and Container with onTap() (Flutter)?

When we want to achieve a button, we can choose raisedButton in flutter lib, also can a Container with onTap() function. So what's the difference between the two and which one should we choose in different situation?
Container function doesnot have onTap option, but you can achieve it by wrapping it in Guesture detector or Inkwell. There are no changes in the backend. But Raised button gives you the elevation, and animation on tap. You can also do it in the container, but it requires you to manually do it.
If you want a simple button quickly use RaisedButton.
If you want a more complex one, use Container or mixture of Containers, RaisedButton etc.
I am gonna offer something different... A tale of a treasure that is known to have answers to many questions, use cases and sometimes even examples. The name of this treasure is: official documentation. ;)
RaisedButton
A raised button is based on a Material widget whose Material.elevation increases when the button is pressed. Use raised buttons to add dimension to otherwise mostly flat layouts, e.g. in long busy lists of content, or in wide spaces. Avoid using raised buttons on already-raised content such as dialogs or cards.
Container
A convenience widget that combines common painting, positioning, and
sizing widgets.
GestureDetector
A widget that detects gestures. Attempts to recognize gestures that
correspond to its non-null callbacks. If this widget has a child, it
defers to that child for its sizing behavior. If it does not have a
child, it grows to fit the parent instead. By default a
GestureDetector with an invisible child ignores touches; this behavior
can be controlled with behavior. GestureDetector also listens for
accessibility events and maps them to the callbacks. To ignore
accessibility events, set excludeFromSemantics to true. See
flutter.dev/gestures/ for additional information. Material design
applications typically react to touches with ink splash effects. The
InkWell class implements this effect and can be used in place of a
GestureDetector for handling taps.
InkWell
A rectangular area of a Material that responds to touch. For a variant
of this widget that does not clip splashes, see InkResponse... The
InkWell widget must have a Material widget as an ancestor. The
Material widget is where the ink reactions are actually painted. This
matches the material design premise wherein the Material is what is
actually reacting to touches by spreading ink.
Well, technically you are right, they can both react to a click event. But a RaisedButton will have all the styles specific to the target platform taken care of for you (it inherits from MaterialButton).
note that it's the same in html: you can use a regular div with a click handler or use a button tag. The button will have a few styles already taken care of for you...

How to suppress scroll-into-view behavior in Flutter?

I have a CustomScrollView with a SliverAppBar that hides on scroll.
On the app bar is a search button that, when pressed, puts a TextField into the app bar.
When the field gets focus, it causes the scroll view to scroll all the way to the top, and the app bar gets stuck up in the "unsafe" area:
The Scaffold docs mention that when the keyboard is shown the scaffold's insets change and the scaffold is rebuilt, causing the "focused widget will be scrolled into view if it's within a scrollable container".
This seems like the behavior I don't want. I looked but couldn't understand the mechanism or how to suppress it. Is doing so possible?
The source code for the view in the image is here.
Also I note that this problem didn't happen in my previous implementation with non-sliver, standard widgets. I suspect this is because the app bar was not in a scrollable view, whereas SliverAppBar is inside the CustomScrollView so that it can interact with the main body.
Edit: This issue was fixed by this PR which appears to have first landed in Flutter 1.22.0.
It took some sleuthing, but I eventually found the mechanism for this behavior.
TextField wraps EditableText. When the latter gains focus, it will invoke _showCaretOnScreen, which includes a call to renderEditable.showOnScreen. This bubbles up and eventually causes the scrolling behavior.
We can force _showCaretOnScreen to return early here if we supply to the TextField a hacked ScrollController that always returns false from hasClients:
class _HackScrollController extends ScrollController {
// Causes early return from EditableText._showCaretOnScreen, preventing focus
// gain from making the CustomScrollView jump to the top.
#override
bool get hasClients => false;
}
The behavior does not seem intentional, so I reported it as bug #60422.
Caveats
This workaround may not be very stable.
I don't know what adverse effects the hasClients override might have.
The docs for TextField say that the scrollController is used "when vertically scrolling the input". In this use case we don't want vertical scrolling anyway, so the workaround might not cause any problems. In my brief testing it didn't seem to cause problems with horizontal (overflow) scrolling.
Just like the documentation mentions try and use resizeToAvoidBottomInset parameter to false (defaults to true) in the scaffold widget https://api.flutter.dev/flutter/material/Scaffold/resizeToAvoidBottomInset.html
Also I would recommend creating ValueListenableBuilder after the scaffold (as the first widget in the body) to avoid rebuilding the whole scaffold and just the body widget