開源項目: FlycoTabLayout

開源項目效果

調用實例

必練基本功

Android studio 項目導入依賴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是一個Android TabLayout庫,目前有3個TabLayout

SlidingTabLayout:參照PagerSlidingTabStrip進行大量修改.關于PagerSlidingTabStrip源碼分析可以參照我以前的一篇博文http://blog.csdn.net/analyzesystem/article/details/50316745?

新增部分屬性

新增支持多種Indicator顯示器

新增支持未讀消息顯示

新增方法setViewPager

/** 關聯ViewPager,用于不想在ViewPager適配器中設置titles數據的情況 */public void setViewPager(ViewPager vp, String[] titles)/** 關聯ViewPager,用于連適配器都不想自己實例化的情況 */public void setViewPager(ViewPager vp, String[] titles, FragmentActivity fa, ArrayList fragments)

1

2

3

4

5

CommonTabLayout:不同于SlidingTabLayout對ViewPager依賴,它是一個不依賴ViewPager可以與其他控件自由搭配使用的TabLayout.

支持多種Indicator顯示器,以及Indicator動畫

支持未讀消息顯示

支持Icon以及Icon位置

新增方法

/** 關聯數據支持同時切換fragments */publicvoidsetTabData(ArrayList tabEntitys, FragmentManager fm,intcontainerViewId, ArrayList fragments)

1

2

SegmentTabLayout:仿照QQ消息列表頭部tab切換的控件

自定義屬性表

