位置: 编程技术 - 正文

PullScrollView详解(三)——PullScrollView实现(pulls toward)

编辑:rootadmin

推荐整理分享PullScrollView详解(三)——PullScrollView实现(pulls toward),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:pullsh,pull settle,pullster,pulls toward,pullstrings,pullstrings,pull sleeve,pull sleeve,内容如对您有帮助,希望把文章链接给更多的朋友!

眼看下周就要休婚假了,感觉真是棒极了,嘿嘿哈哈吼吼,休假前把这个系列写完给大家

相关文章: 1、《PullScrollView详解(一)——自定义控件属性》 2、《PullScrollView详解(二)——Animation、Layout与下拉回弹》 3、《PullScrollView详解(三)——PullScrollView实现》

前面铺垫的已经很多了,这篇就要进入正式环节了,下面就是这个系列最终的效果图: 下面我们就一步步来做,这篇就先跟大家一起来实现一个雏形,先把最基本的功能实现。下篇再对一些问题进行优化。

一、框架搭建

先看看我们要搭建的框架: 大家可以看不明白,它是怎么搭的,我们还是直接上XML代码吧:

1、XML

这里要注意两个地方: 1、ImageView就是我们底部的小狗图片,它利用android:layout_marginTop=”-dp”来将图片向顶部缩进dp,为我们下拉做准备 2、PullScrollView,派生自ScrollView,它是通过将子控件的android:layout_marginTop=”dp”来将底部的图片显示出来的。又由于,PullScrollView的android:layout_height是match_parent,所以我们可以向上滚动,覆盖住底部的图片。千万不要把android:layout_marginTop=”dp”放在PullScrollView里,比如这样:

这样就会有下面的效果: 这就是因为我们将android:layout_marginTop=”dp”放在了PullScrollView中;此时的PullScrollView的布局范围并不是整个屏幕了,而是从屏幕以下dp的地方开始。

2、PullScrollView

在这里,我们只是搭框架,并不会做什么下拉和回弹的操作,所以,我们在这一环节,我们仅仅将PullScrollView派生自ScrollView就好了 代码如下:

3、MainActivity

在这里其实也没什么要做的,就是把TableLayout给填充起来:

核心代码就在showTable()函数中,先构造一个TableRow,在TableRow中添加一个TextView,然后将TableRow添加到TableLayout中;这里不是讲解的重点,难度也不大,所以就不再细讲了。我们用TableLayout 的主要目的就是把PullScrolLView撑开,让它可以上下滚动。

二、下拉随手指移动

这段我们就要看看怎么让顶部的图片和上面的Content 一块随手指移动。像下面的效果: 在上篇我们讲过,让布局跟随手指移动,就是计算出手指的移动距离,然后利用layout()函数来移动布局就好了。

1、首先有关变量的设定:

这里主要分为三个部分: mHeaderView:表示头部的图片的VIEW mContentView:表示PullScrollView的子控件,这里是TableLayout控件对应的VIEW

另外是三个初始化的位置: mTouchPoint:表示用户在滑动手指的初始点击位置。用来计算手指的移动距离的 mHeadInitRect:用来保存头部View初始化位置。用来找到回弹的位置用。 mContentInitRect:保存ContentView的初始化位置。跟mHeadInitRect一样,也是回弹用。

2、变量初始化

首先是mHeaderView和mContentView的初始化 mContentView的初始化非常容易,与第二篇一样,我们直接在onFinishInflate()函数中,就可以获得解析后的变量实例:

但mHeaderView确是需要使用PullScrollView的用户自己传进去的,所以我们需要写一个接口来让使用PullScrollView的用户来设置它要操作的headView

同样,有关mHeadInitRect,mContentInitRect的初始化,都必须在图像显示出来以后,才能获取到头部和Content的位置,所以我们将它们的初始化全都放在当用户点击屏幕的时候,与mTouchPoint一起初始化:

这段代码没什么难度,就是在用户点击屏幕的时候,将headView和contentView的坐标保存起来;

3、布局跟随手指移动

到这一步,就是要让布局跟随手指移动了。当然跟上篇一样,首先计算移动距离,然后使用layout()函数来移动布局。 计算距离: 计算距离的代码如下:

