Android MagicIndicator系列之一 —— 使用MagicIndicator打造千變萬化的ViewPager指示器


說到 ViewPager 指示器,想必大家都不陌生,絕大部分應用中都有這個。使用頻率非常之高。但系統對它的支持並不好,自帶的 PagerTabStrip 和 PagerTitleStrip 太弱,很難滿足需求。當然也有第三方框架諸如 Jake Wharton 大神的 ViewPagerIndicator , PagerSlidingTabStrip 等,我曾經嘗試着使用它們,但還是被它們的可定制能力給嚇退了。

背景


近期交互改版,需要在指示器上增加吸附效果,剛開始我有點懵逼,因為之前的指示器只是簡單的使用了 HorizontalScrollView + 橫向 LinearLayout ,向 LinearLayout 里面添加一些 TextView 當做標題,選中的時候只是簡單的改變 TextView 的顏色,沒有任何動畫,因此實現起來相對簡單(項目前期時間緊迫)。這估計也是大部分應用的做法吧。

考慮到后面如果交互再改版,那我又會懵逼了,所以干脆自己來打造一個可擴展、可定制能力 很強 真TM強 的 ViewPager 指示器框架 —— MagicIndicator


magicindicator.gif

關於命名


之所以叫 MagicIndicator,是因為 鴻神 之前搞了一個 MagicViewPager, 我覺得這兩個可以很好的搭配使用,並且正如大家看到的,它確實比較 Magic。

如何使用


這期就不打算給大家講原理性文章了,只講如何集成(主要是這兩天都在寫這個,被媳婦罵慘了,沒時間寫了),后面我會有一個系列的文章來講這個,涉及到的內容大概有:

  • MagicIndicator 原理

  • 如何擴展 MagicIndicator 打造任意的切換效果

  • 如何使用 MagicIndicator 來打造主流應用(諸如微信主頁的切換)的指示器效果

好,我們開始。

首先,你需要從我的 Github 上將工程代碼 check 下來,直接導入即可運行,里面包含源碼和 demo。工程中有個 Module 叫做 magicindicator,直接拷到你的項目中即可。包結構如下:


Paste_Image.png

不要忘了添加依賴哦:

dependencies {
    compile project(':magicindicator') }

導入成功后,就可以使用啦。你需要先在布局文件里引入 MagicIndicator:

<?xml version="1.0" encoding="utf-8"?> <LinearLayout 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" android:orientation="vertical" tools:context="net.lucode.hackware.magicindicatordemo.MainActivity"> <net.lucode.hackware.magicindicator.MagicIndicator android:id="@+id/magic_indicator" android:layout_width="match_parent" android:layout_height="@dimen/navigator_common_height" android:background="#d43d3d" /> <android.support.v4.view.ViewPager android:id="@+id/view_pager" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:background="@android:color/white" /> </LinearLayout>

再在代碼里面找到它,並進行簡單設置:

final MagicIndicator magicIndicator = (MagicIndicator) findViewById(R.id.magic_indicator); final CommonNavigator commonNavigator = new CommonNavigator(this); commonNavigator.setAdapter(new CommonNavigatorAdapter() { @Override public int getCount() { return mDataList == null ? 0 : mDataList.size(); } @Override public IPagerTitleView getItemView(Context context, final int index) { ClipPagerTitleView clipPagerTitleView = new ClipPagerTitleView(context); clipPagerTitleView.setText(mDataList.get(index)); clipPagerTitleView.setTextColor(Color.parseColor("#f2c4c4")); clipPagerTitleView.setClipColor(Color.WHITE); clipPagerTitleView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mPager.setCurrentItem(index); } }); return clipPagerTitleView; } @Override public IPagerIndicator getIndicator(Context context) { return null; // 沒有指示器,因為title的指示作用已經很明顯了 } }); magicIndicator.setNavigator(commonNavigator);

這樣,你就可以輕松的實現效果圖中 今日頭條 式(效果圖中第一個)切換效果。

額,上面這代碼明顯沒有和 ViewPager 相關聯,因此滑動 ViewPager 時是看不到切換效果的,我們給 ViewPager 添加一個監聽器:

mPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { magicIndicator.onPageScrolled(position, positionOffset, positionOffsetPixels); } @Override public void onPageSelected(int position) { magicIndicator.onPageSelected(position); } @Override public void onPageScrollStateChanged(int state) { magicIndicator.onPageScrollStateChanged(state); } }); mPager.setCurrentItem(1);

這樣, MagicIndicator 就算成功引入項目啦。

  • 注意,以上代碼明顯沒有和 ViewPager 強關聯,因此在不使用 ViewPager 的情況下,仍然可以使用 MagicIndicator。只是需要你手動調用 onPageXXX 系列方法回調即可。當然,后續我會提供幫助類來簡化這個過程。
  • 等 MagicIndicator 基本穩定、成型后,我會把它提交到 MavenCenter 和 JCenter 中,方便大家使用。

內建的指示器


MagicIndicator 目前內建了好幾種指示器,基本可以滿足絕大部分需求,並且每一種指示器都支持通過 插值器(Interpolator) 來微調效果(如果你還不會 巧用插值器,可以參考我的前一篇博文 Android水波紋特效的簡單實現 ),后面我還會不定期的往里面添加更多炫酷的效果,敬請期待。下面演示一下使用內建的指示器實現效果圖中的 小尖角 式切換效果:

