引導頁庫slidingtutorial-android介紹

zhaoqinliang 8年前發布 | 14K 次閱讀 安卓開發 Android開發 移動開發

來自: http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2016/0303/4030.html

先來看看用法。

這里的用法來自于該項目在github上的demo示例。

為了便于講解。首先看看sample項目的代碼結構:

設置主界面

首先你需要自定義一個fragment。

自定義一個繼承自SimplePagerFragment的fragment,這里叫 CustomPresentationPagerFragment

既然是繼承于SimplePagerFragment,為什么叫CustomPresentationPagerFragment而不叫CustomSimplePagerFragment呢?

這是因為SimplePagerFragment其實也是PresentationPagerFragment的子類,不過它寫死了界面上的幾個東西。當然了名字怎么取還是取決于你。

package com.cleveroad.slidingtutorial.sample;

import android.graphics.Color; import android.support.annotation.ColorInt; import android.support.v4.content.ContextCompat; import android.view.View; import android.widget.Toast;

import com.cleveroad.slidingtutorial.PageFragment; import com.cleveroad.slidingtutorial.SimplePagerFragment;

public class CustomPresentationPagerFragment extends SimplePagerFragment {

@Override protected int getPagesCount() { return 6; }

@Override protected PageFragment getPage(int position) { position %= 3; if (position == 0) return new FirstCustomPageFragment(); if (position == 1) return new SecondCustomPageFragment(); if (position == 2) return new ThirdCustomPageFragment(); throw new IllegalArgumentException("Unknown position: " + position); }

@ColorInt @Override protected int getPageColor(int position) { if (position == 0) return ContextCompat.getColor(getContext(), android.R.color.holo_orange_dark); if (position == 1) return ContextCompat.getColor(getContext(), android.R.color.holo_green_dark); if (position == 2) return ContextCompat.getColor(getContext(), android.R.color.holo_blue_dark); if (position == 3) return ContextCompat.getColor(getContext(), android.R.color.holo_red_dark); if (position == 4) return ContextCompat.getColor(getContext(), android.R.color.holo_purple); if (position == 5) return ContextCompat.getColor(getContext(), android.R.color.darker_gray); return Color.TRANSPARENT; }

@Override protected boolean isInfiniteScrollEnabled() { return true; }

@Override protected boolean onSkipButtonClicked(View skipButton) { Toast.makeText(getContext(), "Skip button clicked", Toast.LENGTH_SHORT).show(); return true; } }</pre>

其中,getPagesCount()返回引導界面的個數。getPage()方法則用于設置每一個界面所對應的PageFragment

。在demo中我們定義了三個PageFragment,如下:

@Override
protected PageFragment getPage(int position) {
   position %= 3;
   if (position == 0)
      return new FirstCustomPageFragment();
   if (position == 1)
      return new SecondCustomPageFragment();
   if (position == 2)
      return new ThirdCustomPageFragment();
   throw new IllegalArgumentException("Unknown position: " + position);
}

因為只定義了三個引導頁面,而getPagesCount返回的是6,所以這里每個頁面都被用了兩次。

但是,這里只是定義了每個引導頁面,還需要定義每個頁面的背景顏色。

@Override
protected int getPageColor(int position) {
   if (position == 0)
      return ContextCompat.getColor(getContext(), android.R.color.holo_orange_dark);
   if (position == 1)
      return ContextCompat.getColor(getContext(), android.R.color.holo_green_dark);
   if (position == 2)
      return ContextCompat.getColor(getContext(), android.R.color.holo_blue_dark);
   if (position == 3)
      return ContextCompat.getColor(getContext(), android.R.color.holo_red_dark);
   if (position == 4)
      return ContextCompat.getColor(getContext(), android.R.color.holo_purple);
   if (position == 5)
      return ContextCompat.getColor(getContext(), android.R.color.darker_gray);
   return Color.TRANSPARENT;
}

當然了,每個頁面本身也是可以設置背景顏色的,但是slidingtutorial的設計理念是讓具體的頁面盡可能的簡單,所以把背景顏色分離出來了。

接下來是一個意外驚喜,通過它可以設置引導頁是否無限循環:

<pre>@Override protected boolean isInfiniteScrollEnabled() { return true; }</pre>

顯然我們的demo里面是需要它無限循環。

CustomPresentationPagerFragment上面有一個跳過按鈕,我們需要為這個按鈕設置點擊事件:

@Override
protected boolean onSkipButtonClicked(View skipButton) {
   Toast.makeText(getContext(), "Skip button clicked", Toast.LENGTH_SHORT).show();
   return true;
}

這個關于引導界面的主界面就設置完了,總結一下就是,設置頁面個數,設置具體的每一頁、設置每一頁的背景顏色、設置是否無限循環、設置跳過按鈕的點擊事件。代碼很少。接下來把這個Fragment放在activity中就是了。這個不再講解。

設置引導頁的單個界面

其實這里的頁面內容主要是負責前景元素,不包括背景顏色。

單個引導頁面對應的是PageFragment。從前面的代碼中我們知道,demo總共自定義了三個PageFragment,分別是

FirstCustomPageFragment  

SecondCustomPageFragment

ThirdCustomPageFragment

這里以FirstCustomPageFragment為例,看看PageFragment(每個具體的引導頁面)是如何自定義的。

public class FirstCustomPageFragment extends PageFragment {

@Override protected int getLayoutResId() { return R.layout.fragment_page_first; }

@Override protected TransformItem[] provideTransformItems() { return new TransformItem[]{ new TransformItem(R.id.ivFirstImage, true, 20), new TransformItem(R.id.ivSecondImage, false, 6), new TransformItem(R.id.ivThirdImage, true, 8), new TransformItem(R.id.ivFourthImage, false, 10), new TransformItem(R.id.ivFifthImage, false, 3), new TransformItem(R.id.ivSixthImage, false, 9), new TransformItem(R.id.ivSeventhImage, false, 14), new TransformItem(R.id.ivEighthImage, false, 7) }; } }</pre>

就是這么多點代碼,只做兩件事:

  1. 設置這個頁面的布局資源

  2. 為界面上的各個元素設置移動因素,包括方向和系數。一個TransformItem就是一個界面元素,其中它的第一個參數是界面元素對應的id,第二個參數是是否反向,true表示要,false表示不,第三個參數是移動系數。系數越大移動越慢,為一個界面上的不同元素設置不同的方向和系數,就能形成視差效果。

我們來看看第一個頁面對應的xml布局:

<?xml version="1.0" encoding="utf-8"?>
<android.support.percent.PercentRelativeLayout
    android:id="@+id/rootFirstPage"
    xmlns:android="

<ImageView
    android:id="@+id/ivFirstImage"

    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerInParent="true"

    android:src="@mipmap/s_0_1"

    app:layout_heightPercent="35%"
    app:layout_widthPercent="50%"/>

<ImageView
    android:id="@+id/ivSecondImage"

    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentEnd="true"
    android:layout_alignParentRight="true"

    android:src="@mipmap/s_0_2"

    app:layout_heightPercent="10%"
    app:layout_marginRightPercent="12%"
    app:layout_marginTopPercent="27%"
    app:layout_widthPercent="12%"/>


<ImageView
    android:id="@+id/ivThirdImage"

    android:layout_width="wrap_content"
    android:layout_height="wrap_content"

    android:src="@mipmap/s_0_3"

    app:layout_heightPercent="25%"
    app:layout_marginLeftPercent="14%"
    app:layout_marginTopPercent="49%"
    app:layout_widthPercent="30%"/>

<ImageView
    android:id="@+id/ivFourthImage"

    android:layout_width="wrap_content"
    android:layout_height="wrap_content"

    android:src="@mipmap/s_0_4"

    app:layout_heightPercent="15%"
    app:layout_marginLeftPercent="14%"
    app:layout_marginTopPercent="39%"
    app:layout_widthPercent="20%"/>

<ImageView
    android:id="@+id/ivFifthImage"

    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerHorizontal="true"

    android:src="@mipmap/s_0_5"

    app:layout_heightPercent="15%"
    app:layout_marginTopPercent="22%"
    app:layout_widthPercent="45%"/>

<ImageView
    android:id="@+id/ivSixthImage"

    android:layout_width="wrap_content"
    android:layout_height="wrap_content"

    android:src="@mipmap/s_0_6"

    app:layout_heightPercent="6%"
    app:layout_marginLeftPercent="4%"
    app:layout_marginTopPercent="26%"
    app:layout_widthPercent="6%"/>

<ImageView
    android:id="@+id/ivSeventhImage"

    android:layout_width="wrap_content"
    android:layout_height="wrap_content"

    android:src="@mipmap/s_0_7"

    app:layout_heightPercent="8%"
    app:layout_marginLeftPercent="14%"
    app:layout_marginTopPercent="25%"
    app:layout_widthPercent="9%"/>

