注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好。

原文链接:http://developer.android.com/training/animation/screen-slide.html


屏幕滑动是从一个完整的屏幕转换到另一个屏幕的动画,对于配置向导或者幻灯片的应用场景是很常见的。这节课将会展示如何使用support library.ViewPager提供的ViewPager来自动实现滑动的动画。下面是一个屏幕滑动的动画例子:

屏幕滑动动画

如果你希望略过这部分内容直接看代码样例,可以直接下载样例代码,然后选择淡入淡出动画的例子。下面的文件是实现代码:

  • src/ScreenSlidePageFragment.java
  • src/ScreenSlideActivity.java
  • layout/activity_screen_slide.xml
  • layout/fragment_screen_slide_page.xml

一). 创建视图

创建一个布局文件,你马上就会使用到它作为一个fragment的内容布局。下面的代码是一个例子,包含了一个文本框显示一些文本:

<!-- fragment_screen_slide_page.xml -->
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="match_parent" > <TextView style="?android:textAppearanceMedium"
android:padding="16dp"
android:lineSpacingMultiplier="1.2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/lorem_ipsum" />
</ScrollView>

同时记得给这个fragment定义一个字符串。


二). 创建一个Fragment

创建一个Fragment类,在onCreateView()中返回你刚才创建的布局。当你需要向用户显示新的一页时,你可以之后在父activity中创建这个fragment的实例:

import android.support.v4.app.Fragment;
...
public class ScreenSlidePageFragment extends Fragment { @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
ViewGroup rootView = (ViewGroup) inflater.inflate(
R.layout.fragment_screen_slide_page, container, false); return rootView;
}
}

三). 添加一个ViewPager

ViewPager拥有内置的页面间滑动手势并且默认是显示滑动动画的,所以你不需要创建任何动画。 ViewPager使用PagerAdapter作为一个要显示的新页面的提供者,所以PagerAdapter会使用你之前创建的fragment类。

首先,创建一个包含ViewPager的布局:

<!-- activity_screen_slide.xml -->
<android.support.v4.view.ViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />

创建一个activity,它完成下列事情:

  • 将视图的布局设置为包含了ViewPager的布局。
  • 创建一个继承FragmentStatePagerAdapter抽象类的类,并且实现getItem()方法来提供ScreenSlidePageFragment的实例作为新的页面。这个页面适配器(Pager Adapter)还要求你实现getCount()方法,它返回适配器需要创建的页面数量(比如说有五页)。
  • PagerAdapterViewPager关联起来。
  • 处理设备的后退按键,让它实现在虚拟堆栈中向后移动。如果用户已经在第一页了,回到activity的后退堆栈。
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
...
public class ScreenSlidePagerActivity extends FragmentActivity {
/**
* The number of pages (wizard steps) to show in this demo.
*/
private static final int NUM_PAGES = 5; /**
* The pager widget, which handles animation and allows swiping horizontally to access previous
* and next wizard steps.
*/
private ViewPager mPager; /**
* The pager adapter, which provides the pages to the view pager widget.
*/
private PagerAdapter mPagerAdapter; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_screen_slide); // Instantiate a ViewPager and a PagerAdapter.
mPager = (ViewPager) findViewById(R.id.pager);
mPagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager());
mPager.setAdapter(mPagerAdapter);
} @Override
public void onBackPressed() {
if (mPager.getCurrentItem() == 0) {
// If the user is currently looking at the first step, allow the system to handle the
// Back button. This calls finish() on this activity and pops the back stack.
super.onBackPressed();
} else {
// Otherwise, select the previous step.
mPager.setCurrentItem(mPager.getCurrentItem() - 1);
}
} /**
* A simple pager adapter that represents 5 ScreenSlidePageFragment objects, in
* sequence.
*/
private class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter {
public ScreenSlidePagerAdapter(FragmentManager fm) {
super(fm);
} @Override
public Fragment getItem(int position) {
return new ScreenSlidePageFragment();
} @Override
public int getCount() {
return NUM_PAGES;
}
}
}

二). 通过PageTransformer自定义动画

要显示一个与默认的滑动屏幕动画不同的动画,需要实现ViewPager.PageTransformer接口,并将它提供给ViewPager。该接口有一个共有方法:transformPage()。每次屏幕切换,该方法都会为每一个可见的页面(一般来说都只有一个可见页面)及相邻的离开屏幕范围的页面执行一次。例如,如果当前第三页是可见的,并且用户滑动到了第四页,那么transformPage()方法会在手势执行的过程中,分别为第二页,第三页和第四页进行调用。

在你的transformPage()的实现中,你可以根据当前屏幕所显示的页的位置,确定哪些页需要变化,创建自定义的滑动动画,着可以通过transformPage()方法的position参数获得。

