用两个手指实现平滑滚动

时间:2017-02-02 14:35:47

标签: android animation layout

我试图使用这样的代码用两根手指拖动来滚动(平移)一个对象:

anim = ObjectAnimator.ofInt(mJotView, "Top", newTop);
anim.setDuration(10);
anim.start();

但是,由于这些代码被多次调用,当用户用两根手指拖动时,它实际上什么都不做,只是滚动几个像素。

我错过了什么?

1 个答案:

答案 0 :(得分:1)

尝试将此实现用于OnTouchLisnener

    private class MultiTouchListener implements View.OnTouchListener {

    private static final int INVALID_POINTER_ID = -1;

    public boolean isRotateEnabled = true;

    public boolean isTranslateEnabled = true;

    public boolean isScaleEnabled = true;

    public float minimumScale = 0.5f;

    public float maximumScale = 10.0f;

    private int mActivePointerId = INVALID_POINTER_ID;

    private float mPrevX;

    private float mPrevY;

    private float scale = 1;

    private ScaleGestureDetector mScaleGestureDetector;

    private long startClickTime;

    MultiTouchListener(float minimumScale, float maximumScale, float startScale) {
        this.minimumScale = minimumScale;
        this.maximumScale = maximumScale;
        this.scale = startScale;

        mScaleGestureDetector = new ScaleGestureDetector(new ScaleGestureListener());
    }

    private float adjustAngle(float degrees) {
        if (degrees > 180.0f) {
            degrees -= 360.0f;
        } else if (degrees < -180.0f) {
            degrees += 360.0f;
        }

        return degrees;
    }

    private void move(View view, TransformInfo info) {
        computeRenderOffset(view, info.pivotX, info.pivotY);
        adjustTranslation(view, info.deltaX, info.deltaY);

        // Assume that scaling still maintains aspect ratio.
        float scale = view.getScaleX() * info.deltaScale;
        scale = Math.max(info.minimumScale, Math.min(info.maximumScale, scale));
        this.scale = scale;
        view.setScaleX(scale);
        view.setScaleY(scale);

        float rotation = adjustAngle(view.getRotation() + info.deltaAngle);
        FloatingActionMenu.this.rotation = rotation;
        view.setRotation(rotation);
    }

    private void adjustTranslation(View view, float deltaX, float deltaY) {
        float[] deltaVector = {deltaX, deltaY};
        view.getMatrix().mapVectors(deltaVector);
        view.setTranslationX(view.getTranslationX() + deltaVector[0]);
        view.setTranslationY(view.getTranslationY() + deltaVector[1]);
    }

    private void computeRenderOffset(View view, float pivotX, float pivotY) {
        if (view.getPivotX() == pivotX && view.getPivotY() == pivotY) {
            return;
        }

        float[] prevPoint = {0.0f, 0.0f};
        view.getMatrix().mapPoints(prevPoint);

        view.setPivotX(pivotX);
        view.setPivotY(pivotY);

        float[] currPoint = {0.0f, 0.0f};
        view.getMatrix().mapPoints(currPoint);

        float offsetX = currPoint[0] - prevPoint[0];
        float offsetY = currPoint[1] - prevPoint[1];

        view.setTranslationX(view.getTranslationX() - offsetX);
        view.setTranslationY(view.getTranslationY() - offsetY);
    }

    @Override
    public boolean onTouch(View view, MotionEvent event) {
        mScaleGestureDetector.onTouchEvent(view, event);

        if (!isTranslateEnabled) {
            return true;
        }

        int action = event.getAction();
        switch (action & event.getActionMasked()) {
        case MotionEvent.ACTION_DOWN: {
            mPrevX = event.getX();
            mPrevY = event.getY();

            // Save the ID of this pointer.
            mActivePointerId = event.getPointerId(0);
            break;
        }

        case MotionEvent.ACTION_MOVE: {
            // Find the index of the active pointer and fetch its position.
            int pointerIndex = event.findPointerIndex(mActivePointerId);
            if (pointerIndex != -1) {

                // Only move if the ScaleGestureDetector isn't processing a
                // gesture.
                if (!mScaleGestureDetector.isInProgress()) {
                    adjustTranslation(view, currX - mPrevX, currY - mPrevY);
                }
            }

            break;
        }

        case MotionEvent.ACTION_CANCEL:
            mActivePointerId = INVALID_POINTER_ID;
            break;

        case MotionEvent.ACTION_UP:
            mActivePointerId = INVALID_POINTER_ID;

            break;

        case MotionEvent.ACTION_POINTER_UP: {
            // Extract the index of the pointer that left the touch sensor.
            int pointerIndex =
                    (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >>
                            MotionEvent.ACTION_POINTER_INDEX_SHIFT;
            int pointerId = event.getPointerId(pointerIndex);
            if (pointerId == mActivePointerId) {
                // This was our active pointer going up. Choose a new
                // active pointer and adjust accordingly.
                int newPointerIndex = pointerIndex == 0 ? 1 : 0;
                mPrevX = event.getX(newPointerIndex);
                mPrevY = event.getY(newPointerIndex);
                mActivePointerId = event.getPointerId(newPointerIndex);
            }

            break;
        }
        }

        return true;
    }

    private class ScaleGestureListener
            extends ScaleGestureDetector.SimpleOnScaleGestureListener {

        private float mPivotX;

        private float mPivotY;

        private Vector2D mPrevSpanVector = new Vector2D();

        @Override
        public boolean onScaleBegin(View view, ScaleGestureDetector detector) {
            mPivotX = detector.getFocusX();
            mPivotY = detector.getFocusY();
            mPrevSpanVector.set(detector.getCurrentSpanVector());
            return true;
        }

        @Override
        public boolean onScale(View view, ScaleGestureDetector detector) {
            TransformInfo info = new TransformInfo();
            info.deltaScale = isScaleEnabled ? detector.getScaleFactor() : 1.0f;
            info.deltaAngle = isRotateEnabled ?
                    Vector2D.getAngle(mPrevSpanVector, detector.getCurrentSpanVector()) : 0.0f;
            info.deltaX = isTranslateEnabled ? detector.getFocusX() - mPivotX : 0.0f;
            info.deltaY = isTranslateEnabled ? detector.getFocusY() - mPivotY : 0.0f;
            info.pivotX = mPivotX;
            info.pivotY = mPivotY;
            info.minimumScale = minimumScale;
            info.maximumScale = maximumScale;

            move(view, info);
            return false;
        }
    }

    private class TransformInfo {

        public float deltaX;

        public float deltaY;

        public float deltaScale;

        public float deltaAngle;

        public float pivotX;

        public float pivotY;

        public float minimumScale;

        public float maximumScale;

        @Override public String toString() {
            return "TransformInfo{" +
                    "deltaX=" + deltaX +
                    ", deltaY=" + deltaY +
                    ", deltaScale=" + deltaScale +
                    ", deltaAngle=" + deltaAngle +
                    ", pivotX=" + pivotX +
                    ", pivotY=" + pivotY +
                    ", minimumScale=" + minimumScale +
                    ", maximumScale=" + maximumScale +
                    '}';
        }
    }
}