Android TabLayout和ViewPager

时间:2020-02-23 14:29:19  来源:igfitidea点击:

在本教程中,我们将在我们已经在本教程中实现的TabLayout下实现ViewPager。

Android TabLayout ViewPager概述

ViewPagers用于在数据页面之间滑动。
通常与片段结合使用。
让我们从上一教程中修改布局,如下所示。

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="https://schemas.android.com/apk/res/android"
  xmlns:app="https://schemas.android.com/apk/res-auto"
  xmlns:tools="https://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:fitsSystemWindows="true"
  tools:context="com.theitroad.tablayoutviewpager.MainActivity">

  <android.support.design.widget.AppBarLayout
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:theme="@style/AppTheme.AppBarOverlay">

      <android.support.v7.widget.Toolbar
          android:id="@+id/toolbar"
          android:layout_width="match_parent"
          android:layout_height="?attr/actionBarSize"
          android:background="?attr/colorPrimary"
          app:layout_scrollFlags="scroll|enterAlways"
          app:popupTheme="@style/AppTheme.PopupOverlay" 

      <android.support.design.widget.TabLayout
          android:id="@+id/tabs"
          style="@style/MyStyle"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          app:tabGravity="fill"
          app:tabMode="fixed" 

  </android.support.design.widget.AppBarLayout>

  <android.support.v4.view.ViewPager
      android:id="@+id/viewPager"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      app:layout_behavior="@string/appbar_scrolling_view_behavior" 

  <android.support.design.widget.FloatingActionButton
      android:id="@+id/fab"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_gravity="bottom|end"
      android:layout_margin="@dimen/fab_margin"
      android:src="@android:drawable/ic_dialog_email" 

</android.support.design.widget.CoordinatorLayout>

在MainActivity中添加ViewPager之前,我们先设置它的适配器。

public class ViewPagerAdapter extends FragmentPagerAdapter {

  public ViewPagerAdapter(FragmentManager fm) {
      super(fm);
  }

  @Override
  public Fragment getItem(int position) {
      Fragment fragment = null;
      if (position == 0)
      {
          fragment = new FragmentA();
      }
      else if (position == 1)
      {
          fragment = new FragmentB();
      }
      else if (position == 2)
      {
          fragment = new FragmentC();
      }
      return fragment;
  }

  @Override
  public int getCount() {
      return 3;
  }

  @Override
  public CharSequence getPageTitle(int position) {
      String title = null;
      if (position == 0)
      {
          title = "Tab-1";
      }
      else if (position == 1)
      {
          title = "Tab-2";
      }
      else if (position == 2)
      {
          title = "Tab-3";
      }
      return title;
  }
}

上面的ViewPagerAdapter扩展了FragmentPagerAdapter。
它调用三个片段,每个页面一个。
每个片段都具有一个ListView,如下所示

fragment_list.xml

<?xml version="1.0" encoding="utf-8"?>

<ListView xmlns:android="https://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:id="@+id/list"

FragmentA(/B/C).java如下所示:

public class FragmentA extends Fragment {

  ListView list;

  public FragmentA() {
  }

  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
      View view = inflater.inflate(R.layout.fragment, container, false);

      list = (ListView) view.findViewById(R.id.list);
      ArrayList stringList= new ArrayList();

      stringList.add("Item 1A");
      stringList.add("Item 1B");
      stringList.add("Item 1C");
      stringList.add("Item 1D");
      stringList.add("Item 1E");
      stringList.add("Item 1F");
      stringList.add("Item 1G");
      stringList.add("Item 1H");
      stringList.add("Item 1I");
      stringList.add("Item 1J");
      stringList.add("Item 1K");
      stringList.add("Item 1L");
      stringList.add("Item 1M");
      stringList.add("Item 1N");
      stringList.add("Item 1O");
      stringList.add("Item 1P");
      stringList.add("Item 1Q");
      stringList.add("Item 1R");
      stringList.add("Item 1S");
      stringList.add("Item 1T");
      stringList.add("Item 1U");
      stringList.add("Item 1V");
      stringList.add("Item 1W");
      stringList.add("Item 1X");
      stringList.add("Item 1Y");
      stringList.add("Item 1Z");

