sq_Hayden's blog

Material Design系列实践(二)

2018/06/05 Share

TabLayout+ViewPager+Fragment实现仿微信界面

  • 引言:在上一篇博客中,我们首次认识了Material Design,并通过它实现了侧滑菜单的效果,如果想要再温习一遍的话,可以点击这里。现在的日常生活中,微信已经成了我们聊天交友必不可少的工具,那么今天,我们就利用Material Design为我们提供的控件,实现一个仿微信的界面。

1.TabLayout的相关设置

1.TabLayout的概念

  TabLayout是Support Design库下的控件,它的主要作用是在我们的界面底部或者顶部实现一个可以滑动切换的标签指示器,一般会搭配ViewPager来完成通过滑动标签控制页面切换的效果,类似下面的样子:
   

toolBar
  

2.TabLayout的引入

  由于我们的控件是在Design库下的,因此首先需要进行库资源引入操作,在我们本项目的build.gradle中,添加对Design库的依赖即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
    //TabLayout资源导入
compile 'com.android.support:design:26.1.0'
```

  导入编译成功后,我们就可以引用TabLayout控件了,主布局如下所示:
  
```java
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">

<android.support.design.widget.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
</android.support.design.widget.TabLayout>

</LinearLayout>

  接下来,我们就可以在主Activity中,对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
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
   public class ActivityDemo extends AppCompatActivity {
//TabLayout控件
private TabLayout tabLayout;
//控件标签内容存储集合
private String[] strings = {"标签1","标签2","标签3"};

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_demo);
tabLayout = findViewById(R.id.tab_layout1);
//设置固定
tabLayout.setTabMode(TabLayout.MODE_FIXED);
//设置布局填充
tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
//内容填充
// 添加多个tab
for (int i = 0; i < strings.length; i++) {
//创建子项
TabLayout.Tab tab = tabLayout.newTab();
tab.setText(strings[i]);
//添加
tabLayout.addTab(tab);
}
//监听其选中事件
tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
@Override
public void onTabSelected(TabLayout.Tab tab) {
//被选中弹消息提醒
Toast.makeText(getApplicationContext(),tab.getText()+"被选中了",Toast.LENGTH_SHORT).show();
}

@Override
public void onTabUnselected(TabLayout.Tab tab) { }

@Override
public void onTabReselected(TabLayout.Tab tab) { }
});
}
}

  到了这一步,我们的滑动切换标签控件就引入成功了,那么,上述的控件中有什么要注意的呢?
  首先,我们设置了标签栏的模式为MODE_FIX,它表示宽度始终是tablayout控件指定的宽度,如果标签过多,那么就无限挤压控件;而与之对应的还有一种模式MODE_SCROLLABLE,表示的是每个标签都保持自身宽度,一旦标签过多,给标题栏提供支持横向滑动的功能,我们在开发中,可根据自己的业务模式进行相应选择。
  接着我们设置了标签的对齐方式为填充控件,可选fill和center(注:此两种属性值只有在tabMode设置为fixed的情况下有效),代表了布局是中心对齐(center)还是各自占用同等大小的空间(fill)。
  最后,对TabLayout添加了三个Item子项,分别赋值,监听其子项点击事件,就完成了上述的效果。   

2.ViewPager的相关设置

1.ViewPager的概念

  ViewPager其实相当于一个页面容器控件,允许用户向里面存放View,然后实现左右滑动切换页面从而切换当前View的效果。既然它类似一个容器,那ViewPager自然需要适配器类Adapter给它提供数据。由于它是一个页面间的切换,因此一般都会以多个Fragment来作为数据源进行多重布局,为此android也为我们提供了对应的适配器FragmentPagerAdapter,接下来,就让我们通过实现ViewPager装载多个fragment的例子,掌握这方面的知识。

2.ViewPager结合Fragment

  我们在主布局文件中引入ViewPager控件,并建立四个Fragment类,布局如下所示:

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
    //使用ViewPager控件
<android.support.v4.view.ViewPager
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
</android.support.v4.view.ViewPager>
```

  接着来看Activity中如何去使用:
```java
//fragment集合(此处自己添加定义好的fragment即可)
List<Fragment> fragmentList;
//得到viewPager
mViewPager = (ViewPager)findViewById(R.id.viewpager);
//设置Adapter
MyAdapter adapter = new MyAdapter(getSupportFragmentManager());
mViewPager.setAdapter(adapter);

/**
* 适配器
* Created by lijuan on 2016/8/23.
*/
public class MyAdapter extends FragmentPagerAdapter {

/**
* 构造方法
*/
public MyAdapter(FragmentManager fm) {
super(fm);
}

/**
* 返回显示的Fragment总数
*/
@Override
public int getCount() {
return fragmentList.size();
}

/**
* 返回要显示的Fragment的某个实例
*/
@Override
public Fragment getItem(int position) {
return fragmentList.get(position);
}

/**
* 返回每个Tab的标题
*/
@Override
public CharSequence getPageTitle(int position) {
return null;
}
}

  代码如上所示:可以看到在这里我们定义了一个list用来存储相关的所有Fragment,然后自定义了一个MyAdapter来装载这些Fragment,再通过将adapter赋值给ViewPager,从而完成了ViewPager装载Fragment的切换。
  此时,我们的滑动效果就已经可以展现出来了,效果如下图所示:
   

drawerLayout
   

