使用 RecyclerView 实现 Gallery 画廊效果,并控制 Item 停留位置

RecyclerView 作为一个列表滑动控件,我们都知道它既可以横向滑动,也可以竖直滑动,可以实现线性布局管理,瀑布流布局管理,还有 GridView 布局管理。其实我们可以控制其 Item 的停留位置,并使其实现画廊效果。如果大家熟悉 SnapHelper 的话,估计大家就都会了。

什么是 SnapHelper

SnapHelper 的实现原理就是是监听 RecyclerView.OnFlingListener 中的 onFling 接口。support library 中只提供了一个继承类 LinearSnapHelper ,LinearSnapHelper 是抽象类 SnapHelper 的具体实现。 通过 LinearSnapHelper,我们就可以使 RecyclerView 实现类似 ViewPager 的功能,无论怎么滑动最终都会停留在列表页面正中间。

SnapHelper 和 ViewPager 的区别就是 ViewPager 一次只能滑动一页,而 RecyclerView + SnapHelper 的方式可以实现一次滑动好几页。

效果如下:

居中实现方式

使用 SnapHelper 配合 RecyclerView 实现控制 Item 位置居中显示,非常简单,官方默认提供的 LinearSnapHelper 就是居中的,我们直接使用即可。

代码如下:

  1. LinearLayoutManager linearLayoutManager = new
  2. LinearLayoutManager(this,
  3. LinearLayoutManager.HORIZONTAL, false);
  4. recyclerView.setLayoutManager(linearLayoutManager);
  5. new LinearSnapHelper().
  6. attachToRecyclerView(recyclerView);

自定义 SnapHelper

官方提供的默认是居中显示,其实我们也可以自定义,比如:靠左显示,让可见的第一个 Item 居左显示。

效果图如下

自定义 SnapHelper ,一般需要实现两个方法:

  • int[] calculateDistanceToFinalSnap(RecyclerView.LayoutManager layoutManager, View targetView) 当拖拽或滑动结束时会回调该方法,返回一个out = int[2],out[0]x轴,out[1] y轴,这就是我们需要修改的位置偏移量
  • View findSnapView(RecyclerView.LayoutManager layoutManager) 该方法返回上面方法中需要的 targetView 。

代码如下

public class CustomSnapHelper extends LinearSnapHelper {
 private OrientationHelper mHorizontalHelper;

 @Override
 public int[] calculateDistanceToFinalSnap(RecyclerView.LayoutManager layoutManager, View targetView) {
 int[] out = new int[2];
 //判断支持水平滚动,修改水平方向的位置,是修改的out[0]的值
 if (layoutManager.canScrollHorizontally()) {
 out[0] = distanceToStart(targetView, getHorizontalHelper(layoutManager));
 } else {
 out[0] = 0;
 }
 return out;
 }

 private int distanceToStart(View targetView, OrientationHelper helper) {
 return helper.getDecoratedStart(targetView) - helper.getStartAfterPadding();
 }

 @Override
 public View findSnapView(RecyclerView.LayoutManager layoutManager) {
 return findStartView(layoutManager, getHorizontalHelper(layoutManager));
 }

 private View findStartView(RecyclerView.LayoutManager layoutManager,
 OrientationHelper helper) {

 if (layoutManager instanceof LinearLayoutManager) {
 int firstChild = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition();
 int lastChild = ((LinearLayoutManager) layoutManager).findLastVisibleItemPosition();
 if (firstChild == RecyclerView.NO_POSITION) {
 return null;
 }
 //这行的作用是如果是最后一个,翻到最后一条,解决显示不全的问题
 if (lastChild == layoutManager.getItemCount() - 1) {
 return layoutManager.findViewByPosition(lastChild);
 }

 View child = layoutManager.findViewByPosition(firstChild);
 //获取偏左显示的Item
 if (helper.getDecoratedEnd(child) >= helper.getDecoratedMeasurement(child) / 2
 && helper.getDecoratedEnd(child) > 0) {
 return child;
 } else {
 return layoutManager.findViewByPosition(firstChild + 1);
 }
 }

 return super.findSnapView(layoutManager);
 }


 private OrientationHelper getHorizontalHelper(
 RecyclerView.LayoutManager layoutManager) {
 if (mHorizontalHelper == null) {
            mHorizontalHelper = OrientationHelper.createHorizontalHelper(layoutManager);
 }
 return mHorizontalHelper;
 }
}

调用自定义的 SnapHelper 代码如下,配合 RecyclerView:

  1. CustomSnapHelper mMySnapHelper = new CustomSnapHelper();
  2. mMySnapHelper.attachToRecyclerView(rv);

最后,其实垂直方向也可以实现哦,大家可以尝试一下垂直方向的使用方式是不是非常简单。

代码 Demo 地址:https://github.com/loonggg/SnapHelperDemo

本文分享自微信公众号 - 非著名程序员(non-famous-coder)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2017-02-06

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Jack的Android之旅

android自定义钟表android自定义钟表

接下来就是设定这个自定义View的大小,在没有大小自适应的时候,view的高度我这位整个手机屏幕高度的三分之一,宽度为整个屏幕的宽度

11610
来自专栏码神联盟

碎片化 | 第四阶段-41-struts2字节流生成验证码-视频

如清晰度低,可转PC网页观看高清版本: http://v.qq.com/x/page/r056700jckx.html 验证码实现 需求: 在登录的页面,增...

30990
来自专栏菩提树下的杨过

silverlight:如何在图片上挖个洞?

一、不写代码的方法:用Blend 看图说话: 这是待处理的图片win7 ? 在win7上,画一个矩形,再用钢笔随便画个封闭的path ? 将矩形与path合...

209100
来自专栏java架构师

C#对图片文件的压缩、裁剪操作初探

在做项目时,对图片的处理,以前都采用在上传时,限制其大小的方式,这样带来诸多不便。毕竟网站运维人员不一定会对图片做处理,经常超出大小限制,即使会使用图片处理软件...

35360
来自专栏从零开始学 Web 前端

11 - JavaSE之GUI

PS: Panel 的 setBounds 方法中设置的位置大小是相对于相对装入的 Frame 窗口位置和大小的。

23350
来自专栏Android先生

快给你的app上锁吧(android图案解锁)

思路 这里又是一个九宫格布局,布局可以参考上一篇快给你的app上锁吧(android数字解锁),只不过这里的九宫格上我们画的是图片(bitmap)。onDraw...

34020
来自专栏菩提树下的杨过

silverlight:手写板/涂鸦/墨迹/InkPresenter示例程序

这种应用现在已经比较常见了,比如论坛回贴中的手写功能 ,IM聊天中的个性化手写文字,个性签名等,在Silverlight中要实现该功能其实非常简单,只要一个I...

367100
来自专栏向治洪

Android入门之动画

Android动画 AlphaAnimation RelativeLayout rl_splash = (RelativeLayout) findViewBy...

25370
来自专栏Flutter&Dart

Flutter之DataTable使用详解

69430
来自专栏Hongten

java画图程序_图片用字母画出来_源码发布_版本二

在上一个版本:java画图程序_图片用字母画出来_源码发布 基础上,增加了图片同比例缩放,使得大像素图片可以很好地显示画在Notepad++中。

20720

扫码关注云+社区

领取腾讯云代金券