MagicIndicator系列之一 —— 使用MagicIndicator打造千變?nèi)f化的ViewPager指示器

說到 ViewPager 指示器忘晤,想必大家都不陌生宛蚓,絕大部分應(yīng)用中都有這個。使用頻率非常之高设塔。但系統(tǒng)對它的支持并不好凄吏,自帶的 PagerTabStrip 和 PagerTitleStrip 太弱,很難滿足需求闰蛔。當然也有第三方框架諸如 Jake Wharton 大神的 ViewPagerIndicator , PagerSlidingTabStrip 等痕钢,我曾經(jīng)嘗試著使用它們,但還是被它們的可定制能力給嚇退了序六。

背景


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

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

magicindicator.gif

關(guān)于命名


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

如何使用


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

  • MagicIndicator 原理

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

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

好,我們開始邑彪。

首先瞧毙,你需要從我的 Github 上將工程代碼 check 下來,直接導(dǎo)入即可運行寄症,里面包含源碼和 demo宙彪。工程中有個 Module 叫做 magicindicator,直接拷到你的項目中即可有巧。包結(jié)構(gòu)如下:

Paste_Image.png

不要忘了添加依賴哦:

dependencies {
    compile project(':magicindicator')
}

導(dǎo)入成功后释漆,就可以使用啦。你需要先在布局文件里引入 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>

再在代碼里面找到它篮迎,并進行簡單設(shè)置:

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的指示作用已經(jīng)很明顯了
    }
});
magicIndicator.setNavigator(commonNavigator);

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

額逊笆,上面這代碼明顯沒有和 ViewPager 相關(guān)聯(lián),因此滑動 ViewPager 時是看不到切換效果的岂傲,我們給 ViewPager 添加一個監(jiān)聽器:

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 強關(guān)聯(lián)乃戈,因此在不使用 ViewPager 的情況下,仍然可以使用 MagicIndicator堰乔。只是需要你手動調(diào)用 onPageXXX 系列方法回調(diào)即可偏化。當然,后續(xù)我會提供幫助類來簡化這個過程镐侯。
  • 等 MagicIndicator 基本穩(wěn)定侦讨、成型后,我會把它提交到 MavenCenter 和 JCenter 中苟翻,方便大家使用韵卤。

內(nèi)建的指示器


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

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);

看到?jīng)]有屋厘,如果你想換一個效果,只需在 getItemView 里返回不同的指示器標題(IPagerTitleView)月而,在 getIndicator 里返回不同的指示器(IPagerIndicator)就可以啦汗洒。

如何擴展


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

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);

當然瞻坝,我可不希望每當內(nèi)置指示器達不到你的需求時,你總是去繼承這些個類包晰,為了簡化湿镀,我在最新的代碼里增加了 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

關(guān)于擴展 MagicIndicator伐憾,后面會有詳細的博文來講解,敬請留意赫模。如果你擴展 MagicIndicator 實現(xiàn)了很炫酷的指示器效果树肃,歡迎共享出來。

更多


MagicIndicator 同樣考慮到了 ViewPager 內(nèi)容變化的情況瀑罗,當你的 ViewPager 內(nèi)容發(fā)生變化時胸嘴,除了調(diào)用 PagerAdapter.notifyDataSetChanged ,還記得先調(diào)用 IPagerNavigator.notifyDataSetChanged 哦:

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

結(jié)語


如果大家覺得 MagicIndicator 很好斩祭,對你有幫助劣像,歡迎多多 star + fork,關(guān)注摧玫!關(guān)注耳奕!,也請幫忙推廣一下哈诬像。感激不盡屋群。

MagicIndicator 是我計劃長期維護的項目,由于才剛開始坏挠,現(xiàn)在的指示器效果還不是很多芍躏,后續(xù)會不斷加入更多炫酷的效果,如果你想加入我降狠,打造更好的用戶體驗对竣,私信我吧庇楞。

MagicIndicator 疑難解答,交流請加QQ群:373360748否纬。

今天就到此為止吧姐刁。周末愉快!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末烦味,一起剝皮案震驚了整個濱河市聂使,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌谬俄,老刑警劉巖柏靶,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異溃论,居然都是意外死亡屎蜓,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門钥勋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來炬转,“玉大人,你說我怎么就攤上這事算灸《笈” “怎么了?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵菲驴,是天一觀的道長荐吵。 經(jīng)常有香客問我,道長赊瞬,這世上最難降的妖魔是什么先煎? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮巧涧,結(jié)果婚禮上薯蝎,老公的妹妹穿的比我還像新娘。我一直安慰自己谤绳,他們只是感情好占锯,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著闷供,像睡著了一般烟央。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上歪脏,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天疑俭,我揣著相機與錄音,去河邊找鬼婿失。 笑死钞艇,一個胖子當著我的面吹牛啄寡,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播哩照,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼挺物,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了飘弧?” 一聲冷哼從身側(cè)響起识藤,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎次伶,沒想到半個月后痴昧,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡冠王,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年匀归,在試婚紗的時候發(fā)現(xiàn)自己被綠了搅荞。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片栋荸。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡吁津,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出哟楷,到底是詐尸還是另有隱情瘤载,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布吓蘑,位于F島的核電站惕虑,受9級特大地震影響坟冲,放射性物質(zhì)發(fā)生泄漏磨镶。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一健提、第九天 我趴在偏房一處隱蔽的房頂上張望琳猫。 院中可真熱鬧,春花似錦私痹、人聲如沸脐嫂。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽账千。三九已至,卻和暖如春暗膜,著一層夾襖步出監(jiān)牢的瞬間匀奏,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工学搜, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留娃善,地道東北人论衍。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像聚磺,于是被迫代替她去往敵國和親坯台。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容