      CustomAdapter adapter = new CustomAdapter(stringList,getActivity());
      list.setAdapter(adapter);

      return view;
  }
}

上述ListView的CustomAdapter.java类为:

public class CustomAdapter extends ArrayAdapter {

  private ArrayList dataSet;
  Context mContext;

  //View lookup cache
  private static class ViewHolder {
      TextView txtName;

  }

  public CustomAdapter(ArrayList data, Context context) {
      super(context, R.layout.row_item, data);
      this.dataSet = data;
      this.mContext = context;

  }

  @Nullable
  @Override
  public String getItem(int position) {
      return dataSet.get(position);
  }

  @Override
  public View getView(int position, View convertView, ViewGroup parent) {

      ViewHolder viewHolder; //view lookup cache stored in tag

      if (convertView == null) {

          viewHolder = new ViewHolder();
          LayoutInflater inflater = LayoutInflater.from(getContext());
          convertView = inflater.inflate(R.layout.row_item, parent, false);
          viewHolder.txtName = (TextView) convertView.findViewById(R.id.name);
          convertView.setTag(viewHolder);
      } else {
          viewHolder = (ViewHolder) convertView.getTag();
      }

      viewHolder.txtName.setText(getItem(position));
      //Return the completed view to render on screen
      return convertView;
  }
}

MainActivity.java类如下所示

public class MainActivity extends AppCompatActivity {

  TabLayout tabLayout;
  ViewPager viewPager;
  ViewPagerAdapter viewPagerAdapter;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
      Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
      setSupportActionBar(toolbar);

      FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
      fab.setOnClickListener(new View.OnClickListener() {
          @Override
          public void onClick(View view) {
              Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                      .setAction("Action", null).show();
          }
      });

      viewPager = (ViewPager) findViewById(R.id.viewPager);
      viewPagerAdapter = new ViewPagerAdapter(getSupportFragmentManager());
      viewPager.setAdapter(viewPagerAdapter);
      tabLayout = (TabLayout) findViewById(R.id.tabs);
      tabLayout.setupWithViewPager(viewPager);
  }

}

在上面的代码中,使用setupWithViewPager()将TabLayout与ViewPager连接起来。
FragmentPagerAdapter中的getPageTitle()方法用于设置每个选项卡的标题。
让我们看看上面的代码运行时的输出

问题:为什么Toolbar不能按scrollFlags设置滚动?

这是由于ListView。
CoordinatorLayout不支持ListView(它不是Material Design的一部分),并且具有滚动手势。
因此,建议改用RecyclerView。

注意:属于CoordinatorLayout活动的片段需要使用NestedScrollView或者RecyclerView作为父项,以使滚动手势能够正常工作。

在我们在应用程序中替换ListView实现之前,让我们用NestedScrollView软件包当前片段的布局,如下所示。

fragment_list.xml

<?xml version="1.0" encoding="utf-8"?>

<android.support.v4.widget.NestedScrollView xmlns:android="https://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="wrap_content">

  <ListView xmlns:android="https://schemas.android.com/apk/res/android"
      android:id="@+id/list"
      android:layout_width="match_parent"
      android:layout_height="wrap_content" 

</android.support.v4.widget.NestedScrollView>

让我们看看应用程序现在的行为:

糟糕,滚动是固定的,但ListView现在仅显示一行。
因此,ListView不应与我们的"材料设计"视图类型一起使用。
现在修复该应用程序。

Android TabLayout ViewPager示例代码

activity_main.xml,MainActivity.java和ViewPagerAdapter.java类保持不变。
现在让我们看一下碎片。

片段的布局如下。

fragment.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.RecyclerView android:id="@+id/recycler_view"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  xmlns:android="https://schemas.android.com/apk/res/android" 

下面给出FragmentA(/B/C).java

