ViewPage 聯動效果自帶角標

1. 簡介

常常羨慕於別人分享的自定義ViewPager聯動效果。近期項目中用到聯動效果,找來一個不錯的框架用到了項目中。發現有幾個問題:一是難以適應自己項目的設計風格;二是適應自己項目的交互比較麻煩;三是不知所以然導致維護和修改困難。於是決定自己實現,同時掀一掀它的內幕。

下圖是我們的實現目標:
ViewPager導航聯動帶角標

2. 要點

2.1 角標如何佈局

因爲需要在每一個導航的 tab 右上角加上角標。所以需要寫好角標的佈局。因爲需要讓角標始終在文字的右上角,於是我就想到了 RelativeLayout 相對佈局,它可以設置角標的相對位置,非常適合現在這個場景(當然 ConstraintLauout 也可以)。佈局代碼如下示例:
layout/layout_tab_cell_num.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/rl_tab_cell"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingLeft="2dp"
	android:paddingRight="2dp">

<TextView
    android:id="@+id/tv_tab_name"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerInParent="true"
    android:text="報送"
    android:textColor="#ffffff"
    android:textSize="16dp"
    android:alpha="0.6"
    android:layout_marginLeft="10dp"
    android:layout_marginRight="10dp"
    />


<TextView
    android:id="@+id/tv_msg_num"
    android:layout_width="wrap_content"
    android:layout_height="16dp"
    android:minWidth="16dp"
    android:background="@drawable/shape_tab_msg_bg_red"
    android:layout_gravity="center"
    android:visibility="gone"
    tools:visibility="visible"
    android:paddingLeft="4dp"
    android:paddingRight="4dp"
    android:paddingBottom="0.5dp"
    android:gravity="center"
    android:lines="1"
    android:maxLines="1"
    android:textStyle="bold"
    android:text="99"
    android:textSize="10dp"
    android:textColor="@color/color_white"
    android:layout_toRightOf="@id/tv_tab_name"
    android:layout_above="@id/tv_tab_name"
    android:layout_marginLeft="-14dp"
    android:layout_marginBottom="-12dp"
    />

    <TextView
        android:id="@+id/tv_red_dot"
        android:layout_width="8dp"
        android:layout_height="8dp"
        android:background="@drawable/shape_tab_msg_bg_red"
        android:layout_gravity="center"
        android:visibility="gone"
        tools:visibility="gone"
        android:layout_toRightOf="@id/tv_tab_name"
        android:layout_above="@id/tv_tab_name"
        android:layout_marginLeft="-12dp"
        android:layout_marginBottom="-8dp"
        />

</RelativeLayout>

ViewPager 角標
上面佈局代碼中,通過

android:layout_toRightOf="@id/tv_tab_name"
android:layout_above="@id/tv_tab_name"

控制角標數字或角標紅點的位置,通過

android:layout_marginLeft="-12dp"
android:layout_marginBottom="-8dp"

控制角標向 tab 文字內部縮進(相對於文字向左向下縮進)。

drawable/shape_tab_msg_bg_red.xml 的佈局如下,common:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- 內部顏色 -->
    <solid android:color="@color/color_red" />
    <!-- 邊緣線條顏色 -->
    <stroke
        android:width="1dp"
        android:color="@color/common_color" />
    <!-- 圓角的幅度 -->
    <corners android:radius="100dp" />

</shape>

注意: 邊緣線條顏色 最好 與背景色一致

2.2 如何與Indicator實現聯動

