仿oppo手机浏览器首页的滑动布局

  • 原效果图
  • 我大概实现的样子
    • 这个其实主要是一些事件分发的一些处理

周末的午后,我悠然的躺着床上,甚是无聊,拿起我的oppo手机,打开浏览器准备输入我熟悉的xxx .com,
忽然我发现了一个比较好玩的滑动效果,滑动了几次决定我也要来写一个类似的,就这样,这个事情终结了我访问xxx的行为
话不多说直接上图

原效果图

我大概实现的样子


gif只能传小于5M的,所以会有掉帧卡顿的表现,其实一点也不卡顿!

这个其实主要是一些事件分发的一些处理

手指在布局上下滑动时,TabLayout和底下的ViewPager一个从上至下滑动,一个从上到下滑动,两个View的终点是Toolbar的bottom(同时到达),在TabLayout和ViewPager滑动时中间的View也稍许上下移动,这边我给到的移动范围是TabLayout的高度,外加一个透明度的变化
————————————————————————————————————————————————
这个效果一开始坑也比较多,本来是重写的ScrollView,ScrollView中包含了ViewPager,
ViewPager的item是Fragment,Fragment中是SwipeRefreshLayout+RecycleVIew。

这样嵌套的坑遇到了两个
第一:ViewPager的没有显示出来,应该是嵌套后高度出现了问题,我重写了它的onMeasure方法,遍历它的子view,重新测量它子view的高度,找到高度最高的一个算出heightMeasureSpec,再super回去,ViewPager是显示出来了,又出现了第二个问题;
第二:合并后的滑动问题,视图合并后,RecycleView一直流畅上滑,滑到底部后接着上滑ScrollView把事件拿去了,ScrollView在滑动了,因为我是通过setY的方式改变了布局的位置,所有ScrollView的高度是没变的,继续上滑会滑出空白,后来也想过处理RecycleView的onTouch,但感觉也会比较麻烦,就放弃了这种方案。

后面就直接继承了RelativeLayout,这样看起来就一个地方要修改了,因为是match_parent,ViewPager的高度是除了Toolbar高度+Content高度,但我setY的改变ViewPager位置的时候,尴尬的地方就出现了,ViewPager滑上来的时候底下是空白的,没有RecycleView的填充,因为RecycleView的滚动范围高度也是ViewPager的高度;
这个ViewPager最多可以移动到Toobar的底下,他的高度应该为原本高度+Content的高度!!这样问题就解决了,下面贴一贴主要代码

先贴下布局的代码

<?xml version="1.0" encoding="utf-8"?>
<com.ljp.newsdemo.widget.NewsScrollViewxmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"android:id="@+id/news_scrollview"android:layout_width="match_parent"android:layout_height="match_parent"><RelativeLayoutandroid:id="@+id/rl_content"android:layout_width="match_parent"android:layout_height="wrap_content"><android.support.v7.widget.Toolbarandroid:id="@+id/toolbar"android:layout_width="match_parent"android:layout_height="64dp"android:background="@color/colorAccent"app:title="我是标题"/><TextViewandroid:id="@+id/tv_content"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_below="@+id/toolbar"android:padding="10dp"android:text="@string/content"android:textColor="@color/colorPrimary"android:textSize="14sp"/></RelativeLayout><android.support.design.widget.TabLayoutandroid:id="@+id/tab_layout"android:layout_width="match_parent"android:layout_height="64dp"android:background="@color/colorPrimary"/><com.ljp.newsdemo.widget.NewsViewPagerandroid:id="@+id/view_pager"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_below="@+id/rl_content"android:background="#ffffff"/></com.ljp.newsdemo.widget.NewsScrollView>

