TableLayout+Fragment+VP开发实践

此文为研究ToolBar、TabLayout、Fragment+ViewPager的开发实践复盘以及尚未解决的问题。欢迎评论留言。

XML

TabLayout

添加依赖

1
'android.support.design:28.0.0'

此处添加AppBarLayout作为完整的布局[1]:

AppBarLayout是Android Design Support Library新加的控件继承自LinearLayout,
它用来将Toolbar和TabLayout组合起来作为一个整体。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class XXXFragment extends Fragment {

private View; //创建变量

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}

@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;
}

}

参考[2]

1
2
3
4
5
6
7
8
//此处的含义可能是新增实例,存储值?
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中,原因未知。

关于添加图片,下文有提到。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
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_hotpoint);
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]

1
tab.addTab(tab,i == 0, ? true:false);

FragmentPagerAdapter

需要使用Fragment的话就需要这个适配器

public class一个自定义的适配器名称继承自FragmentPagerAdapter。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    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]

1
public destoryItemId(View view contain,int poition,Object object)

点击切换Tab的操作(两种方式)

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

当tab页面被选中时,会调用这个方法,当tab页面被选中时,切换目前的fragment:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@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为核心方法

方法值:

1
2
3
4
5
6
7
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


同步发布:SegmentFault掘金CSDN简书

此处应该有掘金Barge。


  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 ↩︎

FelixXiong wechat
产品北里,讲述产品和人性、涉及设计、技术和运营的公众号。
你们的赞赏是我更新的动力~