package com.theitroad.tablayoutviewpager;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class FragmentA extends Fragment {

  RecyclerView recyclerView;

  @Nullable
  @Override
  public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
      View rootView = inflater.inflate(
              R.layout.fragment, container, false);
      return rootView;
  }

  @Override
  public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
      super.onViewCreated(view, savedInstanceState);

      String[] items = getResources().getStringArray(R.array.tab_A);
      RecyclerViewAdapter adapter = new RecyclerViewAdapter(items);
      recyclerView = (RecyclerView) view.findViewById(R.id.recycler_view);
      LinearLayoutManager layoutManager = new LinearLayoutManager(getContext());
      recyclerView.setLayoutManager(layoutManager);
      recyclerView.setAdapter(adapter);

  }
}

我们已经将要显示的数据转移到了strings.xml文件中。
在这里定义为

<resources>
  <string name="app_name">TabLayoutViewPager</string>
  <string name="action_settings">Settings</string>

  <string-array name="tab_A">
      <item>Item 1A</item>
      <item>Item 1B</item>
  </string-array>

  <string-array name="tab_B">
      <item>Item 2A</item>
  </string-array>
</resources>

注意:我们已经优化了片段代码逻辑,以使其填充适配器并在创建视图后显示适配器。

RecyclerViewAdapter.java具有一个字符串数组作为参数。
其代码如下。

public class RecyclerViewAdapter extends RecyclerView.Adapter {

  String[] items;

  public RecyclerViewAdapter(String[] items) {
      this.items = items;
  }

  @Override
  public TextItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
      View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_view_list_item, parent, false);
      return new TextItemViewHolder(view);
  }

  @Override
  public void onBindViewHolder(TextItemViewHolder holder, int position) {
      holder.bind(items[position]);
  }

  @Override
  public long getItemId(int position) {
      return position;
  }

  @Override
  public int getItemCount() {
      return items.length;
  }
}

在上面的代码中,我们添加了一个自定义的RecyclerViewHolder类,该类的布局类似于列表项。

下面给出了TextItemViewHolder.java类。

public class TextItemViewHolder extends RecyclerView.ViewHolder {
  private TextView textView;

  public TextItemViewHolder(View itemView) {
      super(itemView);
      textView = (TextView) itemView.findViewById(R.id.list_item);
  }

  public void bind(String text) {
      textView.setText(text);
  }

}

上述自定义ViewHolder的布局为:

recycler_view_list_item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_width="match_parent"
  android:layout_height="wrap_content">
  <TextView
      android:id="@+id/list_item"
      android:textSize="18sp"
      android:paddingTop="@dimen/activity_vertical_margin"
      android:paddingBottom="@dimen/activity_vertical_margin"
      android:paddingRight="8dp"
      android:paddingLeft="8dp"
      android:layout_width="match_parent"
      android:layout_height="wrap_content" 
  <View
      android:id="@+id/separator"
      android:layout_width="match_parent"
      android:layout_height="1dp"
      android:background="#858585" 
</LinearLayout>

实际应用程序的输出如下

布局结构类似于WhatsApp应用程序的布局结构。
为了使其更相似,请进行以下更改:

  • 导入并添加两个菜单图标可绘制对象
  • onCreateOptionsMenu()中的MainActivity.java中对其进行充气
  • 将colorPrimary和colorPrimaryDark分别更改为#00897B和#00796B

要增加菜单布局,请在MainActivity.java中添加以下方法。

@Override
  public boolean onCreateOptionsMenu(Menu menu) {

      getMenuInflater().inflate(R.menu.menu_main, menu);

      return super.onCreateOptionsMenu(menu);
  }

menu_main.xml如下所示:

<menu xmlns:android="https://schemas.android.com/apk/res/android"
  xmlns:app="https://schemas.android.com/apk/res-auto"
  xmlns:tools="https://schemas.android.com/tools"
  tools:context="com.theitroad.tablayoutviewpager.MainActivity">
  <item
      android:id="@+id/action_settings"
      android:orderInCategory="100"
      android:title="@string/action_settings"
      app:showAsAction="never" 

  <item
      android:id="@+id/action_search"
      android:orderInCategory="100"
      android:title="@string/action_settings"
      android:icon="@drawable/search"
      app:showAsAction="ifRoom" 

  <item
      android:id="@+id/action_add"
      android:orderInCategory="100"
      android:title="@string/action_settings"
      android:icon="@drawable/add"
      app:showAsAction="ifRoom" 
</menu>