《Android 开源库》 FlycoTabLayout 从头到脚
简介
FlycoTabLayout,是一个比Google原生TabLayout 功能更强大的TabLayout库。目前有3种TabLayout:
- SlidingTabLayout
- CommonTabLayout
- SegmentTabLayout
具体介绍和使用方法参考开源库的Wiki
官方示例:
源码分析
共有属性名称 | 格式 | 描述 |
---|---|---|
tl_indicator_color | color | 设置显示器颜色 |
tl_indicator_height | 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_divider_color | color | 设置分割线颜色 |
tl_divider_width | dimension | 设置分割线宽度 |
tl_divider_padding | dimension | 设置分割线的paddingTop和paddingBottom |
tl_tab_padding | dimension | 设置tab的paddingLeft和paddingRight |
tl_tab_space_equal | boolean | 设置tab大小等分 |
tl_tab_width | dimension | 设置tab固定大小 |
tl_textsize | dimension | 设置字体大小 |
tl_textSelectColor | color | 设置字体选中颜色 |
tl_textUnselectColor | color | 设置字体未选中颜色 |
tl_textBold | boolean | 设置字体加粗 |
tl_textAllCaps | boolean | 设置字体全大写 |
1. SlidingTabLayout
1.1 特有属性
特有属性 | 格式 | 描述 |
---|---|---|
tl_indicator_width | dimension | 设置显示器固定宽度 |
tl_indicator_gravity | enum | 设置显示器上方(TOP)还是下方(BOTTOM),只对常规显示器有用 |
tl_indicator_style | enum | 设置显示器为常规(NORMAL)或三角形(TRIANGLE)或背景色块(BLOCK) |
tl_indicator_width_equal_title | boolean | 设置显示器与标题一样长(only for SlidingTabLayout) |
tl_underline_color | color | 设置下划线颜色 |
tl_underline_height | dimension | 设置下划线高度 |
tl_underline_gravity | enum | 设置下划线上方(TOP)还是下方(BOTTOM) |
1.2 类结构
1.2.1 构造方法
第一个调用第二个,第二个调用第三个,第三个获取自定义属性值。
public SlidingTabLayout(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);setFillViewport(true);//设置滚动视图是否可以伸缩其内容以填充视口setWillNotDraw(false);//重写onDraw方法,需要调用这个方法来清除flagsetClipChildren(false);//不限制child在其范围内绘制setClipToPadding(false);//滚动时child可以绘制到padding区域this.mContext = context;mTabsContainer = new LinearLayout(context);//tab容器addView(mTabsContainer);//添加到HorizontalScrollView中obtainAttributes(context, attrs);//获取自定义属性,常用的方法,TypedArray记得回收//获取layout_height属性的值,这个方法比较溜,之前没见过String height = attrs.getAttributeValue("http://schemas.android.com/apk/res/android", "layout_height");//针对height做处理if (height.equals(ViewGroup.LayoutParams.MATCH_PARENT + "")) {} else if (height.equals(ViewGroup.LayoutParams.WRAP_CONTENT + "")) {} else {int[] systemAttrs = {android.R.attr.layout_height};TypedArray a = context.obtainStyledAttributes(attrs, systemAttrs);//获取高度mHeight = a.getDimensionPixelSize(0, ViewGroup.LayoutParams.WRAP_CONTENT);a.recycle();}
}
1.2.2 ViewPager
方法 | 描述 |
---|---|
setViewPager(ViewPager vp) | 设置ViewPager内容 |
public void setViewPager(ViewPager vp, String[] titles) | 设置ViewPager内容和标签页的标题 |
/** 关联ViewPager */public void setViewPager(ViewPager vp) {if (vp == null || vp.getAdapter() == null) {throw new IllegalStateException("ViewPager or ViewPager adapter can not be NULL !");}/*本地赋值*/this.mViewPager = vp;/*重新绑定OnPageChangeListener*/this.mViewPager.removeOnPageChangeListener(this);this.mViewPager.addOnPageChangeListener(this);/*viewpager变化,tab页响应处理处理*/notifyDataSetChanged();}
/** 更新数据 */public void notifyDataSetChanged() {mTabsContainer.removeAllViews();//清空tabthis.mTabCount = mTitles == null ? mViewPager.getAdapter().getCount() : mTitles.size();//获取tab数量,优先级mTitles > ViewPager的默认标题/*添加tab*/View tabView;for (int i = 0; i < mTabCount; i++) {tabView = View.inflate(mContext, R.layout.layout_tab, null);CharSequence pageTitle = mTitles == null ? mViewPager.getAdapter().getPageTitle(i) : mTitles.get(i);addTab(i, pageTitle.toString(), tabView);}//更新选中未选中状态更新tabupdateTabStyles();}
/** 创建并添加tab */private void addTab(final int position, 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);}//绑定点击事件,与ViewPager联动tabView.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {int position = mTabsContainer.indexOfChild(v);if (position != -1) {if (mViewPager.getCurrentItem() != position) {if (mSnapOnTabClick) {// transition immediatelymViewPager.setCurrentItem(position, false);} else {//smoothly scroll tomViewPager.setCurrentItem(position);}if (mListener != null) {//自定义tab点击事件处理mListener.onTabSelect(position);}} else {if (mListener != null) {//自定义Reselect事件处理mListener.onTabReselect(position);}}}}});/** 每一个Tab的布局参数,mTabSpaceEqual 属性控制是否均分 */LinearLayout.LayoutParams lp_tab = mTabSpaceEqual ?new LinearLayout.LayoutParams(0, LayoutParams.MATCH_PARENT, 1.0f) :new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);if (mTabWidth > 0) {lp_tab = new LinearLayout.LayoutParams((int) mTabWidth, LayoutParams.MATCH_PARENT);}//添加到Tab容器mTabsContainer.addView(tabView, position, lp_tab);}
private void updateTabStyles() {//遍历设置标题选中颜色,未选中颜色,字体大小,大小写,粗体字for (int i = 0; i < mTabCount; i++) {View v = mTabsContainer.getChildAt(i);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 == TEXT_BOLD_BOTH) {tv_tab_title.getPaint().setFakeBoldText(true);} else if (mTextBold == TEXT_BOLD_NONE) {tv_tab_title.getPaint().setFakeBoldText(false);}}}}
方法 | 描述 |
---|---|
setViewPager(ViewPager vp, String[] titles, FragmentActivity fa, ArrayList< Fragment > fragments) | 设置ViewPager,标题内容,FragmentActivity和用于显示的Fragment,用来设置ViewPager的Adapter |
/** 关联ViewPager,用于连适配器都不想自己实例化的情况 */public void setViewPager(ViewPager vp, String[] titles, FragmentActivity fa, ArrayList<Fragment> fragments) {if (vp == null) {throw new IllegalStateException("ViewPager can not be NULL !");}if (titles == null || titles.length == 0) {throw new IllegalStateException("Titles can not be EMPTY !");}this.mViewPager = vp;/*通过传入的参数构建FragmentPagerAdapter,设置到ViewPager*/this.mViewPager.setAdapter(new InnerPagerAdapter(fa.getSupportFragmentManager(), fragments, titles));this.mViewPager.removeOnPageChangeListener(this);this.mViewPager.addOnPageChangeListener(this);notifyDataSetChanged();}
看下这个内部的InnerPagerAdapter,静态Fragment,不销毁重建,只更新数据内容。
class InnerPagerAdapter extends FragmentPagerAdapter {private ArrayList<Fragment> fragments = new ArrayList<>();private String[] titles;public InnerPagerAdapter(FragmentManager fm, ArrayList<Fragment> fragments, String[] titles) {super(fm);this.fragments = fragments;this.titles = titles;}@Overridepublic int getCount() {return fragments.size();}@Overridepublic CharSequence getPageTitle(int position) {return titles[position];}@Overridepublic Fragment getItem(int position) {return fragments.get(position);}@Overridepublic void destroyItem(ViewGroup container, int position, Object object) {// 覆写destroyItem并且空实现,这样每个Fragment中的视图就不会被销毁// super.destroyItem(container, position, object);}@Overridepublic int getItemPosition(Object object) {return PagerAdapter.POSITION_NONE;}}
方法 | 描述 |
---|---|
onPageScrolled(int position, float positionOffset, int positionOffsetPixels) | 页面滚动,position为当前位置,positionOffset范围[0,1),从当前到下一页,positionOffsetPixels从当前位置滚动的offset,单位px |
onPageSelected(int position) | 选中位置 |
onPageScrollStateChanged(int state) | 滚动状态改变 |
SCROLL_STATE_IDLE(pager处于空闲状态)
SCROLL_STATE_DRAGGING( pager处于正在拖拽中)
SCROLL_STATE_SETTLING(pager正在自动沉降,相当于松手后,pager恢复到一个完整pager的过程)
@Overridepublic void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {/*** position:当前View的位置* mCurrentPositionOffset:当前View的偏移量比例.[0,1)*/this.mCurrentTab = position;this.mCurrentPositionOffset = positionOffset;/*标签栏根据ViewPager的滚动状态联动,滚动到对应位置*/scrollToCurrentTab();/*触发重绘*/invalidate();}@Overridepublic void onPageSelected(int position) {/*根据ViewPager选中状态调整标签页的选中状态*/updateTabSelection(position);}@Overridepublic void onPageScrollStateChanged(int state) {}
/** HorizontalScrollView滚到当前tab,并且居中显示 */private void scrollToCurrentTab() {if (mTabCount <= 0) {return;}int offset = (int) (mCurrentPositionOffset * mTabsContainer.getChildAt(mCurrentTab).getWidth());/**当前Tab的left+当前Tab的Width乘以positionOffset*/int newScrollX = mTabsContainer.getChildAt(mCurrentTab).getLeft() + offset;if (mCurrentTab > 0 || offset > 0) {/**HorizontalScrollView移动到当前tab,并居中*/newScrollX -= getWidth() / 2 - getPaddingLeft();calcIndicatorRect();newScrollX += ((mTabRect.right - mTabRect.left) / 2);}if (newScrollX != mLastScrollX) {mLastScrollX = newScrollX;/** scrollTo(int x,int y):x,y代表的不是坐标点,而是偏移量* x:表示离起始位置的x水平方向的偏移量* y:表示离起始位置的y垂直方向的偏移量*/scrollTo(newScrollX, 0);}}
/*根据是否选中设置字体颜色和粗体*/private void updateTabSelection(int position) {for (int i = 0; i < mTabCount; ++i) {View tabView = mTabsContainer.getChildAt(i);final boolean isSelect = i == position;TextView tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title);if (tab_title != null) {tab_title.setTextColor(isSelect ? mTextSelectColor : mTextUnselectColor);if (mTextBold == TEXT_BOLD_WHEN_SELECT) {tab_title.getPaint().setFakeBoldText(isSelect);}}}}
1.2.3 Tab相关
方法 | 描述 |
---|---|
addNewTab(String title) | 提供给外部使用的新增tab的方法 |
public void addNewTab(String title) {View tabView = View.inflate(mContext, R.layout.layout_tab, null);if (mTitles != null) {mTitles.add(title);}CharSequence pageTitle = mTitles == null ? mViewPager.getAdapter().getPageTitle(mTabCount) : mTitles.get(mTabCount);addTab(mTabCount, pageTitle.toString(), tabView);this.mTabCount = mTitles == null ? mViewPager.getAdapter().getCount() : mTitles.size();updateTabStyles();}
方法 | 描述 |
---|---|
setCurrentTab(int currentTab) | 跳转到指定tab,是否平滑的滚动过去由系统控制 |
setCurrentTab(int currentTab, boolean smoothScroll) | 跳转到制指定tab, smoothScroll控制是否平滑的滚动过去 |
public void setCurrentTab(int currentTab) {this.mCurrentTab = currentTab;mViewPager.setCurrentItem(currentTab);}public void setCurrentTab(int currentTab, boolean smoothScroll) {this.mCurrentTab = currentTab;mViewPager.setCurrentItem(currentTab, smoothScroll);}
1.2.4 Getter和Setter
不做赘述
1.2.5 MsgView相关(未读信息)
方法 | 描述 |
---|---|
showMsg(int position, int num) | 显示未读消息,position为tab位置,num小于等于0显示红点,num大于0显示数字 |
showDot(int position) | 显示未读红点, position为tab位置 |
hideMsg(int position) | 隐藏未读消息, position为tab位置 |
setMsgMargin(int position, float leftPadding, float bottomPadding) | 设置未读消息偏移,原点为文字的右上角.当控件高度固定,消息提示位置易控制,显示效果佳 |
getMsgView(int position) | 当前类只提供了少许设置未读消息属性的方法,可以通过该方法获取MsgView对象从而各种设置 |
2. CommonTabLayout
2.1 特有属性
特有属性 | 格式 | 描述 |
---|---|---|
tl_indicator_width | dimension | 设置显示器固定宽度 |
tl_indicator_gravity | enum | 设置显示器上方(TOP)还是下方(BOTTOM),只对常规显示器有用 |
tl_indicator_style | enum | 设置显示器为常规(NORMAL)或三角形(TRIANGLE)或背景色块(BLOCK) |
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_underline_color | color | 设置下划线颜色 |
tl_underline_height | dimension | 设置下划线高度 |
tl_underline_gravity | enum | 设置下划线上方(TOP)还是下方(BOTTOM) |
tl_iconWidth | dimension | 设置icon宽度(仅支持CommonTabLayout) |
tl_iconHeight | dimension | 设置icon高度(仅支持CommonTabLayout) |
tl_iconVisible | boolean | 设置icon是否可见(仅支持CommonTabLayout) |
tl_iconGravity | enum | 设置icon显示位置,对应Gravity中常量值,左上右下(仅支持CommonTabLayout),LEFT,RIGHT,TOP,BOTTOM |
tl_iconMargin | dimension | 设置icon与文字间距(仅支持CommonTabLayout) |
2.2 区别于SlidingTabLayout
- 不依赖于ViewPager,可以与其他组件搭配
- 支持自定义Tab样式,主要体现在常用的图标+文字的形式。
- SlidingTabLayout继承HorizontalScrollView而CommonTabLayout继承FrameLayout
2.3 类结构
2.3.1 构造方法
与SlidingTabLayout实现类似,获取的属性值不太一样而已。多出一个动画的内容,点击某一个Tab后,indicator的移动动画效果
mValueAnimator = ValueAnimator.ofObject(new PointEvaluator(), mLastP, mCurrentP);
mValueAnimator.addUpdateListener(this);
2.3.2 动画相关
class IndicatorPoint {public float left;public float right;
}private IndicatorPoint mCurrentP = new IndicatorPoint();
private IndicatorPoint mLastP = new IndicatorPoint();class PointEvaluator implements TypeEvaluator<IndicatorPoint> {@Overridepublic IndicatorPoint evaluate(float fraction, IndicatorPoint startValue, IndicatorPoint endValue) {float left = startValue.left + fraction * (endValue.left - startValue.left);float right = startValue.right + fraction * (endValue.right - startValue.right);IndicatorPoint point = new IndicatorPoint();point.left = left;point.right = right;return point;}
}
@Override
public void onAnimationUpdate(ValueAnimator animation) {View currentTabView = mTabsContainer.getChildAt(this.mCurrentTab);IndicatorPoint p = (IndicatorPoint) animation.getAnimatedValue();mIndicatorRect.left = (int) p.left;mIndicatorRect.right = (int) p.right;if (mIndicatorWidth < 0) { //indicatorWidth小于0时,原jpardogo's PagerSlidingTabStrip} else {//indicatorWidth大于0时,圆角矩形以及三角形float indicatorLeft = p.left + (currentTabView.getWidth() - mIndicatorWidth) / 2;mIndicatorRect.left = (int) indicatorLeft;mIndicatorRect.right = (int) (mIndicatorRect.left + mIndicatorWidth);}invalidate();
}
2.3.3 Tab相关
方法 | 描述 |
---|---|
setTabData(ArrayList< CustomTabEntity> tabEntitys) | 设置tab entity |
setTabData(ArrayList< CustomTabEntity> tabEntitys, FragmentActivity fa, int containerViewId, ArrayList< Fragment> fragments) | 关联数据支持同时切换fragments |
notifyDataSetChanged() | 更新数据 |
setCurrentTab(int currentTab) | 设置当前tab |
public void setTabData(ArrayList<CustomTabEntity> tabEntitys) {if (tabEntitys == null || tabEntitys.size() == 0) {throw new IllegalStateException("TabEntitys can not be NULL or EMPTY !");}this.mTabEntitys.clear();/*设置tab标签*/this.mTabEntitys.addAll(tabEntitys);/*更新数据*/notifyDataSetChanged();
}
/** 更新数据 */
public void notifyDataSetChanged() {/*清空容器中的tab*/mTabsContainer.removeAllViews();this.mTabCount = mTabEntitys.size();View tabView;/*根据图标的gravity构建不同的tab样式,图标支持上下左右*/for (int i = 0; i < mTabCount; i++) {if (mIconGravity == Gravity.LEFT) {tabView = View.inflate(mContext, R.layout.layout_tab_left, null);} else if (mIconGravity == Gravity.RIGHT) {tabView = View.inflate(mContext, R.layout.layout_tab_right, null);} else if (mIconGravity == Gravity.BOTTOM) {tabView = View.inflate(mContext, R.layout.layout_tab_bottom, null);} else {tabView = View.inflate(mContext, R.layout.layout_tab_top, null);}/*i添加到tag,但从这个类的方法上看,这一步没有什么必要,因为addTab会传入i,addTab中直接使用i就好,但是如果我们在外部拿到tabView,就可以直接指导它的position,不用循环遍历,还是挺方便的*/tabView.setTag(i);/*添加tab*/addTab(i, tabView);}/*根据选中未选中状态更新tab显示效果*/updateTabStyles();
}
/** 创建并添加tab */
private void addTab(final int position, View tabView) {/*设置文本内容,title*/TextView tv_tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title);tv_tab_title.setText(mTabEntitys.get(position).getTabTitle());/*设置图标内容,添加未选中内容,后面根据选中未选中重新刷一次图片*/ImageView iv_tab_icon = (ImageView) tabView.findViewById(R.id.iv_tab_icon);iv_tab_icon.setImageResource(mTabEntitys.get(position).getTabUnselectedIcon());/*设置tabView的点击事件*/tabView.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {/*前面设置的tab,也就是position*/int position = (Integer) v.getTag();if (mCurrentTab != position) {/*设置当前tab*/setCurrentTab(position);//有OnTabSelectListener则执行对应的处理if (mListener != null) {mListener.onTabSelect(position);}} else {if (mListener != null) {mListener.onTabReselect(position);}}}});/** 每一个Tab的布局参数 ,根据是否均分设置不同的布局,若宽度不为0,则设置宽度*/LinearLayout.LayoutParams lp_tab = mTabSpaceEqual ?new LinearLayout.LayoutParams(0, LayoutParams.MATCH_PARENT, 1.0f) :new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);if (mTabWidth > 0) {lp_tab = new LinearLayout.LayoutParams((int) mTabWidth, LayoutParams.MATCH_PARENT);}mTabsContainer.addView(tabView, position, lp_tab);
}
/*和SlidingTabLayout相似,多了一个图标的处理*/
private void updateTabStyles() {for (int i = 0; i < mTabCount; i++) {View tabView = mTabsContainer.getChildAt(i);tabView.setPadding((int) mTabPadding, 0, (int) mTabPadding, 0);TextView tv_tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title);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 == TEXT_BOLD_BOTH) {tv_tab_title.getPaint().setFakeBoldText(true);} else if (mTextBold == TEXT_BOLD_NONE) {tv_tab_title.getPaint().setFakeBoldText(false);}ImageView iv_tab_icon = (ImageView) tabView.findViewById(R.id.iv_tab_icon);if (mIconVisible) {iv_tab_icon.setVisibility(View.VISIBLE);CustomTabEntity tabEntity = mTabEntitys.get(i);iv_tab_icon.setImageResource(i == mCurrentTab ? tabEntity.getTabSelectedIcon() : tabEntity.getTabUnselectedIcon());LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(mIconWidth <= 0 ? LinearLayout.LayoutParams.WRAP_CONTENT : (int) mIconWidth,mIconHeight <= 0 ? LinearLayout.LayoutParams.WRAP_CONTENT : (int) mIconHeight);if (mIconGravity == Gravity.LEFT) {lp.rightMargin = (int) mIconMargin;} else if (mIconGravity == Gravity.RIGHT) {lp.leftMargin = (int) mIconMargin;} else if (mIconGravity == Gravity.BOTTOM) {lp.topMargin = (int) mIconMargin;} else {lp.bottomMargin = (int) mIconMargin;}iv_tab_icon.setLayoutParams(lp);} else {iv_tab_icon.setVisibility(View.GONE);}}
}
另外一个setTabData
/** 关联数据支持同时切换fragments */
public void setTabData(ArrayList<CustomTabEntity> tabEntitys, FragmentActivity fa, int containerViewId, ArrayList<Fragment> fragments) {/*拿到一个mFragmentChangeManager ,后面setCurrentTab的时候 ,如果这个值不为空,根据这个来切换fragment,实现一种类似FragmentPagerAdapter的效果*/mFragmentChangeManager = new FragmentChangeManager(fa.getSupportFragmentManager(), containerViewId, fragments);setTabData(tabEntitys);
}
public void setCurrentTab(int currentTab) {mLastTab = this.mCurrentTab;this.mCurrentTab = currentTab;/*遍历更新tab选中未选中状态*/updateTabSelection(currentTab);/*如果mFragmentChangeManager 不为空,就根据当前选中的tab显示对应的Fragment*/if (mFragmentChangeManager != null) {mFragmentChangeManager.setFragments(currentTab);}/*indicator动画效果,计算后重绘*/if (mIndicatorAnimEnable) {calcOffset();} else {invalidate();}
}
2.3.4 FragmentChangeManager
public class FragmentChangeManager {private FragmentManager mFragmentManager;private int mContainerViewId;/** Fragment切换数组 */private ArrayList<Fragment> mFragments;/** 当前选中的Tab */private int mCurrentTab;/*构造方法,setTabData的时候看到过*/public FragmentChangeManager(FragmentManager fm, int containerViewId, ArrayList<Fragment> fragments) {this.mFragmentManager = fm;this.mContainerViewId = containerViewId;this.mFragments = fragments;initFragments();}/** 初始化fragments */private void initFragments() {for (Fragment fragment : mFragments) {mFragmentManager.beginTransaction().add(mContainerViewId, fragment).hide(fragment).commit();}setFragments(0);}/** 界面切换控制,CommonTabLayout中的setCurrentTab方法可以控制*/public void setFragments(int index) {for (int i = 0; i < mFragments.size(); i++) {FragmentTransaction ft = mFragmentManager.beginTransaction();Fragment fragment = mFragments.get(i);if (i == index) {ft.show(fragment);} else {ft.hide(fragment);}ft.commit();}mCurrentTab = index;}public int getCurrentTab() {return mCurrentTab;}public Fragment getCurrentFragment() {return mFragments.get(mCurrentTab);}
}
2.3.5 Getter,Setter以及MsgView先关
Getter和Setter方法是属性值的获取和设置,MsgView相关方法和SlidingTabLayout比较相似。
3. SegmentTabLayout
3.1 特有属性
特有属性 | 格式 | 描述 |
---|---|---|
tl_indicator_anim_enable | boolean | 设置显示器支持动画 |
tl_indicator_anim_duration | integer | 设置显示器动画时间 |
tl_indicator_bounce_enable | boolean | 设置显示器支持动画回弹效果 |
tl_bar_color | color | 设置整体颜色 |
tl_bar_stroke_color | color | 设置边框颜色 |
tl_bar_stroke_width | dimension | 设置边框粗细 |
3.2 区别于CommonTabLayout
- 不支持图标,但是可以看做是一个特殊的CommonTabLayout.
3.3 类结构
整体来说,内容基本上和CommonTabLayout,只是少了Icon的对应处理,多出的是Segment样式的处理。
4. MsgView
4.1 自定义属性
属性值 | 格式 | 描述 |
---|---|---|
mv_backgroundColor | color | 圆角矩形背景色 |
mv_cornerRadius | dimension | 圆角弧度,单位dp |
mv_strokeWidth | dimension | 边框粗细,单位dp |
mv_strokeColor | color | 圆角边框颜色 |
mv_isRadiusHalfHeight | boolean | 圆角弧度是高度一半 |
mv_isWidthHeightEqual | boolean | 圆角矩形宽高相等,取较宽高中大值 |
4.2 类结构
项目使用
个人项目Gank.io Android 客户端中使用效果,底部使用的CommonTabLayout,顶部使用的是SlidingTabLayout。整体而言,日常开发过程中,FlycoTabLayout还是很实用的。
《Android 开源库》 FlycoTabLayout 从头到脚相关推荐
- Android开源库集合(控件)
RecycleView: RecycleView功能增强 https://github.com/Malinskiy/SuperRecyclerView RecycleView功能增强(拖拽,滑动删除, ...
- 关于Android开源库分享平台,(GitClub)微信小程序的开发体验
七八月份的深圳一直在下雨,总有人说雨天适合窝在家看书,对于程序开发者来说更是难得的学习机会.我们502工作室的小伙伴利用这个时间学习了一下微信小程序开发,并上线了一个GitClub小程序,目前功能有些 ...
- Android 开源库获取途径整理
最新内容请见原文: http://www.trinea.cn/android/android-open-project-summary/ 介绍目前收藏 Android 开源库比较多的 GitHub 项 ...
- Android开源库集合(UI效果)
动画效果 粒子动画效果 https://github.com/glomadrian/Grav 水波式loading等待动画 https://github.com/race604/WaveLoading ...
- android 日历翻页动画,Android开源库合集:轻松实现Android动态,炫目:日历效果...
前言: 了解过那种动态,炫目的日历效果吗?你知道是怎么 操作的嘛?是否想过,用UI就可以实现,对,也许你说的对,不过UI只是都是动态效果的一部分.那么今天用Annroid开源库,来告诉你android ...
- Android开源库V - Layout:淘宝、天猫都在用的UI框架,赶紧用起来吧!
前言 V- Layout 是阿里出品的基础 UI 框架,用于快速实现页面的复杂布局,在手机天猫 Android版 内广泛使用 让人激动的是,在上个月V- Layout终于在Github上开源! Git ...
- GitHub 上排名前 100 的 Android 开源库介绍
转自:http://www.codeceo.com/article/github-top-100-android-libs.html 本项目主要对目前 GitHub 上排名前 100 的 Androi ...
- Android开源库总结
自己总结的Android开源项目及库. github排名https://github.com/trending, github搜索:https://github.com/search UI Aweso ...
- 排名前100的Android开源库
本项目主要对目前GitHub上排名前100的Android开源库进行简单的介绍,至于排名完全是根据GitHub搜索Java语言选择「BestMatch」得到的结果,然后过滤了跟Android不相关的项 ...
- GitHub 上排名前 100 的 Android 开源库进行简单的介绍
本文转载于:https://github.com/Freelander/Android_Data/blob/master/Android-Librarys-Top-100.md 本项目主要对目前 Gi ...
最新文章
- python怎么画简单图片-python中简单易学的绘图:用turtle画太极图
- iOS下JS与OC互相调用(六)--WKWebView + WebViewJavascriptBridge
- jQuery 文件上传插件:uploadify、swfupload
- C++编程风格(一)
- 经典算法研究系列:十、从头到尾彻底理解傅里叶变换算法、上
- 兵乓球- 经典街机游戏-python小游戏源码下载
- Fortran基础练习02--循环2
- 关于code footprint-reduction-techniques
- msclass 文字滚动_MSClass (通用不间断滚动JS封装类)
- r4烧录卡内核安装_R4烧录卡NDS内核,绝对可用
- 135编辑器html点击图片播放音乐,135编辑器怎么给文章添加音频和视频?135编辑器给文章添加音频和视频教程...
- StretchDIBits
- Markdown文件中图片自动转云图片和自动生成标题序号
- 中间件技术及双十一实践·EagleEye篇
- 分享个PS快速替换背景颜色的方法
- Linux之恢复删除的数据
- Java序列化,碰到serialVersionUID不一致怎么处理?
- 抖音最新风控体系研究
- [算法设计题] 双栈结构
- “System.NullReferenceException”类型的异常在 App_Web_2tjb2nqh.dll 中发生,但未在用户代码中进行处理(C#开发)