滑动选项View

额…其实这个我也不知道应该叫做什么,就是滑动出来的选项,就像ios版微信那样,向左滑动,滑出选项,看着就想试试模仿一下,下面来看看如何写。

首先制定思路,滑动出来的选项是一部分,作为主体内容的是一部分,也就是说这是有两部分组成,那么集成FrameLayout,初始化的时候添加两个子view一个是主题内容的viewGroup,一个是装载选项的viewGroup,我在这里定义为三个选项,放在选项viewGroup中(下文为BtnLayout),一个是确定键,一个是取消键,一个是更多键,当然文字是可以修改的,而且选项是否显示也能控制,那么就完成第一步了,下一步就是测量,其实我这里的测量的方法不是很好,主要是在我没有重写各种addView(),这样就没有限制子view的个数,会破坏思路中的两个组成部分,我就在onMeasure()这里限制,因为初始化的时候添加了两个组成部分,所以如果有第三个view,那么这个view就会添加到主题内容viewGroup中(下文为content),然后多余的就移除掉,这样实属不好,这里设置宽度为充满父布局,高度默认为70dp,贴上代码:

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {int width = MeasureSpec.getSize(widthMeasureSpec);int height = MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY? MeasureSpec.getSize(heightMeasureSpec) : SizeUtils.dp2px(context, 70);btnLayout.setLayoutParams(new LayoutParams(-scroll, height));for (int i = 2; i < getChildCount(); i++) {if (i == 2) {View view = getChildAt(i);removeView(view);LayoutParams layoutParams = (LayoutParams) view.getLayoutParams();if (layoutParams.width == LayoutParams.MATCH_PARENT) {layoutParams.width = width;}if (layoutParams.height == LayoutParams.MATCH_PARENT) {layoutParams.height = height;}content.addView(view, layoutParams);} else {removeView(getChildAt(i));}}measureChildren(widthMeasureSpec, heightMeasureSpec);setMeasuredDimension(width, height);
}

上面可以看到这句

btnLayout.setLayoutParams(new LayoutParams(-scroll, height));

这句就是BtnLayout的设置大小的,height就是它的父布局的高度,而宽度就是滑动的距离,记录开始点,结束的,这样计算出滑动距离,因为向左滑动是负数,所以scroll加了个负号。

测量完之后就是布局了,这样的流程估计大家都很熟悉了,其实布局也没什么,不测量还简单,直接是将contentLayout和BtnLayout的位置放好就可以了,贴代码:

protected void onLayout(boolean b, int i, int i1, int i2, int i3) {int width = getMeasuredWidth();int height = getMeasuredHeight();for (int j = 0; j < getChildCount(); j++) {View view = getChildAt(j);if (view == btnLayout) {btnLayout.layout(width + scroll, 0, width, height);} else if (view == content) {content.layout(scroll, 0, width + scroll, height);}}}

他们的位置是根据滑动的距离改变的,而且是横向改变,当scroll为0 的时候,content充满父布局,当向左滑动的时候,content向左滑动,向左scroll为负数,所以相加就好了。

滑动主要用到dispatchTouchEvent(),onInterceptTouchEvent()和onTouchEvent()这三个方法,首先重写onInterceptTouchEvent(),判断什么情况什么时候拦截,当action为down的时候记录点下的x坐标,action为move的时候,scroll=x-start+getScroll(),其中getScroll()是根据是否打开了BtnLayout返回滑动了多少距离,比如没打开的时候,scroll的初始值是0,打开的时候,BtnLayout就是已经展示出来的了,那么就已经是滑动了BtnLayout的宽度,所以scroll的初始值就是btnLayoutd宽度,当action为up的时候就将start和scroll置为默认值,其实在这里的scroll的意义就是判断是否拦截,因为只是想点击的话就没必要拦截了,不然BtnLayout收不到分发的事件,在打开BtnLayout的时候,当scroll滑动距离大于5dp就判定为想要滑动,然后判断滑动的位置是在content还是BtnLayout,在content的话就是直接拦截,我还加了个判断是是否允许在BtnLayout滑动关闭BtnLayout,是的话就拦截,不是的话就不拦截,走super.onInterceptTouchEvent()继续分发,当BtnLayout没有打开的时候,就直接拦截了,因为不会影响到分发给BtnLayout,贴上代码:

