開(kāi)源項(xiàng)目效果
Android studio 項(xiàng)目導(dǎo)入依賴compile路徑
dependencies{? ? compile'com.android.support:support-v4:23.1.1'compile'com.flyco.tablayout:FlycoTabLayout_Lib:2.0.2@aar'}
1
2
3
4
FlycoTabLayout是一個(gè)Android TabLayout庫(kù),目前有3個(gè)TabLayout
SlidingTabLayout:參照PagerSlidingTabStrip進(jìn)行大量修改.關(guān)于PagerSlidingTabStrip源碼分析可以參照我以前的一篇博文http://blog.csdn.net/analyzesystem/article/details/50316745?
新增部分屬性
新增支持多種Indicator顯示器
新增支持未讀消息顯示
新增方法setViewPager
/** 關(guān)聯(lián)ViewPager,用于不想在ViewPager適配器中設(shè)置titles數(shù)據(jù)的情況 */public void setViewPager(ViewPager vp, String[] titles)/** 關(guān)聯(lián)ViewPager,用于連適配器都不想自己實(shí)例化的情況 */public void setViewPager(ViewPager vp, String[] titles, FragmentActivity fa, ArrayList fragments)
1
2
3
4
5
CommonTabLayout:不同于SlidingTabLayout對(duì)ViewPager依賴,它是一個(gè)不依賴ViewPager可以與其他控件自由搭配使用的TabLayout.
支持多種Indicator顯示器,以及Indicator動(dòng)畫(huà)
支持未讀消息顯示
支持Icon以及Icon位置
新增方法
/** 關(guān)聯(lián)數(shù)據(jù)支持同時(shí)切換fragments */publicvoidsetTabData(ArrayList tabEntitys, FragmentManager fm,intcontainerViewId, ArrayList fragments)
1
2
SegmentTabLayout:仿照QQ消息列表頭部tab切換的控件
自定義屬性表
tl_indicator_colorcolor設(shè)置顯示器顏色tl_indicator_height? ? ? ? dimension? 設(shè)置顯示器高度tl_indicator_width? ? ? ? ? dimension? 設(shè)置顯示器固定寬度tl_indicator_margin_left? ? dimension? 設(shè)置顯示器margin,當(dāng)indicator_width大于0,無(wú)效tl_indicator_margin_top? ? dimension? 設(shè)置顯示器margin,當(dāng)indicator_width大于0,無(wú)效tl_indicator_margin_right? dimension? 設(shè)置顯示器margin,當(dāng)indicator_width大于0,無(wú)效tl_indicator_margin_bottom? dimension? 設(shè)置顯示器margin,當(dāng)indicator_width大于0,無(wú)效tl_indicator_corner_radius? dimension? 設(shè)置顯示器圓角弧度tl_indicator_gravity? ? ? ? enum? ? ? ? 設(shè)置顯示器上方(TOP)還是下方(BOTTOM),只對(duì)常規(guī)顯示器有用tl_indicator_style? ? ? ? ? enum? ? ? ? 設(shè)置顯示器為常規(guī)(NORMAL)或三角形(TRIANGLE)或背景色塊(BLOCK)tl_underline_colorcolor設(shè)置下劃線顏色tl_underline_height? ? ? ? dimension? 設(shè)置下劃線高度tl_underline_gravity? ? ? ? enum? ? ? ? 設(shè)置下劃線上方(TOP)還是下方(BOTTOM)tl_divider_colorcolor設(shè)置分割線顏色tl_divider_width? ? ? ? ? ? dimension? 設(shè)置分割線寬度tl_divider_padding? ? ? ? ? dimension? 設(shè)置分割線的paddingTop和paddingBottomtl_tab_padding? ? ? ? ? ? ? dimension? 設(shè)置tab的paddingLeft和paddingRighttl_tab_space_equal? ? ? ? ? boolean? ? 設(shè)置tab大小等分tl_tab_width? ? ? ? ? ? ? ? dimension? 設(shè)置tab固定大小tl_textsize? ? ? ? ? ? ? ? dimension? 設(shè)置字體大小tl_textSelectColorcolor設(shè)置字體選中顏色tl_textUnselectColorcolor設(shè)置字體未選中顏色tl_textBold? ? ? ? ? ? ? ? boolean? ? 設(shè)置字體加粗tl_iconWidth? ? ? ? ? ? ? ? dimension? 設(shè)置icon寬度(僅支持CommonTabLayout)tl_iconHeight? ? ? ? ? ? ? dimension? 設(shè)置icon高度(僅支持CommonTabLayout)tl_iconVisible? ? ? ? ? ? ? boolean? ? 設(shè)置icon是否可見(jiàn)(僅支持CommonTabLayout)tl_iconGravity? ? ? ? ? ? ? enum? ? ? ? 設(shè)置icon顯示位置,對(duì)應(yīng)Gravity中常量值,左上右下(僅支持CommonTabLayout)tl_iconMargin? ? ? ? ? ? ? dimension? 設(shè)置icon與文字間距(僅支持CommonTabLayout)tl_indicator_anim_enable? ? boolean? ? 設(shè)置顯示器支持動(dòng)畫(huà)(only for CommonTabLayout)tl_indicator_anim_duration? integer? ? 設(shè)置顯示器動(dòng)畫(huà)時(shí)間(only for CommonTabLayout)tl_indicator_bounce_enable? boolean? ? 設(shè)置顯示器支持動(dòng)畫(huà)回彈效果(only for CommonTabLayout)tl_indicator_width_equal_title? boolean 設(shè)置顯示器與標(biāo)題一樣長(zhǎng)(only for SlidingTabLayout)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
該庫(kù)依賴于動(dòng)畫(huà)兼容庫(kù)NineOldAndroids和FlycoRoundView硕勿,稍后在源碼分析里簡(jiǎn)單了解一下FlycoRoundView。
SlidingTabLayout自定義屬性支持下劃線設(shè)置僧须,控制下劃線顯示方向?qū)捀撸梢宰尵€寬=文字寬度传惠,也可以固定比例寬度,可以設(shè)置未讀消息的小紅點(diǎn)诗宣,也可以設(shè)置未讀消息數(shù)量掷豺,當(dāng)前這一切的前提都是基于ViewPager來(lái)實(shí)現(xiàn),都需要綁定ViewPager赎瑰,通過(guò)多種綁定方法
/**關(guān)聯(lián)ViewPager,Adapter重寫(xiě)了getPageTitle方法*/tabLayout.setViewPager(vp);/**關(guān)聯(lián)ViewPager,用于不想在ViewPager適配器中設(shè)置titles數(shù)據(jù)的情況*/tabLayout.setViewPager(vp, mTitles);/**關(guān)聯(lián)ViewPager,用于連適配器都不想自己實(shí)例化的情況王悍,內(nèi)部幫助實(shí)例化了一個(gè)InnerPagerAdapter*/tabLayout.setViewPager(vp, mTitles,this, mFragments);
1
2
3
4
5
6
7
8
下面我們來(lái)看看tabLayout提供幾個(gè)對(duì)我們比較有用的方法
/**顯示指定位置未讀紅點(diǎn)*/tabLayout.showDot(4);/**隱藏指定位置未讀紅點(diǎn)或消息*/tabLayout.hideMsg(5);/**showMsg(int position, int num):position位置,num小于等于0顯示紅點(diǎn),num大于0顯示數(shù)字餐曼,作用:顯示未讀消息压储,如果消息數(shù)量>99,顯示效果99+*/tabLayout.showMsg(3,5);/**? setMsgMargin(int position, float leftPadding, float bottomPadding)設(shè)置未讀消息偏移,原點(diǎn)為文字的右上角.當(dāng)控件高度固定,消息提示位置易控制,顯示效果佳 */tabLayout.setMsgMargin(3,0,10);/**設(shè)置未讀消息消息的背景*/MsgView msgView = tabLayout.getMsgView(3);if(msgView !=null) {? ? msgView.setBackgroundColor(Color.parseColor("#6D8FB0"));? }//...................略...........
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
自定義的屬性那么多,對(duì)應(yīng)的set方法自然也不少源譬,不過(guò)對(duì)照上面自定義屬性xml引用就好集惋,一般情況下哪些方法都用不到了。
SlidingTabLayout對(duì)應(yīng)的方法在這里都適用不再重復(fù)踩娘,CommonTabLayout最重要的就是setTabData(ArrayList tabEntitys)方法刮刑,使得CommonTabLayout不再依賴于ViewPager完成初始化,實(shí)現(xiàn)底部導(dǎo)航或者頭部導(dǎo)航效果养渴,讓我們告別RadioButton+ViewPager的時(shí)代雷绢,CustomTabEntity的命名有點(diǎn)問(wèn)題哈,命名是一個(gè)接口非要定義Entity結(jié)尾理卑,TabEntity實(shí)現(xiàn)該接口翘紊,修改構(gòu)造方法,初始化內(nèi)部參數(shù)藐唠,下面是一個(gè)配合CommonTabLayout+ViewPager的導(dǎo)航實(shí)例
mFragmentList = addFragmentList(R.id.home_frameLayout, fragmentClasses);for(inti =0; i < titles.length; i++) {? ? ? ? ? ? mTabEntities.add(newTabEntity(titles[i], checkeds[i], normals[i]));? ? ? ? }? ? ? ? commonTabLayout.setTabData(mTabEntities);? ? ? ? commonTabLayout.setOnTabSelectListener(newOnTabSelectListener() {@OverridepublicvoidonTabSelect(intposition) {if(position ==1) {? ? ? ? ? ? ? ? ? ? topBarBuilder.configSearchStyle(titles[position], R.drawable.ic_action_search);? ? ? ? ? ? ? ? }else{? ? ? ? ? ? ? ? ? ? topBarBuilder.configTitle(titles[position]);? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? showFragment(R.id.home_frameLayout, position, mFragmentList);? ? ? ? ? ? ? ? onLoggerD("initial callback ,show fragment with position "+ position +";FragmentName:"+ mFragmentList.get(position).toString());? ? ? ? ? ? }@OverridepublicvoidonTabReselect(intposition) {//TODO 重選}? ? ? ? });
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
SegmentTabLayout實(shí)現(xiàn)效果就像qq消息列表頂部的切換效果霞溪,統(tǒng)一支持setTabData(mTitles)不過(guò)這里傳入標(biāo)題數(shù)組孵滞,tabLayout配合ViewPager切換調(diào)用tabLayout提供的方法setCurrentTab,SegmentTabLayout提供的 setTabData(String[] titles, FragmentActivity fa, int containerViewId, ArrayList fragments)方法在我們frameLayout+fragment布局切換Fragment比較實(shí)用的
粗略看過(guò)這個(gè)庫(kù)的自定義屬性文件鸯匹,明悟了件事:自定義屬性的自動(dòng)提示如下(以前我自定義屬性都放在declare-styleable直接定義的)
下面是這些自定義屬性的具體含義(attrs里面有具體說(shuō)明)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
Round系列的View控件自定義 RoundTextView 、RoundFrameLayout 泄伪、RoundLinearLayout RoundRelativeLayout殴蓬,這幾個(gè)控件內(nèi)部源碼實(shí)現(xiàn)并不復(fù)雜,可以說(shuō)簡(jiǎn)單之極蟋滴,構(gòu)造函數(shù)通過(guò)RoundViewDelegate代理解析自定義屬性染厅,其次就是onMeasure和onLayout的測(cè)量相關(guān)的,ToggleButton源碼分析一篇有提到這里使用EXACTLY
@OverrideprotectedvoidonMeasure(intwidthMeasureSpec,intheightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);if(delegate.isWidthHeightEqual() && getWidth() >0&& getHeight() >0) {intmax = Math.max(getWidth(), getHeight());intmeasureSpec = MeasureSpec.makeMeasureSpec(max, MeasureSpec.EXACTLY);super.onMeasure(measureSpec, measureSpec);return;? ? ? ? }super.onMeasure(widthMeasureSpec, heightMeasureSpec);? ? }@OverrideprotectedvoidonLayout(booleanchanged,intleft,inttop,intright,intbottom) {super.onLayout(changed, left, top, right, bottom);if(delegate.isRadiusHalfHeight()) {//如果弧度是高度的一半津函,直接設(shè)置radio為高度一半肖粮,否則調(diào)用delegate.setCornerRadius(getHeight() /2);? ? ? ? }else{? ? ? ? ? ? delegate.setBgSelector();// Ripple效果兼容21+,Ripple效果的實(shí)現(xiàn)有多重尔苦,這里使用的RippleDrawable涩馆,具體使用方法請(qǐng)參考api,這里不是本篇重點(diǎn)}? ? }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
setBgSelector 方法使用到了GradientDrawable允坚、StateListDrawable魂那,沒(méi)了解過(guò)的可以參考Drawable系列這篇博客有相應(yīng)的簡(jiǎn)單介紹,RoundViewDelegate提供了這些自定義屬性的set get方法稠项,我們代碼調(diào)用通過(guò)自定義控件getDelegate獲取構(gòu)造函數(shù)初始化的實(shí)例進(jìn)行設(shè)置和獲取對(duì)應(yīng)屬性涯雅。
MsgView仿照FlycoRoundView庫(kù)編寫(xiě)的一個(gè)自定義控件,主要用于未讀消息的展示展运,大同小異的代碼就此略過(guò)活逆。
SlidingTabLayout自定義控件千篇一律的自定義屬性飄過(guò),來(lái)到必經(jīng)之路setViewPager拗胜,發(fā)現(xiàn)新大陸notifyDataSetChanged()調(diào)用蔗候,通過(guò)dapter的getPageTitle方法獲取標(biāo)題,并inflate添加一個(gè)布局到HorizontalScrollView的子View LinearLayout,并綁定Tab想的監(jiān)聽(tīng)回調(diào)挤土。
/** 更新數(shù)據(jù) */publicvoidnotifyDataSetChanged() {? ? ? ? mTabsContainer.removeAllViews();this.mTabCount = mTitles ==null? mViewPager.getAdapter().getCount() : mTitles.length;? ? ? ? View tabView;for(inti =0; i < mTabCount; i++) {if(mViewPager.getAdapter()instanceofCustomTabProvider) {? ? ? ? ? ? ? ? tabView = ((CustomTabProvider) mViewPager.getAdapter()).getCustomTabView(this, i);? ? ? ? ? ? }else{? ? ? ? ? ? ? ? tabView = View.inflate(mContext, R.layout.layout_tab,null);? ? ? ? ? ? }? ? ? ? ? ? CharSequence pageTitle = mTitles ==null? mViewPager.getAdapter().getPageTitle(i) : mTitles[i];? ? ? ? ? ? addTab(i, pageTitle.toString(), tabView);? ? ? ? }? ? ? ? updateTabStyles();? ? }/** 創(chuàng)建并添加tab */privatevoidaddTab(finalintposition, String title, View tabView) {? ? ? ? TextView tv_tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title);if(tv_tab_title !=null) {if(title !=null) tv_tab_title.setText(title);? ? ? ? }? ? ? ? tabView.setOnClickListener(newOnClickListener() {@OverridepublicvoidonClick(View v) {if(mViewPager.getCurrentItem() != position) {? ? ? ? ? ? ? ? ? ? mViewPager.setCurrentItem(position);if(mListener !=null) {? ? ? ? ? ? ? ? ? ? ? ? mListener.onTabSelect(position);? ? ? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? }else{if(mListener !=null) {? ? ? ? ? ? ? ? ? ? ? ? mListener.onTabReselect(position);? ? ? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? }? ? ? ? ? ? }? ? ? ? });/** 每一個(gè)Tab的布局參數(shù) */LinearLayout.LayoutParams lp_tab = mTabSpaceEqual ?newLinearLayout.LayoutParams(0, LayoutParams.MATCH_PARENT,1.0f) :newLinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);if(mTabWidth >0) {? ? ? ? ? ? lp_tab =newLinearLayout.LayoutParams((int) mTabWidth, LayoutParams.MATCH_PARENT);? ? ? ? }? ? ? ? mTabsContainer.addView(tabView, position, lp_tab);? ? }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
calcIndicatorRect方法根據(jù)不同的屬性計(jì)算出Rect范圍以便以繪制琴庵,具體繪制方法參考Canvas API,這里提一點(diǎn)下面這個(gè)方法非常有必要仰美,如果在自定義控件的構(gòu)造函數(shù)或者其他繪制相關(guān)地方使用系統(tǒng)依賴的代碼迷殿,會(huì)導(dǎo)致可視化編輯器無(wú)法報(bào)錯(cuò)并提示:Use View.isInEditMode() in your custom views to skip code when shown in Eclipseis,加上了isInEditMode的判斷就不會(huì)再報(bào)錯(cuò)了咖杂。
if(isInEditMode() || mTabCount <=0) {return;? ? ? ? }
1
2
3
對(duì)于代碼設(shè)置自定義的屬性值庆寺,會(huì)調(diào)用下面這兩個(gè)方法 invalidate()和 updateTabStyles();涉及到了繪制的則調(diào)用invalidate,可以直接修改的則調(diào)用updateTabStyles(個(gè)人感覺(jué)不太友好,比如代碼設(shè)置一個(gè)屬性值诉字,就需要遍歷所有view,同時(shí)重新調(diào)用屬性賦值懦尝,關(guān)鍵只修改了其中一個(gè)屬性V住!)
private void updateTabStyles() {? ? ? ? for (int i =0; i < mTabCount; i++) {View v = mTabsContainer.getChildAt(i);//? ? ? ? ? ? v.setPadding((int) mTabPadding, v.getPaddingTop(), (int) mTabPadding, v.getPaddingBottom());TextView tv_tab_title = (TextView) v.findViewById(R.id.tv_tab_title);if (tv_tab_title != null) {? ? ? ? ? ? ? ? tv_tab_title.setTextColor(i == mCurrentTab ? mTextSelectColor : mTextUnselectColor);tv_tab_title.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextsize);tv_tab_title.setPadding((int) mTabPadding,0, (int) mTabPadding,0);if (mTextAllCaps) {? ? ? ? ? ? ? ? ? ? tv_tab_title.setText(tv_tab_title.getText().toString().toUpperCase());}? ? ? ? ? ? ? ? if (mTextBold) {? ? ? ? ? ? ? ? ? ? tv_tab_title.getPaint().setFakeBoldText(mTextBold);}? ? ? ? ? ? }? ? ? ? }? ? }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
setMsg 陵霉、setDot方法在調(diào)用示例有提到用法琅轧,這里的show hide狀態(tài)如何保存的呢?這里有用到和AbsListView內(nèi)部狀態(tài)保持一樣的方法:SparseArray來(lái)保存對(duì)應(yīng)位置的狀態(tài)
/**? ? * 顯示未讀消息? ? *? ? * @paramposition 顯示tab位置? ? * @paramnum? ? ? num小于等于0顯示紅點(diǎn),num大于0顯示數(shù)字? ? */publicvoidshowMsg(intposition,intnum) {if(position >= mTabCount) {? ? ? ? ? ? position = mTabCount -1;? ? ? ? }? ? ? ? View tabView = mTabsContainer.getChildAt(position);? ? ? ? MsgView tipView = (MsgView) tabView.findViewById(R.id.rtv_msg_tip);if(tipView !=null) {? ? ? ? ? ? UnreadMsgUtils.show(tipView, num);if(mInitSetMap.get(position) !=null&& mInitSetMap.get(position)) {return;? ? ? ? ? ? }? ? ? ? ? ? setMsgMargin(position,4,2);? ? ? ? ? ? mInitSetMap.put(position,true);? ? ? ? }? ? }/**? ? * 顯示未讀紅點(diǎn)? ? *? ? * @paramposition 顯示tab位置? ? */publicvoidshowDot(intposition) {if(position >= mTabCount) {? ? ? ? ? ? position = mTabCount -1;? ? ? ? }? ? ? ? showMsg(position,0);? ? }/** 隱藏未讀消息 */publicvoidhideMsg(intposition) {if(position >= mTabCount) {? ? ? ? ? ? position = mTabCount -1;? ? ? ? }? ? ? ? View tabView = mTabsContainer.getChildAt(position);? ? ? ? MsgView tipView = (MsgView) tabView.findViewById(R.id.rtv_msg_tip);if(tipView !=null) {? ? ? ? ? ? tipView.setVisibility(View.GONE);? ? ? ? }? ? }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
細(xì)心的你一定會(huì)發(fā)現(xiàn)show并沒(méi)有直接控制View的Visibility顯示隱藏踊挠,而是用了UnreadMsgUtils乍桂,這個(gè)類提供了兩個(gè)方法setSize和show方法,show方法對(duì)show的countSize進(jìn)行了一次判斷轉(zhuǎn)換0為點(diǎn)效床,1-99圓+數(shù)字睹酌,>99則顯示99+,背景的弧度為寬度的一半
再回到setViewPager(ViewPager vp, String[] titles, FragmentActivity fa, ArrayList fragments)方法剩檀,在我們調(diào)用該方法時(shí)內(nèi)部幫我們創(chuàng)建了內(nèi)部定義的InnerPagerAdapter適配器憋沿,如果你想偷懶不想寫(xiě)適配器就可以調(diào)用這個(gè)方法。InnerPagerAdapter重寫(xiě)了getPageTitle,以便于notifyDataSetChanged方法調(diào)用動(dòng)態(tài)添加tab項(xiàng)沪猴。
class InnerPagerAdapter extends FragmentPagerAdapter {privateArrayList fragments =newArrayList<>();privateString[] titles;publicInnerPagerAdapter(FragmentManager fm, ArrayList fragments, String[] titles) {super(fm);this.fragments = fragments;this.titles = titles;? ? ? ? }@OverridepublicintgetCount() {returnfragments.size();? ? ? ? }@OverridepublicCharSequencegetPageTitle(intposition) {returntitles[position];? ? ? ? }@OverridepublicFragmentgetItem(intposition) {returnfragments.get(position);? ? ? ? }@OverridepublicvoiddestroyItem(ViewGroup container,intposition, Object object) {// 覆寫(xiě)destroyItem并且空實(shí)現(xiàn),這樣每個(gè)Fragment中的視圖就不會(huì)被銷毀// super.destroyItem(container, position, object);}@OverridepublicintgetItemPosition(Object object) {returnPagerAdapter.POSITION_NONE;? ? ? ? }? ? }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
CommonTabLayout與上面SlidingTabLayout百分之99的相似度辐啄,重復(fù)的不在敘述,區(qū)別點(diǎn)在于setTabData和notifyDataSetChanged方法字币,notifyDataSetChanged根據(jù)Icon的Gravity屬性進(jìn)入不同布局的View做Tab,雖然TextView有drawableLeftRightTopBottom的相關(guān)屬性则披,但是并不能讓我們那么自由的控制Ui。
/** 更新數(shù)據(jù) */publicvoidnotifyDataSetChanged() {? ? ? ? mTabsContainer.removeAllViews();this.mTabCount = mTabEntitys.size();? ? ? ? View tabView;for(inti =0; i < mTabCount; i++) {if(mIconGravity == Gravity.LEFT) {? ? ? ? ? ? ? ? tabView = View.inflate(mContext, R.layout.layout_tab_left,null);? ? ? ? ? ? }elseif(mIconGravity == Gravity.RIGHT) {? ? ? ? ? ? ? ? tabView = View.inflate(mContext, R.layout.layout_tab_right,null);? ? ? ? ? ? }elseif(mIconGravity == Gravity.BOTTOM) {? ? ? ? ? ? ? ? tabView = View.inflate(mContext, R.layout.layout_tab_bottom,null);? ? ? ? ? ? }else{? ? ? ? ? ? ? ? tabView = View.inflate(mContext, R.layout.layout_tab_top,null);? ? ? ? ? ? }? ? ? ? ? ? tabView.setTag(i);? ? ? ? ? ? addTab(i, tabView);? ? ? ? }? ? ? ? updateTabStyles();? ? }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
setTabData(ArrayList tabEntitys, FragmentActivity fa, int containerViewId, ArrayList fragments)方法內(nèi)部初始化了一個(gè)Fragment的管理輔助類FragmentChangeManager洗出,該類在構(gòu)造函數(shù)動(dòng)態(tài)添加隱藏了fragment士复,對(duì)外提供setFragments(int index)顯示指定位置的Fragment,這個(gè)在frameLayout+Fragment+commonTabLayout布局里面免去了我們管理fagment的煩惱
SegmentTabLayout相比較于CommonTabLayout多了動(dòng)畫(huà)這塊的處理,點(diǎn)擊了某一項(xiàng)Tab翩活,調(diào)用setCurrentTab,間接調(diào)用calcOffset開(kāi)啟了動(dòng)畫(huà)阱洪,動(dòng)畫(huà)的執(zhí)行過(guò)程中onAnimationUpdate重新重繪,調(diào)整位置。
tabView.setOnClickListener(newOnClickListener() {@OverridepublicvoidonClick(View v) {intposition = (Integer) v.getTag();if(mCurrentTab != position) {? ? ? ? ? ? ? ? ? ? setCurrentTab(position);if(mListener !=null) {? ? ? ? ? ? ? ? ? ? ? ? mListener.onTabSelect(position);? ? ? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? }else{if(mListener !=null) {? ? ? ? ? ? ? ? ? ? ? ? mListener.onTabReselect(position);? ? ? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? }? ? ? ? ? ? }? ? ? ? });//setter and getterpublicvoidsetCurrentTab(intcurrentTab) {? ? ? ? mLastTab =this.mCurrentTab;this.mCurrentTab = currentTab;? ? ? ? updateTabSelection(currentTab);if(mFragmentChangeManager !=null) {? ? ? ? ? ? mFragmentChangeManager.setFragments(currentTab);? ? ? ? }if(mIndicatorAnimEnable) {? ? ? ? ? ? calcOffset();? ? ? ? }else{? ? ? ? ? ? invalidate();? ? ? ? }? ? }@OverridepublicvoidonAnimationUpdate(ValueAnimator animation) {? ? ? ? IndicatorPoint p = (IndicatorPoint) animation.getAnimatedValue();? ? ? ? mIndicatorRect.left = (int) p.left;? ? ? ? mIndicatorRect.right = (int) p.right;? ? ? ? invalidate();? ? }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
首先說(shuō)一點(diǎn)這里不提供demo菠镇,需要去官方https://github.com/H07000223/FlycoTabLayout?down ,其次呢這個(gè)庫(kù)看了之后還是有很大收獲的冗荸,比如自定義屬性的運(yùn)用, setViewPager(ViewPager vp, String[] titles, FragmentActivity fa, ArrayList fragments)內(nèi)部實(shí)例一個(gè)adapter適配器利耍,最重要的是自定義屬性解析和屬性值代碼設(shè)置通過(guò)一個(gè)類來(lái)代理完成蚌本。