在两个完整的界面之间进行切换是非常常见的效果,Android提供的ViewPager使我们实现起来非常的便捷,在这里,我将讲解如何用ViewPager实现切换,以及如何自定义切换的动画效果。
一、实现屏幕切换
其实非常简单,实际上我们只需要四个文件即可实现效果,首先创建一个Fragment所使用的布局文件layout/fragment_screen_slide_page,布局文件中包含一个显示文本的TextView:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/contentView"
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子类,它从onCreateView() 方法中返回之前创建的布局。无论何时如果我们需要为用户展示一个新的页面,可以在它的父Activity中创建该Fragment的实例:
ScreenSlidePageFragment.java
package com.example.power.mytest;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
/**
* Created by Power on 2018/10/22.
*/
public class ScreenSlidePageFragment extends Fragment {
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
ViewGroup rootView = (ViewGroup)inflater.inflate(
R.layout.fragment_screen_slide_page, container, false
);
return rootView;
}
}
ViewPager有内建的滑动手势进行页面的转换,而且默认有滑动效果。我们需要使用PagerAdapter为ViewPager补充新的页面,这就需要使用到新建的Fragment。
activity_screen_slide.xml
<?xml version="1.0" encoding="utf-8"?>
<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,其中,继承自FragmentStatePagerAdapter抽象类的类,然后实现getItem()方法来把ScreenSlidePageFragment实例作为新页面补充进来。PagerAdapter还需要实现getCount()方法,它返回 Adapter将要创建页面的总数(例如5个)。并且处理Back按钮,按下变为在虚拟的Fragment栈中回退。如果用户已经在第一个页面了,则在Activity的回退栈(back stack)中回退。
ScreenSlidePagerActivity.java
package com.example.power.mytest;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
/**
* Created by Power on 2018/10/22.
*/
public class ScreenSlidePagerActivity extends FragmentActivity {
private static final int NUM_PAGES = 5;
private ViewPager mPager;
private PagerAdapter mPagerAdapter;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_screen_slide);
mPager = (ViewPager)findViewById(R.id.pager);
mPagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager());
mPager.setAdapter(mPagerAdapter);
mPager.setPageTransformer(true, new DepthPageTransformer());
}
@Override
public void onBackPressed() {
if(mPager.getCurrentItem() == 0){
super.onBackPressed();
}else{
mPager.setCurrentItem(mPager.getCurrentItem() - 1);
}
}
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;
}
}
}
二、自定义切换动画
按照上面的步骤运行后,效果就可以看见了,但是如果我们想自定义切换的效果,要怎么做呢?其实很简单,我们只需要实现ViewPager.PageTransformer接口,然后把它补充到ViewPager中就行了。ViewPager.PageTransformer接口只暴露一个接口transformPage()。每次界面切换,这个方法都会为每个可见页面(通常只有一个页面可见)和刚消失的相邻页面调用一次。例如,第三页可见而且用户向第四页拖动,transformPage()在操作的各个阶段为第二,三,四页分别调用。
在transformPage()的实现中,基于当前屏幕显示的页面的position(position 由transformPage方法的参数给出)决定哪些页面需要被动画转换,这样我们就能创建自己的动画。
但是,在此之前,我们需要先理解ViewPager中的position。position参数表示特定页面相对于屏幕中的页面的位置。它的值在用户滑动页面过程中动态变化。当某一页面填充屏幕,它的值为0。当页面刚向屏幕右侧方向被拖走,它的值为1。如果用户在页面1和页面2间滑动到一半,那么页面1的position为-0.5并且页面2的position为 0.5。根据屏幕上页面的position,我们可以通过setAlpha(),setTranslationX或setScaleX()这些方法设定页面属性来自定义滑动动画。
在实现ViewPager.PageTransformer后,只需要在ScreenSlidePagerActivity.java中添加一行即可(注,XXX代表你的接口名)
mPager.setPageTransformer(true, new XXX());
接下来举例两个实现的接口,可以实现之后看一下效果,理解之后就可以自行定义自己的动画效果了。
ZoomOutPageTransformer
package com.example.power.mytest;
import android.support.v4.view.ViewPager;
import android.view.View;
/**
* Created by Power on 2018/10/22.
*/
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){
view.setAlpha(0);
}else if(position <= 1){
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);
}
view.setScaleX(scaleFactor);
view.setScaleY(scaleFactor);
view.setAlpha(MIN_ALPHA + (scaleFactor - MIN_SCALE) /
(1 - MIN_SCALE) * (1 - MIN_ALPHA));
}else{
view.setAlpha(0);
}
}
}
DepthPageTransformer
package com.example.power.mytest;
import android.support.v4.view.ViewPager;
import android.view.View;
/**
* Created by Power on 2018/10/22.
*/
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){
view.setAlpha(0);
}else if(position <= 0){
view.setAlpha(1);
view.setTranslationX(0);
view.setScaleX(1);
view.setScaleY(1);
}else if(position <= 1){
view.setAlpha(1 - position);
view.setTranslationX(pageWidth * -position);
float scaleFactor = MIN_SCALE
+ (1 - MIN_SCALE) * (1 - Math.abs(position));
view.setScaleX(scaleFactor);
view.setScaleY(scaleFactor);
}else{
view.setAlpha(0);
}
}
}