原标题:仿新版微信的小程序下拉栏

本项目会对金融交易软件中存在的各种View进行模仿绘制,提供详细的实现思路,收集整理相关算法、文档以及专业资料。

https://github.com/scsfwgy/FinancialCustomerView

本文作者

作者:大头呆

链接:

https://www.jianshu.com/p/fe6efe2f5978

本文由作者授权发布。

1

概述

上周微信更新到了6.6.1版本,加入了微信小游戏。朋友圈都在玩跳一跳。而且现在微信把最近用过的小程序放到了首页顶部,轻轻下拉就可以快速访问了。可以看下效果,如果还没升级的朋友可要抓紧了。

自己作为一个安卓程序员,虽然不会写小程序,但也要紧跟热潮(蹭热点)啊。于是乎就干脆仿写下这个下拉控件吧。第七宇宙惯例,先上效果图:

上图的主界面是我上一篇文章《撸一款全手势操作浏览器》https://juejin.im/post/5a43177f5188252a3d384579写的demo。写完这个控件,发现正好可以作为它的下拉菜单栏,就直接用上了。好了,废话不多说,开始介绍下实现流程。

2

流程分析

整个下拉过程分为四个阶段:

阶段一:出现一个圆点,半径随下拉距离变大而变大。位置始终在中间

阶段二:圆点两边出现两个圆点,半径较小。距离随下拉距离变大而变大,中间圆点半径不断变小。位置始终在中间

阶段三:从顶部出现内容列表,位置随手指下拉快速往下移动,同时三个圆点位置不断下移并逐渐消失

阶段四:只剩下内容列表,手指可以继续往下滑动,但阻尼变大。内容列表始终在中间。

上滑分两种情况:

如果开始上滑的时候内容列表已展开,则平移上滑(圆点不会出现)

反之,就是下拉的逆过程了(圆点会出现)。

3

具体实现

熟悉下拉刷新控件的同学可以看出来,上述滑动的流程和下拉刷新很相似,所以为了避免重复造轮子(偷懒),我将下拉刷新控件作了改动,所以主要的实现还是在头部那块。

初始布局位置

将头部放到屏幕外层的方法有很多。我采用了设置负数padding的方法。外层布局继承了LinearLayout,方向竖直。然后为其设置padding:

headerHeight = ( null!= mHeaderLayout) ? mHeaderLayout.getMeasuredHeight() : 0;

intpLeft = getPaddingLeft();

intpTop = -headerHeight;

intpRight = getPaddingRight();

intpBottom = -footerHeight;

setPadding(pLeft, pTop, pRight, pBottom);

paddingTop的值等于负的HeaderLayout的高度,这样正好将头部布局顶到屏幕外面。

处理触摸事件

这块主要内容就是重写写 boolean onInterceptTouchEvent(MotionEvent event)和boolean onTouchEvent(MotionEvent ev)来拦截和处理滑动事件。

@Override