Tab 切換需要一個指示器,用於明確指示我們處在那個頁面,我們需要讓 ViewPager 的頁面和 Tab樣式和指示器一一對應。
我們可以使用動畫,但是有麻煩,如果在頁面切換時使用動畫去實現,我們很難保證指示器的動畫能與 ViewPager 的頁面切換節奏保持一致。節奏不一致,就會不流暢。
怎麼辦呢?我注意到 ViewPager 可以添加一個監聽:addOnPageChangeListener(OnPageChangeListener)
onPageChangeListener 的源碼如下:

    /**
     * Callback interface for responding to changing state of the selected page.
     */
    public interface OnPageChangeListener {

        /**
         * This method will be invoked when the current page is scrolled, either as part
         * of a programmatically initiated smooth scroll or a user initiated touch scroll.
         *
         * @param position Position index of the first page currently being displayed.
         *                 Page position+1 will be visible if positionOffset is nonzero.
         * @param positionOffset Value from [0, 1) indicating the offset from the page at position.
         * @param positionOffsetPixels Value in pixels indicating the offset from position.
         */
        void onPageScrolled(int position, float positionOffset, int positionOffsetPixels);

        /**
         * This method will be invoked when a new page becomes selected. Animation is not
         * necessarily complete.
         *
         * @param position Position index of the new selected page.
         */
        void onPageSelected(int position);

        /**
         * Called when the scroll state changes. Useful for discovering when the user
         * begins dragging, when the pager is automatically settling to the current page,
         * or when it is fully stopped/idle.
         *
         * @param state The new scroll state.
         * @see ViewPager#SCROLL_STATE_IDLE
         * @see ViewPager#SCROLL_STATE_DRAGGING
         * @see ViewPager#SCROLL_STATE_SETTLING
         */
        void onPageScrollStateChanged(int state);
    }

onPageSelectedonPageScrollStateChanged 我們應該很熟悉了,
onPageSelected 在新頁面被選擇示會被調用,動畫未必完成;
onPageScrollStateChanged 在當滾動狀態改版時調用,有三種狀態。
還有一個方法比較少用到:
onPageScrolled 在當前頁面被滾動時調用,有三個參數:

  • position
    翻譯:當前正在顯示的第一頁的位置索引。如果 positionOffset 不爲 0,position+1 頁會顯示。
    事實上:當頁面正在滾動時,即滾動未完成,postion 表示 左邊頁面的下標,無論是左滑還是右滑,postion+1 即是右邊頁面的下標。
  • positionOffset
    從[0, 1)的值,表示頁面的偏移量。
  • positionOffsetPixels
    偏移量的 pixel 值。

通過 onPageScrolled 方法的 position 和 positionOffset 我們可以算出 指示器(Indicator View)
的位置。如下所示:
indicatorCenterX
圖爲指示器中心點位置計算:

int dist = (leftCell.getWidth() + rightCell.getWidth()) / 2;
float indicatorCenterX = leftCell.getLeft() + leftCell.getWidth() / 2 + dist * positionOffset;
int translationX = (int) (indicatorCenterX - mIndicatorView.getWidth() / 2);
mIndicatorView.setTranslationX(translationX);

positionOffset 是隨着頁面的切換而不斷變化的,因此可以,通過setTranslationX 設置 indicatorView 的位移量 translationX 來控制 indicatorView 的移動。

3. 實現

3.1 佈局

導航欄 tab 的佈局上面已經給出,下面是導航、指示器、ViewPager的佈局:
layout/activity_nav.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".nav.NavActivity">

    <HorizontalScrollView
        android:id="@+id/hsv_nav_bar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/common_color"
        android:scrollbars="none">


        <FrameLayout
            android:id="@+id/fl_nav_frame"
            android:layout_width="wrap_content"
            android:layout_height="44dp">

            <LinearLayout
                android:id="@+id/ll_tab_group"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:orientation="horizontal">

            </LinearLayout>

            <View
                android:id="@+id/indicator_view"
                android:layout_width="18dp"
                android:layout_height="2dp"
                android:background="@color/color_white"
                android:layout_gravity="bottom"
                android:layout_marginBottom="4dp"/>

        </FrameLayout>

    </HorizontalScrollView>

    <android.support.v4.view.ViewPager
        android:id="@+id/vp_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />


</LinearLayout>

佈局很簡單,如果tab數量固定且有限,不需要水平滾動條,可以把水平滾動條去掉,在@+id/ll_tab_group 中,根據上面角標佈局,寫自己的 tab 組合。

3.2 導航欄

第一步:準備數據

private void initData() {
    mFuncEntityList.add(new FuncEntity("關注", 0));
    mFuncEntityList.add(new FuncEntity("推薦", 1));
    mFuncEntityList.add(new FuncEntity("視頻", 2));
    mFuncEntityList.add(new FuncEntity("熱點", 3));
    mFuncEntityList.add(new FuncEntity("直播", 4));
    mFuncEntityList.add(new FuncEntity("精品課", 5));
    mFuncEntityList.add(new FuncEntity("娛樂", 6));
    mFuncEntityList.add(new FuncEntity("科技", 7));
    mFuncEntityList.add(new FuncEntity("懂車帝", 8));
    mFuncEntityList.add(new FuncEntity("財經", 9));
    mFuncEntityList.add(new FuncEntity("國際", 10));
    mFuncEntityList.add(new FuncEntity("體育", 11));
    mFuncEntityList.add(new FuncEntity("問答", 12));
}

