GestureDetector向错误的方向投掷

时间:2014-01-29 23:50:18

标签: android gesturedetector

我有BottomDrawer的实现,它实现GestureDetector以确定用户何时翻转底部抽屉。我有两个问题:

1)onFling并不总是被调用。这是一个相对较小的问题。

2)传递给onFling的速度往往是错误的方向。这是一个巨大的问题,因为它导致用户将抽屉投掷关闭,并且打开,反之亦然。这是以前任何人都遇到过的问题吗?怎么解决这个问题?我想也许忽略了不到一定幅度的晃动,但是错误的速度有时会非常大,所以这并没有帮助。

以下是我的BottomDrawer课程的代码,如果有帮助,我也可以将演示项目上传到GitHub:

package com.cbendeb.bottomdrawer.view;

import android.animation.Animator.AnimatorListener;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.widget.LinearLayout;

/**
 * A bottom extensible drawer. Displays two views, one as the handle and one as the content.
 * 
 * @author catherine
 */
public final class BottomDrawer extends LinearLayout implements GestureDetector.OnGestureListener {
    private static final String TAG = BottomDrawer.class.getSimpleName();
    private static final int ANIMATE_DURATION = 500;

    private float lastTouchY;

    // so we don't have to recalculate this stuff all the time
    private float openY;
    private float closedY;
    private float currentY = -1;

    // listeners for the end of the open and close animations
    private AnimatorListener closeListener;
    private AnimatorListener openListener;

    // gestures
    private GestureDetector gestureDetector;
    private boolean flung = false;

    public BottomDrawer(Context context) {
        super(context);
        init(context);
    }

    public BottomDrawer(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public BottomDrawer(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context);
    }

    private void init(Context context) {
        setOrientation(LinearLayout.VERTICAL);
        gestureDetector = new GestureDetector(context, this);
    }

    /**
     * @return true if the drawer is expanded
     */
    public boolean isOpen() {
        return currentY != closedY;
    }

    /**
     * Opens the drawer.
     */
    public void open() {

        animate()
                .translationY(0)
                .setDuration(
                        Math.max(0, (int) (ANIMATE_DURATION * (getY() - openY) / (closedY - openY))))
                .setListener(openListener).start();
    }

    /**
     * Closes the drawer.
     */
    public void close() {

        animate()
                .translationY(getChildAt(1).getHeight())
                .setDuration(
                        Math.max(0,
                                (int) (ANIMATE_DURATION * (closedY - getY()) / (closedY - openY))))
                .setListener(closeListener).start();
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        final int action = ev.getActionMasked();
        final float y = ev.getRawY();

        gestureDetector.onTouchEvent(ev);

        switch (action) {
            case MotionEvent.ACTION_DOWN:
                break;
            case MotionEvent.ACTION_MOVE:
                // Calculate the distance moved
                final float dy = y - lastTouchY;

                if (getY() + dy < closedY && getY() + dy > openY) {
                    setY(getY() + dy);

                    invalidate();
                }
                break;
            case MotionEvent.ACTION_CANCEL:

                flung = false;
                break;
            case MotionEvent.ACTION_UP:
                Log.d(TAG, "flung: " + flung);
                if (!flung) {
                    if (getY() >= (openY + closedY) / 2) {
                        Log.d(TAG, "closing");
                        close();
                    } else {
                        Log.d(TAG, "opening");
                        open();
                    }
                }

                flung = false;
                break;
            case MotionEvent.ACTION_POINTER_UP:
                break;
        }
        lastTouchY = y;
        return true;
    }

    @Override
    public void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        openY = getBottom() - getChildAt(0).getHeight() - getChildAt(1).getHeight();
        closedY = getBottom() - getChildAt(0).getHeight();
        if (currentY == -1) {
            currentY = closedY;
        }
        if (changed && isOpen()) {
            setY(openY);
        } else if (changed && !isOpen()) {
            setY(closedY);
        }
    }

    @Override
    public boolean onDown(MotionEvent e) {
        return true;
    }

    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
        Log.d(TAG, "onFling velocityY: " + velocityY + " currentY " + currentY);
        final float y = getY();
        if (velocityY < 0 && y > openY && y < closedY) { // moving upwards
            Log.d(TAG, "onFling opening");
            open();
        } else if (velocityY > 0 && y > openY && y < closedY) { // moving downwards
            Log.d(TAG, "onFling closing");
            close();
        }
        flung = true;
        return true;
    }

    @Override
    public void onLongPress(MotionEvent e) {
        // Do nothing
    }

    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
        return false;
    }

    @Override
    public void onShowPress(MotionEvent e) {
        // Do nothing

    }

    @Override
    public boolean onSingleTapUp(MotionEvent e) {
        // Do nothing
        return false;
    }
}

我正在研究GrepCode上的GestureDetector实现......但如果有更简单的方法来解决这个问题会很好。

0 个答案:

没有答案