ToolBar、TabLayout、Fragment+ViewPager的開發實踐

故事熊的象限發表於2018-12-02

研究ToolBar、TabLayout、Fragment+ViewPager的開發實踐覆盤以及尚未解決的問題。歡迎評論留言。

XML

TabLayout

新增依賴

'android.support.design:28.0.0'
複製程式碼

此處新增AppBarLayout作為完整的佈局[1]:

AppBarLayout是Android Design Support Library新加的控制元件繼承自LinearLayout, 它用來將Toolbar和TabLayout組合起來作為一個整體。

<android.support.design.widget.AppBarLayout
        android:id="@+id/appbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
    
<android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            app:layout_scrollFlags="scroll|enterAlways" //滑動隱藏功能
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>
<android.support.design.widget.TabLayout
          android:id="@+id/main_tablayout"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"         
          android:background="@color/color_title_bar"/>

<android.support.v4.view.ViewPager <!--TabLayout相關聯的ViewPager-->
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="0px"
        android:layout_weight="1"
        android:background="@android:color/white" />
複製程式碼

TabLayout可選屬性

tab
可更改屬性 屬性說明
tabBackground TabLayout的背景
tabSelectedTextColor 當前標籤的字型顏色
tabIndicator

可以寫一個style,下文中會提到

可更改屬性 屬性說明
tabIndicatorColor 選中線的顏色
tabIndicatorHeight 選中線的高度
tabMode
可更改屬性 屬性說明
FIXED 不可左右滑動,用於標籤較少時
SCROLLABLE 可左右滑動,用於標籤較多時

Fragment

為什麼要建立Fragment:TabLayout中的ViewPager對應著相應的Fragment,所以需要建立。

有的示例僅建立了一個Fragment,其中為定義文字陣列實現,若開發中則需要多個Fragment新增,均用Arratlist於Activity中。

XXXFragment.java:

public class XXXFragment extends Fragment {
    
    private Page/View;  //建立變數
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //mPage = getArguments().getInt(ARG_PAGE);
    }
 
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_page, container, false);
        TextView textView = (TextView) view; //參考[^6]
        textView.setText("Fragment #" + mPage); 
        return view;
    }
 
}
複製程式碼

一些暫未明確的程式碼段

 public static final String TYPE = "TYPE"; //此處未知含義
複製程式碼

參考[2]

//此處的含義可能是新增例項,儲存值?
    public static XXXFragment newInstance(int page) { 
        Bundle args = new Bundle();
        args.putInt(ARG_PAGE, page);
        PageFragment pageFragment = new PageFragment();
        pageFragment.setArguments(args);
        return pageFragment;
    }
複製程式碼

Activity

如果需要定義TableLayout的tab文字,則在其中定義:public static final String[] titles,之後新增集合。

這裡把[2:1]定義文字放在了Adapter中,原因未知。

關於新增圖片,下文有提到。

    private Toolbar toolbar; //增加相關變數
    private TabLayout tabLayout;
    private ViewPager viewPager;

    public static final String[] titles = {"", ""};

    private List<Fragment> fragments; //定義fragment的集合縮寫
    private List<String> tabNames;
    private List<Integer> tabIcs;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.fragment_xxx);
        initView();        //各種初始化:介面、新增的fragment值、事件
        initValue();
        initEvent();
    }

    //各種初始化開始

    private void initView() { //初始化例項

        toolbar = (Toolbar) findViewById(R.id.Toolbar); 
        setSupportActionBar(toolbar); //支援actionbar,此處多種寫法
        getSupportActionBar().setDisplayHomeAsUpEnabled(true); //在首頁顯示

        viewPager = (ViewPager) findViewById(R.id.viewpager); //例項化控制元件
        tabLayout = (TabLayout) findViewById(R.id.tabs);
    }

    private void initValue() { 
    //初始化值,新增每一個TableLayout裡的ArrayList,設定與標題欄一一對應的檢視(片段)集合

        fragments = new ArrayList<>();
        fragments.add(new xxxFragment());
        fragments.add(new xxxFragment()); //有多少個fragment就在這裡新增多少

        tabNames = new ArrayList<>(); //新增標題集合,同上
        tabNames.add(" ");
        tabNames.add(" ");

        /*tabIcs = new ArrayList<>(); 此處尚不明確是否有,使用spanstring或其他方法此處是否需要
        tabIcs.add(R.drawable.tab_xxx);
        tabIcs.add(R.drawable.tab_xxx);*/
        
        //給tabLayout新增選項卡
        for(int i=0;i< fragments.size();i++){
            tabLayout.addTab(tabLayout.newTab().setText((CharSequence) fragments.get(i)));
        }

        FragmentViewPagerAdapter adapter = new FragmentViewPagerAdapter
        (getSupportFragmentManager(), fragments, tabNames,tabIcs); 
        // 初始化ViewPager介面卡        //此處需要增加與新增的集合以及上述定義的值匹配,若未定義則無需新增

        viewPager.setAdapter(adapter); //給ViewPager設定介面卡
        tabLayout.setupWithViewPager(viewPager);  //將TabLayout和ViewPager關聯起來      
        /*setupWithViewPager這個方法會先將tab清除然後再根據ViewPager的adapter裡的count去取pagetitle,這也就是有時遇到用addTab方法新增tab不起作用的問題。*/

        //setupTabIcons();
        viewPager.setCurrentItem(1);
        viewPager.setCurrentItem(0);
    }
複製程式碼

此處的**setupTabIcons()**方法,在下文新增圖片會提到。參考連結

