umano / AndroidSlidingUpPanel

This library provides a simple way to add a draggable sliding up panel (popularized by Google Music and Google Maps) to your Android application. Brought to you by Umano.
http://umano.me
Apache License 2.0
9.5k stars 2.26k forks source link

Panel glitching and stopping in the middle every so often #525

Open PhpXp opened 9 years ago

PhpXp commented 9 years ago

Since I first tried this library I had a problem that every 1 in 50 times or so the panel glitched and got stuck in the middle even though I had no anchor point set.

Example: https://gfycat.com/SeparateInformalAmericanavocet

ignore the View animations it's just an example I think it happens when I try to expand the panel very quickly.

After some debugging I noticed the issue is in the ViewDragHelper:

public boolean continueSettling(boolean deferCallbacks) {
    // Make sure, there is a captured view
    if (mCapturedView == null) {
        return false;
    }
    if (mDragState == STATE_SETTLING) {
        boolean keepGoing = mScroller.computeScrollOffset();
        final int x = mScroller.getCurrX();
        final int y = mScroller.getCurrY();
        final int dx = x - mCapturedView.getLeft();
        final int dy = y - mCapturedView.getTop();

        if(!keepGoing && dy != 0) { //add this 5 lines
            //Invalid drag state
            mCapturedView.setTop(0);
            return true;
        }
        // ...

I don't know why it happens but everytime it does, keepGoing is false but dy is a very large negative number (around -600) instead of 0. The correct behaviour is that when y is getting close to 0, so should dy.

So adding those 5 lines fixes the glitching but it's really just a workaround.

I have Android 5.1.1 on an Z3 Compact, but the issue was already present in 5.0.2.

Does anyone else experience this glitch?

qbraet commented 9 years ago

I was just about to create a ticket with almost the same problem. I thought it was caused by the recyclerview I was using in the panel (I use the latest master version, so should support this), but maybe it's a more general issue.

For me, this seems to happen when, while swiping down, your finger moves over to another cell in the recyclerview. If your finger stays in the same cell while swiping, this issue doesn't seem to appear. It also doesn't happen if you swipe on the empty space below recyclerview cells (e.g. when there is only 1 cell and lots of space left underneath it). So it seems that "crossing views" while swiping causes my error, but I'm not 100% sure about that

PhpXp commented 8 years ago

I just want to say that I've been using the mentioned fix for the last two months with no problems. It fixes the bug completely and brings no other errors. The panel hasn't gotten stuck since.

I really feel like this fix should be implemented. I can make a pull request, but I have yet to learn how to do that ...

Shusshu commented 8 years ago

I also encounter this bug.

Shusshu commented 8 years ago

@PhpXp Can you try and make a pull request? it's very easy https://help.github.com/articles/creating-a-pull-request/

In short:

JShortwhile commented 8 years ago

These 5 lines did not worked for me. But if I delete the second condition in this line:

if ((ady > dragSlop && adx > ady) || !isViewUnder(mDragView, (int) mInitialMotionX, (int) mInitialMotionY)) {

in the onInterceptTouchEvent() function, everything works fine.

Do you know why is there such a condition?

PhpXp commented 8 years ago

Check your imports, maybe you are using the default Android provided ViewDragHelper.

Also, those 5 lines are really a workaround, not a fix. I never found out why it even gets into that state. Maybe your code is the real fix, I'll take a look at it.

kshitijcode commented 8 years ago

I am too facing the issue. It gets stuck while scrolling back up or down particularly if I do an entire "drag" then just a "fling".

dmitriigriazin commented 8 years ago

Hi! I'm facing this bug on all platforms api 16+.

As @qbraet said, "view crossing" causes it, I do confirm that, the same behavior. As a dirty hack I tried to put a transparent clickable view over all the panel layout - did not worked:D Seems like currently we have to fork anyway.

I have a guess, that the coodinate returned by mCapturedView.getTop() is wrong, mb it is relative to the mCapturedView itself or somewhat else, not to the hosting panel. Going to check it out soon.

UPD. Finally found it. continueSettling has nothing to do with that. You will not believe it, but the reason is that the author just really prohibited the dragging, when the "view crossing happens" or dx > dy.

SlidingUpPanelLayout.java

@Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        // ....
        switch (action) {
            // ....
            case MotionEvent.ACTION_MOVE: {
                final float adx = Math.abs(x - mInitialMotionX);
                final float ady = Math.abs(y - mInitialMotionY);
                final int dragSlop = mDragHelper.getTouchSlop();

                /*if ((ady > dragSlop && adx > ady) || !isViewUnder(mDragView, (int) mInitialMotionX, (int) mInitialMotionY)) {
                    mDragHelper.cancel();
                    mIsUnableToDrag = true;
                    return false;
                }*/
                break;
            }

See that commented condition. It solves the issue.

Why it happened and what should we learn from that: This issue will happen really when the scroll is fast. The speed of gestures updates is limited. The author probably expected, that the code will get every drag update and will calculate if the pointer is over the view. However, if the swipe speed is high, the delta value will be high, and the problem rises: view is not positioned to the right place yet, but the new pointer's coordinates are far from this view, so !isViewUnder() is true.

Need also to fix the behavior, when dx > dy , so the cancellation happens, rather than the panel freeze.

Community vs bugs 1 : 0

PS goona make pull request soon

Shusshu commented 8 years ago

a new release on the way? :)

kshitijcode commented 8 years ago

Still doesnt work. When I do a really long drag the panel doesnt go up .

dmitriigriazin commented 8 years ago

@tokudu a3d5838 will not fix, plz reopen

tokudu commented 8 years ago

Can someone create sample project where this happens. I can't reproduce it.

kshitijcode commented 8 years ago

Why isnt it going back up on doing a drag but does so when I fling it back ? Is the issue related to dy ?

tokudu commented 8 years ago

Ping! Can anyone create a sample project with the issue?

citymaps commented 8 years ago

I think I figured out the problem.

My recyclerview will stop panning the moment mIsUnableToDrag = true; happens

This is the check that leads into that case if ((ady > dragSlop && adx > ady) || !isViewUnder(mDragView, (int) mInitialMotionX, (int) mInitialMotionY)) {...}

mInitialMotionX and mInitialMotionY are only set on ACTION_DOWN, even though the user's finger is obviously moving. As soon as the initial touch point is no longer within mDragView, it stops scrolling.

So either, the mInitialMotion variables need to be kept up to date with where the user's finger is, or we shouldn't be using any view inside the scrollable container as the mDragView.

edkimmel commented 8 years ago

Looked into citymaps' answer more.

Instead of messing with properties or state, if the check is changed to use the current event x/y instead, everything works as expected. I don't know the side effects of this.

if ((ady > dragSlop && adx > ady) || !isViewUnder(mDragView, (int) x, (int) y)) {

vaibhavrustogi commented 8 years ago

526 Fixes everything but when you have a list view inside slidingpane and you keep the height of slidingpane more than the height of listview (keep 2-3 items in listview) than on touching over listview you get onClick event on list Items.

If we are able to fix this then it would be stable

@tokudu in the project demo if you remove the linearlayout containing share buttons from the dragview container and just keep listview inside slidingpane then while sliding down from expanded state with speed then you will be able to notice it.

maximPetlyuk commented 8 years ago

526 Fixed this issue.

caiiiycuk commented 7 years ago

In my case panel goes always to top. If I drag it to anchored point and release then panel goes to top. In debuger I see that code

            if(!keepGoing && dy != 0) { //fix #525
                //Invalid drag state
                mCapturedView.setTop(0);
                return true;
            }

executes forever.

I mean mCapturedView.setTop(0); called forever.

Version 3.3.1.

tanvi12 commented 5 years ago

@Override public boolean dispatchTouchEvent(MotionEvent ev) { return getPanelState() == SlidingUpPanelLayout.PanelState.DRAGGING || super.dispatchTouchEvent(ev); }

Just add this it will solve the problem.