ViewPager的使用

tiger.wang 5年前

来自: https://segmentfault.com/a/1190000004544713

一 前言

上次我们用RecyclerView做了一个简单的显示笔记的小程序,今天我们用ViewPager来扩展它的功能:当我们点击笔记列表的其中某条笔记时,它可以跳到另外一个页面完整的显示这条笔记的内容,更人性化的设计是,在某条笔记的详情页面,我们可以左右滑动以查看上一条或者下一条,而不是返回主列表再去选择,话不多说,操作起来!

二 准备工作

1.首先我们创建一个Activity,命名为NotePagerActivity2.定义NotePagerActivity的私有字段:

public class NotePagerActivity extends AppCompatActivity {      private static final String EXTRA_NOTE_ID = "com.aristark.note.note.id";      private ViewPager noteViewPager;      private ArrayList<Note> notes;        @Override      protected void onCreate(Bundle savedInstanceState) {          super.onCreate(savedInstanceState);          setContentView(R.layout.activity_note_pager);      }  }

因为我们是从列表Activity那里点击某一个笔记项才进入到NotePagerActivity,因此需要传入该笔记项的UUID(很容易想到两个Activity之间传递数据所使用的方法是Intent附加参数,也就是putExtra()方法,因此我们将该常量命名为EXTRA_NOTE_ID,养成这样良好的命名方法对以后读懂这段代码是很重要的!先不用好奇为什么要把它设为私有,一会儿就明白其中的妙处了),noteViewPager和notes自然不用多说,这是今天的主角。

3.在布局中activity_note_pager设置ViewPager直接上代码

<android.support.v4.view.ViewPager      xmlns:android="http://schemas.android.com/apk/res/android"      android:layout_width="fill_parent"      android:layout_height="wrap_content"      android:id="@+id/activity_note_pager_view_pager"/>      

4为NotePagerActivity编写newIntent方法

public static Intent newIntent(Context context,UUID uuid){      Intent i = new Intent(context,NotePagerActivity.class);      i.putExtra(EXTRA_NOTE_ID,uuid);      return i;  }

这样我们每次想要启动NotePagerActivity时只需调用这个静态方法,而不用再balabalabala重复一堆昨天的故事。

三 设置ViewPager

其实我也不知道为什么用设置这个词,应该用使用?装配?其实不需要太在意,我们的目的现在很简单,就是按照ViewPager给的接口传入相应的参数,让它工作起来就行(对新手而言)!先贴上NoteListsFragment的代码

