然后正好最近飞聊app比较火,主要是我们产品抄了很多头条系app的功能让我也注意到了这个app,看了一下飞聊app 的图片查看,发现他们的在图片放大查看时,做类似微信的交互,回退时,图片的位置改了(其实是recyclerView滑动了)
飞聊图片退场前会滑动recycleview让图片显示全.gif
不禁惊叹,哇,还可以这样操作,如果让图片全部显示全,那么退场时图片坐标都可以一一对应,退场动画也就不会抖动了,OK,有了思路我们开始实现
首先图片可以点击,那么item一定是可见的,我们需要知道imageView getTop 的距离是不是小于0,来确定顶部遮挡,以及getBottom的距离是不是大于RecyclerView的高度 来确定底部遮挡,
想的太简单.png
但是在我写完debug时,拿到的距离无论是getTop还是getBottom都是固定的数,列表滑动再点击,拿到的数也不会改,纳尼?这是什么鬼,(后来发现其实是我们基类组件Adapter封装的有问题,正常情况下是可以拿到的)
getTop和getY拿到的值始终是固定的
看来这个方案是不行了,于是我把所有view获取坐标的方法都写上打印出来,看看能不能找出规律,果不其然。。。
重点看getLocalVisibleRect
先复习一下这几个View获取坐标的方法
View.getGlobalVisibleRect()
这个方法会返回一个View是否可见的boolean值,同时还会将该View的可见区域left,top,right,bottom值保存在一个rect对象中,以屏幕左上角为原点
View.getLocalVisibleRect()
这个方法和getGlobalVisibleRect有些类似,也可以拿到这个View在屏幕的可见区域的坐标,唯一的区别getLocalVisibleRect(rect)获得的rect坐标系的原点是View自己的左上角,而不是屏幕左上角。其也会调用getGlobalVisibleRect()方法
public final boolean getLocalVisibleRect(Rect r) {
final Point offset = mAttachInfo != null ? mAttachInfo.mPoint : new Point();
if (getGlobalVisibleRect(r, offset)) {
r.offset(-offset.x, -offset.y); // make r local
return true;
}
return false;
}
好了,我们先看正常图片未被遮挡时ImageView 的坐标依次是 Rect(int left, int top, int right, int bottom), 通过getLocalVisibleRect 得到
而ImageView的高度等于right坐标的绝对值,等于bottom坐标都是996(这个值好诡异)
正常情况的坐标.png
上面被遮挡时的坐标 【左 上 右 下】Rect(int left, int top, int right, int bottom)
上面被遮挡时的坐标.png
发现top的值变了,其余坐标还是原来样子,
下面被遮挡时的坐标 Rect(int left, int top, int right, int bottom)
下面被遮挡时的坐标.png
发现和正常情况相比 bottom的坐标变了,发现了规律
1,正常情况下left 和 top 坐标都是0,0 代表我们图片头部上半部分 是始终可见的
2,上面被遮挡时图片的top坐标会增加,其余坐标不会变
3,下面被遮挡时图片的bottom坐标会减少,其余坐标不会变
按照这个规律,那么可以得出下面代码
/***
* 解决列表图片被遮挡时 RecyclerView 滑动一段距离 显示出完整的预览图
* 根据getLocalVisibleRect 相对view自身坐标计算偏移量 只要top和left都是0 right等于view宽度 bottom等于view高度 即图片没有被隐藏
* 上面被隐藏 top肯定大于0 滑动偏移量即为-top
* 下面被隐藏 bottom肯定小于 view高度 偏移量即为view高度-bottom
*
* 参照 飞聊app 解决方案
*/
public WBPreviewBuilder setFixHideForRecyclerView(RecyclerView recyclerView, ImageView imageView) {
if (null != recyclerView && null != imageView) {
int height = imageView.getHeight();
Rect rect = new Rect();
imageView.getLocalVisibleRect(rect);
if (rect.top > 0 && rect.left == 0 && rect.bottom == height) {
//上面被遮挡
int offset = rect.top;
recyclerView.scrollBy(0, -offset);
} else if (rect.top == 0 && rect.left == 0 && rect.bottom < height) {
//下面被遮挡
int offset = height - rect.bottom;
recyclerView.scrollBy(0, offset);
}
}
return this;
}
1,即如果top坐标大于0,并且left坐标等于0,并且bottom坐标和图片高度相等,这时肯定是图片上半部分被遮挡了,我们需要让recyclerView滑动一段距离让view全部显示,这个偏移量也特别好计算 就是top的坐标,但是需要注意因为是图片上半部分被遮挡,我们滑动recyclerView需要是负的值,即
int offset = rect.top;
recyclerView.scrollBy(0, -offset);
2,如果left坐标和top坐标都是0,并且bottom坐标小于图片高度,那么这时图片肯定是下半部分被遮挡了,这时滑动的偏移量即
view的高度减去 bottom坐标
int offset = height - rect.bottom;
recyclerView.scrollBy(0, offset);
上面我是计算的ImageView 这个方法可以扩展一下,来计算View是否被遮挡,遮挡的话,计算遮挡距离,然后滑动RecycleView
很方便也很使用的计算方式.png
改进后的效果
改进后的效果.gif
OK,我在项目中试了一下,完美解决问题,希望有类似需求的小伙伴可以参考这种方法,解决你的问题,周末愉快~
网友评论