數據類如下

import java.io.Serializable;

public class FuncEntity implements Serializable {


    /**
     * funName : 關注
     * id : 2
     */

    private String funName;
    private int id;


    public FuncEntity() {
    }

    public FuncEntity(String funName, int id) {
        this.funName = funName;
        this.id = id;
    }


    public String getFunName() {
        return funName;
    }

    public void setFunName(String funName) {
        this.funName = funName;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }
}

第二步:初始化導航欄,爲 ViewPager 設置適配器

    @Override
    public void initView() {
        mFragmentManager = getSupportFragmentManager();
        //find views
        mHsvNavBar = (HorizontalScrollView) findViewById(R.id.hsv_nav_bar);
        mFlNavFrame = (FrameLayout) findViewById(R.id.fl_nav_frame);
        mLlTabGroup = (LinearLayout) findViewById(R.id.ll_tab_group);
        mIndicatorView = findViewById(R.id.indicator_view);
        mVpContent = (ViewPager) findViewById(R.id.vp_content);


        //初始化導航欄
        for (int i = 0; i < mFuncEntityList.size(); i++) {
            FuncEntity funcEntity = mFuncEntityList.get(i);
            RelativeLayout rlTabCell = (RelativeLayout) getLayoutInflater().inflate(R.layout.layout_tab_cell_num, mLlTabGroup, false);
            TextView tvTabName = (TextView) rlTabCell.findViewById(R.id.tv_tab_name);
            TextView tvMsgNum = (TextView) rlTabCell.findViewById(R.id.tv_msg_num);
            TextView tvRedDot = (TextView) rlTabCell.findViewById(R.id.tv_red_dot);
            tvMsgNum.setVisibility(View.GONE);
            tvRedDot.setVisibility(View.GONE);
            tvTabName.setText(funcEntity.getFunName());
            rlTabCell.setTag(funcEntity.getId());
            mLlTabGroup.addView(rlTabCell);
        }

        mPagerAdapter = new FragmentPagerAdapter(mFragmentManager) {
            @Override
            public Fragment getItem(int position) {
                return getFuncFragment(mFuncEntityList.get(position));
            }

            @Override
            public int getCount() {
                return mFuncEntityList.size();
            }
        };
        mVpContent.setAdapter(mPagerAdapter);

		//請求角標數量
        for (FuncEntity funcEntity : mFuncEntityList) {
            requestMsgNum(funcEntity);
        }

    }
    
    /**
     * Map集合,關聯FuncEntity和Fragment,保存二者鍵值對,使二者具有一一對應關係。
     */
    private Map<FuncEntity, BaseFuncFragment> mFuncFragmentMap = new HashMap<>();

    private BaseFuncFragment getFuncFragment(FuncEntity funcEntity) {
        BaseFuncFragment funcFragment = mFuncFragmentMap.get(funcEntity);
        if (funcFragment == null) {
            funcFragment = CommFuncFragment.newInstance(funcEntity);
            if (funcFragment != null) {
                mFuncFragmentMap.put(funcEntity, funcFragment);
            }
        }

        return funcFragment;

    }

    Random random = new Random();

    private int getMsgNum() {
        int num = random.nextInt(99) + 1;
//        Log.i("NavActivity", "getMsgNum: " + num);
        return num;
    }

    /**
     *  請求角標數量
     */
    private void requestMsgNum(FuncEntity funcEntity) {
        //請求角標數量
        //......

        //更新角標
        updateTabNum(funcEntity.getId(), getMsgNum());
    }

    /**
     * 更新數字
     *
     * @param tabId
     * @param tabNum
     */
    public void updateTabNum(int tabId, int tabNum) {
        View tabView = mLlTabGroup.findViewWithTag(tabId);
        if (tabView != null) {
            TextView tvMsgNum = tabView.findViewById(R.id.tv_msg_num);
            String tabNumStr = tabNum > 99 ? String.valueOf(99).concat("+") : String.valueOf(tabNum);
            tvMsgNum.setText(tabNumStr);
            tvMsgNum.setVisibility(tabNum == 0 ? View.GONE:View.VISIBLE);
        }
    }

    /**
     * 清除角標
     * @param tabId
     */
    public void clearTabNum(int tabId) {
        updateTabNum(tabId, 0);
    }

