Android 快速實現 ViewPager 滑動頁卡切換(可用做整個 app上導航)

我記得在前面,我寫了一篇Android 微信6.1 tab欄圖標和字體顏色漸變的實現,若是你們僅僅認爲這篇文章的功能只是模仿微信顏色漸變效果,那就大錯特錯了!認真閱讀了這篇文章的朋友,應該知道,這裏面代碼可用做 app 通用的底部欄導航,經過它能快速的實現相似微信6.0版本以底部導航的 app 總體架構,而且在 MainActivity 中須要編寫的代碼很是簡潔。若是有興趣的朋友能夠去看看。css

效果:

今天這篇 blog的內容一樣能夠拿來作 app 的總體架構,但與前面那篇 blog 不一樣,不一樣之處是前面那篇文章所講的內容可用做底部導航,而這篇 blog 的內容,是用做頂部導航,老版本的微信就是此效果,ok,來看看效果圖 
這裏寫圖片描述java

實現原理

根據效果圖,不難分析,能夠經過自定義 ViewGroup 來實現,但這樣代碼量偏多,看了個人前面 blog 的朋友應該清楚,這裏最好的實現方式是經過重寫 LinearLayout,相比經過 ViewGroup 來實現,省略了測量onMeasure()和佈局onLayout()方法的實現,由於這些LinearLayout已經幫咱們實現好了,而咱們真正要作的就是爲 LinearLayout 填充內容,填充內容可大體可分爲如下四個步驟:android

一、填充每一個 item 的內容canvas

二、繪製每一個 item 之間的分割線微信

三、繪製底部線條markdown

四、繪製指示器的內容架構

代碼實現

一、先把須要用的屬性定義出來 
須要的屬性 
一、頁卡指示器的顏色 
二、分割線的顏色 
三、底部線條的顏色 
四、頁卡指示器的高度 
五、分割線距離上下邊距的距離 
六、分割線的寬度app

<?xml version="1.0" encoding="utf-8"?> <resources> <attr name="indicatorColor" format="color"/> <attr name="dividerColor" format="color"/> <attr name="bottomLineColor" format="color"/> <attr name="dividerMargin" format="dimension"/> <attr name="indicatorHeight" format="dimension"/> <attr name="bottomLineHeight" format="dimension"/> <attr name="dividerWidth" format="dimension"/> <declare-styleable name="SlidingTabLayout"> <attr name="indicatorColor"/> <attr name="dividerColor"/> <attr name="bottomLineColor"/> <attr name="dividerMargin"/> <attr name="indicatorHeight"/> <attr name="bottomLineHeight"/> <attr name="dividerWidth"/> </declare-styleable> </resources>

 

二、代碼中獲取屬性,並附上相應的默認值ide

/*默認的頁卡顏色*/ private final int DEFAULT_INDICATOR_COLOR = 0xffff00ff; /*默認分割線的顏色*/ private final int DEFAULT_DIVIDER_COLOR = 0xff000000; /*默認title字體的大小*/ private final int DEFAULT_TEXT_SIZE = 16; /*默認padding*/ private final int DEFAULT_TEXT_PADDING = 16; /*divider默認的寬度*/ private final int DEFAULT_DIVIDER_WIDTH = 1; /*indicator 的高度*/ private final int DEFAULT_INDICATOR_HEIGHT = 5; /*底部線條的高度默認值*/ private final int DEFAULT_BOTTOM_LINE_HEIGHT = 2; /*分割線距離上下邊緣的距離默認爲8*/ private final int DEFAULT_DIVIDER_MARGIN = 8; /*底部線條的顏色默認值*/ private final int DEFAULT_BOTTOM_LINE_COLOR = 0xff000000;

 

/*獲取TypedArray*/ TypedArray typedArray = getResources().obtainAttributes(attrs, R.styleable.SlidingTabLayout); /*獲取自定義屬性的個數*/ int N = typedArray.getIndexCount(); Log.v("zgy","=========getIndexCount========="+N) ; for (int i = 0; i < N; i++) { int attr = typedArray.getIndex(i); switch (attr) { case R.styleable.SlidingTabLayout_indicatorColor: /*獲取頁卡顏色值*/ mIndicatorColor = typedArray.getColor(attr, DEFAULT_INDICATOR_COLOR); break; case R.styleable.SlidingTabLayout_dividerColor: /*獲取分割線顏色的值*/ mDividerColor = typedArray.getColor(attr, DEFAULT_DIVIDER_COLOR); break; case R.styleable.SlidingTabLayout_bottomLineColor: /*獲取底部線條顏色的值*/ mBottomLineColor = typedArray.getColor(attr, DEFAULT_BOTTOM_LINE_COLOR); break; case R.styleable.SlidingTabLayout_dividerMargin: /*獲取分割線的距離上線邊距的距離*/ mDividerMargin = (int) typedArray.getDimension(attr, DEFAULT_DIVIDER_MARGIN * getResources().getDisplayMetrics().density); Log.v("zgy","=========mDividerMargin========="+mDividerMargin) ; break; case R.styleable.SlidingTabLayout_indicatorHeight: /*獲取頁卡的高度*/ mIndicatorHeight = (int) typedArray.getDimension(attr, DEFAULT_INDICATOR_HEIGHT * getResources().getDisplayMetrics().density); break; case R.styleable.SlidingTabLayout_bottomLineHeight: /*獲取底部線條的高度*/ mBottomLineHeight = (int) typedArray.getDimension(attr, DEFAULT_BOTTOM_LINE_HEIGHT * getResources().getDisplayMetrics().density); break; case R.styleable.SlidingTabLayout_dividerWidth: /*獲取分割線的寬度*/ mDividerWidth = (int) typedArray.getDimension(attr, DEFAULT_DIVIDER_WIDTH * getResources().getDisplayMetrics().density); break; } } /*釋放TypedArray*/ typedArray.recycle();

 