3.TabLayout+ViewPager+Fragment实现微信界面

  经过上述的练习,我们已经学会如何使用TabLayout及ViewPager,接下来,让我们趁热打铁,完成微信界面的仿制吧。
  首先是主Activity布局文件:   

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">
    //微信主界面
    <android.support.v4.view.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        >
    </android.support.v4.view.ViewPager>
   //微信底部的滑动标签栏
    <android.support.design.widget.TabLayout
        android:id="@+id/tab_layout"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        >
    </android.support.design.widget.TabLayout>

</LinearLayout>

  其次,是我们的菜单栏中各子项的布局文件tab_custom:

   <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    >
    //微信的子项图标
    <ImageView
        android:id="@+id/tab_img"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        />
   //微信的子项文字
    <TextView
        android:id="@+id/tab_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        //这里添加一个文字选择器,选中时变为绿色
        android:textColor="@drawable/tab_text_selector"
        />
</LinearLayout>

最后,还有两类选择器,一个是文字的选择器布局:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
  //选中时变为绿色
  <item android:state_selected="true" android:color="@color/tab_tv_selected"/>
  //未选中时为黑色
  <item android:state_selected="false" android:color="@color/tab_tv_normal"/>
</selector>

还有图片的选择器布局(图片可去网上找,共四个图片选择器,举例一个):

   <selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_selected="true" android:drawable="@drawable/chat_check"/>
    <item android:state_selected="false" android:drawable="@drawable/chat_normal"/>
</selector>

最终Activity中的代码:

   public class MainActivity extends AppCompatActivity {
    //底部菜单栏布局
    private TabLayout mTabLayout;
    //ViewPager对象
    private ViewPager mViewPager;
    //fragment集合
    private List<Fragment> fragmentList;
    //标题集合
    private String[] strings = {"微信","通讯录","发现","我"};
    //图片集合
    private int[] img_Id = {R.drawable.tab_chat_selector,R.drawable.tab_contract_selector,
            R.drawable.tab_find_selector,R.drawable.tab_me_selector};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initData();
        initViews();
    }

    /**
     * 添加Fragment
     */
    private void initData() {
        if(fragmentList==null){
            fragmentList= new ArrayList<>();
        }
        fragmentList.add(new ChatFragment());
        fragmentList.add(new ContractFragment());
        fragmentList.add(new FindFragment());
        fragmentList.add(new MeFragment());
    }

    private void initViews() {
        //得到tab控件
        mTabLayout = (TabLayout)findViewById(R.id.tab_layout);
        //设置布局填充
        mTabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
        //设置固定
        mTabLayout.setTabMode(TabLayout.MODE_FIXED);
        //隐藏底部横线
        mTabLayout.setSelectedTabIndicatorHeight(0);

        //得到viewPager
        mViewPager = (ViewPager)findViewById(R.id.viewpager);
        //设置Adapter
        MyAdapter adapter = new MyAdapter(getSupportFragmentManager());
        mViewPager.setAdapter(adapter);

        //关联Tab
        mTabLayout.setupWithViewPager(mViewPager);

        //设置Item项的参数
        for(int i=0;i<strings.length;i++){
            TabLayout.Tab tab = mTabLayout.getTabAt(i);
            if (tab != null) {
                //设置自定义的子项视图
                View view = tab.setCustomView(R.layout.tab_custom).getCustomView();
                if(view!=null) {
                    TextView textView = view.findViewById(R.id.tab_text);
                    textView.setText(strings[i]);
                    ImageView imageView = view.findViewById(R.id.tab_img);
                    imageView.setImageResource(img_Id[i]);
                }
            }
        }
    }

    /**
     * 适配器
     * Created by lijuan on 2016/8/23.
     */
    public class MyAdapter extends FragmentPagerAdapter {

        /**
         * 构造方法
         */
        public MyAdapter(FragmentManager fm) {
            super(fm);
        }

        /**
         * 返回显示的Fragment总数
         */
        @Override
        public int getCount() {
            return fragmentList.size();
        }

        /**
         * 返回要显示的Fragment的某个实例
         */
        @Override
        public Fragment getItem(int position) {
            return fragmentList.get(position);
        }

        /**
         * 返回每个Tab的标题
         */
        @Override
        public CharSequence getPageTitle(int position) {
            return strings[position];
        }
    }
}

从上述的代码中,我们可以看到,首先我们将创建好的四个Fragment封装到了List集合中,然后通过Adapter赋值给了ViewPager,完成了Fragment的滑动切换。接着,我们通过TabLayout的setUpWithViewPager()方法,将刚才设定好的Viewpager与TabLayout进行了绑定,最后我们对TabLayout设置了其四个子项的布局。从而完成了仿微信界面的效果。
大功告成,让我们看看最终的实现效果吧:
   

viewPager

  好了,这篇博客就写到这里,后期会继续总结一些Material Design中比较炫酷的控件实现,敬请期待。

  

CATALOG
  1. 1. TabLayout+ViewPager+Fragment实现仿微信界面
    1. 1.1. 1.TabLayout的相关设置
      1. 1.1.1. 1.TabLayout的概念
      2. 1.1.2. 2.TabLayout的引入
    2. 1.2. 2.ViewPager的相关设置
      1. 1.2.1. 1.ViewPager的概念
      2. 1.2.2. 2.ViewPager结合Fragment
    3. 1.3. 3.TabLayout+ViewPager+Fragment实现微信界面