Android打造不一样的新手引导页面(二)


本系列主要分为两篇博客

Android打造不一样的新手引导页面(一)

Android打造不一样的新手引导页面(二)

关于页面导航器的,可以查看我的这一篇博客仿网易新闻的顶部导航指示器

上一篇博客主要讲解怎样自定义一个CirclePageIndicator控件

这篇博客主要讲解怎样更改ViewPager切换的效果。

首先我们先来看一下默认的ViewPager的切换效果,感觉是不是很普通,因为大多数时候我们经常没有用到ViewPager的动画切换效果 ,这种想过见多了,也就觉得平淡了

下面我们来看一下我们自己实现的ViewPager页面的 切换效果,总共有 四种不同的样式

实现原理说明

其实要实现上述的 效果非常简单,只需要以下几行代码,就搞定了。

viewpager.setPageTransformer(true, new  ViewPager.PageTransformer() {    @Override    public void transformPage(View page, float position) {        // do transformation here        }});

Google官方关于两个参数的解释是

reverseDrawingOrder boolean: true if the supplied PageTransformer requires page views to be drawn from last to first instead of first to last.

transformer ViewPager.PageTransformer: PageTransformer that will modify each page's animation properties

第一个布尔型参数表示的意思就是在两个页面切换产生动画效果时候是否要反转一下让下一个页面在上一个页面底下,因为ViewPager默认下一个页面是绘制在上一个页面的上面,这里一般传入true。

第二次参数才是重点,这里实现了PageTransformer接口,然后我们所有需要的动画效果都在transformPage这个接口方法里面实现,现在我们来看看这个方法。

transformPage void transformPage (View page,                 float position)

page View: Apply the transformation to this page
position

float: Position of page relative to the current front-and-center position of the pager. 0 is front and center. 1 is one full page position to the right, and -1 is one page position to the left.

下面我们借用一张图片来解释position的变化

页面切换

假设当前我们屏幕中的页面是B:

  • 那么该页面的position是1,A页面的position是-1,C页面的position是1.
  • 当我们从B页面滑到c页面的时候,B页面的变化是从0减少到-1,C页面的 变化是从1减少到0,A页面的变化是从从-1向负无穷变化。当我们切好滑动到一半的时候B页面的position是-0.5,c页面的position是0.5。
  • 当我们从B页面滑动到A页面的时候,B页面的变化是【0,1】,A页面的变化是【-1,0】,c页面的变化是从1向正无穷变化

解释完这些参数是什么意思,下面让我们来看一下我们是怎样实现的

Google的两个例子

首先我们先来看一下官方的两个例子,地址是:http://developer.android.com/training/animation/screen-slide.html

ZoomOutPageTransformer

public class ZoomOutPageTransformer implements ViewPager.PageTransformer {    private static final float MIN_SCALE = 0.85f;    private static final float MIN_ALPHA = 0.5f;    public void transformPage(View view, float position) {        int pageWidth = view.getWidth();        int pageHeight = view.getHeight();        if (position < -1) { // [-Infinity,-1)            // This page is way off-screen to the left.            view.setAlpha(0);        } else if (position <= 1) { // [-1,1]            // Modify the default slide transition to shrink the page as well            float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position));            float vertMargin = pageHeight * (1 - scaleFactor) / 2;            float horzMargin = pageWidth * (1 - scaleFactor) / 2;            if (position < 0) {                view.setTranslationX(horzMargin - vertMargin / 2);            } else {                view.setTranslationX(-horzMargin + vertMargin / 2);            }            // Scale the page down (between MIN_SCALE and 1)            view.setScaleX(scaleFactor);            view.setScaleY(scaleFactor);            // Fade the page relative to its size.            view.setAlpha(MIN_ALPHA +                    (scaleFactor - MIN_SCALE) /                    (1 - MIN_SCALE) * (1 - MIN_ALPHA));        } else { // (1,+Infinity]            // This page is way off-screen to the right.            view.setAlpha(0);        }    }}

运行到上述的代码,效果图如下

从上述效果图可以看到,页面切换的时候,主要是页面大小的 变化,水平移动距离的变化以及透明度的变化,这些也可以从代码中体现回来,我们主要关心[-1,1]的时候就OK,因为在[-Infinity,-1)和(1,+Infinity]的时候是不可见的。

if (position < -1) { // [-Infinity,-1)    // This page is way off-screen to the left.    page.setAlpha(0);} else if (position <= 1) { // [-1,1]    // Modify the default slide transition to shrink the page as well    float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position));    float vertMargin = pageHeight * (1 - scaleFactor) / 2;    float horzMargin = pageWidth * (1 - scaleFactor) / 2;    if (position < 0) {        page.setTranslationX(horzMargin - vertMargin / 2);    } else {        page.setTranslationX(-horzMargin + vertMargin / 2);    }    // Scale the page down (between MIN_SCALE and 1)    page.setScaleX(scaleFactor);    page.setScaleY(scaleFactor);    // Fade the page relative to its size.    page.setAlpha(MIN_ALPHA +            (scaleFactor - MIN_SCALE) /                    (1 - MIN_SCALE) * (1 - MIN_ALPHA));} else { // (1,+Infinity]    // This page is way off-screen to the right.    page.setAlpha(0);}

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) { // [-Infinity,-1)            // This page is way off-screen to the left.            view.setAlpha(0);        } else if (position <= 0) { // [-1,0]            // Use the default slide transition when moving to the left page            view.setAlpha(1);            view.setTranslationX(0);            view.setScaleX(1);            view.setScaleY(1);        } else if (position <= 1) { // (0,1]            // Fade the page out.            view.setAlpha(1 - position);            // Counteract the default slide transition            view.setTranslationX(pageWidth * -position);            // Scale the page down (between MIN_SCALE and 1)            float scaleFactor = MIN_SCALE                    + (1 - MIN_SCALE) * (1 - Math.abs(position));            view.setScaleX(scaleFactor);            view.setScaleY(scaleFactor);        } else { // (1,+Infinity]            // This page is way off-screen to the right.            view.setAlpha(0);        }    }}

运行上述代码以后,可以看到的变化是


下面来看一下我们自己实现的两个例子

看到上述图以后,仔细分析可以看到在我们滑动的时候主要是旋转角度的 变化,并且Y轴旋转中心是页面的中心点,当position<0的时候,X轴的中心是view.getWidth,当position>0的时候,x轴的中心是0,代码如下。

public class CubeOutTransformer extends BaseTransformer {    @Override    protected void onTransform(View view, float position) {        view.setPivotX(position < 0f ? view.getWidth() : 0f);        view.setPivotY(view.getHeight() * 0.5f);        view.setRotationY(90f * position);    }    @Override    public boolean isPagingEnabled() {        return true;    }}

TableTransformer

public class TableTransformer extends BaseTransformer {    private static final Matrix OFFSET_MATRIX = new Matrix();    private static final Camera OFFSET_CAMERA = new Camera();    private static final float[] OFFSET_TEMP_FLOAT = new float[2];    private static final float  minScale=0.6f;    @Override    protected void onTransform(View view, float position) {        final float rotation = (position < 0 ? 30f : -30f) * Math.abs(position);        view.setTranslationX(getOffsetXForRotation(rotation, view.getWidth(), view.getHeight()));        view.setPivotX(view.getWidth() * 0.5f);        view.setPivotY(0);        view.setRotationY(rotation);        float scaleX=Math.max(1-Math.abs(position),minScale);        view.setScaleX(scaleX);    }    protected static final float getOffsetXForRotation(float degrees, int width, int height) {        OFFSET_MATRIX.reset();        OFFSET_CAMERA.save();                OFFSET_CAMERA.rotateY(Math.abs(degrees));        OFFSET_CAMERA.getMatrix(OFFSET_MATRIX);        OFFSET_CAMERA.restore();        OFFSET_MATRIX.preTranslate(-width * 0.5f, -height * 0.5f);        OFFSET_MATRIX.postTranslate(width * 0.5f, height * 0.5f);        OFFSET_TEMP_FLOAT[0] = width;        OFFSET_TEMP_FLOAT[1] = height;        OFFSET_MATRIX.mapPoints(OFFSET_TEMP_FLOAT);        return (width - OFFSET_TEMP_FLOAT[0]) * (degrees > 0.0f ? 1.0f : -1.0f);    }}

到此我们的源码分析为止


题外话

如果各位觉得还行的话,欢迎在github上面 star或者 fork,谢谢 ,github项目地址ViewPagerTabIndicator

转载请注明原博客地址

源码下载地址:

更多相关文章

  1. Android欢迎页面2秒钟后自动跳转到主页面
  2. Android调用.NET Webservice报org.ksoap2.serialization.SoapPri
  3. SlidingMenu和ActionBarSherlock结合做出出色的App布局,Facebook
  4. 修复Android(安卓)App在开机后入口类被启动两次的bug
  5. Android(安卓)后台任务(五)Service
  6. 我是新手,我在学Android
  7. Android横向智能刷新框架-SmartRefreshHorizontal+ScrollView 实
  8. 详解Android中的屏幕方向
  9. 解决Android编辑框在全屏模式下无法检测布局变化的问题

随机推荐

  1. Android(安卓)进入Activity中默认不弹出
  2. EditText
  3. Android(安卓)Studio第六期 - 横向GridVi
  4. Android(安卓)layout_weight案例分析总结
  5. Android--遍历SQLite数据库下的所有表名
  6. android实现回车键的监听
  7. Android取得系统信息和分辨率内存信息
  8. Android--取得布局中指定控件的宽高
  9. Android(安卓)按键驱动
  10. Android(安卓)ListView二三事