public boolean onInterceptTouchEvent(MotionEvent ev) {switch (ev.getAction()) {case MotionEvent.ACTION_DOWN:start = (int) ev.getX();scroll = start;break;case MotionEvent.ACTION_MOVE:scroll = (int) (ev.getX() - start + getScroll());break;case MotionEvent.ACTION_UP:start = 0;scroll = getScroll();break;}//判断是否打开BtnLayoutif (isOpenBtn) {//滑动距离超过5dp判定用户意向为滑动if (scroll != start && scroll >= getScroll() + SizeUtils.dp2px(context, 5)) {//起点在contentView部分是直接滑动,在BtnLayout部分要判断是否可以滑动关闭if (start <= getMeasuredWidth() - getBtnWidth()) {return true;} else if (isBtnClose) {return true;}}} else if (scroll != start && scroll <= getScroll() - SizeUtils.dp2px(context, 5)) {return true;}return super.onInterceptTouchEvent(ev);}

那么写完是否拦截就改重写onTouchEvent(),如何消费,当拦截之后就要消费这个事件,首先也是跟拦截一样,action是down的时候就记录start的坐标,而且加入是在recyclerView之类的item布局中,那么就不让父布局拦截这个事件,使得这个事件自己消费,当action为move的时候,先判断用户是纵向滑动还是横向滑动,如果是纵向滑动就不拦截父布局,让父布局消费,反正继续自己消费,然后根据是否打开BtnLayout来刷新界面,当action为up的时候,判断滑动距离是否超过BtnLayout的宽度的三分之一,是的话且是向左滑动,也就是想打开BtnLayout,向右滑动的话就是想关闭BtnLayout,那么就自身滑动过去,这时候用的是属性动画,贴上代码:

public boolean onTouchEvent(MotionEvent ev) {switch (ev.getAction()) {case MotionEvent.ACTION_DOWN:start = (int) ev.getX();getParent().requestDisallowInterceptTouchEvent(true);return true;case MotionEvent.ACTION_MOVE://超过一定距离,判断用户想要上下滑动if (isTB(ev.getRawY())) {getParent().requestDisallowInterceptTouchEvent(false);return false;} else {getParent().requestDisallowInterceptTouchEvent(true);}scroll = (int) (ev.getX() - start + getScroll());if (isOpenBtn) {if (scroll < getScroll()) {scroll = getScroll();} else if (scroll > 0) {scroll = 0;}} else {if (scroll > getScroll()) {scroll = getScroll();} else if (scroll < -getBtnWidth()) {scroll = -getBtnWidth();}}requestLayout();return true;case MotionEvent.ACTION_CANCEL:case MotionEvent.ACTION_UP:if (isOpenBtn) {if (scroll >= -getBtnWidth() / 3 * 2) {isOpenBtn = false;if (btnChangeListener != null) {btnChangeListener.onChange(false);}normalPosition(scroll, getScroll());} else {normalPosition(scroll, -getBtnWidth());}} else {if (scroll <= -getBtnWidth() / 3) {isOpenBtn = true;if (btnChangeListener != null) {btnChangeListener.onChange(true);}normalPosition(scroll, getScroll());} else {normalPosition(scroll, 0);}}return true;}return true;}

动画代码:

private void normalPosition(int start, int end) {animator = ValueAnimator.ofInt(start, end);animator.setDuration(Math.abs(start - end));animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator valueAnimator) {ScrollView.this.start = 0;scroll = (int) valueAnimator.getAnimatedValue();requestLayout();}});animator.start();}

基本上就这些是核心,还有的就是是否分发这个方法没重写,在这里我只是做了当动画在执行时就不分发,返回false,让父布局消费

@Overridepublic boolean dispatchTouchEvent(MotionEvent ev) {if (animator != null && animator.isRunning()) {return false;}return super.dispatchTouchEvent(ev);}

好了,基本就是这样了,我还写了两个方法,一个是打开,一个是关闭,不过没有写成是有动画的打开关闭

public void openBtn() {if (!isOpenBtn) {if (btnChangeListener != null) {btnChangeListener.onChange(true);}}isOpenBtn = true;scroll = getScroll();requestLayout();}public void closeBtn() {if (isOpenBtn) {if (btnChangeListener != null) {btnChangeListener.onChange(false);}}isOpenBtn = false;scroll = getScroll();requestLayout();}

以上就是滑动选项view的主要代码,我也在自己的练习项目使用,目前没发现什么问题,如大家发现问题可以指正,如果能帮到有需要帮助的人就更好了。

也可以添加我微信互相讨论哦!

wx:Zhang—JY

