本文属于滑动内联动效系列的第二篇。仓库地址
滑动内联动效 指的是 在容器滑动的过程中,其子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随滑动容器滑动,出现平行逆差/缩放和透明度变化的一种展示效果。