Android ViewPager实现图片浏览器
一、目标
左右滑动浏览笔记中的所有图片。
二、体验地址
神马笔记最新版本:【神马笔记Version1.1.0_beta.apk】
三、方案选择
Android中可以作为左右滑动,并将子控件停留在居中位置的容器有2个。
- RecyclerView with PagerSnapHelper
- ViewPager
将RecyclerView作为可选方案的原因是RecyclerView在神马笔记中应用非常广泛,基本上每个界面都用到了RecyclerView。继续使用RecyclerView可以降低了项目代码的管理难度。
最终选择ViewPager作为实现方案。
选择ViewPager作为容器的关键原因,是ViewPager中有一段代码。
protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
if (v instanceof ViewGroup) {
final ViewGroup group = (ViewGroup) v;
final int scrollX = v.getScrollX();
final int scrollY = v.getScrollY();
final int count = group.getChildCount();
// Count backwards - let topmost views consume scroll distance first.
for (int i = count - 1; i >= 0; i--) {
// TODO: Add versioned support here for transformed views.
// This will not work for transformed views in Honeycomb+
final View child = group.getChildAt(i);
if (x + scrollX >= child.getLeft() && x + scrollX < child.getRight()
&& y + scrollY >= child.getTop() && y + scrollY < child.getBottom()
&& canScroll(child, true, dx, x + scrollX - child.getLeft(),
y + scrollY - child.getTop())) {
return true;
}
}
}
return checkV && v.canScrollHorizontally(-dx);
}
这段代码用于让ViewPager的子控件处理水平滑动。非常符合图片浏览的使用场景。
当图片放大超过控件宽度时,应该优先移动图片。当图片到达边界时,才可以移动控件显示下一张图片。
四、PageTransformer
使用ViewPager的额外好处是可以通过设置PageTransformer来实现页面的切换效果。
GitHub上有一个非常棒的项目实现了一系列效果——Viewpager-Transformation。
GitHub项目地址:https://github.com/dipanshukr/Viewpager-Transformation
Wiki帮助手册:https://github.com/dipanshukr/Viewpager-Transformation/wiki
五、剪裁控件
Android提供了2中方式裁剪控件
- setClipBounds(Rect clipBounds)
- setOutlineProvider(ViewOutlineProvider provider)
setClipBounds接受一个Rect参数,以矩形方式进行裁剪。
setOutlineProvider接受一个ViewOutlineProvider参数,支持矩形、圆形、圆角矩形3中裁剪方式。
六、ClipPageTransformer
在左右滑动图片时,变换子控件的裁剪区域实现图片逐渐进入视野的效果。
private static class ClipPageTransformer implements ViewPager.PageTransformer {
Rect clipRect;
int gutterWidth;
ClipPageTransformer(int gutterWidth) {
this.clipRect = new Rect();
this.gutterWidth = gutterWidth;
}
@Override
public void transformPage(@NonNull View page, float position) {
if (position >= 1 || position <= -1) {
page.setClipBounds(null);
} else if (position < 0) {
int width = (int)(position * gutterWidth);
clipRect.set(0, 0, page.getWidth() + width, page.getHeight());
page.setClipBounds(clipRect);
} else if (position < 1) {
int width = (int)(position * gutterWidth);
clipRect.set(width, 0, page.getWidth(), page.getHeight());
page.setClipBounds(clipRect);
}
}
}
七、Final
ViewPager的使用方式比较容易,网上有很多不错的介绍文章。也可以参考官方的示例代码了解ViewPager的使用方式。
FragmentPagerAdapter
和FragmentStatePagerAdapter
是2个非常不错的参考示例。