預設顯示第一個Tab[3]

tab.addTab(tab,i == 0, ? true:false);
複製程式碼

FragmentPagerAdapter

需要使用Fragment的話就需要這個介面卡

public class一個自定義的介面卡名稱繼承自FragmentPagerAdapter。

    List<Fragment> xxxfragment;
    List<String> titleList;

public MyTableViewAdapter(FragmentManager fm , List<Fragment> pagerList , List<String> titleList) {
        super(fm);
    this.pagerList = pagerList; // 此處使用this.與上述定義匹配
  
}
    
public Fragment getItem(int poition)
    super.

public int getCount(int poition) { return (tab個數) } 
   return xxxfragment.get(position); //普通情況
   return xxxfragment != null ? pagerList.size() : 0; //設定不等於null的情況,參考[^4]

public long getItemId(int poition)  { return super.getItemId(position) }
return xxxfragment.get(position);
複製程式碼

此處可能還有,參考 [3:1]

public destoryItemId(View view contain,int poition,Object object)
複製程式碼

點選切換Tab的操作(兩種方式)

  1. .setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() 方法[3:2]

當tab頁面被選中時,會呼叫這個方法,當tab頁面被選中時,切換目前的fragment:

@Override
public void onTabSelected(TabLayout.Tab tab) {
int position = tab.getPosition();
    
Fragment fragment = (Fragment)adapter.instantiateItem(container, position);
    
adapter.setPrimaryItem(container, pos, fragment);
adapter.finishUpdate(container);
    
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
複製程式碼
  1. 使用selector代替[4]

高階

在TabLayout中新增圖片

方法

getTabView()[4:1]

此方法為我首先嚐試使用,可以更改圖示顏色以及狀態。

步驟:

  1. 在Activity.java中設定圖片點選(使用selector)陣列public int[]
  2. 設定setupTabIcons();
  3. 建立getTabView()方法

這裡[^4 ][2:2]把此方法放到了FragmentAdapter中,個人猜測原因可能是一同將getTabView()或imagespan使用。

SpannableString

更多支援:介紹參考連結[5]

SpannableString這個類實現了CharSequence這個介面,所以可以在Adapter中的getPageTitle()中返回。

SpannableString的構造方法需要一個引數:CharSequence(超級字串的基本顯示內容),

setSpan為核心方法

方法值:

public void setSpan(Object what, int start, int end, int flags) {
    super.setSpan(what, start, end, flags);
          //what:向這個超級字串中新增的內容。例如:前景色、背景色、圖片、連結、下劃線等
          //start:開始的位置(0為開始)
          //結束的位置
          //flags:標識在span範圍內的文字前後輸入新的字元時是否也應用這個效果
}
複製程式碼

SpanString舉例由於眾多,表格與文末[6]

經搜尋:

其中使用ImageSpan的兩種方法,發現以下兩種均為僅新增圖示方法,而不適用於點選切換顏色:

使用SpanString和Imagespan:[2:3]
  1. 在SimpleFragmentPagerAdapter中設定陣列int[]
  2. 樣式檔案定義
保留字串並設定空,新增圖片方法[7]
  1. 修改Adapter的構造方法:設定tabName和tabIcons變數:每個Tab上的文字和圖示的變數
  2. 修改getPageTitle()方法:if-else語句:如果不設定文字,則保留一個字元,如果設定圖示,則使用span
  3. 新增定義style(關鍵):textAllCaps、android:textAllCaps必須設定為false,之後XML中TabLayout設定style。

SpanString舉例,示例程式碼[6:1],專案完整地址[8].

可更改屬性 屬性說明
AbsoluteSizeSpan 單位為物理畫素
AlignmentSpan 支援ALIGN_NORMAL,ALIGN_OPPOSITE,ALIGN_CENTER
BackgroundColorSpan 文字背景色改變
BulletSpan 小圓圈
ClickableSpan 可點選
DrawableMarginSpan Drawable,不佔位
DynamicDrawableSpan DynamicDrawable,佔位
ForegroundColorSpan 前景色
IconMarginSpan 圖示margin,不佔位
ImageSpan 圖片,佔位
LeadingMarginSpan 控制行前空隙
QuoteSpan 左側出現引用符號 豎線
RelativeSizeSpan 字型放大
ScaleXSpan 字型寬度放大
StrikethroughSpan 刪除線
StyleSpan 主要由正常、粗體、斜體和同時加粗傾斜四種樣式,常量值定義在Typeface類中
SubscriptSpan 下標
SuperscriptSpan 上標
TextAppearanceSpan Sets the text color, size, style, and typeface to match a TextAppearance
TypefaceSpan 字型設定
UnderlineSpan 下劃線
URLSpan URL

此文優先釋出於我的個人部落格:TB+TableLayout+Fragment+VP開發實踐


  1. Android Design Support Library(一)用TabLayout實現類似網易選項卡動態滑動效果 ↩︎

  2. android design library提供的TabLayout的用法,很多教程都參考了此文章。 ↩︎ ↩︎ ↩︎ ↩︎

  3. 利用TabLayout和fragment搭建app框架 ↩︎ ↩︎ ↩︎

  4. Android TabLayout setCustomView 實現帶圖示的tab ↩︎ ↩︎

  5. android設計庫提供的TabLayout的簡單使用(TabLayout + ViewPager + Fragment) ↩︎

  6. SpannableString ↩︎ ↩︎

  7. TabLayout與ViewPager的聯合使用 ↩︎

  8. onlyloveyd/SpannableDemo ↩︎

相關文章