position变量指出了某个页面相对于中心的位置。这个变量会随着用户在页面间切换而动态变化。当一个页面充满屏幕时,它的position值是0。当一个页面被拉出到了屏幕右侧,它的position值是1。如果用户在页面一和页面二切换过程中,那么页面一的position值为-0.5,页面二的position值为0.5。根据页面对于屏幕的位置,你可以通过设置页面的属性,比如:setAlpha()setTranslationX()setScaleY(),来创建自定义的滑动动画。

当你有一个PageTransformer的实现,在你的实现中调用setPageTransformer()来应用你的自定义动画。例如,如果你有一个叫ZoomOutPageTransformerPageTransformer,你可以这样设置你的自定义动画:

ViewPager mPager = (ViewPager) findViewById(R.id.pager);
...
mPager.setPageTransformer(true, new ZoomOutPageTransformer());

拉远页面切换(Zoom-out)

这个动画会缩小页面然后在滑动过程中淡化相邻的页面。在一个页面接近中心的时候,它会回到它的标准大小并且淡入。

Zoom-out动画

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);
}
}
}

深度页面动画(Depth) 

这个动画对于向左滑动的页面使用默认的滑动动画,而对于从右侧滑入的页面使用深度动画。该动画淡出页面,并且线性地缩小它的大小。

Depth动画

Note:

在深度动画过程中,默认的动画(屏幕滑动)仍然发生,所以你必须用一个负X方向来抵消屏幕滑动,例如

view.setTranslationX(-1 * view.getWidth() * position);

下面的例子展示了如何在一个工作页面中,抵消默认的屏幕滑动动画:

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);
}
}
}

【Android Developers Training】 70. 使用ViewPager实现屏幕滑动的更多相关文章

  1. 【Android Developers Training】 12. 支持不同屏幕

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  2. 【Android Developers Training】 68. 序言:添加动画

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  3. 【Android Developers Training】 10. 序言:支持不同设备

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  4. 【Android Developers Training】 60. 在你的UI中显示位图

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  5. 【Android Developers Training】 58. 缓存位图

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  6. 【Android Developers Training】 55. 序言:高效显示位图

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  7. 【Android Developers Training】 9. 覆盖于布局之上的Action Bar

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  8. 【Android Developers Training】 7. 添加Action Buttons

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  9. 【Android Developers Training】 4. 启动另一个Activity

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

随机推荐

  1. Tomcat--各个目录详解(二)

    Tomcat整体目录: 一.bin文件(存放启动和关闭tomcat脚本) 其中.bat和.sh文件很多都是成对出现的,作用是一样的,一个是Windows的,一个是Linux. ① startup文件: ...

  2. 由typedef和函数指针引起的危机

    由typedef和函数指针引起的危机 昨天阅读了大神强哥的代码,发现里面用到了函数指针,也用到的typedef.本来我自以为对这两个概念有一定的认识,但是突然发现这两个东西居然用到了一起!!!!(在一 ...

  3. 用户登录安全框架shiro—用户的认证和授权(一)

     ssm整合shiro框架,对用户的登录操作进行认证和授权,目的很纯粹就是为了增加系统的安全线,至少不要输在门槛上嘛. 这几天在公司独立开发一个供公司内部人员使用的小管理系统,客户不多但是登录一直都是 ...

  4. 无限极分类class

    class Category { /** * 返回一维数组 * @static * @param array $cate 要递归的数组 * @param string $html 子级分类前要显示的缩 ...

  5. 机器学习:Python实现聚类算法(一)之K-Means

    1.简介 K-means算法是最为经典的基于划分的聚类方法,是十大经典数据挖掘算法之一.K-means算法的基本思想是:以空间中k个点为中心进行聚类,对最靠近他们的对象归类.通过迭代的方法,逐次更新各 ...

  6. 【Java并发系列03】ThreadLocal详解

    img { border: solid 1px } 一.前言 ThreadLocal这个对象就是为多线程而生的,没有了多线程ThreadLocal就没有存在的必要了.可以将任何你想在每个线程独享的对象 ...

  7. angular实现的按钮提示

    用angularJS简单实现了一个小的按钮提示,html文件中需要引入jquery.js和angular.js css代码: <style type="text/css"&g ...

  8. Python3.6_x86通过FFpmeg获取视频或音频的时长和分辨率

    前言 前段时间公司在做流媒体服务,与许多厂家合作拿了许多视频过来,现在要对这些视频文件进行整理,通过特殊的编码排列,获取他们的时长以及分辨率,这里我遇到一个大坑,请往下面看. # -*- coding ...

  9. 【Python中if __name__ == '__main__': 的解析】

    在很多Python代码中,在代码的最下方会看到  if __name__ == '__main__':,这段代码到底有什么用呢? 在理解这个语句的作用前,需要知道的是,一般的Python文件后缀为.p ...

  10. Android Apk的反编译和加密

    这几天在上海出差,忙里偷闲学习了一下Apk的反编译工具的基本使用.下面就简单介绍一下如何将我们从网上下载的Apk文件进行反编译得到我们想要获得的资源文件和源码. Android的应用程序APK文件说到 ...