用当前的手指所在的Y轴位置减去点击时的位置。就得到了手指的移动距离:

但手指的移动距离并不代表是headView和contentView允许移动的距离,凡事都有一个最大值,这里假设最大值就是headview的高度。所以当手指的移动距离超过headView的高度时,我们就不再增大移动距离,而是将headView直接赋值给deltaY:

然后就是计算headView和contentView的应该所在位置了,并移动他们了,写出来完整的ACTION_MOVE的代码吧:

先看判断语名:

deltaY > 0很容易理解,表示手指的移动距离是正值,即手指是向下移动的; 那另外一个deltaY >= getScrollY()是个什么鬼? 我们先看一下,把这个判断语句去掉,效果会怎样:(即只保留deltaY > 0) 看到了没,当先向上滑一段之后,再下滑,会发现,headView也会跟着下滑;这明显是不对的,因为headview应该在我们超过原始位置的时候再下滑才是正确的。所以要判断当前PullScrollView是不是已经滚动。如果手指的移动距离大于滚动距离,这才说明,我们已经超过了原始位置在下拉。这时候再移动headView; 计算高度: 使用layout移动View前,先计算当前headview和contentView应该移动的距离。

明显,headview要比contentview移动的慢,因为我们在计算headerMoveHeight 时多乘以了一个0.5;这其实也是为了增加一个效果:让用户觉得下拉比较困难,移动的速度慢。当然你也可以去掉,也可以改成其它值。

在计算好移动高度以后,就是计算要移动的位置了,有关mHeaderCurTop、mHeaderCurBottom和mContentTop、mContentBottom的计算就不讲了,没什么意思,就是在原始高度的基础上,加上移动的高度。 移动view: 最后是使用layout移动View:

PullScrollView详解(三)——PullScrollView实现(pulls toward)

这里做了一个判断,即contentView的上边沿不能低于headView的底边。如果低于headView的底边,那就是contentView和headView分离了,这怎么能行。不能分离! 符合条件以后,就移动headview和contentview。

三、松手回弹

在上面的那段代码中,大家可以发现,在移动headview和contentview时,设置了一个变量mIsMoving = true;这个变量是用来标识,headview和contentview是否已经被移动了位置。如果移动了位置则需要反弹; 我们上篇也讲了有关反弹的动画代码写法:先利用layout()将布局还原,然后再做动画,让它从跟随手移动的位置移动到初始位置。 先来看看代码:

首先判断当前view是否移动,如果移动了,则返回;有关返回部分的代码,我就不再细了,如果有不理解的同学,可以参考上篇文章《PullScrollView详解(二)——Animation、Layout与下拉回弹》; 这时候的效果基本上就完成了,效果图如下:

四、BUG修复及优化1、拦截点击事件

首先,有关事件拦截的问题,大家可以先看这篇文章:《Android-onInterceptTouchEvent()和onTouchEvent()总结》,看完这篇文章以后,大家可以会了解到,有关Touch拦截与分发消费的问题。 假如,我们在MainActivity中,添加了如下代码:

即,当用户点击TableLayout的某一个ITEM时,弹出一个TOAST。换句话说,就是在PullScrollView的子控件中消费了点击事件。 那现在我们再运行代码,这时候就出现了问题: 在录像上可能看不出来,大家仔细看,在headview上点击向下拖动是没有问题的;但当用手指放在contentview上向下拖动的时候,contentview会突然下滑一下,然后再向下拖动。 刚开始,我也没理解这是怎么回事,后来经过打LOG发现,,MotionEvent.ACTION_DOWN里的代码根本没有运行,这是为什么? 想必大家看过上面的《Android-onInterceptTouchEvent()和onTouchEvent()总结》之后,应该就能理解出来,OnTouchEvent()走的是事件的消费阶段,只有它的所有子控件不消费的事件才会传到它这来。也就是说,只有PullScrollView中的所有子控件都不消费的事件,才会传递到PullScrollView的OnTouchEvent()中来处理。而我们在TableLayout中已经为每个ITEM添加了onClick()事件的响应,也就是已经消费了点击事件,所以,PullScrollView肯定就不会再收到点击相关的事件了,因为已经被它的子控件消费掉了。 所以,我们要在事件分发阶段拦截点击事件,以保证肯定被运行。要在分发阶段拦截,就需要重写onInterceptTouchEvent()函数,在其中做处理:

