在兩個完整的界面之間進行切換是非常常見的效果,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);
}
}
}