你好社区我想知道你是否可以帮助我解决以下问题。我正在做一个项目,当我触摸它时,我需要能够将位图移动一定距离。(快照中的第 2 步)但是,在到达边界时,应将图像包裹到另一侧,如第 3 步所示。
我阅读了属性动画师以及它如何允许在推特上发布视图,但我不明白我应该使用什么样的布局。我应该使用RelativeLayout
orLinearLayout
吗?还是我应该使用一个canvas
?如何屏蔽父视图(快照中的视图 B)以实现视图环绕效果。
非常感谢你,
你好社区我想知道你是否可以帮助我解决以下问题。我正在做一个项目,当我触摸它时,我需要能够将位图移动一定距离。(快照中的第 2 步)但是,在到达边界时,应将图像包裹到另一侧,如第 3 步所示。
我阅读了属性动画师以及它如何允许在推特上发布视图,但我不明白我应该使用什么样的布局。我应该使用RelativeLayout
orLinearLayout
吗?还是我应该使用一个canvas
?如何屏蔽父视图(快照中的视图 B)以实现视图环绕效果。
非常感谢你,
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"/>
我希望这个能帮上忙