package com.aristark.note;
import android.os.Bundle;  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;  import android.widget.TextView;    import java.util.ArrayList;  import java.util.Calendar;  import java.util.List;    public class NotesListFragment extends Fragment {      private RecyclerView noteRecycler;      private NoteAdapter noteAdapter;
    public NotesListFragment() {          // Required empty public constructor      }
    @Override      public View onCreateView(LayoutInflater inflater, ViewGroup container,                           Bundle savedInstanceState) {          // Inflate the layout for this fragment  //        return inflater.inflate(R.layout.fragment_notes_list, container, false);          View root = inflater.inflate(R.layout.fragment_notes_list,container,false);            noteRecycler = (RecyclerView) root.findViewById(R.id.note_recycler_view);          noteRecycler.setLayoutManager(new LinearLayoutManager(getActivity()));  //        NoteLab noteLab = NoteLab.getNoteLab(getActivity());  //        ArrayList<Note> notes = noteLab.getNotes();  //        noteAdapter = new NoteAdapter(notes);  //        noteRecycler.setAdapter(noteAdapter);          updateView();          return root;      }        @Override      public void onResume() {          super.onResume();          updateView();      }        private class NoteHolder extends RecyclerView.ViewHolder{          private TextView noteTitle;          private TextView noteContent;          private TextView noteDate;            public NoteHolder(View root) {              super(root);              noteTitle = (TextView) root.findViewById(R.id.list_item_note_title);              noteContent = (TextView) root.findViewById(R.id.list_item_note_content);              noteDate = (TextView) root.findViewById(R.id.list_item_note_date);          }            public void bindView(Note n){              this.note = n;              noteTitle.setText(note.getTitle());              noteContent.setText(note.getContent());              Calendar calendar = Calendar.getInstance();              calendar.setTime(note.getDate());              int year = calendar.get(1);              int day = calendar.get(5);              int month = calendar.get(2)+1;              String date = year+"年"+month+"月"+day+"日";              noteDate.setText(date);          }        }        private class NoteAdapter extends RecyclerView.Adapter<NoteHolder>{          private List<Note> notes;            public NoteAdapter(List<Note> notes){              this.notes = notes;          }            public void setNotes(List<Note> notes) {              this.notes = notes;          }            @Override          public NoteHolder onCreateViewHolder(ViewGroup parent, int viewType) {              LayoutInflater layoutInflater = LayoutInflater.from(getActivity());              View view = layoutInflater.inflate(R.layout.list_item_note,parent,false);              return new NoteHolder(view);          }            @Override          public void onBindViewHolder(NoteHolder holder, int position) {              Note note = notes.get(position);              holder.bindView(note);          }            @Override          public int getItemCount() {              return notes.size();          }      }        public void updateView(){          NoteLab noteLab = NoteLab.getNoteLab(getActivity());          ArrayList<Note> notes = noteLab.getNotes();          if (noteAdapter == null){              noteAdapter = new NoteAdapter(notes);              noteRecycler.setAdapter(noteAdapter);              return;          }            noteAdapter.setNotes(notes);          noteRecycler.setAdapter(noteAdapter);        }    }

和上回的代码略有不同,我做了一些小小的封装。我们把注意力集中到类NoteHolder的构造方法这里来,它传入的参数root的类型是View,也就是笔记列表项的每一个笔记记录,我们在这里设置一个监听器,当用户点击的时候,我们就让页面跳转到笔记详情页面,也就是CrimePagerActivity,来,写代码:

    public NoteHolder(View root) {          super(root);          root.setOnClickListener(new View.OnClickListener() {              @Override              public void onClick(View v) {                  Intent i = NotePagerActivity.newIntent(getActivity(),note.getUuid());
                startActivity(i);              }          });          noteTitle = (TextView) root.findViewById(R.id.list_item_note_title);          noteContent = (TextView) root.findViewById(R.id.list_item_note_content);          noteDate = (TextView) root.findViewById(R.id.list_item_note_date);      }

下面把注意力转移到CrimePagerActivity:1.获取ViewPager:

 noteViewPager = (ViewPager) findViewById(R.id.note_view_pager);

2.从传来的Intent里获取uuid,并以此uuid从全局静态对象NoteLab中获取notes:

 UUID uuid = (UUID)getIntent().getSerializableExtra(EXTRA_NOTE_ID);   notes = NoteLab.getNoteLab(this).getNotes();

这里再一次体会到了EXTRA_NOTE_ID的方便之处吧。3.为ViewPager设置Adapter(ViewPager和RecyclerView一样,每个页面的布局都是一样的,只是填充的数据不一样,因为需要Adapter去适配,这里感叹一句想到这种机制的大神真的应该膜拜!简直解放了生产力有没有!)OK,show you the code:

 FragmentManager fragmentManager = getSupportFragmentManager();          noteViewPager.setAdapter(new FragmentPagerAdapter(fragmentManager) {              @Override              public Fragment getItem(int position) {                  return null;              }                @Override              public int getCount() {                  return notes.size();              }          });

是不是似曾相识?之所以要用FragmentPagerAdapter,是因为它可以为我们省去从Activity中启动Fragment的一系列事务代码,十分方便。写到这里我忽然忘记我们把笔记详情页给忘了,没有它我们该拿什么去显示笔记的详情呢,好吧,赶快去新建一个fragment命名为NoteDetailFragment:

public class NoteDetailFragment extends Fragment {      private static String ARG_NOTE_ID;      private Note note;      TextView noteDate;      TextView noteTitle;      TextView noteContent;        public NoteDetailFragment() {          // Required empty public constructor      }         public static Fragment newFragment(UUID uuid){           Bundle args = new Bundle();           args.putSerializable(ARG_NOTE_ID,uuid);           Fragment fragment = new NoteDetailFragment();           fragment.setArguments(args);           return fragment;         }        @Override      public void onCreate(Bundle savedInstanceState) {          super.onCreate(savedInstanceState);          UUID uuid = (UUID) getArguments().getSerializable(ARG_NOTE_ID);          note = NoteLab.getNoteLab(getActivity()).getNote(uuid);      }        @Override      public View onCreateView(LayoutInflater inflater, ViewGroup container,                           Bundle savedInstanceState) {          View root = inflater.inflate(R.layout.fragment_note_detail,container,false);          noteDate = (TextView) root.findViewById(R.id.note_date);          noteTitle = (TextView) root.findViewById(R.id.note_title);          noteContent = (TextView) root.findViewById(R.id.note_content);          noteDate.setText(note.getDate().toString());          noteTitle.setText(note.getTitle());          noteContent.setText(note.getContent());      }      return root;  }

上面的newFragment方法和之前的newIntent所使用的技巧是一样的。从Activity中启动Fragment传参的方法是setArguments,自然的,我们就有了ARG_NOTE_ID这个常量。对应的布局文件代码如下:

<?xml version="1.0" encoding="utf-8"?>  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"      android:orientation="vertical" android:layout_width="match_parent"      android:layout_height="match_parent"      android:layout_marginTop="10dp">        <TextView          android:layout_width="wrap_content"          android:layout_height="wrap_content"          android:id="@+id/note_date"          android:layout_weight="3"/>        <View android:layout_height="1px" android:background="@android:color/darker_gray" android:layout_width="fill_parent"></View>
    <LinearLayout          android:layout_width="match_parent"          android:layout_height="wrap_content"          android:orientation="vertical">            <TextView              android:layout_width="match_parent"              android:layout_height="wrap_content"              android:id="@+id/note_title"/>            <LinearLayout              android:layout_width="match_parent"              android:layout_height="wrap_content">                <TextView                  android:layout_width="wrap_content"                  android:layout_height="wrap_content"                  android:id="@+id/note_content" />            </LinearLayout>        </LinearLayout>    </LinearLayout>

回到NotePagerActivity中:

  @Override          public Fragment getItem(int position) {              Note note = notes.get(position);              return NoteDetailFragment.newFragment(note.getUuid());          }

好,编译,运行,添加几组测试数据后我们会发现不管从哪条笔记记录点击进去,都是从第一条开始显示,不用急,此时我们可以在getItem下面添加如下代码:

for (int i=0;i<notes.size();i++){              if (notes.get(i).getUuid().equals(uuid)){                  noteViewPager.setCurrentItem(i);                  break;              }          }

用setCurrentItem来设置正确的笔记项就行了。因为结果需要动态演示,我就不贴图啦,如果有人需要代码的话我就联系我吧!我的qq:891871898求批评指正!