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

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

滑动内联动效 指的是 在容器滑动的过程中,其子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的伴生变换)