<ImageView
    android:id="@+id/ivEighthImage"

    android:layout_width="wrap_content"
    android:layout_height="wrap_content"

    android:src="@mipmap/s_0_8"

    app:layout_heightPercent="6%"
    app:layout_marginLeftPercent="77%"
    app:layout_marginTopPercent="38%"
    app:layout_widthPercent="8%"/>

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:layout_centerHorizontal="true"

    android:gravity="center"

    android:text="@string/text_web_ceo"
    android:textColor="@android:color/white"
    android:textSize="@dimen/text_size_large"

    app:layout_heightPercent="15%"
    app:layout_marginBottomPercent="11%"
    app:layout_widthPercent="45%"/>

</android.support.percent.PercentRelativeLayout></pre>

使用的居然是百分比布局。不過用什么布局沒有關系。

小結

整個用法就是這么簡單,你把主Fragment放到activity里就可以了。使用這個庫的好處是,我們不用為每個頁面專門寫邏輯,只要指定好頁面元素的id ,方向和系數就好了。

技巧

這個庫的亮點在于對抽象方法的使用。就拿PageFragment來說,有兩個抽象方法:provideTransformItems()以及getLayoutResId(),要建立一個新的頁面,只需實現這兩個方法就可以了。

不過我仔細想了下,這兩個方法的作用就是提供兩個(或者說是兩組)變量的值。為什么不用set的形式呢,那樣的話都不用去自定義三個類。就新建一個類,然后調用各自的set方法。各位可以嘗試下。但是可以肯定的是,使用set的方式代碼不會太好看。

還有一個東西就是 transformItem ,它是抽象出來的一個東西,在界面上并沒有對應的實體。代表一個被移動元素的引用以及相關數據,比如系數和移動方向。我們看看 slidingtutorial-android 是如何利用它來變換頁面上的元素的。

首先,為了單獨對頁面的元素做錯落有致的移動,在PresentationPagerFragment中定義了一個FragmentTransformer,它繼承自PageTransformer:

/**

  • Implementation of {@link android.support.v4.view.ViewPager.PageTransformer} that dispatch
  • transform page event whenever a visible/attached page is scrolled. */ private class FragmentTransformer implements ViewPager.PageTransformer {

    public void transformPage(View view, float position) { Object obj = view.getTag(R.id.page_fragment); if (obj instanceof PageFragment) {

      ((PageFragment) obj).transformPage(view, position);
    

    } } }</pre>

    對ViewPager熟悉的同學應該對PageTransformer很熟悉,它可以利用自己transformPage(View view, float position)方法中的position參數的值去設置view參數的屬性,常見的是設置透明度,x/y信息等。可以看到在FragmentTransformer把transformPage里的參數信息傳遞給了PageFragment的transformPage()方法。

    PageFragment的transformPage()方法定義如下:

    void transformPage(View view, float position) {
    holder.transformPage(view.getWidth(), position);
    }

    再一次的,PageFragment的transformPage()方法又把這些信息傳遞給holder.transformPage()

    這個holder是LayersHolder對象,LayersHolder的定義如下:

    class LayersHolder {
    TransformItem[] transformItems;

    public LayersHolder(View view, TransformItem[] transformItems) { this.transformItems = transformItems;

    for (TransformItem transformItem : transformItems) {

      transformItem.setView(view.findViewById(transformItem.getViewResId()));
    

    } }

    /**

    • Method that apply a custom transformation to the page views *
    • @param pageWidth pageWidth
    • @param position Position of page relative to the current front-and-center
    • position of the pager. 0 is front and center. 1 is one full
    • page position to the right, and -1 is one page position to the left. / public void transformPage(int pageWidth, float position) { for (TransformItem transformItem : transformItems) { float translationX = (position) (pageWidth / transformItem.getShiftCoefficient());

      transformItem.getView().setTranslationX(transformItem.isReverseShift() ? -translationX : translationX); } } }</pre>

      在LayersHolder的transformPage里面,它直接遍歷了所有的transformItem數組。然后根據傳遞進來的數據,結合自身的系數和移動方向,設置了自己的x信息。

    總結

    在所有的引導頁庫中, slidingtutorial-android 算是功能比較完善,用法也和簡單的一個庫。

    </div>

 本文由用戶 zhaoqinliang 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!