注:本文翻译自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. Jdk1.6 JUC源码解析(1)-atomic-AtomicXXX

    转自:http://brokendreams.iteye.com/blog/2250109 功能简介: 原子量和普通变量相比,主要体现在读写的线程安全上.对原子量的是原子的(比如多线程下的共享变量i+ ...

  2. 全景智慧城市——NOW!!!VRSHOPPING颠覆你的购物认知!

    互联网+时代,人们对现有的网络资源已经不再感冒,一般的图片.文字信息已经无法满足人们对互联网的需求,虚拟现实.身临其境的体验是不可小觑的发展趋势,尤其是VR逛街.购物,更会深入人心,再次改变人们的生活 ...

  3. MySQL编译安装错误提示合集

    1>安装mysql在初始化的时候,出现/usr/local/mysql/bin/mysqld:error while loading shared libraries:libaio.so.1 : ...

  4. RUN vs CMD vs ENTRYPOINT - 每天5分钟玩转 Docker 容器技术(17)

    RUN.CMD 和 ENTRYPOINT 这三个 Dockerfile 指令看上去很类似,很容易混淆.本节将通过实践详细讨论它们的区别. 简单的说: RUN 执行命令并创建新的镜像层,RUN 经常用于 ...

  5. Java并发编程:Callable、Future和FutureTask的实现

    启动线程执行任务,如果需要在任务执行完毕之后得到任务执行结果,可以使用从Java 1.5开始提供的Callable和Future 下面就分析一下Callable.Future以及FutureTask的 ...

  6. Natas Wargame Level20 Writeup(会话状态注入/篡改)

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAArMAAACmCAYAAADJYwcaAAAABHNCSVQICAgIfAhkiAAAIABJREFUeF

  7. Hibernate map enum type

    1. Bean @Entity @Table(name = "entities") public class Entities { public enum entityType { ...

  8. yum 安装rabbitMQ

    环境:linux centos6.5 1.安装erlang 下载rpm仓库:wget http://packages.erlang-solutions.com/erlang-solutions-1.0 ...

  9. 一天搞定CSS:支持IE的Layout布局--16

    1.BFC和Layout区别: BFC和Layout的作用是一样的,只是对浏览器的支持不同而已. BFC- -标准浏览器所具有的 Layout- -IE浏览器所具有的 BFC详解地址:http://b ...

  10. 模板C++ 03图论算法 2最短路之全源最短路(Floyd)

    3.2最短路之全源最短路(Floyd) 这个算法用于求所有点对的最短距离.比调用n次SPFA的优点在于代码简单,时间复杂度为O(n^3).[无法计算含有负环的图] 依次扫描每一点(k),并以该点作为中 ...