首先我們先分析一下掌閱在書城書架的切換效果:
- 首先書架判帮、書城兩個視圖都會移動袱饭,速度不同所以大概得出在擺放的時候會有一定的偏移雌桑。
- 再有就是透明度汇跨、和移動位置隨著手指的滑動而變化务荆。
- 書架視圖的右邊界有一個陰影來達到層疊的效果。
在模仿別人的視圖中穷遂,一般都會使用到系統(tǒng)的顯示布局邊界的功能函匕。
- 在這個圖片中可以看到右邊有一條邊界線應(yīng)該是視圖的初始位置,可以證明第一個特點蚪黑,下層視圖有一定的偏移盅惜,大概的偏移量為屏幕的4/5中剩。所以在onLayout()就需要對布局重新排布一下。
DisplayMetrics dm = context.getResources().getDisplayMetrics();
widthPixels = dm.widthPixels;
// 用于計算被覆蓋的移動的距離抒寂,產(chǎn)生上下同時完成單速度不同的效果
firstLayoutOffset = (widthPixels / 5)*4;
getChildAt(0).layout(getChildAt(0).getLeft() + firstLayoutOffset,
0,getChildAt(0).getLeft() + getChildAt(0).getWidth()
+ firstLayoutOffset,
getChildAt(0).getMeasuredHeight()); ```
- 重寫onTouchEvent()方法结啼,在MotionEvent.ACTION_MOVE:中計算X軸的偏移距離,從而根據(jù)偏移的大小來變化透明度和偏移量屈芜。通過X滑動大小和方向來進行變化郊愧。
private void doAnimation(int dx, boolean isMoveToLeft) {
isStartDrag = true;
// 計算移動中當(dāng)前透明度的值,通過變化因子和變化值計算
currentAlpha += (float) alphaForctor * dx;
// 計算當(dāng)前的偏移值
currentTranslate += translateFactor * dx;
// 防止超過透明度的開始值也為最大值
currentAlpha = currentAlpha < START_ALPHA ? currentAlpha : START_ALPHA;
if (currentAlpha <= 0) {
currentAlpha = 0;
}
if ((currentTranslate <= 0 && !isCollapse)
|| (currentTranslate >= 0 && isCollapse)) {
this.invalidate();
} else {
currentTranslate = START_TRANSLATE;
}
}
- 在MotionEvent.ACTION_UP:中根據(jù)當(dāng)前移動的偏移距離來判斷是取消動畫還是完成動畫井佑。
case MotionEvent.ACTION_UP:
if (x >= mFirstMotionX) {
isMoveToRight = true;
} else {
isMoveToRight = false;
}
lastAlpha = currentAlpha;
lastTranslate = currentTranslate;
if (isMoveToRight) {
if (x - mFirstMotionX > widthPixels * 0.5f) {
endAnimation();
} else {
cancelAnimation();
}
} else {
if (x + (widthPixels - mFirstMotionX) < widthPixels * 0.5f) {
endAnimation();
} else {
cancelAnimation();
}
}
break;
- 結(jié)束動畫属铁、和取消動畫。
private void endAnimation() {
//根據(jù)已經(jīng)完成的距離躬翁,來計算一下還需要多長時間來完成后續(xù)的動畫
int duration = (int) (((1 - Math.abs(currentTranslate)) * SCREEN_DIVID_BY) * averageDuration);
accelerantTween.start(duration);
}
private void cancelAnimation() {
this.isCancel = true;
accelerantTween.start(CANCEL_ANIMATION_TIME);
}
- AccelerantTween類:創(chuàng)建一個線程焦蘑,根據(jù)需要完成的時間,和每一幀的時間來進行事件的回調(diào)盒发,完成相應(yīng)的動作例嘱。
Runnable mTick = new Runnable() {
public void run() {
long baseTime = mBaseTime;
long now = SystemClock.uptimeMillis();
long diff = now - baseTime;
int duration = mDuration;
float val = diff / (float) duration;
val = Math.max(Math.min(val, 1.0f), 0.0f);
currentValue = val;
if (!isPause) {
if (diff >= duration) {
mCallback.onTweenFinished(next);
isLastFrame = true;
}
mCallback.onTweenValueChanged(currentValue, isLastFrame);
} else {
mCallback.onTweenStop();
}
int frame = (int) (diff / FRAME_TIME);
next = baseTime + ((frame + 1) * FRAME_TIME);
if (diff < duration && !isPause) {
mHandler.postAtTime(this, next);
}
if (diff >= duration) {
mRunning = false;
}
}
};
- 在根據(jù)計算出的偏移距離和透明度進行繪制。
- 大概邏輯詳細可以看源碼:https://github.com/zhaoyongchao/SlideSwitchScreen