ToolBar、TabLayout、Fragment+ViewPager的开发实践

研究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]定义文字放在了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]

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

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

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

当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. 在Activity.java中设置图片点击(使用selector)数组public int[]
  2. 设置setupTabIcons();
  3. 创建getTabView()方法

这里[^4 ][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]
  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],项目完整地址[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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,366评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,521评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,689评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,925评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,942评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,727评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,447评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,349评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,820评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,990评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,127评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,812评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,471评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,017评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,142评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,388评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,066评论 2 355

推荐阅读更多精彩内容