RecyclerView实现Gallery画廊效果
使用RecyclerView实现一个画廊效果,主要是使用support库中最新加入的PagerSnapHelper类,通过计算滑动偏移来计算scale的值。

基本实现
首先需要为RecyclerView添加一个滚动监听,然后为RecyclerView的第一个与最后一个itemView添加一个ItemDecoration,使位于第一个与最后一个itemView的位置居中对齐。
public void attachToRecyclerView(final RecyclerView recyclerView) {
this.recyclerView = recyclerView;
snapHelper.attachToRecyclerView(recyclerView);
recyclerView.addOnScrollListener(scrollListener);
recyclerView.addItemDecoration(new ScalableCardItemDecoration());
recyclerView.post(new Runnable() {
@Override
public void run() {
pageScrolled();
}
});
}
ScalableCardItemDecoration用于计算itemView左右剩余空间,然后为第一个itemView与最后一个itemView添加偏移量。
private static class ScalableCardItemDecoration extends RecyclerView.ItemDecoration {
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
RecyclerView.ViewHolder holder = parent.getChildViewHolder(view);
int position = holder.getAdapterPosition() == RecyclerView.NO_POSITION ? holder.getOldPosition() : holder.getAdapterPosition();
RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
int itemCount = layoutManager.getItemCount();
if(position != 0 && position != itemCount - 1){
return;
}
int peekWidth = getPeekWidth(parent, view);
boolean isVertical = layoutManager.canScrollVertically();
//移除item时adapter position为-1。
if (isVertical) {
if (position == 0) {
outRect.set(0, peekWidth, 0, 0);
} else if (position == itemCount - 1) {
outRect.set(0, 0, 0, peekWidth);
} else {
outRect.set(0, 0, 0, 0);
}
} else {
if (position == 0) {
outRect.set(peekWidth, 0, 0, 0);
} else if (position == itemCount - 1) {
outRect.set(0, 0, peekWidth, 0);
} else {
outRect.set(0, 0, 0, 0);
}
}
}
}
在为item添加ItemDecoration时,需要计算两边的空间。这里需要手动测量itemView的宽高, 然后计算第一个itemView左边的偏移与最后一个itemView右边的偏移。这里碰到个问题,如果LayoutMangaer的方面是垂直或水平的且RecyclerView对应的的高度或宽度设为wrap_content时,这里计算的值不会正确。
public static int getPeekWidth(RecyclerView recyclerView, View itemView) {
RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
boolean isVertical = layoutManager.canScrollVertically();
int position = recyclerView.getChildAdapterPosition(itemView);
//TODO RecyclerView使用wrap_content时,获取的宽度可能会是0。
int parentWidth = recyclerView.getMeasuredWidth();
int parentHeight = recyclerView.getMeasuredHeight(); //有时会拿到0
parentWidth = parentWidth == 0 ? recyclerView.getWidth() : parentWidth;
parentHeight = parentHeight == 0 ? recyclerView.getHeight() : parentHeight;
int parentEnd = isVertical ? parentHeight : parentWidth;
int parentCenter = parentEnd / 2;
int itemSize = isVertical ? itemView.getMeasuredHeight() : itemView.getMeasuredWidth();
if (itemSize == 0) {
ViewGroup.LayoutParams layoutParams = itemView.getLayoutParams();
int widthMeasureSpec =
RecyclerView.LayoutManager.getChildMeasureSpec(parentWidth,
layoutManager.getWidthMode(),
recyclerView.getPaddingLeft() + recyclerView.getPaddingRight(),
layoutParams.width, layoutManager.canScrollHorizontally());
int heightMeasureSpec =
RecyclerView.LayoutManager.getChildMeasureSpec(parentHeight,
layoutManager.getHeightMode(),
recyclerView.getPaddingTop() + recyclerView.getPaddingBottom(),
layoutParams.height, layoutManager.canScrollVertically());
itemView.measure(widthMeasureSpec, heightMeasureSpec);
itemSize = isVertical ? itemView.getMeasuredHeight() : itemView.getMeasuredWidth();
}
/*
计算ItemDecoration的大小,确保插入的大小正好使view的start + itemSize / 2等于parentCenter。
*/
int startOffset = parentCenter - itemSize / 2;
int endOffset = parentEnd - (startOffset + itemSize);
return position == 0 ? startOffset : endOffset;
}
添加完ItemDecoration后,我们需要在RecyclerView每次滚动的时候计算左、中、右3个itemView的缩放比例。
private void pageScrolled() {
if (recyclerView == null || recyclerView.getChildCount() == 0)
return;
RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
View snapingView = snapHelper.findSnapView(layoutManager);
int snapingViewPosition = recyclerView.getChildAdapterPosition(snapingView);
View leftSnapingView = layoutManager.findViewByPosition(snapingViewPosition - 1);
View rightSnapingView = layoutManager.findViewByPosition(snapingViewPosition + 1);
float leftSnapingOffset = calculateOffset(recyclerView, leftSnapingView);
float rightSnapingOffset = calculateOffset(recyclerView, rightSnapingView);
float currentSnapingOffset = calculateOffset(recyclerView, snapingView);
if (snapingView != null) {
snapingView.setScaleX(currentSnapingOffset);
snapingView.setScaleY(currentSnapingOffset);
}
if (leftSnapingView != null) {
leftSnapingView.setScaleX(leftSnapingOffset);
leftSnapingView.setScaleY(leftSnapingOffset);
}
if (rightSnapingView != null) {
rightSnapingView.setScaleX(rightSnapingOffset);
rightSnapingView.setScaleY(rightSnapingOffset);
}
if(snapingView != null && currentSnapingOffset >= 1){
OnPageChangeListener listener = pageChangeListenerRef != null ? pageChangeListenerRef.get(): null;
if(listener != null)
listener.onPageSelected(snapingViewPosition);
}
Log.d(TAG, String.format("left: %f, right: %f, current: %f", leftSnapingOffset, rightSnapingOffset, currentSnapingOffset));
}
计算缩放比例时是根据左、中、右三个itemView的中间点与RecyclerView中间点的距离来计算的。
private float calculateOffset(RecyclerView recyclerView, View view) {
if (view == null)
return -1;
RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
boolean isVertical = layoutManager.canScrollVertically();
int viewStart = isVertical ? view.getTop() : view.getLeft();
int viewEnd = isVertical ? view.getBottom() : view.getRight();
int centerX = isVertical ? recyclerView.getHeight() / 2 : recyclerView.getWidth() / 2;
int childCenter = (viewStart + viewEnd) / 2;
int distance = Math.abs(childCenter - centerX);
if (distance > centerX)
return STAY_SCALE;
float offset = 1.f - (distance / (float) centerX);
return (1.f - STAY_SCALE) * offset + STAY_SCALE;
}
项目地址: https://github.com/yjwfn/recyclerview-gallery
《架构文摘》每天一篇架构领域重磅好文,涉及一线互联网公司应用架构(高可用、高性 能、高稳定)、大数据、机器学习等各个热门领域。
RecyclerView实现Gallery画廊效果的更多相关文章
- RecyclerView 实现gallery画廊效果
1.RecyclerView的基本用法 首先主Activity的布局文件: [html] view plaincopy <RelativeLayout xmlns:android="h ...
- RecyclerView实现终极画廊效果 中间突出并且压住两侧布局
先给大家上个gif 要不然下面很枯燥 忘记原来在哪里看到了..... 这个效果我找了NNNNNN长时间,,,我认为凭我现在的能力 写出来需要好久 所以 退而求其次找大神写好的... 你们不要小看了这个 ...
- Swift - 使用CollectionView实现图片Gallery画廊效果(左右滑动浏览图片)
1,效果图 (1)图片从左至右横向排列(只有一行),通过手指拖动可以前后浏览图片. (2)视图滚动时,每张图片根据其与屏幕中心距离的不同,显示尺寸也会相应地变化.越靠近屏幕中心尺寸就越大,远离屏幕中心 ...
- 第31讲 UI组件之 Gallery画廊控件
第31讲 UI组件之 Gallery画廊控件 1.Gallery的简介 Gallery(画廊)是一个锁定中心条目并且拥有水平滚动列表的视图,一般用来浏览图片,并且可以响应事件显示信息.Gallery只 ...
- 仿百度壁纸客户端(六)——完结篇之Gallery画廊实现壁纸预览已经项目细节优化
仿百度壁纸客户端(六)--完结篇之Gallery画廊实现壁纸预览已经项目细节优化 百度壁纸系列 仿百度壁纸客户端(一)--主框架搭建,自定义Tab + ViewPager + Fragment 仿百度 ...
- 使用RecyclerView打造Gallery
RecyclerView概述 RecyclerView是谷歌推出的用于向大型数据集提供有限窗口的灵活视图.可以通过导入support-v7对其进行使用. 据官方的介绍,该控件用于在有限的窗口中展示大量 ...
- Android画廊效果
Android画廊效果 前言:Gallery是一个内部元素控件,可以水平滚动,并且可以把当前选择的子元素定位在它中心的布局组件:画廊Gallery一般用来显示可左右移动图片的列表(具体请看实例). 效 ...
- 仿百度壁纸client(六)——完结篇之Gallery画廊实现壁纸预览已经项目细节优化
仿百度壁纸client(六)--完结篇之Gallery画廊实现壁纸预览已经项目细节优化 百度壁纸系列 仿百度壁纸client(一)--主框架搭建,自己定义Tab + ViewPager + Fragm ...
- UI组件之AdapterView及其子类(四)Gallery画廊控件使用
听说 Gallery如今已经不使用了,API使用ViewPaper取代了,以后再学专研ViewPaper吧如今说说Gallery画廊,就是不停显示图片的意思 Gallery是用来水平滚动的显示一系列项 ...
随机推荐
- Nginx入门(一):在centos上安装nginx
CenterOS7安装Nginx =================== 参考:https://www.xuliangwei.com/bgx/972.html nginx官网下载地址:http://n ...
- JavaWeb实现增删查改(图书信息管理)——之查询
关于此次CRUD所需要的jar包,本人把文件放在了百度网盘,需要的自行去下载: 链接:https://pan.baidu.com/s/1Pqe88u6aPaeVjjOq1YFQ-w 提取码:pim ...
- JPA多条件复杂SQL动态分页查询
概述 ORM映射为我们带来便利的同时,也失去了较大灵活性,如果SQL较复杂,要进行动态查询,那必定是一件头疼的事情(也可能是lz还没发现好的方法),记录下自己用的三种复杂查询方式. 环境 spring ...
- 微服务时代之网关相关技术选型及部署(nacos+gateway)
1.场景描述 因要用到微服务,关于注册中心这块,与同事在技术原型上做了讨论,初步定的方案是使用:阿里巴巴的nacos+springcloud gateway,下面表格是同事整理的注册中心对比,以前用的 ...
- zoj - 4059 Kawa Exam scc + dsu
Kawa Exam 题解:先scc把图变成树, 然后对于这若干棵树在进行dsu的操作. dsu就是先找到最大的子树放在一边,然后先处理小的子树,最后处理大的子树.无限递归. 重要的一点就是 是否重新添 ...
- hdu 1028 Ignatius and the Princess III 母函数
Ignatius and the Princess III Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K ...
- ZOJ 3876 May Day Holiday
As a university advocating self-learning and work-rest balance, Marjar University has so many days o ...
- Pytorch读取,加载图像数据(一)
在学习Pytorch的时候,先学会如何正确创建或者加载数据,至关重要. 有了数据,很多函数,操作的效果就变得很直观. 本文主要用其他库读取图像文件(学会这个,你就可以在之后的学习中,将一些效果直观化) ...
- SVN更新失败
一.svn更新失败 使用svn遇到的问题是,更新失败,代码被锁定. 解决办法: 在项目上右键,如图所示: 图一: 图二: 之后再更新,基本上都没有问题了.如果还有问题,看下面. 二.工具清理 ...
- 【Offer】[50-2] 【字符流中第一个只出现一次的字符】
题目描述 思路分析 测试用例 Java代码 代码链接 题目描述 请实现一个函数用来找出字符流中第一个只出现一次的字符.例如,当从字符流中只读出前两个字符"go"时,第一个只出现一次 ...