使用ViewPager 实现多屏滑动(Screen Slides)
原文链接
本篇博文介绍如何使用ViewPager
实现屏幕滑动。下面是其动画效果展示:
- 创建新项目,并且创建下面四个文件
- src/ScreenSlidePageFragment.java
- src/ScreenSlideActivity.java
- layout/activity_screen_slide.xml
- layout/fragment_screen_slide_page.xml
- src/ScreenSlidePageFragment.java
创建视图
创建一个布局文件,你可以在其添加一个Fragment
用来展示内容。我们的例子使用了TextView
来展示文本内容:
<!-- 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
,只需要实现onCreateView()
方法。当你需要向用户展示一个新的page
时,只需在父Activity
创建一个新的实例:
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
内置了滑动手势,可以进行页面的切换,并且将Screen Slides
作为其默认的动画效果,所以你不需要创建其他任何代码。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
,对其进行以下操作:
- 将其
content view
设置为ViewPager
的布局文件。 创建一个
Adapter
继承FragmentStatePagerAdapter
,覆写getItem()
方法用来返回Page
实例,以及getCount()
方法,返回Page
数量。将
PagerAdapter
与ViewPager
连接。监听设备
返回键
,当用户点击时,返回之前的页面
,如果已经是第一个页面
,则返回之前的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自定义动画效果
为了实现与默认滑动动画不同的动画效果,需要实现ViewPager.PageTransformer
接口。该接口向外只暴露一个方法–transformPage()
。当屏幕的任何一个点进行了移动,任何可见的页面以及刚刚消失的页面都会调用这个方法。例如,如果第三个页面可见,并且用户将其向第四个页面进行拖动,则第二个,第三个,第四个页面都会调用一次transformPage()
方法。
实现了transformPage()
方法以后,就可以创建自定义的滑动动画。根据页面在屏幕中显示的位置,决定哪个页面将会被移动。transformPage()
方法中包含 position
参数。
position
参数表示当前页面相对于屏幕中心的位置。当用户滑动时,该参数动态的变化。当屏幕完整的显示时,position
的值为0
,当屏幕刚刚被拉出右侧屏幕时,position
的值为1
。如果用户将Page
拖动到一半,此时Page 1
和 Page 2
各显示一半,则Page 1
的position
值为-0.5
,Page 2
的position
值为0.5
。根据position
值,可以通过setAlpha()
,setTranslationX()
,setScaleY()
等方法创建自定义的动画效果。
通过调用setPageTransformer()
方法,可以设置自定义动画效果。
下面举两个例子:
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动画效果
Note: During the depth animation, the default animation (a screen slide) still takes place, so you must counteract the screen slide with a negative X translation. For example:
在Depth动画效果执行期间,默认的
Screen Slide
动画效果仍然在执行,必须抵消掉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);
}
}
}