前言
頂部導航欄,是我們在開發(fā)中比較常見的一種顯示布局,它的實現(xiàn)可以有多種方式,那么今天我們就來講講 TabLayout 對它的實現(xiàn)。
此篇文章參考以下鏈接
TabLayout輕松實現(xiàn)仿今日頭條頂部tab導航效果
在此表示感謝。
今天涉及的內容有:
- 實現(xiàn)導航欄的幾種方式
- 庫的導入
- TabLayout的具體使用
- 效果圖
一.實現(xiàn)導航欄的幾種方式及解析
我們在實現(xiàn)頂部導航的時候,可以有多種選擇:
- ViewPagerIndicator + Fragment + ViewPager
- ActionBar + Fragment + ViewPager
- 自定義一個View實現(xiàn)
基于第一種需要和activity的主題相結合,對activity主題的限制比較高,第二種 actionBar耦合也高,第三種自定義view會比較繁瑣。
所以今天我們介紹TabLayout的使用。
二.庫的導入
TabLayout是android中Material Design庫中控件,因此需要做以下庫導入:
//TabLayout
compile 'com.android.support:design:27.1.1'
compile 'com.android.support:support-v4:27.1.1'
三.TabLayout的具體使用
3.1 先展示在mainActivity中的xml代碼
實現(xiàn)頂部導航,所以TabLayout要結合ViewPager使用,xml代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.android.testdemo.main.MainActivity">
<android.support.design.widget.TabLayout
android:id="@+id/tablayout"
android:layout_width="0dp"
android:layout_height="@dimen/dp_40"
app:tabIndicatorColor="@color/green"
app:layout_constraintEnd_toStartOf="@+id/button1"
app:layout_constraintStart_toStartOf="parent"
app:tabMode="scrollable">
</android.support.design.widget.TabLayout>
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="測試"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="MissingConstraints"/>
<android.support.v4.view.ViewPager
android:id="@+id/viewPager"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="5dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tablayout" />
</android.support.constraint.ConstraintLayout>
這里需要注意的是 app:tabIndicatorColor="@color/green" 設置的是每個item切換時下面短橫線的顏色,為了適應導航欄中項目較多,可以滑動顯示的需求,需要設置 app:tabMode="scrollable"
3.2 展示Viewpager的適配器
使用到ViewPager,肯定少不了其對應的適配器,現(xiàn)在給出TabFragmentAdapter類的代碼:
package com.android.testdemo.function;
import android.content.Context;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import java.util.List;
/**
* Title:
* Description:
* <p>
* Created by pei
* Date: 2018/9/20
*/
public class TabFragmentAdapter extends FragmentPagerAdapter {
private String[] mTitles;
private Context mContext;
private List<Fragment> mFragments;
public TabFragmentAdapter(List<Fragment> fragments,String[] titles, FragmentManager fm, Context context) {
super(fm);
this.mContext = context;
this.mFragments = fragments;
this.mTitles = titles;
}
@Override
public Fragment getItem(int position) {
return mFragments.get(position);
}
@Override
public int getCount() {
return mTitles.length;
}
@Override
public CharSequence getPageTitle(int position) {
return mTitles[position];
}
}
其中 getPageTitle(int position) 返回的是每個頁面的導航標題。
3.3 ViewPager中需要加載的Fragment
ViewPager滑動時會切換不同的Fragemnt,現(xiàn)在為了簡潔展示起見,就讓加載同一個Fragment,然后展示不同的導航標題
下面給出MyFragment的代碼:
public class MyFragment extends AppFragment {
@BindView(R.id.tv_name)
TextView mTvName;
private String mName;
@Override
public void onCreate(@Nullable Bundle bundle) {
super.onCreate(bundle);
if(getArguments()!=null){
mName = getArguments().getString("text");
}
}
@Override
public int getContentViewId() {
return R.layout.fragment_my;
}
@Override
public void initData() {
mTvName.setText(mName);
}
@Override
public void setListener() {
}
@Override
protected void onVisible(boolean isFirstTimeLoad) {
}
@Override
protected void onInvisible() {
}
}
其中 mName = getArguments().getString("text"); 用于接收并在fragment中展示導航標題
3.4 TabLayout在mainActivity的使用
package com.android.testdemo.main;
import android.graphics.Color;
import android.os.Bundle;
import android.support.design.widget.TabLayout;
import android.support.v4.app.Fragment;
import android.support.v4.view.ViewPager;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.android.testdemo.R;
import com.android.testdemo.base.BaseActivity;
import com.android.testdemo.function.MyFragment;
import com.android.testdemo.function.TabFragmentAdapter;
import com.android.testdemo.tsf.AffairHelper;
import com.android.testdemo.utils.LogUtil;
import com.android.testdemo.utils.ScreenUtil;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import butterknife.BindView;
public class MainActivity extends BaseActivity{
@BindView(R.id.tablayout)
TabLayout mTabLayout;
@BindView(R.id.button1)
Button mBtnText;
@BindView(R.id.viewPager)
ViewPager mViewPager;
private String mTitles[] = {
"上海", "頭條推薦", "生活", "娛樂八卦", "體育",
"段子", "美食", "電影", "科技", "搞笑",
"社會", "財經(jīng)", "時尚", "汽車", "軍事",
"小說", "育兒", "職場", "萌寵", "游戲",
"健康", "動漫", "互聯(lián)網(wǎng)"};
private List<Fragment> mFragments;
private TabFragmentAdapter mTabFragmentAdapter;
private int mIndex=0;
@Override
public int getContentViewId() {
return R.layout.activity_main;
}
@Override
public void initData() {
mFragments = new ArrayList<>();
for (int i = 0; i < mTitles.length; i++) {
Fragment fragment = new MyFragment();
Bundle bundle = new Bundle();
bundle.putString("text", mTitles[i]);
fragment.setArguments(bundle);
mFragments.add(fragment);
}
mTabFragmentAdapter = new TabFragmentAdapter(mFragments, mTitles, getSupportFragmentManager(), mContext);
// mViewPager.setOffscreenPageLimit(mFragments.size());// 設置預加載Fragment個數(shù)
mViewPager.setOffscreenPageLimit(6);// 設置預加載Fragment個數(shù)
mViewPager.setAdapter(mTabFragmentAdapter);
mViewPager.setCurrentItem(0);// 設置當前顯示標簽頁為第一頁
// 將ViewPager和TabLayout綁定
mTabLayout.setupWithViewPager(mViewPager);
// 設置tab文本的沒有選中(第一個參數(shù))和選中(第二個參數(shù))的顏色
mTabLayout.setTabTextColors(Color.BLACK, Color.RED);
reflex(mTabLayout);
}
@Override
public void setListener() {
mBtnText.setOnClickListener(this);
}
@Override
public void onClick(View v) {
super.onClick(v);
switch (v.getId()) {
case R.id.button1:
LogUtil.i("====我點擊了====");
break;
default:
break;
}
}
public void reflex(final TabLayout tabLayout) {
//了解源碼得知 線的寬度是根據(jù) tabView的寬度來設置的
tabLayout.post(new Runnable() {
@Override
public void run() {
try {
//拿到tabLayout的mTabStrip屬性
LinearLayout mTabStrip = (LinearLayout) tabLayout.getChildAt(0);
int dp10 = ScreenUtil.dp2px(10, tabLayout.getContext());
for (int i = 0; i < mTabStrip.getChildCount(); i++) {
View tabView = mTabStrip.getChildAt(i);
//拿到tabView的mTextView屬性 tab的字數(shù)不固定一定用反射取mTextView
Field mTextViewField = tabView.getClass().getDeclaredField("mTextView");
mTextViewField.setAccessible(true);
TextView mTextView = (TextView) mTextViewField.get(tabView);
tabView.setPadding(0, 0, 0, 0);
//因為我想要的效果是 字多寬線就多寬,所以測量mTextView的寬度
int width = 0;
width = mTextView.getWidth();
if (width == 0) {
mTextView.measure(0, 0);
width = mTextView.getMeasuredWidth();
}
//設置tab左右間距為10dp 注意這里不能使用Padding 因為源碼中線的寬度是根據(jù) tabView的寬度來設置的
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) tabView.getLayoutParams();
params.width = width;
params.leftMargin = dp10;
params.rightMargin = dp10;
tabView.setLayoutParams(params);
tabView.invalidate();
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
});
}
}
其中 reflex(final TabLayout tabLayout) 是為了設置 導航欄下短橫線與左右兩邊間距的。