ToolBar、TabLayout、Fragment+ViewPager的開發實踐
此文優先發佈於我的個人部落格:TB+TableLayout+Fragment+VP開發實踐
研究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的操作(兩種方式)
- .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) {
複製程式碼
- 使用selector代替[4]
高階
在TabLayout中新增圖片
方法
getTabView()[4:1]
此方法為我首先嚐試使用,可以更改圖示顏色以及狀態。
步驟:
- 在Activity.java中設定圖片點選(使用selector)陣列public int[]
- 設定setupTabIcons();
- 建立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]
- 在SimpleFragmentPagerAdapter中設定陣列int[]
- 樣式檔案定義
保留字串並設定空,新增圖片方法[7]
- 修改Adapter的構造方法:設定tabName和tabIcons變數:每個Tab上的文字和圖示的變數
- 修改getPageTitle()方法:if-else語句:如果不設定文字,則保留一個字元,如果設定圖示,則使用span
- 新增定義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 |