Android ViewPager实现图片浏览器

Android ViewPager实现图片浏览器

一、目标

左右滑动浏览笔记中的所有图片。

二、体验地址

神马笔记最新版本:【神马笔记Version1.1.0_beta.apk

三、方案选择

Android中可以作为左右滑动,并将子控件停留在居中位置的容器有2个。

  1. RecyclerView with PagerSnapHelper
  2. ViewPager

将RecyclerView作为可选方案的原因是RecyclerView在神马笔记中应用非常广泛,基本上每个界面都用到了RecyclerView。继续使用RecyclerView可以降低了项目代码的管理难度。

最终选择ViewPager作为实现方案。

选择ViewPager作为容器的关键原因,是ViewPager中有一段代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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

在左右滑动图片时,变换子控件的裁剪区域实现图片逐渐进入视野的效果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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的使用方式。

FragmentPagerAdapterFragmentStatePagerAdapter是2个非常不错的参考示例。