tl_indicator_colorcolor設置顯示器顏色tl_indicator_height? ? ? ? dimension? 設置顯示器高度tl_indicator_width? ? ? ? ? dimension? 設置顯示器固定寬度tl_indicator_margin_left? ? dimension? 設置顯示器margin,當indicator_width大于0,無效tl_indicator_margin_top? ? dimension? 設置顯示器margin,當indicator_width大于0,無效tl_indicator_margin_right? dimension? 設置顯示器margin,當indicator_width大于0,無效tl_indicator_margin_bottom? dimension? 設置顯示器margin,當indicator_width大于0,無效tl_indicator_corner_radius? dimension? 設置顯示器圓角弧度tl_indicator_gravity? ? ? ? enum? ? ? ? 設置顯示器上方(TOP)還是下方(BOTTOM),只對常規顯示器有用tl_indicator_style? ? ? ? ? enum? ? ? ? 設置顯示器為常規(NORMAL)或三角形(TRIANGLE)或背景色塊(BLOCK)tl_underline_colorcolor設置下劃線顏色tl_underline_height? ? ? ? dimension? 設置下劃線高度tl_underline_gravity? ? ? ? enum? ? ? ? 設置下劃線上方(TOP)還是下方(BOTTOM)tl_divider_colorcolor設置分割線顏色tl_divider_width? ? ? ? ? ? dimension? 設置分割線寬度tl_divider_padding? ? ? ? ? dimension? 設置分割線的paddingTop和paddingBottomtl_tab_padding? ? ? ? ? ? ? dimension? 設置tab的paddingLeft和paddingRighttl_tab_space_equal? ? ? ? ? boolean? ? 設置tab大小等分tl_tab_width? ? ? ? ? ? ? ? dimension? 設置tab固定大小tl_textsize? ? ? ? ? ? ? ? dimension? 設置字體大小tl_textSelectColorcolor設置字體選中顏色tl_textUnselectColorcolor設置字體未選中顏色tl_textBold? ? ? ? ? ? ? ? boolean? ? 設置字體加粗tl_iconWidth? ? ? ? ? ? ? ? dimension? 設置icon寬度(僅支持CommonTabLayout)tl_iconHeight? ? ? ? ? ? ? dimension? 設置icon高度(僅支持CommonTabLayout)tl_iconVisible? ? ? ? ? ? ? boolean? ? 設置icon是否可見(僅支持CommonTabLayout)tl_iconGravity? ? ? ? ? ? ? enum? ? ? ? 設置icon顯示位置,對應Gravity中常量值,左上右下(僅支持CommonTabLayout)tl_iconMargin? ? ? ? ? ? ? dimension? 設置icon與文字間距(僅支持CommonTabLayout)tl_indicator_anim_enable? ? boolean? ? 設置顯示器支持動畫(only for CommonTabLayout)tl_indicator_anim_duration? integer? ? 設置顯示器動畫時間(only for CommonTabLayout)tl_indicator_bounce_enable? boolean? ? 設置顯示器支持動畫回彈效果(only for CommonTabLayout)tl_indicator_width_equal_title? boolean 設置顯示器與標題一樣長(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

該庫依賴于動畫兼容庫NineOldAndroidsFlycoRoundView,稍后在源碼分析里簡單了解一下FlycoRoundView。

SlidingTabLayout調用

SlidingTabLayout自定義屬性支持下劃線設置,控制下劃線顯示方向寬高,可以讓線寬=文字寬度,也可以固定比例寬度,可以設置未讀消息的小紅點,也可以設置未讀消息數量,當前這一切的前提都是基于ViewPager來實現,都需要綁定ViewPager,通過多種綁定方法

/**關聯ViewPager,Adapter重寫了getPageTitle方法*/tabLayout.setViewPager(vp);/**關聯ViewPager,用于不想在ViewPager適配器中設置titles數據的情況*/tabLayout.setViewPager(vp, mTitles);/**關聯ViewPager,用于連適配器都不想自己實例化的情況,內部幫助實例化了一個InnerPagerAdapter*/tabLayout.setViewPager(vp, mTitles,this, mFragments);

1

2

3

4

5

6

7

8

下面我們來看看tabLayout提供幾個對我們比較有用的方法

/**顯示指定位置未讀紅點*/tabLayout.showDot(4);/**隱藏指定位置未讀紅點或消息*/tabLayout.hideMsg(5);/**showMsg(int position, int num):position位置,num小于等于0顯示紅點,num大于0顯示數字,作用:顯示未讀消息,如果消息數量>99,顯示效果99+*/tabLayout.showMsg(3,5);/**? setMsgMargin(int position, float leftPadding, float bottomPadding)設置未讀消息偏移,原點為文字的右上角.當控件高度固定,消息提示位置易控制,顯示效果佳 */tabLayout.setMsgMargin(3,0,10);/**設置未讀消息消息的背景*/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

自定義的屬性那么多,對應的set方法自然也不少,不過對照上面自定義屬性xml引用就好,一般情況下哪些方法都用不到了。

CommonTabLayout調用

SlidingTabLayout對應的方法在這里都適用不再重復,CommonTabLayout最重要的就是setTabData(ArrayList tabEntitys)方法,使得CommonTabLayout不再依賴于ViewPager完成初始化,實現底部導航或者頭部導航效果,讓我們告別RadioButton+ViewPager的時代,CustomTabEntity的命名有點問題哈,命名是一個接口非要定義Entity結尾,TabEntity實現該接口,修改構造方法,初始化內部參數,下面是一個配合CommonTabLayout+ViewPager的導航實例

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調用

SegmentTabLayout實現效果就像qq消息列表頂部的切換效果,統一支持setTabData(mTitles)不過這里傳入標題數組,tabLayout配合ViewPager切換調用tabLayout提供的方法setCurrentTab,SegmentTabLayout提供的 setTabData(String[] titles, FragmentActivity fa, int containerViewId, ArrayList fragments)方法在我們frameLayout+fragment布局切換Fragment比較實用的

源碼分析

FlycoRoundView源碼分析

粗略看過這個庫的自定義屬性文件,明悟了件事:自定義屬性的自動提示如下(以前我自定義屬性都放在declare-styleable直接定義的)

下面是這些自定義屬性的具體含義(attrs里面有具體說明)

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,這幾個控件內部源碼實現并不復雜,可以說簡單之極,構造函數通過RoundViewDelegate代理解析自定義屬性,其次就是onMeasure和onLayout的測量相關的,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()) {//如果弧度是高度的一半,直接設置radio為高度一半,否則調用delegate.setCornerRadius(getHeight() /2);? ? ? ? }else{? ? ? ? ? ? delegate.setBgSelector();// Ripple效果兼容21+,Ripple效果的實現有多重,這里使用的RippleDrawable,具體使用方法請參考api,這里不是本篇重點}? ? }

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,沒了解過的可以參考Drawable系列這篇博客有相應的簡單介紹,RoundViewDelegate提供了這些自定義屬性的set get方法,我們代碼調用通過自定義控件getDelegate獲取構造函數初始化的實例進行設置和獲取對應屬性。

FlycoTabLayout Lib庫源碼分析

MsgView仿照FlycoRoundView庫編寫的一個自定義控件,主要用于未讀消息的展示,大同小異的代碼就此略過。

SlidingTabLayout自定義控件千篇一律的自定義屬性飄過,來到必經之路setViewPager,發現新大陸notifyDataSetChanged()調用,通過dapter的getPageTitle方法獲取標題,并inflate添加一個布局到HorizontalScrollView的子View LinearLayout,并綁定Tab想的監聽回調。

/** 更新數據 */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();? ? }/** 創建并添加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);? ? ? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? }? ? ? ? ? ? }? ? ? ? });/** 每一個Tab的布局參數 */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方法根據不同的屬性計算出Rect范圍以便以繪制,具體繪制方法參考Canvas API,這里提一點下面這個方法非常有必要,如果在自定義控件的構造函數或者其他繪制相關地方使用系統依賴的代碼,會導致可視化編輯器無法報錯并提示:Use View.isInEditMode() in your custom views to skip code when shown in Eclipseis,加上了isInEditMode的判斷就不會再報錯了。