模仿ios微信滑动选项View相关推荐

  1. android模仿ios滚动,模仿iOS版微信的滑动View效果

    前言 最近经常交替使用Android和iOS手机.对于两个系统,从我们常用的列表来看,Android一般的列表菜单是通过长按出来的,而iOS是通过滑动出现的.比如我们常用的微信,对于Android版本 ...

  2. 模仿iOS版微信的滑动View

    最近几个月终于有大把时间总结这两年来所学 2019.5.23 前言 最近经常交替使用Android和iOS手机.对于两个系统,从我们常用的列表来看,Android一般的列表菜单是通过长按出来的,而iO ...

  3. php仿微信底部菜单,Android实现简单底部导航栏 Android仿微信滑动切换效果

    Android仿微信滑动切换最终实现效果: 大体思路: 1. 主要使用两个自定义View配合实现; 底部图标加文字为一个自定义view,底部导航栏为一个载体,根据需要来添加底部图标; 2. 底部导航栏 ...

  4. android仿微信的activity平滑水平切换动画,Android实现简单底部导航栏 Android仿微信滑动切换效果...

    Android实现简单底部导航栏 Android仿微信滑动切换效果 发布时间:2020-10-09 19:48:00 来源:脚本之家 阅读:96 作者:丶白泽 Android仿微信滑动切换最终实现效果 ...

  5. android滑动菜单图标,Android实现简单底部导航栏 Android仿微信滑动切换效果

    Android仿微信滑动切换最终实现效果: 大体思路: 1. 主要使用两个自定义View配合实现; 底部图标加文字为一个自定义view,底部导航栏为一个载体,根据需要来添加底部图标; 2. 底部导航栏 ...

  6. android 底部滑动效果怎么做,Android实现简单底部导航栏 Android仿微信滑动切换效果...

    android仿微信滑动切换最终实现效果: 大体思路: 1. 主要使用两个自定义view配合实现; 底部图标加文字为一个自定义view,底部导航栏为一个载体,根据需要来添加底部图标; 2. 底部导航栏 ...

  7. Android Activity 滑动返回。支持微信滑动返回样式、横屏滑动返回、全屏滑动返回

    BGASwipeBackLayout-Android 项目地址:bingoogolapple/BGASwipeBackLayout-Android  简介:Android Activity 滑动返回. ...

  8. iOS 微信 7.0.16 内测更新!支持只删除聊天列表不删除聊天记录!附内测地址!

    Android 微信 7.0.19 刚刚更新,iOS 微信 7.0.16 也开始内测. 本次内测有哪些更新呢?我们一起来看看! 速览 新增聊天框"不显示"选项: 新增表情搜索: 视 ...

  9. 小程序禁用ios 左右滑动_如何在使用应用程序时禁用iOS控制中心

    小程序禁用ios 左右滑动 The Control Center has proven to be a thoughtful and welcome addition to iOS, but it c ...

最新文章

  1. Stack and queue.
  2. 成都Uber优步司机奖励政策(2月1日)
  3. linux系统管理命令--系统测试工具
  4. python下载文件到指定目录-Python获取指定文件夹下的文件名的方法
  5. c语言输出最后不带空格,新人提问:如何将输出时每行最后一个空格删除
  6. ctr 平滑_预算平滑技术在58商业的探索与实践
  7. php获取ip几种方法区别,php获取客户端IP地址的几种方法
  8. 多径信道理论的直观感受与MATLAB仿真
  9. 基于MVVM的知乎日报应用安卓源码
  10. Solidity 0.5 address payable和address的区别是什么?
  11. python selenium --一些常用方法
  12. 如何用js语句给mysql添加内容_在js里写SQL的方法
  13. UWA TIPS:让你的项目更懂你!
  14. vue 报错 Error: timeout of 5000ms exceeded
  15. 技巧:如何从苹果Mac跟踪设备上所有电池的电量?
  16. 非线性视频编辑软件百科全书式介绍
  17. idea打包jar程序
  18. 使用开源组件slidingmenu_library来模拟实现人人客户端的主页侧滑界面
  19. HTML表格边框空隙
  20. 这是一个猜数字的游戏。判断输入的第1个字符,略过其余的字符。

热门文章

  1. 【list】C++ ——实现链表反转逆序
  2. java memory copy_Java Unsafe.copyMemory java.lang.IllegalArgumentException
  3. 项目管理软件选型【OA与项目管理】
  4. ACM大牛!!!!!!
  5. 高收益债券信用风险评估:预期损失率模型
  6. 会议平板安卓系统下不能使用视频会议功能?要选配摄像头麦克风?
  7. 解除计算机屏保密码设置密码,屏保密码怎么取消
  8. Docker部署web项目
  9. “三智”战略与世界人工智能大会同频 华人运通车路协同技术成行业标杆
  10. VS编译器中光标由竖线变为方格(方块)解决办法(笔记本)