publicfinalbooleanonInterceptTouchEvent(MotionEvent event){

finalintaction = event.getAction();

//不拦截

if(action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {

mIsHandledTouchEvent = false;

returnfalse;

}

//如果不是重新开始触摸且已经判断需要拦截,就一直拦截整套触摸事件

if(action != MotionEvent.ACTION_DOWN && mIsHandledTouchEvent) {

returntrue;

}

switch(action) {

caseMotionEvent.ACTION_DOWN:

mLastMotionY = event.getY();

mIsHandledTouchEvent = false;

break;

caseMotionEvent.ACTION_MOVE:

finalfloatdeltaY = event.getY() - mLastMotionY;

finalfloatabsDiff = Math.abs(deltaY);

// 位移差大于mTouchSlop(TouchSlop是系统所能识别出的被认为是滑动的最小距离)

//这是为了防止快速拖动引发刷新

if((absDiff > mTouchSlop)) {

mLastMotionY = event.getY();

// 第一个显示出来,Header已经显示或拉下

if(isPullRefreshEnabled() && isReadyForPullDown()) {

// 1,Math.abs(getScrollY()) > 0:表示当前滑动的偏移量的绝对值大于0,表示当前HeaderView滑出来了或完全

// 不可见,存在这样一种case,当正在刷新时并且RefreshableView已经滑到顶部,向上滑动,那么我们期望的结果是

// 依然能向上滑动,直到HeaderView完全不可见

// 2,deltaY > 0.5f:表示下拉的值大于0.5f

mIsHandledTouchEvent = (Math.abs(getScrollYValue()) > 0|| deltaY > 0.5f);

}

}

break;

default:

break;

}

returnmIsHandledTouchEvent; //true:拦截,false不拦截

}

如果拦截了,我们处理滑动.其中offsetRadio是滑动阻尼值。

@Override

publicfinalbooleanonTouchEvent(MotionEvent ev){

booleanhandled = false;

switch(ev.getAction()) {

caseMotionEvent.ACTION_DOWN:

mLastMotionY = ev.getY();

mIsHandledTouchEvent = false;

break;

caseMotionEvent.ACTION_MOVE:

finalfloatdeltaY = ev.getY() - mLastMotionY;

mLastMotionY = ev.getY();

if(isPullRefreshEnabled() && isReadyForPullDown()) {

pullHeaderLayout(deltaY / offsetRadio);

handled = true;

} else{

mIsHandledTouchEvent = false;

}

break;

caseMotionEvent.ACTION_CANCEL:

caseMotionEvent.ACTION_UP:

if(mIsHandledTouchEvent) {

mIsHandledTouchEvent = false;

// 当第一个显示出来时

if(isReadyForPullDown()) {

// 调用刷新

if(mPullRefreshEnabled && (mPullDownState == State.RELEASE_TO_REFRESH)) {

startRefreshing();

handled = true;

}

resetHeaderLayout();

}

}

break;

default:

break;

}

returnhandled;

}

最终我们会通过 pullHeaderLayout()调用View的scrollBy(x, y)方法将布局整体滚动:

protectedvoidpullHeaderLayout(floatdelta){

// 向上滑动,并且当前scrollY为0时,不滑动

intoldScrollY = getScrollYValue();

if(delta < 0&& (oldScrollY - delta) >= 0) {

setScrollTo( 0, 0);

if( null!= mHeaderLayout && 0!= mHeaderHeight) {

mHeaderLayout.setState(State.RESET);

mHeaderLayout.onPull( 0);

}

return;

}

//滑动布局

setScrollBy( 0, -( int) delta); //调用View的 scrollBy(x, y)

intscrollY = Math.abs(getScrollYValue());

if( null!= mHeaderLayout && 0!= mHeaderHeight) {

if(scrollY >= headerListHeight) {

mHeaderLayout.setState(State.arrivedListHeight);

setOffsetRadio( 2.0f); //内容列表完全展开后阻尼值变大

} else{

setOffsetRadio( 1.0f);

}

mHeaderLayout.onPull(scrollY); //将滑动距离实时传给头部,以实现出我们需要的动画

}

}

遇到的一个问题

我在上面这样写好之后,跑了一遍,发现 onInterceptTouchEvent只执行了ACTION_DOWN,后续的ACTION_MOVE和ACTION_UP事件不会执行,也就无法拦截和进行滑动了。百度下原来有这么一个规则:

onInterceptTouchEvent返回false表示将down事件交由子View来处理;若某一层子View的onTouchEvent返回了true,后续的move、up等事件都将先传递到ViewGroup的onInterceptTouchEvent的方法,并继续层层传递下去,交由子View处理;若子View的onTouchEvent都返回了false,则down事件将交由该ViewGroup的onTouchEvent来处理;如果ViewGroup的onTouchEvent返回true,后续事件不再经过该ViewGroup的onInterceptTouchEvent方法,直接传递给onTouchEvent方法处理。

因为目前的子View(中间内容部分)是RelativeLayout,它的onTouchEvent默认返回了false(ListView等其他可滑动的控件不会有这个问题)。解决办法是设置android:clickable="true"。

头部的实现

上面我说过滑动有四个阶段,只要将滑动距离传递给自定义头部,根据距离判断状态,实时改变内容列表的TranslationY,圆点的TranslationY和Alpha就可以了。实现起来虽然内容比较多,但都比较简单,详细的代码就不贴了,大家感兴趣的可以去看源码。至于圆点动画,也是一个自定义View,外层只要根据滑动距离换算下动画的百分比传进去,在里面画出需要的图形就行了,判断当百分比到0.5的时候画三个圆 :

publicclassExpendPointextendsView{

floatpercent;

floatmaxRadius = 15;

floatmaxDist = 60;

Paint mPaint;

publicExpendPoint(Context context, @Nullable AttributeSet attrs){

super(context, attrs);

mPaint = newPaint();

mPaint.setAntiAlias( true);

mPaint.setColor(Color.GRAY);

}

publicvoidsetPercent(floatpercent){

this.percent = percent;

invalidate();

}

@Override

protectedvoidonDraw(Canvas canvas){

super.onDraw(canvas);

floatcenterX = getWidth() / 2;

floatcenterY = getHeight() / 2;

if(percent <= 0.5f) {只画一个圆

mPaint.setAlpha( 255);

floatradius = percent * 2* maxRadius;

canvas.drawCircle(centerX, centerY, radius, mPaint);

} else{ //画三个个圆

floatafterPercent = (percent - 0.5f) / 0.5f;

floatradius = maxRadius - maxRadius / 2* afterPercent;

canvas.drawCircle(centerX, centerY, radius, mPaint);

canvas.drawCircle(centerX - afterPercent * maxDist, centerY, maxRadius / 2, mPaint);

canvas.drawCircle(centerX + afterPercent * maxDist, centerY, maxRadius / 2, mPaint);

}

}

}

拓展:上拉栏

有了上面的基础,实现上拉加载栏也是很简单的,逻辑基本相同,只是方向变了而已。我们来看下最终效果:

最后贴下本项目github地址:

https://github.com/renjianan/SimpleBrowser

最后推荐一下我做的网站,玩Android: wanandroid.com,包含详尽的知识体系、好用的工具,还有本公众号文章合集,欢迎体验和收藏!返回搜狐,查看更多

责任编辑:

android微信下拉出现小程序,仿新版微信的小程序下拉栏相关推荐

  1. android微信下拉出现小程序,Android 仿新版微信的小程序下拉栏

    Android 仿新版微信的小程序下拉栏 上周微信更新到了 6.6.1 版本,加入了微信小游戏.朋友圈都在玩跳一跳.而且现在微信把最近用过的小程序放到了首页顶部,轻轻下拉就可以快速访问了.可以看下效果 ...

  2. iOS高仿新版微信扫一扫源码

    iOS版本高仿新版微信V8.0.6扫一扫.支持全屏扫码,支持识别多个二维码,支持选择指定二维码,支持从相册选取二维码,支持光线暗打开手电筒.无需多余的文件,一个Controller即可搞定,可继承,可 ...

  3. Android仿新版微信的小程序下拉栏

    作者:大头呆 链接:https://juejin.im/post/5a4c90c15188257c4d1b8d0c 本文经作者授权推送. 上周微信更新到了6.6.1版本,加入了微信小游戏.朋友圈都在玩 ...

  4. android手机新版微信,安卓机怎么升级为最新版微信8.0?安卓手机如何才能体验微信8.0?...

    安卓微信怎么升级 微信发布了最新版微信8.0.与以往不同的是,作为一款已风靡十年的社交产品,微信此次版本更新带来许多全新玩法和小创意. 目前苹果手机用户可以点击"关于微信"进行自动 ...

  5. 小肚皮最新版本_小肚皮最新版apk下载-小肚皮最新版app安卓版下载 5.20.2-老铁下载网...

    小肚皮是一款年轻人必备的交友应用,大家能够 在软件里肆意地谈论游戏.电影评分和学习等等.他们还可以一起玩游戏,玩出新奇的玩法,独特的成长体系,同龄人不再无聊的聚集在一起. 软件亮点 1.职业任务:艺术 ...

  6. 仿新版支付宝账单页面滑动时月份栏被下一个月给顶上去

    前段时间支付宝账单出现了新特效,就是下月账单可以推送上月账单的吸顶位置. 不多说上代码: 首先:HTML <div class="list" v-for="item ...

  7. 仿网易蜗牛读书小程序

    最近一段时间在学习怎么写小程序,然后自己利用课外时间,也撸了一个.一直都很喜欢网易蜗牛读书这款App,对于喜爱的事物总是情不自禁的,于是就仿照网易蜗牛读书的App简单做了这款小程序. 项目地址:杳杳飞 ...

  8. viicms仿乐享微信源码官方版

    名称:viicms仿乐享微信源码官方版 版本:1.0 软件大小:56.6MB 软件语言:简体中文 软件授权:免费版 应用平台:WinXp/vista/win7//win8/2000/2003 viic ...

  9. 微信小程序仿系统自带下拉刷新效果

    微信小程序仿系统自带下拉刷新效果 前言 思路分析 实现 尾巴 前言 看到标题也许有人会说:系统不是已经自带了下拉刷新,你去仿照系统的下拉刷新是不是吃多了没事干?其实真相并不是这样的.在微信小程序手把手 ...

最新文章

  1. sersync 文件同步系统(一) 服务初步搭建
  2. 2压缩备份数据库_为什么您的企业需要备份数据库
  3. DELPHI怎样编写COM组件
  4. 怎么快速搭建属于自己的博客
  5. 认识Python基础环境搭建
  6. 深入浅出Mybatis系列(七)---mapper映射文件配置之insert、update、delete
  7. win8游戏开发教程开篇
  8. 乐玩模块脚本实战教程辅助脚本制作开发视频
  9. html好看鼠标光标特效
  10. 腾讯天天P图负责人、喜马拉雅副总裁、朋友印象创始人等16位大咖齐开讲,关于未来,关于产品...
  11. redis集群搭建管理入门
  12. 推荐系统系列——经典推荐算法
  13. 关于st-link与stm32f103c8t6连接
  14. WebSocket 是什么原理?为什么可以实现持久连接
  15. 甘超波:NLP价值观
  16. SA-UNet: Spatial Attention U-Net for Retinal Vessel Segmentation
  17. 【linux】循序渐进学运维-wc
  18. java杀毒软件_震宇大神的杀毒软件 (Java代码)
  19. 树莓派 Raspberry Pi 3B+安装官方系统(一)
  20. GPS与GPRS区别

热门文章

  1. 【web前端开发教程】
  2. 寻找漂流瓶上人快老板
  3. mac下Intelij IDEA中修改maven国内镜像
  4. java swing 实现鼠标滑轮聚焦缩放图片
  5. PPI_DPI 对比
  6. sort和sortby的区别:
  7. c语言填字母游戏蓝桥杯,蓝桥杯2017国赛JAVAB组 填字母游戏 题解
  8. 纸片人「活」了。Meta AI新作:只需几分钟,手绘小人有了灵魂
  9. MATLAB中 分数化简
  10. DIYGW-UI-PHP是一款基于thinkphp framework和 element admin开发而成的前后端分离系统