Android仿饿了么详情页可以跟随手指移动 viewpager变详情页

源码地址[https://github.com/githubwing/ZoomHeader]


不是共享元素!不是共享元素!不是共享元素!重要的话说三遍。共享元素不可以随手指移动的。
先吐槽下饿了么。不提示左右可以滑动。我还是无意中发现的。不提示我怎么知道可以滑动??
这是一个模仿饿了么详情页的例子。并非一个库,并非拿来就可以用,主要讲解思路以及如何实现,可能有一些细节没有处理。 讲述了如何实现。具体祥见源码。
他是一个Activity还是两个?
相信你肯定有这样的疑问,答案是一个。所以这不是用共享元素实现的,使用共享元素会导致图片无法跟随手指移动。
你看到的中间imageview是viewpager。在Viewpager上面是一个透明的View。当然,这个Activity的背景也是透明的。
实现思路
我使用CoordinatorLayout+Behavior实现的。说实话,Behavior真心强大。。
viewpager+头部
整个实现的思路是这样的。整体布局从上到下依次是:
透明View
viewpager
RecyclerView

其中透明View和Viewpager 合并成一个自定义的Header。当这个Header上移的时候,图片放大,并且RecyclerView联动上衣,从透明转向并且不透明。
所以首先要定制一个透明的可移动的HeaderView。
在onTouchEvent处理一下手势。。

@Override public boolean onTouchEvent(MotionEvent ev) { 
switch (ev.getAction()) { 
case MotionEvent.ACTION_DOWN:
 return true; 
case MotionEvent.ACTION_MOVE: 
if(上下移动到阀值){            展开为详情()      
}else if(上下滑动到阀值,恢复viewpager){       
}else if(下滑,则关闭Activity)

将header分为三种状态:
上移。则展开为详情页。
下移,则恢复为viewpager。
再下移,则finish Activity。

在上移的过程中,遇到了一点小挑战,这里分享下:
上移的过程中,图片需要放大。但是在做的过程中,不能使用LayoutParams实现。这里就关系到一些动画的小细节。
动画使用LayoutParams实现是一个禁忌。他会导致不停requestLayout,从而影响UI性能。
所以这里我的一个解法就是,我放大图片,不是真正的改变ImageView大小,而是去Scale图片。即使看起来变大了,他的View真正大小也不会变。
所以,有一句话叫做真亦是假、假亦是真 真真假假,你又何必当真呢?动画效果只要遵循这句话,基本上都是可以实现的。你所看到的效果都是假的。都是障眼法。View变大不是真正的变大。View悬浮不是真正的悬浮(有可能是显隐)。就像变魔术一样。。其实很简单。
接下来又遇到问题了。图片放大了,文字如何对齐? 文字的位置当然也不能真正改变。所以这里使用TranslationX实现。在图片放大的过程中,使用scale的系数,与两个端点值进行一个线性变化计算。主要文字对齐代码如下:

bottom.offsetLeftAndRight( (int) (target.getWidth() / 2 - target.getWidth() * (1 + progress) / 2 + MarginConfig.MARGIN_LEFT_RIGHT - bottom.getX()));

第二个点。就是在图片放大过程中,底部文字和按钮左右padding不能变。这也是我没有封装成一个拿来就用的View的原因(其实还是水平不够)。因为这些空间需要全部按照上方的方法进行动态计算。。所以也是比较坑爹的。。
ViewPager
拿了网上一个画廊的效果。直接

setPageTransformer(true, new ZoomOutPageTransformer());

这里注意,需要改变一下view的绘制顺序,保证当前view是最后绘制处于最上层

/改变系统绘制顺序
 @Override protected int getChildDrawingOrder(int childCount, int i) { 
int position = getCurrentItem(); 
if(position<0){
 return i; 
}else{ if(i == childCount - 1){//这是最后一个需要刷新的item 
if(position>i){ 
position=i; } 
return position; } 
if(i == position){//这是原本要在最后一个刷新的item return childCount - 1; } } 
return i; }}

RecyclerView
RecyclerView最开始是完全透明的。并且跟随HeaderView上移而上移,在上移的过程中渐渐显示出来。 需要监听RecyclerView滚动,当RecyclerView滚动到顶部的时候。告知Header,该恢复最初原样了。

@Override 
public boolean onNestedFling(CoordinatorLayout coordinatorLayout, View child, View target, float velocityX, float velocityY, boolean consumed) { 
//向下Fling并且到顶部 if (velocityY < 0 && ((RecyclerView) target).getChildAt(0).getY() == 0) { mDependency.restore(mDependency.getY()); } 
return super.onNestedFling(coordinatorLayout, child, target, velocityX, velocityY, consumed); } 
@Override 
public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dx, int dy, int[] consumed) { 
//如果在顶部 if (((RecyclerView) target).getChildAt(0).getY() == 0) { //向下滑动 
if (dy < 0) { mDependency.setY(mDependency.getY() - dy); //小于阀值 
if (mDependency.getY() < 500) { mDependency.restore(mDependency.getY()); } } } 
super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed); }}

Behavior
让header和RecyclerView关联起来的就是Behavior了。Behavior之前写过几篇介绍过了,这里就不再啰嗦。
denpendcy为HeaderView。并且监听RecyclerView的滑动。
具体的细节还是看源码吧~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 174,787评论 25 709
  • 内容抽屉菜单ListViewWebViewSwitchButton按钮点赞按钮进度条TabLayout图标下拉刷新...
    皇小弟阅读 46,961评论 22 665
  • “黑魔大泽这次血祭失败,灰溜溜离去,痛快痛快啊。”淳御帝君也哈哈笑道。 一旁的贪鹏帝君却笑眯眯的:“应山雪鹰之前一...
    im喵小姐阅读 442评论 0 0
  • 赶路再次路过此地,有偶遇,却缺憾。
    一念归远阅读 138评论 0 0
  • 新茶清挈,望枫林晚,烟雨方歇。大河远山无续,才抬望眼、春风催发。杨柳新折残月,正清明时节。尔悠悠、十年沧海,多少新...
    枫林路植物人阅读 286评论 0 1