我試圖在RecyclerView
行中創建動畫,Helper
類延伸ItemTouchHelper.Callback
。使用ItemTouchHelper.Callback實現「回彈」RecyclerView動畫
ItemTouchHelper
默認的「滑動」行爲是,如果一行以足夠的速度滑動,它將從視圖中消失(即滑動到昏暗)。就我而言,我想創建一個動畫,如果發生這樣的事件,會導致該行直線跳回。
我已經能夠創建一個ValueAnimator
,如果將它從屏幕上移開,就可以將行重新設置爲視圖。但問題是,我無法讓父類ItemTouchHelper
類識別它存儲的x
值已從行的寬度(因此它完全在屏幕外)變爲0
(以便它重新顯示在屏幕上)。
這意味着,無論何時我在完成自定義動畫之後與該行進行交互,其行爲就好像該行仍處於屏幕外,即使它完全可見。這通常意味着按下它意味着行從X
位置0
跳轉到行寬度的X
位置,因此再次從屏幕邊緣再次進入動畫。它會在完全重置並正常運行之前執行此操作幾次。
此視頻將幫助顯示問題。由於前兩次刷卡不在屏幕外,所以默認行爲有效。之後該行被刷過不過屏幕和彈回,點擊行顯示它從右側邊緣查驗回:
這裏是我用來進行動畫代碼:
public class CustomItemTouchHelper extends ItemTouchHelper.Callback {
private RecoverAnimation ra;
private boolean animatorRunning;
//...
@Override
public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
final float per = (dX/viewHolder.itemView.getWidth());
if (per > 0.8F && !animatorRunning && !isCurrentlyActive) {
ra = new RecoverAnimation(c, recyclerView, viewHolder, ItemTouchHelper.ANIMATION_TYPE_SWIPE_CANCEL, actionState, dX, dY, 0, 0);
ra.start();
} else {
getDefaultUIUtil().onDraw(c, recyclerView, viewHolder.itemView, dX, dY, actionState, isCurrentlyActive);
}
}
//...
注意,這個內部類,RecoverAnimation
,從ItemTouchHelper
源代碼拉:
private class RecoverAnimation implements AnimatorListenerCompat {
final float mStartDx;
final float mStartDy;
final float mTargetX;
final float mTargetY;
final Canvas mCanvas;
final RecyclerView mRecyclerView;
final RecyclerView.ViewHolder mViewHolder;
final int mActionState;
private final ValueAnimatorCompat mValueAnimator;
float mX;
float mY;
// if user starts touching a recovering view, we put it into interaction mode again,
// instantly.
boolean mOverridden = false;
private boolean mEnded = false;
private float mFraction;
public RecoverAnimation(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder,
int actionState, float startDx, float startDy, float targetX, float targetY) {
mRecyclerView = recyclerView;
mCanvas = c;
mActionState = actionState;
mViewHolder = viewHolder;
mStartDx = startDx;
mStartDy = startDy;
mTargetX = targetX;
mTargetY = targetY;
mValueAnimator = AnimatorCompatHelper.emptyValueAnimator();
mValueAnimator.addUpdateListener(
new AnimatorUpdateListenerCompat() {
@Override
public void onAnimationUpdate(ValueAnimatorCompat animation) {
setFraction(animation.getAnimatedFraction());
update();
}
});
mValueAnimator.setTarget(viewHolder.itemView);
mValueAnimator.addListener(this);
setFraction(0f);
}
public void setDuration(long duration) {
mValueAnimator.setDuration(duration);
}
public void start() {
animatorRunning = true;
mViewHolder.setIsRecyclable(false);
mValueAnimator.start();
}
public void cancel() {
mValueAnimator.cancel();
}
public void setFraction(float fraction) {
mFraction = fraction;
}
/**
* We run updates on onDraw method but use the fraction from animator callback.
* This way, we can sync translate x/y values w/ the animators to avoid one-off frames.
*/
public void update() {
if (mStartDx == mTargetX) {
mX = ViewCompat.getTranslationX(mViewHolder.itemView);
} else {
mX = mStartDx + mFraction * (mTargetX - mStartDx);
}
if (mStartDy == mTargetY) {
mY = ViewCompat.getTranslationY(mViewHolder.itemView);
} else {
mY = mStartDy + mFraction * (mTargetY - mStartDy);
}
getDefaultUIUtil().onDraw(mCanvas, mRecyclerView, mViewHolder.itemView, mX, mY, mActionState, false);
}
@Override
public void onAnimationStart(ValueAnimatorCompat animation) {
}
@Override
public void onAnimationEnd(ValueAnimatorCompat animation) {
animatorRunning = false;
mEnded = true;
getDefaultUIUtil().onDraw(mCanvas, mRecyclerView, mViewHolder.itemView, 0, 0, ItemTouchHelper.ACTION_STATE_IDLE, false);
getDefaultUIUtil().clearView(mViewHolder.itemView);
}
@Override
public void onAnimationCancel(ValueAnimatorCompat animation) {
setFraction(1f); //make sure we recover the view's state.
}
@Override
public void onAnimationRepeat(ValueAnimatorCompat animation) {
}
}
是療法我能做的任何事情來抵消這個問題,還是根本不可能(但)?
你知道如何解決這個問題嗎? – IgorOliveira
@IgorOliveira不!我最終認定這不值得冒險,並採用不同的解決方案。 – PPartisan
按照你的代碼,我管理了一個很好的解決方案。不是最好的解決方案,但它的流暢和可靠(至少現在)。 – IgorOliveira