仿掌阅书城书架切换

首先我们先分析一下掌阅在书城书架的切换效果:

  • 首先书架、书城两个视图都会移动,速度不同所以大概得出在摆放的时候会有一定的偏移。
  • 再有就是透明度、和移动位置随着手指的滑动而变化。
  • 书架视图的右边界有一个阴影来达到层叠的效果。

在模仿别人的视图中,一般都会使用到系统的显示布局边界的功能。

  • 在这个图片中可以看到右边有一条边界线应该是视图的初始位置,可以证明第一个特点,下层视图有一定的偏移,大概的偏移量为屏幕的4/5。所以在onLayout()就需要对布局重新排布一下。
DisplayMetrics dm = context.getResources().getDisplayMetrics();
widthPixels = dm.widthPixels;
// 用于计算被覆盖的移动的距离,产生上下同时完成单速度不同的效果
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轴的偏移距离,从而根据偏移的大小来变化透明度和偏移量。通过X滑动大小和方向来进行变化。

private void doAnimation(int dx, boolean isMoveToLeft) {
isStartDrag = true;
// 计算移动中当前透明度的值,通过变化因子和变化值计算
currentAlpha += (float) alphaForctor * dx;
// 计算当前的偏移值
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:中根据当前移动的偏移距离来判断是取消动画还是完成动画。

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;

- 结束动画、和取消动画。

private void endAnimation() {
//根据已经完成的距离,来计算一下还需要多长时间来完成后续的动画
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类:创建一个线程,根据需要完成的时间,和每一帧的时间来进行事件的回调,完成相应的动作。

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;
        }
    }
};
- 在根据计算出的偏移距离和透明度进行绘制。
- 大概逻辑详细可以看源码:https://github.com/zhaoyongchao/SlideSwitchScreen
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 背景 一年多以前我在知乎上答了有关LeetCode的问题, 分享了一些自己做题目的经验。 张土汪:刷leetcod...
    土汪阅读 12,788评论 0 33
  • ¥开启¥ 【iAPP实现进入界面执行逐一显】 〖2017-08-25 15:22:14〗 《//首先开一个线程,因...
    小菜c阅读 6,639评论 0 17
  • 教程一:视频截图(Tutorial 01: Making Screencaps) 首先我们需要了解视频文件的一些基...
    90后的思维阅读 4,826评论 0 3
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 135,082评论 19 139
  • 我一直搞不清楚春天的雨是下在哪几天,又是落到了哪些个地方去了,我问我家门前那棵反季而开的桂花树,它说,春天的雨总是...
    租了五颗星阅读 243评论 0 3