3.3 導航欄與ViewPager聯動

需要爲每一個 tab 設置點擊監聽:

for (int i = 0; i < mLlTabGroup.getChildCount(); i++) {
    final int pos = i;
    mLlTabGroup.getChildAt(i).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            mVpContent.setCurrentItem(pos);
        }
    });
}

3.4 tab切換效果


mVpContent.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
    private int lastPost = 0;

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        super.onPageScrolled(position, positionOffset, positionOffsetPixels);

        if (Math.abs(position - lastPost) > 0) {
            int llPos = lastPost;
            int lrPos = lastPost == mFuncEntityList.size() - 1 ? lastPost : lastPost + 1;
            int clPos = position;
            int crPos = position == mFuncEntityList.size() - 1 ? position : position + 1;
            if (llPos != clPos && llPos != crPos) {
                mLlTabGroup.getChildAt(llPos).findViewById(R.id.tv_tab_name).setAlpha(0.6f);
            }
            if (lrPos != clPos && lrPos != crPos) {
                mLlTabGroup.getChildAt(lrPos).findViewById(R.id.tv_tab_name).setAlpha(0.6f);
            }
        }

        //設置指示器位移
        RelativeLayout leftCell = (RelativeLayout) mLlTabGroup.getChildAt(position);
        int rightPos = position == mFuncEntityList.size() - 1 ? position : position + 1;
        RelativeLayout rightCell = (RelativeLayout) mLlTabGroup.getChildAt(rightPos);
        float dist = (leftCell.getWidth() + rightCell.getWidth()) / 2f;
        float indicatorCenterX = leftCell.getLeft() + leftCell.getWidth() / 2f + dist * positionOffset;
        int translationX = (int) (indicatorCenterX - mIndicatorView.getWidth() / 2f);
        mIndicatorView.setTranslationX(translationX);

        //水平滾動條自動滾動
        mHsvNavBar.scrollTo((int) (indicatorCenterX - mHsvNavBar.getWidth() / 2f), 0);

        //文字透明度
        if (position != rightPos) {
            rightCell.findViewById(R.id.tv_tab_name).setAlpha(0.6f + 0.4f * positionOffset);
            leftCell.findViewById(R.id.tv_tab_name).setAlpha(1f - 0.4f * positionOffset);
        } else {
            leftCell.findViewById(R.id.tv_tab_name).setAlpha(1f - 0.4f * positionOffset);
        }

        lastPost = position;
    }
});

4. 代碼

完整代碼:
NavActivity.java

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.wzhy.viewpagerserial.base.BaseActivity;
import com.wzhy.viewpagerserial.R;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

public class NavActivity extends BaseActivity {

    private HorizontalScrollView mHsvNavBar;
    private FrameLayout mFlNavFrame;
    private LinearLayout mLlTabGroup;
    private View mIndicatorView;
    private ViewPager mVpContent;

    private ArrayList<FuncEntity> mFuncEntityList = new ArrayList<>();
    private FuncEntity mCurrFuncEntity;

    private FragmentManager mFragmentManager;
    private FragmentPagerAdapter mPagerAdapter;