2、拦截MOVE事件

同理,我们不能祈祷PullScrollView的所有子控件都不处理MotionEvent.ACTION_MOVE事件,我们必须拦截MOVE事件,以保证我们的代码一定能够运行,同样,我们要重写onInterceptTouchEvent()函数,而且在要保证我们在移动的时候,不能把ACTION_MOVE事件传递给子控件;也就是我们在移动的时候禁止所有子控件的对MOVE事件的捕捉,所以要返回true,所以完整的onInterceptTouchEvent()代码如下:

通过返回true,来禁止事件继续传递。

3、拖动时禁止ScollView本身的滚动行为

我们要做到,我们移动布局时不受任何的干扰,在上面我们在通过拦截ACTION_MOVE事件来禁止PullScrollView所有子控件的移动;由于我们的PullScrollView派生自ScrollView,除了禁止子控件的移动以外,还要在移动时禁止ScrollView自身的滚动行为。 首先,我们定义一个变量来标识当前是否要禁止ScrollView自身的默认行为:

然后当我们移动布局时设置为True,其它时候都设置为FALSE:

最后在return时:

这句就厉害了,由于mEnableMoving和super.onTouchEvent(event);用的是或运算符,所以当mEnableMoving为true时,就不会执行super.onTouchEvent(event),也就不会执行ScrollView的默认操作;相反,当mEnableMoving为false时,就会执行super.onTouchEvent(event),就会执行ScrollView默认操作。 到这里,基本所有的问题都解决了。下面我们就再优化一下操作。

4、只允许布局在初始状态时,才允许用户滚动

由于我们在用户点击时获取当前布局的位置的,但当用户先将布局向上滚,然后再点击向下拉。这时我们获取到的初始值就会出错。所以反弹就肯定会出问题。所以我们要想办法,只让在布局在初始状态时,才允许用户拖拽。效果如下: 可以看到,当向上滚动后再向下拉是拉不动的。只有在初始位置时才能拖动。 在ScrollView中,正好有一个值来判断当前的ScrollView是不是在初始化状态,即getScrollY()是不是等于0,当等于0时,肯定是初始化状态。 所以,首先,定义一个变量来标识当前布局是不是初始化状态:

在点击的时候,判断当前是不是初始状态:

在ACTION_MOVE的时候,判断当前是否能够移动:

5、使用declare-styleable来自定义属性

在代码中,我们的拖动的最大高度,直接是通过headview.getHeight()来获取的:

在第一篇中,我们讲述了如何通过declare-styleable来自定义控件属性,这里我们就通过自定义的属性来预定义PullScrollView的这项参数,当然,大家也可以发挥想象,把其它的可变参数,也可以由用户通过参数来自定义。 首先,在values文件夹下新建一个attrs.xml文件:

我这里除了headerHeight(头部高度)变量,还额外申请了几个,以便大家进一步认识declare-styleable的用法,虽然这里也用不到…… 然后,在activity_main.xml中使用:

在XML中使用declare-styleable自定义的属性,前面我们讲过,首先要在根布局添加:

然后在使用时,直接使用app:XXXX即可;具体可以参考本系列第一篇。 然后在PullScrollView中得到定义的值并使用: 先是获取定义的值:

然后在用到mHeaderView.getHeight()的地方改成mHeaderHeight; 即把下面的:

改成:

好了,到这里基本就全部完成了,源码在文章底部给出

参考文章: 1、PullScrollView 2、Android仿IOS回弹效果 ScrollView回弹 总结 3、Android ScrollView回弹效果(二) 4、高仿QQ的上下回弹效果之自定义的ScrollView 5、自定义上拉下拉反弹ScrollView 6、android坐标 7、Android-onInterceptTouchEvent()和onTouchEvent()总结 8、scrollView的fillviewport 9、Android 自定义UI View - 圆形图片控件之自定义属性

如果本文有帮到你,记得加关注哦

源码下载地址: 谢谢

版权声明:本文为博主原创文章,未经博主允许不得转载。

