转载请标明出处:
http://blog.csdn.net/iamzgx/article/details/52663783
本文出自:【iGoach的博客】
前段时间,遇到一个问题,今日头条的Tab栏下面大致可以分为2种布局,一种是新闻列表,一种是视频列表。怎么实现这种效果呢?Tab栏有很多种实现方式,使用ViewPagerIndicator、TabLayout或者自己通过HorizontalScrollView写一个,这个没问题,遇到的问题是ViewPager搭配什么Adapter和Fragment结合更好呢,Tab比较少的情况下,个人平时习惯使用FragmentPagerAdapter,那么Tab很多的情况下,使用FragmentPagerAdapter就不太适合了,因为生成Fragment都会保存在内存中。还有没有类似的Adapter呢?显然是有的,那就是FragmentStatePagerAdapter,它会释放不可见Fragment的资源,进行内存优化。所以FragmentStatePagerAdapter更适合Tab多的情况下。所以这篇博客通过HorizontalScrollView+ViewPager+FragmentStatePagerAdapter+Fragment实现一个类似网易新闻客户端的Tab。
概述
有很多应用APP主页都是使用Tab来切换栏目的,比如今日头条,网易新闻客户端,知乎之类的App。仔细去体验这个功能,我们会发现以下几个特点:
- 根据栏目的数量分为可滚动和不可滚动
- 选中的Tab字体和其他Tab字体颜色和大小有区别
- Tab字体底部具有全宽或者和字体等宽的指示器
- ViewPager切换Tab栏会随着滚动
- Tab栏切换,只会在第一次初始化时请求数据。
- Tab栏可能具有红点 或者红点数字提醒
- Tab栏中间具有间隔分割
等等。
功能实现
下面通过HorizontalScrollView来实现上面几点,当然,TabLayout也可以实现上面几点,但很多API具有局限性,比如指示器宽度定义,红点提醒等等,很多也是需要自己来实现。所以使用HorizontalScrollView来实现更好点,自由度更大,哈哈。
首先,需要定义一个继承HorizontalScrollView的子视图ZTabLayout。那么我们就需要定义一些属性,仔细想想,可以得到下面一些属性。
<declare-styleable name="ZTabLayout">
<attr name="tab_normal_textSize" format="dimension"/>
<attr name="tab_select_textSize" format="dimension"/>
<attr name="tab_textColor" format="reference"/>
<attr name="tab_indicatorColor" format="color"/>
<attr name="tab_indicatorHeight" format="dimension"/>
<attr name="tab_min_width" format="dimension"/>
<attr name="tab_dividerWidth" format="dimension"/>
<attr name="tab_dividerColor" format="color"/>
<attr name="tab_dividerPadding" format="dimension"/>
<attr name="tab_Padding" format="dimension"/>
<attr name="tab_dividerShow" format="boolean"/>
</declare-styleable>
上面的属性基本上是看名知意,这里就不多说了,下面就是一些属性的定义了
//默认字体大小
private final int DEFAULT_NORMAL_TEXT_SIZE_SP = AppUtils.sp2px(14);
private int mNormalTextSize = DEFAULT_NORMAL_TEXT_SIZE_SP;
//选中字体大小
private final int DEFAULT_SELECT_TEXT_SIZE_SP = AppUtils.sp2px(16);
private int mSelectTextSize = DEFAULT_SELECT_TEXT_SIZE_SP;
//字体颜色
private final int DEFAULT_NORMAL_TEXT_COLOR = Color.BLACK;
private final int DEFAULT_SELECT_TEXT_COLOR = Color.RED;
private ColorStateList mTextColor;
//指示器高度
private final int DEFAULT_INDICATOR_HEIGHT_DP = AppUtils.dp2px(2);
private int mIndicatorHeight = DEFAULT_INDICATOR_HEIGHT_DP ;
//指示器颜色
private final int DEFAULT_INDICATOR_COLOR = Color.RED;
private int mIndicatorColor = DEFAULT_INDICATOR_COLOR ;
//中间线
private final int DEFAULT_DIVIDER_WIDTH =AppUtils.dp2px(1);
private int mDividerWidth = DEFAULT_DIVIDER_WIDTH;
private final int DEFAULT_DIVIDER_COLOR = Color.GRAY;
private int mDividerColor = DEFAULT_DIVIDER_COLOR;
private Paint mDividerPaint;
private int DEFAULT_DIVIDER_PADDING = AppUtils.dp2px(5);
private int mDividerPadding = DEFAULT_DIVIDER_PADDING ;
private boolean hasShowDivider = false ;
//红点显示
private final int DEFAULT_MSG_ROUND_COLOR = Color.RED;
private int mMsgRoundColor = DEFAULT_MSG_ROUND_COLOR;
private SparseBooleanArray mInitSetMap ;
private SparseIntArray mMsgNumMap;
private Paint mMsgPaint;
private Paint mMsgNumPaint;
private int mMsgNumColor = Color.WHITE;
private int mMsgTextSizeSp = AppUtils.sp2px(8);
private int mMsgPadding;
//tab最小宽度
private final int DEFAULT_TAB_MIN_WIDTH = AppUtils.dp2px(50);
private int mMinTabWidth = DEFAULT_TAB_MIN_WIDTH;
//tab之间的间距
private int mTabPadding;
//关联的viewpager
private ViewPager mViewPager;
//第一个子View
private IndicationTabLayout mTabContainer;
//Tab总数
private int mTabCount;
//当前选中的Tab
private int mCurrentTabPosition;
//当前切换Tab的偏移量
private float mCurrentOffset;
//数据源
private List<String> mDataList;
属性大致是根据Tab字体属性,指示器属性,Tab之间间隔线属性、红点提醒属性以及Tab之间间距和大小属性和Tab显示的数据源等等。这里说下上面的mInitSetMap 和mMsgNumMap,mInitSetMap 主要是用来保存各个Tab是否要显示红点提醒,mMsgNumMap主要是保存各个Tab要显示红点提醒上的数量。
然后我们就要对一些属性进行初始化,
public ZTabLayout(Context context) {
this(context,null);
}
public ZTabLayout(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public ZTabLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initStyle(context,attrs);
/*让子View视图属性生效*/
setFillViewport(true);
/*不显示滚动条*/
setHorizontalScrollBarEnabled(false);
/*LinearLayout的子View,主要是处理指示器的作用*/
mTabContainer = new IndicationTabLayout(context);
/*设置指示器的颜色*/
mTabContainer.setSelectedIndicatorColor(mIndicatorColor);
/*设置指示器的高度*/
mTabContainer.setSelectedIndicatorHeight(mIndicatorHeight);
/*添加HorizontalScrollView的根View*/
addView(mTabContainer,0, new HorizontalScrollView.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT));
/*Tab栏要显示的数据*/
mDataList = new ArrayList<>();
/*创建指示器画笔*/
mDividerPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
/*创建红点画笔*/
mMsgPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
/*创建红点数字画笔*/
mMsgNumPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
/*保存Tab是否显示红点作用*/
mInitSetMap = new SparseBooleanArray();
/*保存Tab显示红点数量*/
mMsgNumMap = new SparseIntArray();
}
/*一些自定义属性的初始化*/
private void initStyle(Context context, AttributeSet attrs){
TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs,R.styleable.ZTabLayout,0,0);
mNormalTextSize = typedArray.getDimensionPixelSize(R.styleable.ZTabLayout_tab_normal_textSize,DEFAULT_NORMAL_TEXT_SIZE_SP);
mSelectTextSize = typedArray.getDimensionPixelSize(R.styleable.ZTabLayout_tab_select_textSize,DEFAULT_SELECT_TEXT_SIZE_SP);
mTextColor = typedArray.getColorStateList(R.styleable.ZTabLayout_tab_textColor);
if(mTextColor==null)
mTextColor = createDefaultTextColor();
mIndicatorHeight = (int) typedArray.getDimension(R.styleable.ZTabLayout_tab_indicatorHeight,DEFAULT_INDICATOR_HEIGHT_DP);
mIndicatorColor = typedArray.getColor(R.styleable.ZTabLayout_tab_indicatorColor,DEFAULT_INDICATOR_COLOR);
mMinTabWidth = typedArray.getColor(R.styleable.ZTabLayout_tab_min_width,DEFAULT_TAB_MIN_WIDTH);
mDividerColor = typedArray.getColor(R.styleable.ZTabLayout_tab_dividerColor,DEFAULT_DIVIDER_COLOR);
mDividerWidth = (int) typedArray.getDimension(R.styleable.ZTabLayout_tab_dividerWidth,DEFAULT_DIVIDER_WIDTH);
mDividerPadding = (int) typedArray.getDimension(R.styleable.ZTabLayout_tab_dividerPadding,DEFAULT_DIVIDER_PADDING);
mTabPadding = (int) typedArray.getDimension(R.styleable.ZTabLayout_tab_Padding,0);
hasShowDivider = typedArray.getBoolean(R.styleable.ZTabLayout_tab_dividerShow,false);
typedArray.recycle();
}
private ColorStateList createDefaultTextColor(){
ColorStateList colorStateList = new ColorStateList(new int[][]{{android.R.attr.state_selected}
,{0}}, new int[]{DEFAULT_SELECT_TEXT_COLOR,DEFAULT_NORMAL_TEXT_COLOR});
return colorStateList;
}
属性初始化完之后,自然我们就要把ViewPager和Tab栏数据源传入进来,然后根据ViewPager来添加Tab的View到mTabContainer线性布局里面,
/*Tab要显示的数据*/
public void setDataList(List<String> dataList){
this.mDataList.clear();
this.mDataList.addAll(dataList);
}
/*很ViewPager相关联,同时根据ViewPager添加Tab的View*/
public void setupWithViewPager(ViewPager viewPager){
this.mViewPager = viewPager ;
if(viewPager == null)
throw new IllegalArgumentException("viewpager not is null");
PagerAdapter pagerAdapter = viewPager.getAdapter() ;
if(pagerAdapter == null)
throw new IllegalArgumentException("pagerAdapter not is null");
/*添加ViewPager滚动监听*/
this.mViewPager.addOnPageChangeListener(new TabPagerChanger());
/*需要添加Tab的总数*/
mTabCount = pagerAdapter.getCount();
/*当前选中的Tab*/
mCurrentTabPosition = viewPager.getCurrentItem();
notifyDataSetChanged();
}
/*创建Tab的View,然后添加view*/
public void notifyDataSetChanged(){
mTabContainer.removeAllViews();
for (int i = 0 ; i<mTabCount;i++) {
final int currentPosition = i ;
TextView tabTextView = createTextView() ;
tabTextView.setPadding(mTabPadding,0,mTabPadding,0);
tabTextView.setText(mDataList.get(i));
tabTextView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
mViewPager.setCurrentItem(currentPosition);
}
});
mTabContainer.addView(tabTextView,new LinearLayout.LayoutParams(0,LinearLayout.LayoutParams.MATCH_PARENT,1));
}
/*设置第一个选中的Tab的样式*/
setSelectedTabView(mCurrentTabPosition);
}
/*基本创建TextView*/
private TextView createTextView(){
TextView textView = new TextView(getContext());
textView.setTextSize(TypedValue.COMPLEX_UNIT_PX,mNormalTextSize);
textView.setTextColor(mTextColor);
textView.setMinWidth(mMinTabWidth);
textView.setTypeface(Typeface.DEFAULT_BOLD);
textView.setGravity(Gravity.CENTER);
return textView;
}
/*处理选中Tab的样式*/
protected void setSelectedTabView(int position)
{
for (int i = 0; i < mTabCount; i++) {
View view = mTabContainer.getChildAt(i);
if (view instanceof TextView)
{
TextView textView = (TextView)view;
textView.setSelected(position==i);
textView.setTextSize(TypedValue.COMPLEX_UNIT_PX,position==i?mSelectTextSize:mNormalTextSize);
}
}
}
接下来,我们就要根据ViewPager的监听事件来对ViewPager滚动时候Tab栏样式改变,
/*ViewPager的监听事件*/
private class TabPagerChanger implements ViewPager.OnPageChangeListener{
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
/*通过偏移量来设置指示器的滚动位置*/
setScrollPosition(position,positionOffset);
}
@Override
public void onPageSelected(int position) {
/*设置选中Tab的样式*/
setSelectedTabView(position);
}
@Override
public void onPageScrollStateChanged(int state) {
}
}
private void setScrollPosition(int position, float positionOffset){
this.mCurrentTabPosition = position ;
this.mCurrentOffset = positionOffset ;
mTabContainer.setIndicatorPositionFromTabPosition(position, positionOffset);
/*处理选择屏幕边界的Tab,HorizontalScrollView自动滚动到响应的位置*/
scrollTo(calculateScrollXForTab(mCurrentTabPosition,mCurrentOffset), 0);
/*测试红点功能作用*/
if(position==3)
hideMsg(position);
}
/*使用TabLayout的计算方式,主要的计算方式是当前选中Tab左边距+当前选中的Tab和下一个Tab宽度中间的中点到mTabContainer屏幕内宽度中点间距做为HorizontalScrollView的水平滚动位置*/
private int calculateScrollXForTab(int position, float positionOffset) {
final View selectedChild = mTabContainer.getChildAt(position);
final View nextChild = position + 1 < mTabContainer.getChildCount()
? mTabContainer.getChildAt(position + 1)
: null;
final int selectedWidth = selectedChild != null ? selectedChild.getWidth() : 0;
final int nextWidth = nextChild != null ? nextChild.getWidth() : 0;
return selectedChild.getLeft()
+ ((int) ((selectedWidth + nextWidth) * positionOffset * 0.5f))
+ (selectedChild.getWidth() / 2)
- (getWidth() / 2);
}
接下来我们就来绘制Tab之间可能要显示的间隔线和可能要显示的红点提醒,这个操作主要是在onDraw方法里面操作
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
/*Tab总数小于0,不处理*/
if (isInEditMode() || mTabCount <= 0) {
return;
}
int height = getHeight();
int paddingLeft = getPaddingLeft();
/*当间隔线宽度大于0并且属性定义为需要绘制的时候绘制Tab之间的间隔线*/
if (mDividerWidth > 0&&hasShowDivider) {
mDividerPaint.setStrokeWidth(mDividerWidth);
mDividerPaint.setColor(mDividerColor);
for (int i = 0; i < mTabCount - 1; i++) {
View tab = mTabContainer.getChildAt(i);
/*间隔线绘制在Tab最右边的位置上,mDividerPadding做为顶部和底部的间距*/
canvas.drawLine(paddingLeft + tab.getRight(), mDividerPadding, paddingLeft + tab.getRight(), height - mDividerPadding, mDividerPaint);
}
}
/*绘制提示消息*/
for (int i = 0; i < mTabCount - 1; i++) {
if (mInitSetMap.get(i)) {
updateMsgPosition(canvas,mTabContainer.getChildAt(i),mMsgNumMap.get(i));
}
}
}
/*计算绘制红点的位置*/
private void updateMsgPosition(final Canvas canvas,final View updateView,final int msgNum) {
if(updateView == null)
return;
int circleX, circleY;
if (updateView.getWidth() > 0) {
int selectTextPadding = (int) ((updateView.getWidth()-measureTextLength(updateView))/2+0.5f);
circleX = updateView.getRight()-selectTextPadding+mMsgPadding;
circleY = (int) ((mTabContainer.getHeight() - measureTextHeight(updateView))/2 -mMsgPadding);
drawMsg(canvas,circleX,circleY,msgNum);
}
}
/*通过相应画笔绘制红点以及红点上数量大于0的时候绘制红点数量*/
private void drawMsg(Canvas canvas,int mMsgCircleX,int mMsgCircleY,int mMsgNum){
mMsgPaint.setStyle(Paint.Style.FILL);
mMsgPaint.setColor(mMsgRoundColor);
if(mMsgNum>0){
/*数量大于0,进行红点和数量绘制*/
mMsgNumPaint.setTextSize(mMsgTextSizeSp);
mMsgNumPaint.setColor(mMsgNumColor);
mMsgNumPaint.setTextAlign(Paint.Align.CENTER);
String showTxt = mMsgNum>99?"99+":String.valueOf(mMsgNum);
int mMsgNumRadius = (int) Math.max(mMsgNumPaint.descent()-mMsgNumPaint.ascent(),
mMsgNumPaint.measureText(showTxt))/2+AppUtils.dp2px(2);
canvas.drawCircle(mMsgCircleX+mMsgNumRadius,mMsgCircleY,mMsgNumRadius, mMsgPaint);
Paint.FontMetricsInt fontMetrics = mMsgNumPaint.getFontMetricsInt();
/*字体基线的计算*/
int baseline = (int) ((2*mMsgCircleY - (fontMetrics.descent- fontMetrics.ascent))/2 - fontMetrics.ascent+0.5f);
canvas.drawText(showTxt, mMsgCircleX+mMsgNumRadius,
baseline,mMsgNumPaint);
}else{
/*数量大于0,进行小红点绘制*/
canvas.drawCircle(mMsgCircleX+AppUtils.dp2px(2),mMsgCircleY,AppUtils.dp2px(2), mMsgPaint);
}
}
/*需要显示红点调用方法*/
public void showMsg(int msgPosition,int msgNum,int msgPadding) {
mInitSetMap.put(msgPosition,true);
this.mMsgNumMap.put(msgPosition,msgNum);
mMsgPadding = msgPadding;
ViewCompat.postInvalidateOnAnimation(this);
}
/*需要隐藏红点调用方法*/
public void hideMsg(int msgPosition) {
mInitSetMap.put(msgPosition,false);
this.mMsgNumMap.delete(msgPosition);
ViewCompat.postInvalidateOnAnimation(this);
}
private float measureTextLength(View measureView){
if(measureView instanceof TextView){
TextView textView = ((TextView)measureView);
String text =textView .getText().toString();
return textView.getPaint().measureText(text);
}
return 0;
}
private float measureTextHeight(View measureView){
if(measureView instanceof TextView){
TextView textView = ((TextView)measureView);
Paint textPaint =textView.getPaint();
return textPaint.descent()-textPaint.ascent();
}
return 0;
}
实现指示器
我们都知道TabLayout是通过SlidingTabStrip来实现指示器处理的。我们也可以通过同样的方法来实现指示器的处理,下面通过IndicationTabLayout来实现指示器
public class IndicationTabLayout extends LinearLayout {
/*指示器高度*/
private int mSelectedIndicatorHeight;
/*指示器画笔*/
private Paint mSelectedIndicatorPaint;
/*当前选中的Tab位置*/
private int mSelectedPosition = -1;
/*ViewPager滚动的偏移量*/
private float mSelectionOffset;
/*指示器左边位置*/
private int mIndicatorLeft = -1;
/*指示器右边位置*/
private int mIndicatorRight = -1;
public IndicationTabLayout(Context context) {
this(context,null);
}
public IndicationTabLayout(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public IndicationTabLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setWillNotDraw(false);
setOrientation(LinearLayout.HORIZONTAL);
setGravity(Gravity.CENTER_HORIZONTAL);
mSelectedIndicatorPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
}
/*设置指示器颜色*/
public void setSelectedIndicatorColor(int color) {
if (mSelectedIndicatorPaint.getColor() != color) {
mSelectedIndicatorPaint.setColor(color);
ViewCompat.postInvalidateOnAnimation(this);
}
}
/*设置指示器高度*/
public void setSelectedIndicatorHeight(int height) {
if (mSelectedIndicatorHeight != height) {
mSelectedIndicatorHeight = height;
ViewCompat.postInvalidateOnAnimation(this);
}
}
/*外部调用,来移动指示器*/
public void setIndicatorPositionFromTabPosition(int position, float positionOffset) {
mSelectedPosition = position;
mSelectionOffset = positionOffset;
updateIndicatorPosition();
}
private void updateIndicatorPosition() {
final View selectedTitle = getChildAt(mSelectedPosition);
int left, right;
if (selectedTitle != null && selectedTitle.getWidth() > 0) {
/*字体离最左边位置间距*/
int selectTextPadding = (int) ((selectedTitle.getWidth()-measureTextLength(selectedTitle))/2+0.5f);
left = selectedTitle.getLeft()+selectTextPadding;
right = selectedTitle.getRight()-selectTextPadding;
if (mSelectionOffset > 0f && mSelectedPosition < getChildCount() - 1) {
View nextTitle = getChildAt(mSelectedPosition + 1);
int textPadding = (int) ((nextTitle.getWidth()-measureTextLength(nextTitle))/2+0.5f);
/*移动到下一个Tab左边需要移动的距离*/
int moveLeft = nextTitle.getLeft()+textPadding-left;
/*移动到下一个Tab右边需要移动的距离*/
int moveRight = nextTitle.getRight()-textPadding-right;
left = (int) (left + moveLeft * mSelectionOffset);
right = (int) (right + moveRight * mSelectionOffset);
}
} else {
left = right = -1;
}
setIndicatorPosition(left, right);
}
/*判断位置是否相同,不相同才进行绘制*/
private void setIndicatorPosition(int left, int right) {
if (left != mIndicatorLeft || right != mIndicatorRight) {
mIndicatorLeft = left;
mIndicatorRight = right;
ViewCompat.postInvalidateOnAnimation(this);
}
}
/*测量字体宽度*/
private float measureTextLength(View measureView){
if(measureView instanceof TextView){
TextView textView = ((TextView)measureView);
String text =textView .getText().toString();
return textView.getPaint().measureText(text);
}
return 0;
}
@Override
public void draw(Canvas canvas) {
super.draw(canvas);
/*绘制指示器*/
if (mIndicatorLeft >= 0 && mIndicatorRight > mIndicatorLeft) {
canvas.drawRect(mIndicatorLeft, getHeight() - mSelectedIndicatorHeight,
mIndicatorRight, getHeight(), mSelectedIndicatorPaint);
}
}
}
简单使用
功能基本上实现了,下面就来简单使用下
基本布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="40dp"
android:orientation="horizontal"
android:gravity="center_vertical">
<com.goach.tabdemo.view.ZTabLayout
android:id="@+id/id_tab_pager_indicator"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
<ImageView
android:id="@+id/id_add_channel_entry_iv"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:src="@drawable/add_channel_icon"
android:paddingLeft="10dp"
android:paddingRight="10dp"/>
</LinearLayout>
<android.support.v4.view.ViewPager
android:id="@+id/id_view_Pager"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
然后就是MainActivity和两个Fragment
public class MainActivity extends AppCompatActivity{
private ZTabLayout tabLayout;
private ViewPager mViewPager;
private MainActivity.MyViewPager myViewPagerAdapter;
private List<String> mDataList = Arrays.asList("推荐","热点","军事","图片","社会","娱乐","科技","体育","深圳","财经");
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_simple_tab);
initView();
initData();
}
private void initView(){
tabLayout = (ZTabLayout) findViewById(R.id.id_tab_pager_indicator);
mViewPager = (ViewPager) findViewById(R.id.id_view_Pager);
}
private void initData(){
myViewPagerAdapter = new MainActivity.MyViewPager(getSupportFragmentManager(),mDataList);
tabLayout.setDataList(mDataList);
mViewPager.setAdapter(myViewPagerAdapter);
tabLayout.setupWithViewPager(mViewPager);
/*显示红点作用*/
tabLayout.showMsg(3,100,0);
tabLayout.showMsg(2,0,0);
}
/*使用FragmentStatePagerAdapter来实现各个Tab栏目布局*/
public class MyViewPager extends FragmentStatePagerAdapter {
private List<String> mDataList;
private boolean[] mInit ;
private Map<Integer,LazyFragment> baseFragmentMap = new HashMap<>();
public MyViewPager(FragmentManager fm, List<String> list) {
super(fm);
mDataList = list ;
mInit = new boolean[mDataList.size()];
}
@Override
public Fragment getItem(int position) {
LazyFragment fragment = baseFragmentMap.get(position);
if(fragment==null){
if(position%2==0)
fragment = OneFragment.newInstance();
else
fragment = TwoFragment.newInstance(mDataList.get(position));
baseFragmentMap.put(position,fragment);
}
return fragment;
}
@Override
public int getCount() {
return mDataList.size();
}
/*主要处理每个Tab只网络请求一次*/
@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
super.setPrimaryItem(container, position, object);
if (!mInit[position]) {
LazyFragment lazyFragment = (LazyFragment) object;
if (lazyFragment.getTargetView() != null) {
mInit[position] = true;
lazyFragment.initNet();
}
}
}
}
}
抽象出一个方法initNet进行初始化网络请求
public abstract class LazyFragment extends Fragment{
public abstract void initNet();
public View getTargetView(){
return getView() ;
}
}
然后两个Fragment继承LazyFragment
public class OneFragment extends LazyFragment {
private View mContainerView;
public static OneFragment newInstance(){
OneFragment oneFragment = new OneFragment();
return oneFragment;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
mContainerView = inflater.inflate(R.layout.fragment_one,container,false);
return mContainerView;
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
@Override
public void initNet() {
}
}
public class TwoFragment extends LazyFragment {
private String tabName;
private TextView mTabNameTv;
private View mContainerView;
public static TwoFragment newInstance(String tabTitle){
TwoFragment twoFragment = new TwoFragment();
Bundle bundle = new Bundle();
bundle.putString("tabName",tabTitle);
twoFragment.setArguments(bundle);
return twoFragment;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
tabName = getArguments().getString("tabName");
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
mContainerView = inflater.inflate(R.layout.fragment_two,container,false);
return mContainerView;
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mTabNameTv = (TextView) mContainerView.findViewById(R.id.id_fragment_two);
mTabNameTv.setText(String.valueOf("布局2"+tabName));
initNet();
}
@Override
public void initNet() {
}
}
接下来测试下,得到结果
又或者我们再定义下自定义的那些属性起效没,改变下布局看下效果
<com.goach.tabdemo.view.ZTabLayout
android:id="@+id/id_tab_pager_indicator"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
app:tab_Padding="25dp"
app:tab_dividerShow="true"
app:tab_normal_textSize="14sp"
app:tab_select_textSize="16sp"
app:tab_dividerPadding="5dp"
app:tab_textColor="@color/tab_text_color"
app:tab_dividerWidth="1dp"
app:tab_dividerColor="@android:color/holo_blue_light"
app:tab_indicatorHeight="2dp"
app:tab_indicatorColor="#FF0000"/>
得到的效果就是
最右边的icon主要是想实现今日头部编辑栏目的效果,还没实现完,这里就不说了。