    @Override

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_nav);

        initData();
        initView();
        setListeners();

        //請求角標數量
        for (FuncEntity funcEntity : mFuncEntityList) {
            requestMsgNum(funcEntity);
        }


    }

    private void initData() {
        mFuncEntityList.add(new FuncEntity("關注", 0));
        mFuncEntityList.add(new FuncEntity("推薦", 1));
        mFuncEntityList.add(new FuncEntity("視頻", 2));
        mFuncEntityList.add(new FuncEntity("熱點", 3));
        mFuncEntityList.add(new FuncEntity("直播", 4));
        mFuncEntityList.add(new FuncEntity("精品課", 5));
        mFuncEntityList.add(new FuncEntity("娛樂", 6));
        mFuncEntityList.add(new FuncEntity("科技", 7));
        mFuncEntityList.add(new FuncEntity("懂車帝", 8));
        mFuncEntityList.add(new FuncEntity("財經", 9));
        mFuncEntityList.add(new FuncEntity("國際", 10));
        mFuncEntityList.add(new FuncEntity("體育", 11));
        mFuncEntityList.add(new FuncEntity("問答", 12));


        mCurrFuncEntity = mFuncEntityList.get(0);
    }

    @Override
    public void initView() {
        mFragmentManager = getSupportFragmentManager();
        //find views
        mHsvNavBar = (HorizontalScrollView) findViewById(R.id.hsv_nav_bar);
        mFlNavFrame = (FrameLayout) findViewById(R.id.fl_nav_frame);
        mLlTabGroup = (LinearLayout) findViewById(R.id.ll_tab_group);
        mIndicatorView = findViewById(R.id.indicator_view);
        mVpContent = (ViewPager) findViewById(R.id.vp_content);


        //初始化導航欄
        for (int i = 0; i < mFuncEntityList.size(); i++) {
            FuncEntity funcEntity = mFuncEntityList.get(i);
            RelativeLayout rlTabCell = (RelativeLayout) getLayoutInflater().inflate(R.layout.layout_tab_cell_num, mLlTabGroup, false);
            TextView tvTabName = (TextView) rlTabCell.findViewById(R.id.tv_tab_name);
            TextView tvMsgNum = (TextView) rlTabCell.findViewById(R.id.tv_msg_num);
            TextView tvRedDot = (TextView) rlTabCell.findViewById(R.id.tv_red_dot);
            tvMsgNum.setVisibility(View.GONE);
            tvRedDot.setVisibility(View.GONE);
            tvTabName.setText(funcEntity.getFunName());
            rlTabCell.setTag(funcEntity.getId());
            mLlTabGroup.addView(rlTabCell);
        }

        mPagerAdapter = new FragmentPagerAdapter(mFragmentManager) {
            @Override
            public Fragment getItem(int position) {
                return getFuncFragment(mFuncEntityList.get(position));
            }

            @Override
            public int getCount() {
                return mFuncEntityList.size();
            }
        };
        mVpContent.setAdapter(mPagerAdapter);

    }

    /**
     * Map集合,關聯FuncEntity和Fragment,保存二者鍵值對,使二者具有一一對應關係。
     */
    private Map<FuncEntity, BaseFuncFragment> mFuncFragmentMap = new HashMap<>();

    private BaseFuncFragment getFuncFragment(FuncEntity funcEntity) {
        BaseFuncFragment funcFragment = mFuncFragmentMap.get(funcEntity);
        if (funcFragment == null) {
            funcFragment = CommFuncFragment.newInstance(funcEntity);
            if (funcFragment != null) {
                mFuncFragmentMap.put(funcEntity, funcFragment);
            }
        }

        return funcFragment;

    }

    Random random = new Random();

    private int getMsgNum() {
        int num = random.nextInt(99) + 1;
//        Log.i("NavActivity", "getMsgNum: " + num);
        return num;
    }

    /**
     * 請求角標數量
     */
    private void requestMsgNum(FuncEntity funcEntity) {
        //請求角標數量
        //......

        //更新角標
        updateTabNum(funcEntity.getId(), getMsgNum());
    }

    /**
     * 更新數字
     *
     * @param tabId
     * @param tabNum
     */
    public void updateTabNum(int tabId, int tabNum) {
        View tabView = mLlTabGroup.findViewWithTag(tabId);
        if (tabView != null) {
            TextView tvMsgNum = tabView.findViewById(R.id.tv_msg_num);
            String tabNumStr = tabNum > 99 ? String.valueOf(99).concat("+") : String.valueOf(tabNum);
            tvMsgNum.setText(tabNumStr);
            tvMsgNum.setVisibility(tabNum == 0 ? View.GONE : View.VISIBLE);
        }
    }

    /**
     * 清除角標
     *
     * @param tabId
     */
    public void clearTabNum(int tabId) {
        updateTabNum(tabId, 0);
    }

    @Override
    public void setListeners() {

        for (int i = 0; i < mLlTabGroup.getChildCount(); i++) {
            final int pos = i;
            mLlTabGroup.getChildAt(i).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    mVpContent.setCurrentItem(pos);
                }
            });
        }