NewsScrollView为RelativeLayout,拦截了整个view的触摸事件做了处理

 @Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) {//点击事件不拦截int evY = (int) ev.getY();switch (ev.getAction()) {case MotionEvent.ACTION_DOWN:downEvY = evY;return super.onInterceptTouchEvent(ev);case MotionEvent.ACTION_UP:Log.d(TAG, "onInterceptTouchEvent: evY - downEvY = " + (evY - downEvY));//小于等于5 就算是点击,正常的点击 down-up=0if (Math.abs(evY - downEvY) <= 5) {return super.onInterceptTouchEvent(ev);}break;default:break;}//其他情况看 是否已经合并了 如果已经合并了  不拦截;如果没合并,拦截掉if (isMerge) {return super.onInterceptTouchEvent(ev);} else {return true;}}

下面是滑动的处理,一开始写了很多代码,慢慢简化到了这一点。这块是主要逻辑代码了
逻辑是这样的,要有一个滑动距离范围,这个范围就是整个布局View除了Toolbar和底下的ViewPager的高度;
move的时候来计算移动的距离,通过回调把move的距离传出去,如果已经是合并状态的话,这边就不处理了,就交由下面的子view处理,可能就是刷新和点击事件了;
up和cancel的时候判断滑动的距离是否超过了范围的一半,如果超过了一半就做合并处理,反之就还原处理,up和cancel的事件都是回调出去做的动画效果处理;

 @Overridepublic boolean onTouchEvent(MotionEvent ev) {//手指距离view顶部的位置int evY = (int) ev.getY();switch (ev.getAction()) {case MotionEvent.ACTION_DOWN:downEvY = evY;return super.onTouchEvent(ev);case MotionEvent.ACTION_MOVE:if (isMerge) {return super.onTouchEvent(ev);}//最大可移动范围 为scrollview中去除recyclerView的距离//计算滚动距离mMoveY = downEvY - evY;if (mMoveY <= 0) {mMoveY = 0;} else if (mMoveY >= mMaxScrollViewRange) {mMoveY = mMaxScrollViewRange;}if (mOnScrollListener != null) {mOnScrollListener.onScrollChange(-mMoveY, mMaxScrollViewRange, false);}break;case MotionEvent.ACTION_UP:case MotionEvent.ACTION_CANCEL:if (mOnScrollListener != null) {//如果滑动的距离小于于最大距离的一半 让两个view做动画还原if (Math.abs(mMoveY) < mMaxScrollViewRange / 2) {//还原isMerge = false;mOnScrollListener.onScrollChange(0, mMaxScrollViewRange, true);} else {//合并isMerge = true;mOnScrollListener.onScrollChange(-mMaxScrollViewRange, mMaxScrollViewRange, true);}}break;default:break;}if (isMerge) {return super.onTouchEvent(ev);} else {return true;}}

重写的viewPager中的主要代码

 private int maxHeight = 0;@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {if (maxHeight != 0) {heightMeasureSpec = MeasureSpec.makeMeasureSpec(maxHeight, MeasureSpec.EXACTLY);}super.onMeasure(widthMeasureSpec, heightMeasureSpec);}public void setMaxHeight(int maxHeight) {this.maxHeight = maxHeight;requestLayout();}//外面调用mViewPager.setMaxHeight(mTvContent.getMeasuredHeight() + mViewPager.getMeasuredHeight());

MainActivity中的主要代码

private final int animDuration = 500;mViewPager.post(new Runnable() {@Overridepublic void run() {//设置viewpager的高度mViewPager.setMaxHeight(mTvContent.getMeasuredHeight() + mViewPager.getMeasuredHeight());//设置滑动的最大距离mNewScrollview.setMaxScrollViewRange(mTvContent.getMeasuredHeight());//初始化时把tablayout移除屏幕外mTabLayout.setTranslationY(-mTabLayout.getMeasuredHeight());initData();initListener();}});mNewScrollview.setOnScrollListener(new NewsScrollView.OnScrollListener() {@Overridepublic void onScrollChange(final float y, int maxRange, boolean isAnim) {//计算tabLayout要移动的距离float height = mTabLayout.getHeight();//计算倍率float power = height / maxRange;//计算tablayout的滚动距离float tabMoveY = -height + power * Math.abs(y);//透明度的计算0—1float alphaPower = 1f / maxRange;float alpha = 1 - (alphaPower * Math.abs(y));//mRlContent 也一起移动 最多移动tablayout的高度,计算如下float contentMoveY = -(height + tabMoveY);if (isAnim) {AnimListener animListener = new AnimListener();ViewCompat.animate(mViewPager).translationY(y).setDuration(animDuration).setListener(animListener).start();ViewCompat.animate(mTabLayout).translationY(tabMoveY).setDuration(animDuration).start();ViewCompat.animate(mRlContent).translationY(contentMoveY).setDuration(animDuration).start();if (y == 0) {//还原了ViewCompat.animate(mRlContent).alpha(1).setDuration(animDuration).start();} else {//合并了ViewCompat.animate(mRlContent).alpha(0).setDuration(animDuration).start();}} else {mViewPager.setTranslationY(y);mTabLayout.setTranslationY(tabMoveY);mRlContent.setTranslationY(contentMoveY);mRlContent.setAlpha(alpha);}}});//恢复layout的动画private void restoreLayoutAnim() {ViewCompat.animate(mViewPager).translationY(0).setDuration(animDuration).start();ViewCompat.animate(mTabLayout).translationY(-mTabLayout.getHeight()).setDuration(animDuration).start();ViewCompat.animate(mRlContent).alpha(1).setDuration(animDuration).start();ViewCompat.animate(mRlContent).translationY(0).setDuration(animDuration).start();//要让recyclerview第一个条目滚动置顶try {NewsFragment fragment = ((ClassifyVpAdapter) mViewPager.getAdapter()).getItem(mViewPager.getCurrentItem());fragment.setRvScrollTop();} catch (Exception e) {e.printStackTrace();Log.d(TAG, "restoreLayoutAnim: e=" + e.getMessage());}}@Overridepublic boolean onKeyDown(int keyCode, KeyEvent event) {if (keyCode == KeyEvent.KEYCODE_BACK) {if (mNewScrollview.getIsMerge()) {mNewScrollview.scrollTo(0, 0);//恢复原来的样子restoreLayoutAnim();mNewScrollview.setMergeState(false);return true;}}return super.onKeyDown(keyCode, event);}

写完了发现比较简单,但是感觉优化的地方还是有的,比如ViewPager的高度问题,在Activiy的init时候获取view宽高的问题,感觉用post的方式不太合理,大佬有建议希望指点一二!


github地址:https://github.com/15863459070/news_scrollview

仿oppo手机浏览器首页的滑动布局相关推荐

  1. 仿百度动态Android源码,Android 仿百度手机助手首页滑动效果

    今天看到百度手机助手首页上的滑动效果非常nice,主要功能归结为: 1.当手指上划时,顶部搜索栏随手指移动距离而缩小到隐藏,隐藏后内容还是可以继续移动 2.手指下滑时,当显示内容达到第一个时,顶部搜索 ...

  2. 仿360手机卫士首页[android平台]

    学习android几个月了,对android的UI开发部分一直不是很熟悉.于是最近拿360手机卫士首页来练手,做了个小demo,想与各位多多交流.效果图如下: (1)首页 (2)transformat ...

  3. OPPO手机浏览器获取cookie异常

    写h5项目要兼容一堆手机   其中大部分都没问题   OPPO今年是第二个问题了   以前是调支付键盘出来时 OPPO手机点不出来  也没法完成支付  查了半天原因 是他的安卓版本过低  不兼容键盘调 ...

  4. android像360一样跳转到系统菜单,Android开源库-仿360手机助手底部动画菜单布局

    效果对比:360手机助手效果演示:本库实现的效果(Icon来自360手机助手,侵删) 使用方法: xml布局文件 注:为了美观,讲每个Button的高度以及固定,设置wrap_content时候是最大 ...

  5. 基于HTML仿oppo手机商城电商项目的设计与实现6个页面

    常见网页设计作业题材有 个人. 美食. 公司. 学校. 旅游. 电商. 宠物. 电器. 茶叶. 家居. 酒店. 舞蹈. 动漫. 服装. 体育. 化妆品. 物流. 环保. 书籍. 婚纱. 游戏. 节日. ...

  6. web前端,仿oppo手机项目html+css

    源码下载: http://download.csdn.net/detail/zhaihaohao1/9101305 参考视频: http://www.sifangku.com/

  7. 仿QQ手机管家首页菜单写的一个开源组件MultiCardMenu。

    详情自https://github.com/wujingchao/MultiCardMenu MultiCardMenu 可以在android上打开和关闭动画的多功能菜单需要API级别> = 1 ...

  8. UC浏览器首页滑动动画实现

    UC浏览器首页滑动动画实现 我们先来看下UC浏览器首页的滑动动画和我最终实现的动画效果 使用方式 <cn.ittiger.ucpage.view.UCIndexViewxmlns:android ...

  9. 原来OPPO手机还能这样清理垃圾,怪不得别人都手机都能再用5年

    使用过安卓手机的朋友都知道,手机使用时间过长会缓存大量的垃圾,同时会对手机造成卡顿.手机卡顿的原因有很多中,不经常对手机进行清理也会造成一定的卡顿,下面就看看怎样彻底让手机告别卡顿吧! 缓存数据清理 ...

最新文章

  1. python 协程和异步的关系_python协程与异步协程
  2. 支付宝支付 第三集:搭建项目及测试(含代码)
  3. shell脚本判断进程是否运行
  4. 在 Mac 上多开微信,还能看到朋友撤回的信息:WeChatTweak
  5. java list取值_Java集合详解
  6. Netty实战 IM即时通讯系统(四)服务端启动流程
  7. 巧改注册表拥有超级cpu
  8. 贝叶斯网的R实现( Bayesian networks in R)bnlearn(3)
  9. labview 快捷键
  10. matlab的hilbert变换的实现
  11. 【MATLAB生信分析】MATLAB生物信息分析工具箱(二)
  12. 5.2 Photoshop复制图层的几种方式 [原创Ps教程]
  13. sublime text里面中文字体显示异常解决方案
  14. 大神教你用Python破解压缩文件zip密码
  15. 简单好用的服务器压力测试小工具 ab
  16. 大航海时代: 流行5掠夺篇
  17. 浮点数的表示方法是什么?
  18. 使用Laravel提交POST请求出现The page has expired due to inactivity错误
  19. 计算机哪个方向就业好,计算机就业的几个方向
  20. Oracle to_char()函数的用法

热门文章

  1. 整理了产品岗经常遇到的英文缩写专业名词解释,值得收藏!
  2. recovery升级遇到的问题及其流程简单分析
  3. 拉卡拉支付明确自身定位 推动市场变革
  4. java 建立索引_java中怎么创建索引
  5. 小程序加入人脸识别_小程序“知学谷”暖心上线,赶快加入我们吧!!!
  6. python django校园二手商城
  7. 三星在世界移动大会上宣布Galaxy S5智能手机
  8. 新东方人工智能中台建设和AI部门管理经验分享
  9. 数据库查询关键字显示所有结果
  10. 火山引擎A/B测试平台设计思路与技术实现