if(isInEditMode() || mTabCount <=0) {return;? ? ? ? }

1

2

3

對于代碼設置自定義的屬性值,會調用下面這兩個方法 invalidate()和 updateTabStyles();涉及到了繪制的則調用invalidate,可以直接修改的則調用updateTabStyles(個人感覺不太友好,比如代碼設置一個屬性值,就需要遍歷所有view,同時重新調用屬性賦值,關鍵只修改了其中一個屬性!!)

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方法在調用示例有提到用法,這里的show hide狀態如何保存的呢?這里有用到和AbsListView內部狀態保持一樣的方法:SparseArray來保存對應位置的狀態

/**? ? * 顯示未讀消息? ? *? ? * @paramposition 顯示tab位置? ? * @paramnum? ? ? num小于等于0顯示紅點,num大于0顯示數字? ? */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);? ? ? ? }? ? }/**? ? * 顯示未讀紅點? ? *? ? * @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

細心的你一定會發現show并沒有直接控制View的Visibility顯示隱藏,而是用了UnreadMsgUtils,這個類提供了兩個方法setSize和show方法,show方法對show的countSize進行了一次判斷轉換0為點,1-99圓+數字,>99則顯示99+,背景的弧度為寬度的一半

再回到setViewPager(ViewPager vp, String[] titles, FragmentActivity fa, ArrayList fragments)方法,在我們調用該方法時內部幫我們創建了內部定義的InnerPagerAdapter適配器,如果你想偷懶不想寫適配器就可以調用這個方法。InnerPagerAdapter重寫了getPageTitle,以便于notifyDataSetChanged方法調用動態添加tab項。

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) {// 覆寫destroyItem并且空實現,這樣每個Fragment中的視圖就不會被銷毀// 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的相似度,重復的不在敘述,區別點在于setTabData和notifyDataSetChanged方法,notifyDataSetChanged根據Icon的Gravity屬性進入不同布局的View做Tab,雖然TextView有drawableLeftRightTopBottom的相關屬性,但是并不能讓我們那么自由的控制Ui。

/** 更新數據 */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)方法內部初始化了一個Fragment的管理輔助類FragmentChangeManager,該類在構造函數動態添加隱藏了fragment,對外提供setFragments(int index)顯示指定位置的Fragment,這個在frameLayout+Fragment+commonTabLayout布局里面免去了我們管理fagment的煩惱

SegmentTabLayout相比較于CommonTabLayout多了動畫這塊的處理,點擊了某一項Tab,調用setCurrentTab,間接調用calcOffset開啟了動畫,動畫的執行過程中onAnimationUpdate重新重繪,調整位置。

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

小結

首先說一點這里不提供demo,需要去官方https://github.com/H07000223/FlycoTabLayout?down ,其次呢這個庫看了之后還是有很大收獲的,比如自定義屬性的運用, setViewPager(ViewPager vp, String[] titles, FragmentActivity fa, ArrayList fragments)內部實例一個adapter適配器,最重要的是自定義屬性解析和屬性值代碼設置通過一個類來代理完成。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,048評論 6 542
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,414評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,169評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,722評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,465評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,823評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,813評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,000評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,554評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,295評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,513評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,035評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,722評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,125評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,430評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,237評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,482評論 2 379

推薦閱讀更多精彩內容