美文网首页
滑动内联动效的实现之item的伴生变换

滑动内联动效的实现之item的伴生变换

作者: CysionLiu | 来源:发表于2017-08-16 12:20 被阅读0次

    本文属于滑动内联动效系列的第二篇。仓库地址

    滑动内联动效 指的是 在容器滑动的过程中,其子View对应展现出来的一些效果。本篇主要记录的是在容器滑动过程中,它的item伴随进行缩放和透明度变化。

    上图,明了。

    图1.gif

    图1中,随着滑动,内部item呈现先变大再变小的趋势,同时透明度上也是先变亮在变暗的趋势。

    图2.gif

    图2中,主要是横向的一些特效,分别有图片逆差效果,缩放效果以及透明度变换效果。

    方案分析

    思路基本同滑动内联动效的实现之图片平行逆差效果,整体还是需要一个自定义的伴生容器,作为内联item的父布局。在实现方式上还是有些差别。具体分析步骤如下:

    • 1 获得外面滑动容器的滑动事件。
      因为是做滑动内联效果,那么理应得到滑动事件才行。还是跟其上篇一样,使用ViewTreeObserver.OnScrollChangedListener这个接口。

    • 2 得到滑动容器的位置范围。
      这个滑动容器可大可小,滑动内联效果肯定是与这个有关系的。假设有个点,刚好位于滑动容器的最下边。当滑动进行时,这个点便会跟着向下移动,当其到滑动容器最上边时,这个点刚好走了滑动容器的上下距离。这个过程,也代表了比较理想的内联动效的起始和最终位置。这个容器范围可表示为屏幕上的一个矩形,这个矩形可以在滑动容器显示到屏幕上时动态的设置给内部item。

    • 3 确定包装容器和图片的内联滑动
      滑动开始了,也知道什么时候内联滑动开始了,那么内联容器应该怎么内联呢。这个涉及一些数学计算。与图片内联效果有些不同的是,在缩放和透明度变化上,这里有两种比较常见的展示。
      - 线性计算:随着滑动,item的属性线性单调变化;
      - 曲线变化:随着滑动,item的属性先变大再变小,使得item位于容器中间时属性最明显。

    这里再声明一下两个概念:
    a- 滑动容器:即平时用的具有滑动效果的View,比如ListView,RecyclerView;
    b- 内联容器:使其内容具有伴生效果的ViewGroup;
    c- 内联item:在滑动容器滑动时,具有伴生动效的item,其父布局是内联容器,普通item放到内联容器中,即为内联item。

    代码实现

    整体实现思路同滑动内联动效的实现之图片平行逆差效果,效果只是写几个AdStyle,然后添加到内联容器中即可。这里以纵向缩放为例,简单分析一下。

    public class VerticalScaleStyle extends SimpleStyle implements AdjointStyle {
        @Override
        public void onAttachedToImageView(AdjointContainer view) {
        }
        @Override
        public void onDetachedFromImageView(AdjointContainer view) {
        }
        @Override
        public void transform(AdjointContainer aContainer, Canvas canvas, int[] viewLocation, Rect parentLocation) {
            //获得内联容器的y坐标
            int y = viewLocation[1];
            //获得滑动容器的顶部和底部位置
            int ptop = parentLocation.top;
            int pbottom = parentLocation.bottom;
            //获得内联容器的内部可用宽和高
            int vWidth = aContainer.getWidth() - aContainer.getPaddingLeft() - aContainer.getPaddingRight();
            int vHeight = aContainer.getHeight() - aContainer.getPaddingTop() - aContainer.getPaddingBottom();
            // device's height
            int dHeight = ScreenUtil.getScreenHeight(aContainer.getContext());
            //取滑动低点
            dHeight = dHeight < pbottom ? dHeight : pbottom;
    
            // 避免过度滑动
            if (y < ptop - vHeight) {
                y = ptop - vHeight;
            } else if (y > dHeight) {
                y = dHeight;
            }
            y = y - ptop;
            int itemMaxMoveScope = pbottom - ptop - vHeight;
            float index = y;
            if (index <= 0) {
                index = 1.0f;
            }
            if (index >= itemMaxMoveScope) {
                index = itemMaxMoveScope;
            }
            float al = 1.0f;
            //是否线性计算
            if (isLinearable()) {
                if (index < getLinearPos() * itemMaxMoveScope) {
                    index = 0;
                }
                al = (1 - getMinScale()) * (itemMaxMoveScope - index) / itemMaxMoveScope + getMinScale();
            } else {//非线性实现
                al = (4 * getMinScale() - 4.0f) * index * index / (itemMaxMoveScope * itemMaxMoveScope)
                        + (4.0f - 4 * getMinScale()) * index / itemMaxMoveScope + getMinScale();
            }
            //设置最小的缩放比例
            if (al < getMinScale()) {
                al = getMinScale();
            }
            al = al * getFactor();
            canvas.scale(al, al, vWidth/2, vHeight*getPrivotY());
        }
    }
    

    使用方式

    整体实现思路同滑动内联动效的实现之图片平行逆差效果,简述为:

    1. 布局,内联容器作为需要内联item的容器;
    2. 设置区域,给内联容器设置滑动容器的矩形区域;
    3. 创建一个或多个AdjointStyle,添加到内联容器中。

    此时,若是设置得当,便会得到内部item随滑动容器滑动,出现平行逆差/缩放和透明度变化的一种展示效果。


    上面主要介绍了思路。完整例子见github仓库

    相关文章

      网友评论

          本文标题:滑动内联动效的实现之item的伴生变换

          本文链接:https://www.haomeiwen.com/subject/rlcirxtx.html