本文属于滑动内联动效系列的第二篇。仓库地址
滑动内联动效 指的是 在容器滑动的过程中,其子View对应展现出来的一些效果。本篇主要记录的是在容器滑动过程中,它的item伴随进行缩放和透明度变化。
上图,明了。
图1中,随着滑动,内部item呈现先变大再变小的趋势,同时透明度上也是先变亮在变暗的趋势。
图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()); } }
使用方式
整体实现思路同滑动内联动效的实现之图片平行逆差效果,简述为:
布局,内联容器作为需要内联item的容器;
设置区域,给内联容器设置滑动容器的矩形区域;
创建一个或多个AdjointStyle,添加到内联容器中。
此时,若是设置得当,便会得到内部item随滑动容器滑动,出现平行逆差/缩放和透明度变化的一种展示效果。