1

你好社区我想知道你是否可以帮助我解决以下问题。我正在做一个项目,当我触摸它时,我需要能够将位图移动一定距离。(快照中的第 2 步)但是,在到达边界时,应将图像包裹到另一侧,如第 3 步所示。

我阅读了属性动画师以及它如何允许在推特上发布视图,但我不明白我应该使用什么样的布局。我应该使用RelativeLayoutorLinearLayout吗?还是我应该使用一个canvas?如何屏蔽父视图(快照中的视图 B)以实现视图环绕效果。

非常感谢你,

在此处输入图像描述

4

1 回答 1

0
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.LinearInterpolator;
import android.view.animation.OvershootInterpolator;
import android.widget.Button;


public class AnticiButton extends Button {

    private static final LinearInterpolator sLinearInterpolator = new LinearInterpolator();
    private static final DecelerateInterpolator sDecelerator = new DecelerateInterpolator(8);
    private static final AccelerateInterpolator sAccelerator = new AccelerateInterpolator();
    private static final OvershootInterpolator sOvershooter = new OvershootInterpolator();
    private static final DecelerateInterpolator sQuickDecelerator = new DecelerateInterpolator();

    private float mSkewX = 0;
    ObjectAnimator downAnim = null;
    boolean mOnLeft = true;
    RectF mTempRect = new RectF();

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

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

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

    private void init() {
        setOnTouchListener(mTouchListener);
        setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                runClickAnim();
            }
        });
    }


    @Override
    public void draw(Canvas canvas) {
        if (mSkewX != 0) {
            canvas.translate(0, getHeight());
            canvas.skew(mSkewX, 0);
            canvas.translate(0,  -getHeight());
        }
        super.draw(canvas);
    }


    private void runPressAnim() {
        downAnim = ObjectAnimator.ofFloat(this, "skewX", mOnLeft ? .5f : -.5f);
        downAnim.setDuration(2500);
        downAnim.setInterpolator(sDecelerator);
        downAnim.start();
    }

    private void runClickAnim() {
        // Anticipation
        ObjectAnimator finishDownAnim = null;
        if (downAnim != null && downAnim.isRunning()) {
            // finish the skew animation quickly
            downAnim.cancel();
            finishDownAnim = ObjectAnimator.ofFloat(this, "skewX",
                    mOnLeft ? .5f : -.5f);
            finishDownAnim.setDuration(150);
            finishDownAnim.setInterpolator(sQuickDecelerator);
        }


        ObjectAnimator moveAnim = ObjectAnimator.ofFloat(this,
                View.TRANSLATION_X, mOnLeft ? 400 : 0);
        moveAnim.setInterpolator(sLinearInterpolator);
        moveAnim.setDuration(150);


        ObjectAnimator skewAnim = ObjectAnimator.ofFloat(this, "skewX",
                mOnLeft ? -.5f : .5f);
        skewAnim.setInterpolator(sQuickDecelerator);
        skewAnim.setDuration(100);
        // and wobble it
        ObjectAnimator wobbleAnim = ObjectAnimator.ofFloat(this, "skewX", 0);
        wobbleAnim.setInterpolator(sOvershooter);
        wobbleAnim.setDuration(150);
        AnimatorSet set = new AnimatorSet();
        set.playSequentially(moveAnim, skewAnim, wobbleAnim);
        if (finishDownAnim != null) {
            set.play(finishDownAnim).before(moveAnim);
        }
        set.start();
        mOnLeft = !mOnLeft;
    }


    private void runCancelAnim() {
        if (downAnim != null && downAnim.isRunning()) {
            downAnim.cancel();
            ObjectAnimator reverser = ObjectAnimator.ofFloat(this, "skewX", 0);
            reverser.setDuration(200);
            reverser.setInterpolator(sAccelerator);
            reverser.start();
            downAnim = null;
        }
    }


    private View.OnTouchListener mTouchListener = new View.OnTouchListener() {

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            switch (event.getAction()) {
            case MotionEvent.ACTION_UP:
                if (isPressed()) {
                    performClick();
                    setPressed(false);
                    break;
                }
                // No click: Fall through; equivalent to cancel event
            case MotionEvent.ACTION_CANCEL:
                // Run the cancel animation in either case
                runCancelAnim();
                break;
            case MotionEvent.ACTION_MOVE:
                float x = event.getX();
                float y = event.getY();
                boolean isInside = (x > 0 && x < getWidth() &&
                        y > 0 && y < getHeight());
                if (isPressed() != isInside) {
                    setPressed(isInside);
                }
                break;
            case MotionEvent.ACTION_DOWN:
                setPressed(true);
                runPressAnim();
                break;
            default:
                break;
            }
            return true;
        }
    };

    public float getSkewX() {
        return mSkewX;
    }


    public void setSkewX(float value) {
        if (value != mSkewX) {
            mSkewX = value;
            invalidate();             // force button to redraw with new skew value
            invalidateSkewedBounds(); // also invalidate appropriate area of parent
        }
    }


    private void invalidateSkewedBounds() {
        if (mSkewX != 0) {
            Matrix matrix = new Matrix();
            matrix.setSkew(-mSkewX, 0);
            mTempRect.set(0, 0, getRight(), getBottom());
            matrix.mapRect(mTempRect);
            mTempRect.offset(getLeft() + getTranslationX(), getTop() + getTranslationY());
            ((View) getParent()).invalidate((int) mTempRect.left, (int) mTempRect.top,
                    (int) (mTempRect.right +.5f), (int) (mTempRect.bottom + .5f));
        }
    }
}

添加您的 xml 布局:

 <view
        class="com.example.android.anticipation.AnticiButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="AnticiButton"/>

我希望这个能帮上忙

于 2014-03-25T05:19:51.340 回答