今天逛Google Play无意间发现Google把原生计算器应用单独发布了,
这几年虽然一直坚持使用原生Android系统,但由于计算器这种工具软件使用频率较低(也就每个月填报销的时候打开用一下),一直没怎么特别留意,今天特意使用了一会,发现设计还是有很多亮点的,符合Google简洁、易用的风格。
这是打开应用后的主页:
这是滑动显示数学公式后的页面:
为了描述方便,我们把第一页(也就是包含0-9数字和常用+-×/=操作的页面)称为page1,把显示数学计算公式的页面称为page2,手指在page1向左滑动,page2会从屏幕后侧缓缓滑入,滑动的过程中page1位置保持不动,page2完全滑入后也没有把page1完全覆盖,左边还是留有间距的,想回到page1只需要往右一滑就可以了,而这个过程中page2则是从屏幕右侧缓缓滑出。
有点像水平方向的抽屉,设计比较新颖,看一下它的源码。
先从googlesourse把源码clone到本地
|
|
然后导入Android Studio,从清单文件找到应用的入口Activity————Calculator.java,看一下它的布局文件,由于计算器的源码适配了不同分辨率、不同屏幕方向的的手机和pad,我们只分析一种就行了
根布局是LinearLayout,有两个子view,垂直显示。由第二个CalculatorPadViewPager的android:layout_weight=”1”可以看出这两个子view是按照1:1的高度平分整个屏幕的。@layout/display是显示输入的数字和运算结果的,就是两个EditText,我们不用关注。重点看一下下面的布局。
CalculatorPadViewPager继承于ViewPager,相关代码一会再看。它包含两个子view,一个LinearLayout,一个pad_advanced的layout,打开pad_advanced.xml可以看到这就是显示各种数学公式的view。上面的@layout/pad_numeric是数字的layout,4行3列,@layout/pad_operator_one_col是+-×/=操作的布局,5行1列,这两个布局水平方向占据的宽度根据style里定义的layout_weight进行计算,比较简单这里就不贴代码了。
布局看完之后可能会有疑问,既然计算器底部的布局其实就是一个ViewPager+2两个子View的构成,那么相对于计算器有几个疑问:
1:为什么在显示page1的时候page2会显示出来一部分呢(右侧青色那一条)?
2:为什么向左滑动的时候page1的位置一直保持不动?不应该是向左侧滑出吗?
3:还有就是当page2滑出后宽度为什么没有铺满、左边还要留出一部分透明区域呢?
要搞清这几个问题,我们重点看一下CalculatorPadViewPager的代码。
|
|
关于第一个疑问,答案在第78行。setPageMargin(-24);由于是负数,这样每个page之间就会有重叠,就出现了明明显示的第一个view,结果在右侧显示了一部分第二个view的layout。看到这里突然想起以前写图片浏览器的时候,PM让两个图片之间不要紧挨着,留有一定的间隙,用的就是这个方法实现的。
第二个疑问涉及到ViewPager的切换动画。看第79行,setPageTransformer(false, mPageTransformer); 这里mPageTransformer的定义在53~66行。在transformPage方法里根据position设置当前view的x轴偏移量。
|
|
看一下源码里的方法说明,这里的position其实是相对的,并不是常规理解的位置下标,它是以当前屏幕的正中心为坐标原点,当page的中心和屏幕的原点重合(即page正在完全显示时)position=0;
当page向左侧滑动,慢慢淡出屏幕时,该过程中page的中心相对屏幕的中心原点在沿着X轴向左移动,此时positon < 0,当page完全滑出屏幕时,positon = -1;
同理,当page向右滑动,慢慢淡出屏幕时,该过程中page的中心相对屏幕的中心原点在沿着X轴向右移动,此时positon > 0,当page完全滑出屏幕时,positon = 1;
有了上面的分析,其实可以把positon看成正在滑动的page滑出屏幕的比例,正负代表往哪个方向滑动。所以,要想在滑出数学计算公式的page过程中保持当前输入的page位置不动,根据滑出屏幕的比例设置该page在X轴的偏移量就可以了,view.setTranslationX(getWidth() * -position); 同理,把数学计算公式的page滑出时取消这个偏移量,view.setTranslationX(0); 到这里疑问2也解决了。
更多的ViewPager切换动画请参考开源项目JazzyViewPager
最后看下疑问3,为什么page2滑入屏幕后并没有完全占满屏幕的宽度而右侧有一部分的间隙呢?继续看源码,在第26行发现了端倪。原来是复写了PagerAdapter的getPageWidth方法,看一下该方法的说明:
|
|
说的很清晰了,根据position设置当前页面宽度的百分比。所以疑问3也解决啦。
到这里代码的分析已经结束了,给我最大的感触就是:多读源码!多读源码!多读源码!如果把原生计算器的需求给你,你能第一时间想到会用ViewPager去实现底部的交互吗?只有在对ViewPager源码很了解、对setPageTransformer、getPageWidth()、setPageMargin()这些方法的原理和使用很清晰的时候,你才会想到原来用ViewPager用不了多少行代码就能很优雅的实现啦。