这是个看脸的时代,如果你没有个Beautiful Face(B脸),都不好意思写博客。继上一次我通宵加班(钥匙锁家里了,门也砸了)给大家介绍了UC浏览器基本布局的实现(轻点这里),帅气的我又来水文了。今天我们将实现UC浏览器主页的交互,No picture you say a ...

相似度是不是很高O(∩_∩)O? 如果你喜欢或者想和我一起完成这个项目,请github一波(欢迎star):

https://github.com/zibuyuqing/UCBrowser

由于页面管理(堆叠视图)实现起来很复杂,我放到下一篇水文中。 这篇文章将按照以下顺序讲故事:

1.UCRootView简介(照顾没看过第一篇的同学:轻点这里)

2.自定义基本父布局(BaseLayout)

3.网页导航栏(HeadLayout)视图更新

4.贝塞尔背景(BezierLayout)实现

5.底部菜单栏(Bottombar)视图更新

6.其他view简析

下面开始表演

UCRootView简介

UCRootView是这些可滑动布局(除了堆叠视图)的Parent,里面重写了onInterceptTouchEvent和onTouchEvent方法,定义了通用滑动接口:

    public interface ScrollStateListener{void onStartScroll();void onScroll(float rate);void onEndScroll();void onTouch(float x,float y);//手指位置}
复制代码

滑动状态通过滑动距离与目标距离之间的比值rate来表示。在这个布局下,所有子布局的位置、大小,透明度等属性通过rate来控制。今天重点不是讲这个,如果想具体了解,请点这里。

自定义基本父布局(BaseLayout)

从上图可以看出,BaseLayout是UC浏览器主页面所有View组件的父类,里面定义了基本的移位(translate,目前只针对Y方向)、缩放(scale)、渐变(alpha)等方法,所有的view的属性变化都是基于Rootview传过来的rate计算得到,子view通过扩展父类实现不同场景的界面切换效果。

移位

控制开关:mTranslateEnable 方向:Y 初始化:

    /**** @param from 起始位置* @param to 最终位置*/public void initTranslationY(int from, int to){mFromPosition = from;mToPosition = to;setTranslationY(from);mDistance = from - to;}
复制代码

计算TransY:

    /*** * @param rate 滑动的相对比率* @return*/private float calculateTransY(float rate){Log.i(TAG,"rate :: =;" + rate);return mFromPosition + mDistance * rate;}
复制代码

调用:在 onScroll(rate)方法中调用 setTranslationY(calculateTransY(rate));

缩放

控制开关:mScaleEnable 方向:X,Y 初始化:

    public void initScale(float startScale,float endScale){mStartScale = startScale;mEndScale = endScale;setScaleX(startScale);setScaleY(startScale);mScale = endScale - startScale;}
复制代码

计算Scale:

    private float calculateScale(float rate){return mStartScale + mScale * rate;}
复制代码

调用:

    private void setScaleXY(float rate){setScaleX(calculateScale(rate));setScaleY(calculateScale(rate));}
复制代码

渐变同上,很简单。这样就把最基本的父布局写完了O(∩_∩)O哈哈~,然后我们就要写各个部件的更新啦。

网页导航栏(HeadLayout)视图更新

这张图展示了UC浏览器HeadLayout布局结构,其中的BezierLayout包裹了天气栏、搜索栏、导航栏,其下方是网站列表,“刷新进入UC头条”提示默认不可见。现在打开手机UC浏览器,一起向上滑,预备,走!我们看到,当向上滑时,整个layout逐渐变小,并且小幅度向上移动,同时变黑,怎么实现这个效果呢?我们来分解一下:

变小 —— scale,上移 —— transY,变黑 —— foreground(黑色)改变Alpha渐显。

初始化

        mUCHeadLayout.setTranslateEnable(true);   // 可移动mUCHeadLayout.initTranslationY(0, -100);   // 小幅移动
复制代码

开始移动

@Overridepublic void onStartScroll() {// mUCCoverLayout 为下拉时所看到的提示“上滑进入UC头条”的布局mUCCoverLayout.setVisibility(VISIBLE);mUCCoverLayout.setAlpha(0.f);super.onStartScroll();}复制代码

更新视图

@Overridepublic void onScroll(float rate) {if(rate > 0) {// 下拉// 显示提示语并下移mCoverTip.setTranslationY(100 * Math.abs(rate));// 提示布局逐渐显现mUCCoverLayout.setAlpha(rate * 1.5f);} else {// 上滑// 隐藏提示布局mUCCoverLayout.setVisibility(GONE);// foreground 逐渐显现,布局变黑mForeground.setAlpha((int) (ALPHA_255 * Math.abs(rate)));float adjustRate = 1.0f + rate * 0.05f;// 布局内容逐渐变小mCategoryContain.setScaleX(adjustRate);mCategoryContain.setScaleY(adjustRate);mWebsiteContain.setScaleX(adjustRate);mWebsiteContain.setScaleY(adjustRate);}super.onScroll(rate);}
复制代码

正如之前所说,整个过程受相对滑动比率rate控制,这样就实现了我们的HeadLayout界面更新,接下来我们看其下拉时背景效果实现。

贝塞尔背景(BezierLayout)实现

关于贝塞尔的相关知识感兴趣的可以百度一波哈。 我想告诉你ScrollStateListener接口中的onTouch(float x, float y)方法就是为了这货添加的,因为我们在开始构建贝塞尔曲线的时候要有控制点,总不能写死吧。当用户向下滑动时,我们动态的更新布局大小(Y方向),并把我们的控制点始终放在底部,贝塞尔曲线的起始点和终止点高度(Y)更新慢于控制点,就可以达到效果了。

设置画笔

        mPaint = new Paint();mPaint.setColor(mThemeColor);mPaint.setAntiAlias(true); // 抗锯齿mPaint.setStyle(Paint.Style.FILL); // 填充
复制代码

初始化位置

mEdgeHeight = mHeight; // mEdgeHeight 为左右两个边的高度
mControlPoint = new Point(0,mHeight); // 初始位置为整个视图的底部,这样一开始画出来是条直线
复制代码

绘制贝塞尔区域

    @Overrideprotected void dispatchDraw(Canvas canvas) {drawBg(canvas);super.dispatchDraw(canvas);}private void drawBg(Canvas canvas) {mPath.reset();// 顶部开始mPath.moveTo(0,0);mPath.lineTo(0,mEdgeHeight);// 贝塞尔曲线mPath.quadTo(mControlPoint.x,mControlPoint.y,mScreenWidth,mEdgeHeight);mPath.lineTo(mScreenWidth,0);// 闭合mPath.lineTo(0,0);canvas.drawPath(mPath,mPaint);}
复制代码

这里用到的drawPath方法,大家可以详细了解一下Path的用法,很多炫酷效果是用这货弄的。

当手指下滑时,我们开始变弯了。

开始滑动并设置控制点

    @Overridepublic void onStartScroll() {mStartScroll = true;super.onStartScroll();}public void touch(float x, float y) {mControlPoint.set((int) x, mControlPoint.y);invalidate();}
复制代码

更新视图

@Overridepublic void onScroll(float rate) {if(!mStartScroll){return;}// 获取 LayoutParams 根据滑动状态动态更新视图大小if(mLayoutParams == null){mLayoutParams = getLayoutParams();}if(rate >= 0) {// 下拉// FINAL_DISTANCE 为最大能滑动的距离int dis = (int) (FINAL_DISTANCE * rate);// 左右边界更新速度是控制点的0.5倍mEdgeHeight = (int) (mHeight + dis * 0.5f);//控制点更新mControlPoint.set(mControlPoint.x, mHeight + dis);// 视图内容改变大小,位置和透明度mContain.setScaleX(1.0f - rate * 0.2f);mContain.setScaleY(1.0f - rate * 0.2f);mContain.setTranslationY(dis * 0.5f);mContain.setAlpha(1.0f - rate * 1.5f);} else {// 上滑mControlPoint.set(0,mHeight);}// 改变视图大小mLayoutParams.height = mControlPoint.y;setLayoutParams(mLayoutParams);requestLayout();super.onScroll(rate);}复制代码

结束

    @Overridepublic void onEndScroll() {mStartScroll = false;super.onEndScroll();}
复制代码

上面注释的很详细,我们来看一下效果,不虚,不虚 O(∩_∩)O

底部菜单栏(Bottombar)视图更新

底部菜单栏视图更新原理和上面一样,只不过要根据menu位置计算更新速率,还有横向滑动。效果可以看前面的高清无码动图,这里我直接贴代码了。

计算中间Menu横向移动TransX

    private float calculateMenuBtnTransX(float rate){float dis = mScreenWidth / 5;return - dis * rate;}
复制代码

计算新闻Menu竖向移动TransY

上滑时我们会看到新闻按钮(头条、视频、订阅)会根据不同速率依次滑动到指定位置,计算方法如下:

    private float calculateNewsBtnTransY(int finalY, float rate, float velocity){// velocity 是调整速率float adjustRate = rate * velocity;rate = adjustRate < -1.0f ? -1.0f : adjustRate;return 0 + finalY * rate;}
复制代码

计算Menu透明度

    private float calculateBtnAlpha(float rate){return 1.0f + rate;}
复制代码

更新视图

    @Overridepublic void onScroll(float rate) {Log.(TAG,"onScroll :: rate =:" + rate);if(rate > 0){return;}//第1,2,4个按钮渐隐ivForward.setAlpha(calculateBtnAlpha(rate));ivBack.setAlpha(calculateBtnAlpha(rate));flWindowNum.setAlpha(calculateBtnAlpha(rate));// 第三个按钮移动到第四个位置ivMenu.setTranslationX(calculateMenuBtnTransX(rate));// 新闻按钮依次上升出现tvSubscribe.setTranslationY(calculateNewsBtnTransY(mHalfHeight,rate,1.0f));tvVideo.setTranslationY(calculateNewsBtnTransY(mHalfHeight,rate,1.5f));tvHeadline.setTranslationY(calculateNewsBtnTransY(mHalfHeight ,rate,2.0f));}
复制代码

其他view简析

除了以上view组件,我们还要顶部搜索条(searchbar),新闻分类标签(newsTab)的更新没说呢,别急哈,很简单,用BaseLayout做这两个view组件的父布局,然后init一波就可以了,以searchbar为例

写布局

<?xml version="1.0" encoding="utf-8"?>
<com.zibuyuqing.ucbrowser.base.BaseLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:background="@color/themeBlue"android:padding="8dp"android:layout_height="@dimen/dimen_48dp"><ImageViewandroid:layout_gravity="center"android:src="@drawable/ic_searchbar_book"style="@style/SearchBoxImageIconStyle"/><TextViewandroid:gravity="center"android:textSize="13dp"android:textColor="@color/windowBg"android:text="UC头条"android:layout_width="wrap_content"android:layout_height="match_parent" /><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:background="@drawable/search_box_bg"android:padding="6dp"android:layout_marginLeft="8dp"android:layout_height="32dp"><ImageViewandroid:layout_gravity="center_vertical"android:layout_width="14dp"android:layout_height="14dp"android:layout_alignParentStart="true"android:layout_marginLeft="8dp"android:src ="@drawable/ic_search" /><TextViewandroid:textColor="@color/windowBg"android:gravity="center"android:layout_marginLeft="8dp"android:textSize="13dp"android:text="搜索你感兴趣的内容"android:layout_width="wrap_content"android:layout_height="match_parent" /></LinearLayout>
</com.zibuyuqing.ucbrowser.base.BaseLayout>
复制代码

初始化

       // 可移动mTopSearchBar.setTranslateEnable(true);// 这方法是在view layout 之后获取大小,避免获取的大小全是 0mTopSearchBar.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {@Overridepublic void onGlobalLayout() {mTopSearchBar.getViewTreeObserver().removeOnGlobalLayoutListener(this);// 初始化移动参数mTopSearchBar.initTranslationY(-mTopSearchBar.getHeight(), 0);}});
复制代码

大功告成,是不是很简单

说点其他的

文章写得很详细,能看到这个地方也算难为你了,给你点赞(也给我点个吧,顺手牵个赞O(∩_∩)O),如果你喜欢我的博客,请关注一下,我会不断将有意思的事情写出来,你也可以给我发一些需求,我来帮你实现或者给些建议,大家一起学习一起进步。 项目地址:github.com/zibuyuqing/…,欢迎踩踏。

下篇文章我们将探讨堆叠视图的实现,敬请期待

转载请注明:juejin.im/post/5a291a…

上一篇:尝试写个UC浏览器(布局篇)

转载于:https://juejin.im/post/5a291aeb51882533d022f6ba

尝试写个UC浏览器(主页交互篇)相关推荐

  1. 尝试写个UC浏览器(布局篇)

    个人认为UC浏览器的主界面交互逻辑还是挺好的,界面过度流畅,动画具有引导性,美观大方.我们现在尝试实现它,先来一张美图: 我按照从入门到跑路的过程分以下步骤给你们讲故事: 静态布局搭建 -->自 ...

  2. 尝试写个UC浏览器(堆叠视图A)

    背景:快过年了,问题那个多呀,最近手都敲出老茧了,上班打个卡都要识别几分钟,不知道身为程序猿的你是不是有同样的感受.唉,不说了,老子名下还有200多个bug... 既然前面已经吹了两次逼( 布局篇 和 ...

  3. 自定义Behavior的艺术探索-仿UC浏览器主页

    出处:http://www.jianshu.com/p/f7989a2a3ec2 前言&效果预览 最近几个周末基本在研究CoordinatorLayout控件和自定义Behavior当中,这期 ...

  4. Behavior实现UC浏览器首页动画效果

    老规矩,还是先上效果图 github地址 前面我也写过一篇关于UC浏览器首页滑动动画效果的文章UC浏览器首页滑动动画实现,只不过这篇文章是通过自定义View的方式实现这个滑动效果.最近在看Behavi ...

  5. 手机uc新窗口打开的html标签,在电脑UC浏览器的新窗口页中如何打开书签

    在电脑UC浏览器的新窗口页中如何打开书签 UC浏览器是一个很不错的查询资料的软件,我们可以在UC浏览器的新标签页中打开书签,那么如何打开呢?小编就来为大家介绍一下吧. 具体如下: 1. 第一步,双击并 ...

  6. 极简文艺的浏览器主页推荐,无广告,文艺又清新的网址导航

    home主页是一款特别文艺极简的浏览器网址导航主页. 看图就知道了,非常简单,文艺,每天都会获取ONE一个的精美图文作为背景和每日一句,每天给你不一样的惊喜. 而且home主打的是自定义DIY,打造属 ...

  7. uc打开html文件是空的,UC浏览器中打开不出现主页的解决方法

    小伙伴们的uc浏览器打开后怎么不出现主页?现在使用UC浏览器的人很多,但是不管是手机版还是电脑版都有用户在反映,uc浏览器为什么打开后不出现主页? 今天,学习啦小编就教大家在UC浏览器中打开不出现主页 ...

  8. 一个EXE引发的危机 — 浏览器劫持实战篇

    一个EXE引发的危机 --浏览器劫持实战篇 作者:小金 转载请注明出处和作者 一. 一个EXE引发的危机 网络程序员小李最近有点忙,公司要做的网页工程项目已经快到尾期了,可是开发小组的进度仍然迟迟跟不 ...

  9. 2345浏览器网址_2345网址导航回应“浏览器主页劫持”丨开发者日报

    1.2345网址导航回应"浏览器主页劫持" "浏览器主页被2345劫持怎么解决?""如何解决浏览器被2345主页劫持的问题?"--在网民吐槽 ...

最新文章

  1. Redis命令——Keys相关
  2. MFC DLL对话框调用
  3. mysql 使用不同引擎_mysql 不同引擎的比较
  4. C++primer第十章 泛型算法 10.1 概述 10.2 初识泛型算法
  5. 云米冰箱能控制扫地机器人_实现家电互联,从一台云米冰箱开始
  6. 天气预报如何得获得?
  7. 【IDEA】idea中Git的使用小技巧
  8. 开关电源测试系统用哪个软件,开关电源测试系统
  9. 汇编:1位16进制数到ASCII码转换
  10. 计算机组成原理第五版第四章课后答案,计算机组成原理第4章习题参考答案
  11. 高一计算机基础知识ppt课件,高一信息技术课件
  12. JProfiler ERROR: Invalid license key. Aborting.
  13. 厦大计算机考研学硕,2021厦大计算机考研招生、复试、书目专业大解析!
  14. 树莓派配置文件config.txt详细介绍
  15. 产品研究:WPS如何在Office的“围剿”下突围
  16. SA(需求分析师)笔试题目整理
  17. winds主机部署zabbix_agent
  18. html鼠标滑过导航条展开导航条,jquery css实现鼠标滑过导航菜单栏动画效果
  19. 成功率100%的通达信指标公式,你敢相信吗?
  20. AdaBoost -> GBDT -> XGBOOST 的区别

热门文章

  1. CSDN 个性化推荐的数据治理
  2. 求无序数组中第k大的数
  3. 微信小程序背景渐变效果
  4. 高通沈劲:无人便利店的价值还需要进一步的市场检验
  5. 【云原生 | 从零开始学Docker】六、如何写出自己的镜像——Docker file
  6. 经典仿句100例_精美仿句100例
  7. OpenGL-着色器
  8. unity 表面着色器、顶点、片元着色器
  9. 中小型企业为什么要开发微信小程序?
  10. docker入门(一)win10安装与使用