mVpContent.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
    private int lastPost = 0;

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        super.onPageScrolled(position, positionOffset, positionOffsetPixels);

        if (Math.abs(position - lastPost) > 0) {
            int llPos = lastPost;
            int lrPos = lastPost == mFuncEntityList.size() - 1 ? lastPost : lastPost + 1;
            int clPos = position;
            int crPos = position == mFuncEntityList.size() - 1 ? position : position + 1;
            if (llPos != clPos && llPos != crPos) {
                mLlTabGroup.getChildAt(llPos).findViewById(R.id.tv_tab_name).setAlpha(0.6f);
            }
            if (lrPos != clPos && lrPos != crPos) {
                mLlTabGroup.getChildAt(lrPos).findViewById(R.id.tv_tab_name).setAlpha(0.6f);
            }
        }

        //設置指示器位移
        RelativeLayout leftCell = (RelativeLayout) mLlTabGroup.getChildAt(position);
        int rightPos = position == mFuncEntityList.size() - 1 ? position : position + 1;
        RelativeLayout rightCell = (RelativeLayout) mLlTabGroup.getChildAt(rightPos);
        float dist = (leftCell.getWidth() + rightCell.getWidth()) / 2f;
        float indicatorCenterX = leftCell.getLeft() + leftCell.getWidth() / 2f + dist * positionOffset;
        int translationX = (int) (indicatorCenterX - mIndicatorView.getWidth() / 2f);
        mIndicatorView.setTranslationX(translationX);

        //水平滾動條自動滾動
        mHsvNavBar.scrollTo((int) (indicatorCenterX - mHsvNavBar.getWidth() / 2f), 0);

        //文字透明度
        if (position != rightPos) {
            rightCell.findViewById(R.id.tv_tab_name).setAlpha(0.6f + 0.4f * positionOffset);
            leftCell.findViewById(R.id.tv_tab_name).setAlpha(1f - 0.4f * positionOffset);
        } else {
            leftCell.findViewById(R.id.tv_tab_name).setAlpha(1f - 0.4f * positionOffset);
        }

        lastPost = position;
    }
});
    }

    private FuncEntity getCurrFuncEntity() {
        return mFuncEntityList.get(mVpContent.getCurrentItem());
    }

    @Override
    public void onClick(View v) {

    }

}

NavActivity.java

import android.support.v7.app.AppCompatActivity;
import android.view.View;

public abstract class BaseActivity extends AppCompatActivity implements IView {


    protected View.OnClickListener mOnClickListener;

    protected View.OnClickListener getOnClickListener() {
        if (mOnClickListener == null) {
            mOnClickListener = new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    BaseActivity.this.onClick(v);
                }
            };
        }

        return mOnClickListener;
    }
}

IView.java


import android.view.View;

public interface IView {

    void initView();

    void setListeners();

    void onClick(View v);
}

BaseFuncFragment.java

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;

import com.wzhy.viewpagerserial.base.IView;

public abstract class BaseFuncFragment extends Fragment implements IView {

    protected FuncEntity mFuncEntity;

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Bundle args = getArguments();
        if (args.containsKey("funcEntity")) {
            mFuncEntity = (FuncEntity) args.getSerializable("funcEntity");
        }
    }
}

CommFuncFragment.java

import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import com.wzhy.viewpagerserial.R;

/**
 *
 */
public class CommFuncFragment extends BaseFuncFragment {


    private View mView;

    public CommFuncFragment() {
    }

    public static CommFuncFragment newInstance(FuncEntity funcEntity) {
        Bundle args = new Bundle();
        args.putSerializable("funcEntity", funcEntity);
        CommFuncFragment fragment = new CommFuncFragment();
        fragment.setArguments(args);
        return fragment;
    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        mView = inflater.inflate(R.layout.fragment_comm_func, container, false);
        initView();
        return mView;
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        setListeners();
    }

    @Override
    public void initView() {
        ((TextView) mView.findViewById(R.id.tv_page_name)).setText(mFuncEntity.getFunName());
    }

    @Override
    public void setListeners() {

    }

    @Override
    public void onClick(View v) {

    }
}

fragment_comm_func.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".nav.CommFuncFragment">

<TextView
    android:id="@+id/tv_page_name"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textSize="48dp"
    tools:text="tabName"
    android:textColor="@color/common_color"
    android:layout_gravity="center"/>

</FrameLayout>

5. 參考

項目地址:
github:https://github.com/wangzhengyangNo1/ViewPagerSerialDemo

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章