本篇我们通过ViewPager来实现日记记录的左右滑动查看。
重命名NoteItemActivity类为NotePagerActivity,我们直接在这个基础上进行修改。
要想使用ViewPager首先我们的添加相关的依赖:
同样,我们这里选择的androidx下的ViewPager。
ViewPager是一种布局管理器,它能够允许用户在数据页面之间左右翻转。 ViewPager通常和Fragment结合使用,能够便捷的对管理每个页面生命周期进行管理。 ViewPager需要和准适配器一起协同工作,常见为FragmentPagerAdapterFragmentStatePagerAdapter。
`
``handlebars
创建ViewPager布局文件
新建布局文件activity_note_pager.xml,添加ViewPager:
```css
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.viewpager.widget.ViewPager
android:id="@+id/note_pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
activity_note_pager布局与NotePagerActivity关联
修改NotePagerActivity使其继承BaseActivity,在getActivityLayout中返回ViewPager的资源id。
public class NotePagerActivity extends BaseActivity {
private ViewPager viewPager;
private List<NoteItem> noteItemList = new ArrayList<>();
@Override
protected void initActivityData() {
for(int i = 0; i < 20; i++){
NoteItem item = new NoteItem();
item.setNoteTitle("标题".concat(String.valueOf(i)));
item.setNoteTitle("日记内容".concat(String.valueOf(i)));
noteItemList.add(item);
}
}
@Override
protected void initActivityListener() {
}
@Override
protected void initActivityView() {
viewPager = findViewById(R.id.note_pager);
}
@Override
protected int getActivityLayout() {
return R.layout.activity_note_pager;
}
}
在 NotePagerActivity中实现FragmentStatePagerAdapter
private class NotePagerAdapter extends FragmentStatePagerAdapter {
public NotePagerAdapter(@NonNull FragmentManager fm, int behavior) {
super(fm, behavior);
}
@NonNull
@Override
public Fragment getItem(int position) {
return NoteItemFragment.newInstance(noteItemList.get(position));
}
@Override
public int getCount() {
return noteItemList.size();
}
}
NotePagerAdapter 的两个方法简单直接。 getCount()方法返回数组列表中包含的列表项数目。getItem(int)方法才是神奇所在,它首先获取数据集中指定位置的NoteItem 实例,然后利用该NoteItem 实例返回一个经过有效配置的NoteItemFragment。
在实现FragmentStatePagerAdapter的时候,我们还需要提供一个构造方法,网上不少资料会使用
public FragmentStatePagerAdapter (FragmentManager fm)
在androdx中这个方法已经不推荐大家使用,替代方法是:
FragmentStatePagerAdapter(FragmentManager, int)
其中参数为BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT,该参数的意思是指定当前的fragment处于Lifecycle.State.RESUMED状态,其他的fragment处于Lifecycle.State STARTED状态。
FragmentStatePagerAdapter是负责管理与ViewPager的对话并协同工作。它首先将getItem(int)方法返回的fragment添加给activity,然后才能使用fragment完成自己的工作。这也就是创建FragmentStatePagerAdapter实例时,需要FragmentManager的原因。
接下我们需要创建NotePagerAdapter的实例:
@Override
protected void initActivityView() {
viewPager = findViewById(R.id.note_pager);
FragmentManager fragmentManager = getSupportFragmentManager();
notePagerAdapter = new NotePagerAdapter(fragmentManager,FragmentStatePagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
viewPager.setAdapter(notePagerAdapter);
}
当然了,别忘了定义notePagerAdapter 变量:
private NotePagerAdapter notePagerAdapter;
其中setAdapter方法如下;
ok,经过这么简单的配置我们的程序就能正确的左右滑动查看了。
运行程序,虽然基础工作做完了,但是这里又出来一个问题,那就是使用返回键返回日记记录页面后,不管点击哪一个列表项,进入NotePagerActivity始终显示的是第一个记录。
写到这里突然觉得BaseActivity好像又有点不太对,边做边改吧。。
这里我们在BaseActivity中新增一个抽象方法initViewOptions(),用来在组件初始化后执行一些和组件有关的数据绑定等等。如果有小伙伴真的再看我写的东西,别见怪。。。
在NotePagerActivity中实现initViewOptions方法,在其中使用setCurrentItem方法设置ViewPaper当前显示的fragment。
androidx.viewpager.widget.ViewPager
public void setCurrentItem(int item)
@Override
protected void initViewOptions() {
NoteItem extraItem = getIntent().getParcelableExtra(NoteItemFragment.EXTRA_NOTE);
for(int i = 0; i< noteItemList.size();i++){
if(noteItemList.get(i).getUid().toString().equals(extraItem.getUid().toString())){
viewPager.setCurrentItem(i);
break;
}
}
}
这里我们获取Activity的intent中传递的数据,根据NoteItem的uid查找对应的NoteItem索引,然后设置为ViewPaper的显示页面。
看看效果:
我们选择第六个日记记录,结果发现还是第一页面。那么问题出在哪里呢?
如果真有人是一篇篇看过来的,那么应该很快就能找到问题了,程序中使用的数据都是独立分开的,并没有使用同一份数据。
回忆下前面我们讲过添加Gson,但是却没有使用。这里我们就重新维护下我们的数据,当然了这也是临时的,后面还是要和数据库打交道的。
修改NoteListFragment中initFragmentData方法如下:
protected void initFragmentData() {
SharedPreferences.Editor editor = getActivity().getSharedPreferences("notelist", Context.MODE_PRIVATE).edit();
for (int i = 0; i < 20; i++) {
NoteItem noteItem = new NoteItem();
noteItem.setNoteTitle("标题".concat(String.valueOf(i)));
noteItem.setNoteContent("内容".concat(String.valueOf(i)));
noteItem.setDateCreate(new Date());
noteItemList.add(noteItem);
}
editor.putString("notelist", new Gson().toJson(noteItemList));
editor.apply();
}
这里我们利用Gson将list对象数组转化为字符串,然后保存在SharedPreferences中,其本质上是一个xml文件,让我们看看其存储路径:
/data/data/包名/shared_prefs/文件名.xml
/data/data/com.qiushangge.likenotes/shared_prefs/notelist.xml
当然了,获取SharedPreferences还有两种方式,可能文件的名称会有所差异。
这里需要注意的使用editor完成数据的添加后,必须要调用 editor.apply()进行提交,从而完成数据的存储工作。
同理,我们还需要修改NotePagerActivity中获取日记列表的代码:
@Override
protected void initActivityData() {
SharedPreferences preferences = getSharedPreferences("notelist", MODE_PRIVATE);
String noteString = preferences.getString("notelist", "");
noteItemList = new Gson().fromJson(noteString, new TypeToken<List<NoteItem>>() {
}.getType());
}
运行程序:
ok,到这里就算完成了。
不过呢,还有一个问题这里我们也提出来,那就是用户使用返回键的时候,比如目前页面如下:
按下返回键:
页面尽然返回了列表页,显然这和我们的期望有点差异,按道理来讲,我们是希望返回上一篇日记内容的。
此时我们需要重载onBackPressed方法来处理用户返回键:
/**
* 重载onBackPressed,处理页面
*/
@Override
public void onBackPressed() {
if (viewPager.getCurrentItem() == 0) {
//如果当前页面为起始页面,销毁页面,相当于finish调用
super.onBackPressed();
} else {
// 不是起始页面,返回上一个页面
viewPager.setCurrentItem(viewPager.getCurrentItem() - 1);
}
}
此时运行程序,一切就如我们预期的一样工作了。