轉載請標明出處:
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主要是想實現今日頭部編輯欄目的效果,還沒實現完,這裏就不說了。