模拟Material design实现可伸缩标题栏

开发项目需求,需要写一个可伸缩的头部。本来打算直接使用Material支持库来实现效果,Android Design Support Library 的 代码实验——几行代码,让你的 APP 变得花俏。后来发现,这个库目前不能很好的支持复杂的内容,尤其是包含多个tab的时候。Google了一下,一些库都是只支持基本布局的,实现起来不方便,于是只好自己写了。正好之前研究了一番UltraPullToRefresh的实现方法,原理相通,修改了一些逻辑就大功告成了。 

源码地址: https://github.com/captainbupt/PseudoMaterialHeader

下面是效果图(虽然界面是丑了点,不过都是可自定义,美化工作很轻松):

来一个开发完成的效果图,看起来好多了~

一、 基本模块

之前的博客中已经讲解过MotionEvent的传递机制了, MotionEvent事件传递个人总结。因此,想实现这个效果,主要是需要自定义一个ViewPager,来自己分配MotionEvent事件。同时,为了实现自定义效果,header和content都是通过接口来实现事件的传递。
主要类有:
  • ContentHandler:Content类需要实现的接口,用来判断是否到顶端(如,ListView第一项显示)。其中DefaultContentHandler已经支持了大部分的基础View
  • HeaderHandler:Header类需要实现的接口。其中的方法会被父布局给调用,从而实时的通知Header 高度的变化,包括当前比例。Header可以根据这些信息自定义动画效果。
  • MaterialHeaderLayout:继承自ViewGroup。会负责MotionEvent事件的传递和分发,以及屏幕的滚动效果。
  • MotionEventIndicator:一个辅助类。用来记录MotionEvent的值,并且计算偏移量,时间,是否到达边界值等。

二、 ViewGroup实现

主要重写的方法如下:
  • onFinishInflate:用来统计子view数量,并分配header和content
  • onMeasure:重绘时会调用,用来获取header的高度,同时使子view也开始计算其自身宽高
  • onLayout:重绘时会调用,用来定义子View的位置
  • dispatchTouchEvent:主要的逻辑代码。通过Indicator的辅助,计算MotionEvent的传递方法。主要的判断在ACTION_MOVE中,通过判断方向和速度来进行滚动或者传递。
  • SchollerChecker:辅助滑动类。保证滑动准确无误。
大部分的代码和逻辑都参照了UltraPullToRefresh的实现。

三、坑

遇到的最主要的一个问题是关于LayoutParams的问题。之前没有进行详细研究,导致一直报ClassCastException。参考网上文章,原来每个ViewGroup基本都定义了自己的LayoutParams,用来实现不同的布局效果(如LinearLayout只关心权重和margin,而RelativeLayout则需要获取各种依赖属性)。而默认的ViewGroup.LayoutParams是只包含高和宽这两个属性的,而我们在计算高度的时候使用到了margin,因此会产生不兼容的问题。查阅资料后得知,ViewGroup是通过调用generateLayoutParams()来传入xml文件中的参数的,因此需要重写这个方法,并自己定义一个LayoutParams读取AttributeSet中的各个属性。同时,也要重写checkLayoutParams(),才能保证布局验证通过。
另外在传递事件的时候,考虑到content中可能需要横向滑动,因此不能够完全屏蔽MotionEvent事件,因此修改MotionEvent中的Y值,将横向滑动事件传递了进去。不过实际验证发现,这样会造成严重的卡顿效果,可能是跟同时滑动有关。因此,还是使用了比较传统的方法,即通过判断角度来决定是否传递事件。

四、小结

通过这样一个重写,对MtionEvent的传递机制理解的更深了。同时,通过模仿UltraPullToRefresh,自己尝试了dispatchTouchEvent的操作过程。相信以后如果还需要使用到类似的动画效果,也能够很快的自己实现出来。Anyway,虽然不提倡重复造轮子,但一定要明白轮子是怎么造的,只是简单的使用别人开发好的控件,还是无法使自己的技能水平得到进阶。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值