LinearLayout layout_weight解析 LinearLayout是Android布局中经常使用的一种布局,layout_weight属性经在Linearlayout布局中常使用,至于layout_weight的宽度是怎样计算出来的,只有了解了其中的

Java项目的*.java 文件打开后注释乱码问题解决办法。 方法很简单,到项目的src文件下,右键选中任意一个.java文件然后选择打开方式,里面会有写字板和文本文件连个选项然后选中文本文件,这样就可以了

在Android中解析XML 在Android中解析XML知识点概述:1.DOM解析XML2.SAX解析XML3.Pull解析XML知识点详述:前序:XML是可扩展性标记语言,可以自己定义标签.在android中处理xml数据很常见,

标签: pulls toward

本文链接地址:https://www.jiuchutong.com/biancheng/380948.html 转载请保留说明!

上一篇:[置顶] android简单定时器 直接用([置顶]星陨计划)

下一篇:LinearLayout layout_weight解析

  • 销售商品的差价怎么算
  • 融资租赁税率是什么意思
  • 单位卖二手车需要交什么税
  • 哪些进项税额可以转出
  • 员工补充医疗保险报销范围
  • 减半征收企业所得税的项目有哪些?
  • 企业搬迁到外省之前的债务怎么处理
  • 住宿发票专票可抵扣吗
  • 退货报废计入哪类费用
  • 借长期借款贷在建工程
  • 购买原材料已付款怎么记账
  • 不得税前扣除的税金
  • 一般纳税人预缴税款几个点
  • 自然人个税起征点2019税率表
  • 收到教育费附加返还款现金2000元会计分录
  • 海关对现金携带数量有要求吗
  • 企业工资和社保缴费基数
  • 本月没有销项只有进项,月末怎么做账
  • 域名注册费用的会计分录
  • 向关联企业借款债资比
  • 保险保障基金的管理单位是
  • 银行增值税免税收入有哪些
  • 农村合作社收到财政拨款怎么做分录
  • vue3如何
  • php总结
  • 为员工租房租金怎么入账
  • 交际应酬费可以抵扣吗
  • aspnet_admin.exe进程是安全的吗 aspnet_admin进程信息查询
  • php字符串的三种定义方式
  • 购货方获得现金折扣的会计分录怎么写
  • php ftp上传文件
  • 现金流量套期的分录
  • 借条丢了怎么办打电话给家长
  • fs是什么文件
  • win10平板模式怎么切换
  • PHP:pcntl_signal()的用法_PCNTL函数
  • Wat Chaloem Phra Kiat Phrachomklao Rachanusorn的浮庙,泰国南邦 (© pa_YON/Getty Images)
  • 建筑业统一发票真伪查询
  • php错误级别有哪些
  • deepwiser怎么用
  • 挂靠设计公司费用标准 怎么记账
  • 【C#+JavaScript+SQL Server】实现Web端考试系统 六:后台管理模块设计(附源码和资源)
  • 广告费成本包括哪些内容
  • 售后租回交易的第二年利息怎么算
  • 物流公司账务处理特点
  • 亏损合同预计负债的会计分录
  • 高效快速编制会计分录如何做?
  • 所得税汇算清缴需要调增的项目
  • 财务上大写数字420.1怎么写
  • 行政性收费属于什么科目
  • MySQL读写分离企业方案
  • 小规模出售固定资产账务处理
  • 房地产采取按揭销售的,其销售的入账时间为
  • 采购返利是什么意思
  • 哪些发票能做公章
  • 股东向公司借款协议
  • 企业一般用什么系统
  • jquery常用的事件绑定函数有哪些
  • window部署服务
  • linux wget命令详解
  • solaris删除文件夹命令
  • win7更改电脑设置在哪里
  • 升级怎么玩
  • win7老是自动开机启动是怎么回事啊
  • win8 preview
  • win10家庭版关闭
  • mac 怎么复制文件
  • Win7自带的扫雷怎么都打不开
  • ssh密钥根据什么生成
  • html5lib
  • cmd attribute
  • python time.now
  • 好用的css
  • js日期操作
  • python运行py文件没反应
  • javascript选项
  • 广东税务增值税发票查验平台
  • 山西国家税务总局官网
  • 增值税发票选择确认平台已勾选未确认的发票怎么撤销?
  • 怎样以实际行动争取入团
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设