final MagicIndicator magicIndicator = (MagicIndicator) findViewById(R.id.magic_indicator); final CommonNavigator commonNavigator = new CommonNavigator(this); commonNavigator.setAlwaysScrollToCenter(true); commonNavigator.setAdapter(new CommonNavigatorAdapter() { @Override public int getCount() { return mDataList == null ? 0 : mDataList.size(); } @Override public IPagerTitleView getItemView(Context context, final int index) { SimplePagerTitleView simplePagerTitleView = new SimplePagerTitleView(context); simplePagerTitleView.setText(mDataList.get(index)); simplePagerTitleView.setNormalColor(Color.parseColor("#333333")); simplePagerTitleView.setSelectedColor(Color.parseColor("#e94220")); simplePagerTitleView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mPager.setCurrentItem(index); } }); return simplePagerTitleView; } @Override public IPagerIndicator getIndicator(Context context) { TriangularPagerIndicator indicator = new TriangularPagerIndicator(context); indicator.setLineColor(Color.parseColor("#e94220")); return indicator; } }); magicIndicator.setNavigator(commonNavigator);

看到沒有,如果你想換一個效果,只需在 getItemView 里返回不同的指示器標題(IPagerTitleView),在 getIndicator 里返回不同的指示器(IPagerIndicator)就可以啦。

如何擴展


當內建的指示器不能滿足你的需求時,你可以輕易的擴展,如果你的需求貌似可以使用 HorizontalScrollView + 橫向 LinearLayout 方式實現,建議繼承 IPagerTitleViewIPagerIndicator 即可,如果不行,那就完全自定義吧,繼承 IPagerNavigator (導航器 —— 我覺得上面的那些效果本質是一個導航器,指示器只是包含在導航器中的一個元素而已) 吧。效果圖中的最后一個效果就是如此:

final MagicIndicator magicIndicator = (MagicIndicator) findViewById(R.id.magic_indicator); final CircleNavigator circleNavigator = new CircleNavigator(this); circleNavigator.setCount(mDataList.size()); circleNavigator.setCircleColor(Color.RED); magicIndicator.setNavigator(circleNavigator);

當然,我可不希望每當內置指示器達不到你的需求時,你總是去繼承這些個類,為了簡化,我在最新的代碼里增加了 CommonPagerTitleView,使用方法如下:

final MagicIndicator magicIndicator = (MagicIndicator) findViewById(R.id.magic_indicator); CommonNavigator commonNavigator = new CommonNavigator(this); commonNavigator.setAdapter(new CommonNavigatorAdapter() { @Override public int getCount() { return mDataList == null ? 0 : mDataList.size(); } @Override public IPagerTitleView getItemView(Context context, final int index) { CommonPagerTitleView commonPagerTitleView = new CommonPagerTitleView(MainActivity.this); commonPagerTitleView.setContentView(R.layout.simple_pager_title_layout); // 初始化 final ImageView titleImg = (ImageView) commonPagerTitleView.findViewById(R.id.title_img); titleImg.setImageResource(R.mipmap.ic_launcher); final TextView titleText = (TextView) commonPagerTitleView.findViewById(R.id.title_text); titleText.setText(mDataList.get(index)); commonPagerTitleView.setOnPagerTitleChangeListener(new CommonPagerTitleView.OnPagerTitleChangeListener() { @Override public void onSelected(int index) { titleText.setTextColor(Color.RED); } @Override public void onDeselected(int index) { titleText.setTextColor(Color.BLACK); } @Override public void onLeave(int index, float leavePercent, boolean leftToRight) { titleImg.setScaleX(1.3f + (0.8f - 1.3f) * leavePercent); titleImg.setScaleY(1.3f + (0.8f - 1.3f) * leavePercent); } @Override public void onEnter(int index, float enterPercent, boolean leftToRight) { titleImg.setScaleX(0.8f + (1.3f - 0.8f) * enterPercent); titleImg.setScaleY(0.8f + (1.3f - 0.8f) * enterPercent); } }); commonPagerTitleView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mPager.setCurrentItem(index); } }); return commonPagerTitleView; } @Override public IPagerIndicator getIndicator(Context context) { return null; } }); magicIndicator.setNavigator(commonNavigator);

效果圖:


custom.gif

關於擴展 MagicIndicator,后面會有詳細的博文來講解,敬請留意。如果你擴展 MagicIndicator 實現了很炫酷的指示器效果,歡迎共享出來。

更多


MagicIndicator 同樣考慮到了 ViewPager 內容變化的情況,當你的 ViewPager 內容發生變化時,除了調用 PagerAdapter.notifyDataSetChanged ,還記得先調用 IPagerNavigator.notifyDataSetChanged 哦:

mDataList.clear(); mDataList.add("歡迎關注"); mDataList.add("我的博客"); mDataList.add("hackware.lucode.net"); commonNavigator.notifyDataSetChanged(); mAdapter.notifyDataSetChanged();

結語


如果大家覺得 MagicIndicator 很好,對你有幫助,歡迎多多 star + fork,關注!關注!,也請幫忙推廣一下哈。感激不盡。

MagicIndicator 是我計划長期維護的項目,由於才剛開始,現在的指示器效果還不是很多,后續會不斷加入更多炫酷的效果,如果你想加入我,打造更好的用戶體驗,私信我吧。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM