引导界面大多都是利用ViewPager实现,通过左右滑动来展示应用程序的功能、特色、使用方式等。具体的实现也很简单,写几个要展示的xml布局文件,通过ViewPager的Adapter适配给ViewPager,下面的小圆点指示器可以用一个线性布局来容纳,选中状态可以利用drawable中的enable状态来指定相应的圆点图片,在程序中根据页面的滑动情况(onPageSelected(int position))将圆点ImageView设置setEnable状态就行了。我之前写过一个循环滚动的例子,可以看一下:自动滚动广告条。
重点来了,如果在滚动的过程中,页面各个元素的移动速度不一样,页面切换平滑过渡,那么这样的视觉效果就会给人提别舒服的感觉,让人印象深刻。这种视觉效果往往叫做视差(Parallax)。
具体怎么实现呢?每个元素移动速度都不一样,就需要为每个元素设置x,y和alpha的进入和推出速度的属性,所以要自定义ImageView添加这些属性,或者不自定义View直接自定义这6个属性就行了。在滑动的过程中,根据滑动的距离以及各个View的x,y,alpha的6个速度值计算出各个View实际应滑动的距离。这个大家肯定会想到利用ViewPager的PageChangeListener来监听欢动状态,在不断回调的onPageScrolled方法中进行计算,但ViewPager还有一个用来监听滑动事件的回调方法ViewPager.PageTransformer接口的transformPage(View view, float position),利用setPageTransformer来指定这个回调。transformPage方法的第一个参数是当前滑动的View。position指当前滑动状态,以屏幕左边界为原点向右画一个数轴,position也就是View的左边界距离屏幕左边界多少个身位(宽度),以向右为正。当前View在屏幕中央时position是0.0,滑动到右边不可见时position为1.0,滑动到左边不可见时为-1.0。
由于滑动的缓冲,position小于-1.0或者大于1.0是很有可能的,所以判断并设置动画时,页面从左边离开屏幕时position<1;滑动过程中-1<=position<=1,其中[-1,0]是左边的页面,(0,1]是右边的页面;从右边离开屏幕时position>1。在页面滑动的过程中可以让View根据position的变化而变化。例如官方示例中的DepthPageTransformer:
public class DepthPageTransformer implements ViewPager.PageTransformer { private static final float MIN_SCALE = 0.75f; public void transformPage(View view, float position) { int pageWidth = view.getWidth(); if (position < -1) { // [-∞,-1) // 当前页面从左侧离开屏幕 view.setAlpha(0); } else if (position <= 0) { // [-1,0] //左边的页面使用ViewPager默认的过渡动画 view.setAlpha(1); view.setTranslationX(0); view.setScaleX(1); view.setScaleY(1); } else if (position <= 1) { // (0,1] // 右边的页面缩放淡入淡出,右侧页面从右侧进入时position:1→0,右侧页面从右侧退出时position:0→1。 view.setAlpha(1 - position); // 抵消默认的滑动过渡动画 view.setTranslationX(pageWidth * -position); // 让页面在MIN_SCALE和1之间缩放 float scaleFactor = MIN_SCALE + (1 - MIN_SCALE) * (1 - Math.abs(position)); view.setScaleX(scaleFactor); view.setScaleY(scaleFactor); } else { // (1,+∞] // 当前页面从右侧离开屏幕 view.setAlpha(0); } } }
我也写了一下,滑动过程中让页面的每个元素按照自己的速率移动,虽然可以达到类似视差的效果,但页面之间的边界很清晰,左边页面的Views在滑动过程中会被右边页面的边界笔直切割,我这个强迫症肯定受不了。那怎么办呢?在ViewPager外面包裹一个FrameLayout帧布局也不行,还好看到了w446108264/XhsParallaxWelcome,他也是应用了prolificinteractive/ParallaxPager的思想。我们想一下,我们需要用FrameLayout让页面和元素能够平滑覆盖切换,我们还得用ViewPager的滑动特性,那就好办了,我自定义一个FrameLayout,把这些页面元素都加到这个帧布局中,再最上层覆盖一个空的ViewPager,这样既能使用到ViewPager的滑动特性又能让元素平滑覆盖切换,是不是很聪明、是不是很贱啊,^_^
为了不被说重复制造轮子,我在其代码基础上进行了调整和优化,以适应我的需求。