這裏說一個細節,我常常在這裏獲取屬性的時候習慣性的把佈局

case R.styleable.SlidingTabLayout_indicatorColor:

寫成

case R.attr.indicatorColor:

 

並且這裏不會報錯,不過結果可想而知,沒法獲取咱們設置的屬性內容,這裏若是有跟我犯一樣錯誤的朋友記得注意一下。

三、爲 LinearLayout 填充內容

/** * 設置viewPager,初始化SlidingTab, * 在這個方法中爲SlidingLayout設置 * 內容, * * @param viewPager */ public void setViewPager(ViewPager viewPager) { /*先移除因此已經填充的內容*/ removeAllViews(); /* viewPager 不能爲空*/ if (viewPager == null) { throw new RuntimeException("ViewPager不能爲空"); } mViewPager = viewPager; mViewPager.setOnPageChangeListener(new InternalViewPagerChange()); //填充內容 populateTabLayout(); }

 

/** * 填充layout,設置其內容 */ private void populateTabLayout() { final PagerAdapter adapter = mViewPager.getAdapter(); final OnClickListener tabOnClickListener = new TabOnClickListener(); mItemName = (TabItemName) adapter; for (int i = 0; i < adapter.getCount(); i++) { TextView textView = createDefaultTabView(getContext()); textView.setOnClickListener(tabOnClickListener); textView.setText(mItemName.getTabName(i)); addView(textView); } }

 

根據ViewPager中頁面的個數,填充相應的 tab。

四、繪製相應的內容 
繪製內容,確定在 onDraw()方法中 
繪製底部線條

canvas.drawRect(0,height - mBottomLineHeight,getWidth(),height,mBottomPaint);

 

繪製分割線

for (int i = 0; i < getChildCount() - 1; i++) { View child = getChildAt(i); canvas.drawLine(child.getRight(), mDividerMargin,child.getRight(), height - mDividerMargin,mDividerPaint); }

 

重點:繪製滑動頁卡

/*當前頁面的View tab*/
        View selectView = getChildAt(mSelectedPosition);
        /*計算開始繪製的位置*/
        int left = selectView.getLeft(); /*計算結束繪製的位置*/ int right = selectView.getRight(); if (mSelectionOffset > 0) { View nextView = getChildAt(mSelectedPosition + 1); /*若是有偏移量,從新計算開始繪製的位置*/ left = (int) (mSelectionOffset * nextView.getLeft() + (1.0f - mSelectionOffset) * left); /*若是有偏移量,從新計算結束繪製的位置*/ right = (int) (mSelectionOffset * nextView.getRight() + (1.0f - mSelectionOffset) * right); } /*繪製滑動的頁卡*/ canvas.drawRect(left, height - mIndicatorHeight, right, height, mIndicatorPaint);

 

運用案例

爲了體現他的簡潔之處,這裏把 xml 中的代碼也貼出來

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:zgy="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <demo.slidingtablayout.view.SlidingTabLayout android:id="@+id/id_tab" android:layout_width="match_parent" android:layout_height="wrap_content" zgy:bottomLineColor="#AEAEAE" zgy:dividerMargin="15dp" zgy:indicatorColor="#77e69c" zgy:indicatorHeight="5dp" zgy:bottomLineHeight="2dp" android:background="#eeeeee"> </demo.slidingtablayout.view.SlidingTabLayout> <android.support.v4.view.ViewPager android:layout_below="@+id/id_tab" android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/id_view_pager"/> </RelativeLayout>

 

MainActivity.java

public class MainActivity extends ActionBarActivity { /*viewPager*/ private ViewPager mViewPager ; /*自定義的 tabLayout*/ private SlidingTabLayout mTabLayout ; /*每一個 tab 的 item*/ private List<PagerItem> mTab = new ArrayList<>() ; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mViewPager = (ViewPager) findViewById(R.id.id_view_pager) ; mTabLayout = (SlidingTabLayout) findViewById(R.id.id_tab) ; mTab.add(new PagerItem("tab1","FirstPager")) ; mTab.add(new PagerItem("tab2","SecondPager")) ; mTab.add(new PagerItem("tab3","ThirdPager")) ; mTab.add(new PagerItem("tab4","FourthPager")) ; mViewPager.setAdapter(new ViewPagerAdapter(getSupportFragmentManager())); /*須要先爲 viewpager 設置 adapter*/ mTabLayout.setViewPager(mViewPager); } private class ViewPagerAdapter extends FragmentPagerAdapter implements SlidingTabLayout.TabItemName{ public ViewPagerAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int position) { return mTab.get(position).createFragment(); } @Override public int getCount() { return mTab.size(); } @Override public String getTabName(int position) { return mTab.get(position).getTitle(); } } }

 

點擊下載源碼

 
相關文章
相關標籤/搜索