一、ViewPager简介
二、FragmentPagerAdapter 和 FragmentStatePagerAdapter 的区别
三、功能实现
四、RecyclerView内部居中问题
一、
ViewPager 直接继承了 ViewGroup,所已它是一个布局,是一个容器类,可以在其中添加其他的 view 类。ViewPager 需要一个 PagerAdapter 适配器类给它提供数据。ViewPager 经常和 Fragment 一起使用,并且提供了专门的 FragmentPagerAdapter 和 FragmentStatePagerAdapter 类供 Fragment 中的 ViewPager 使用。
二、
FragmentPagerAdapter:
拥有自己的缓存策略,当和ViewPager配合使用的时候,会缓存当前Fragment以及左边一个、右边一个,一共三个Fragment对象。适合用来做固定的较少数量的场合
FragmentStatePagerAdapter:
这个适配器对实现多个Fragment界面的滑动是非常有用的,它的工作方式和listview是非常相似的。当Fragment对用户不可见的时候,整个Fragment会被销毁,只会保存Fragment的保存状态。基于这样的特性,FragmentStatePagerAdapter比FragmentPagerAdapter更适合用于很多界面之间的转换,而且消耗更少的内存资源。
三、
例子实现:
先上效果图:
布局文件如下:
MainActivity对应的布局文件:activity_home
<?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">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<android.support.v4.view.ViewPager
android:id="@+id/viewPage"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:layout_width="400dp"
android:layout_height="400dp"
/>
<RadioGroup
android:id="@+id/botton"
android:layout_width="match_parent"
android:layout_height="75dp"
android:background="#FFFFF0"
android:layout_alignParentBottom="true"
android:orientation="horizontal"
>
<RadioButton
android:id="@+id/index"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="首页"
android:padding="5dp"
android:button="@null"
android:gravity="center"
android:checked="true"
android:drawableTop="@mipmap/home"/>
<RadioButton
android:id="@+id/search"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="查找"
android:padding="5dp"
android:button="@null"
android:gravity="center"
android:drawableTop="@mipmap/search"/>
<RadioButton
android:id="@+id/my"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="我的"
android:padding="5dp"
android:button="@null"
android:gravity="center"
android:drawableTop="@mipmap/my"/>
</RadioGroup>
</RelativeLayout>
</LinearLayout>
里面@mipmap对应的文件可以是任意的图片资源
mainActivity里面代码:
public class MainActivity extends FragmentActivity {
private List<Fragment> mlist = new ArrayList<>();
private List<Button> buttonList = new ArrayList<>();
private int[] all={0,1,2};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
initView();
}
public void initView() {
final ViewPager viewPager = findViewById(R.id.viewPage);
HomeFragment homeFragment = HomeFragment.newInstance();
HomeMyFragment homeMyFragment = HomeMyFragment.newInstance();
HomeSearchFragment homeSearchFragment = HomeSearchFragment.newInstance();
//添加fragment到list
mlist.add(homeFragment);
mlist.add(homeSearchFragment);
mlist.add(homeMyFragment);
final HomeViewPageAdapter viewPageAdapter =
new HomeViewPageAdapter(getSupportFragmentManager(), mlist);
viewPager.setAdapter(viewPageAdapter);
viewPager.addOnPageChangeListener(new pageChangeListener());
RadioButton button1 = findViewById(R.id.index);
RadioButton button2 = findViewById(R.id.search);
RadioButton button3 = findViewById(R.id.my);
//添加button到list
buttonList.add(button1);
buttonList.add(button2);
buttonList.add(button3);
final RadioGroup radioGroup = findViewById(R.id.botton);//监听button组点击事件切换fragment
radioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
int i = 0;
for (Button button : buttonList){
if(button.getId() == checkedId){
viewPager.setCurrentItem(i);//设置当前显示的fragment
break;
}
i++;
}
}
});
}
class pageChangeListener implements ViewPager.OnPageChangeListener{
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
for(int i:all){
if(i==position){
((RadioButton)buttonList.get(i)).setChecked(true);
}else{
((RadioButton)buttonList.get(i)).setChecked(false);
}
}
}
@Override
public void onPageScrollStateChanged(int state) {
}
}
在三个自定义fragment里面,只有HomeFragment里面设置了数据源如下:
public class HomeFragment extends Fragment {
private List<User> userList = new ArrayList<>();//首页fragment中第一个RecyclerView
private RecyclerView rv;
public static HomeFragment newInstance() {
Bundle args = new Bundle();
HomeFragment fragment = new HomeFragment();
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public void onDestroy() {
super.onDestroy();
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater,
@Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.activity_home_main,container,false);
rv = view.findViewById(R.id.recyclerview_1);
rv.setLayoutManager(new LinearLayoutManager(getContext(),RecyclerView.VERTICAL,false));
for (int i = 0;i < 5;i ++){
userList.add(new User(i+"",i,i+":首页"));
}
rv.addItemDecoration(new DividerItemDecoration(getContext(),
DividerItemDecoration.VERTICAL));//设置线性布局管理器
HomeMainAdapterOne homeMainAdapterOne = new HomeMainAdapterOne(userList,getContext());
rv.setAdapter(homeMainAdapterOne);
return view;
}
@Override
public void onDestroyView() {
super.onDestroyView();
}
}
其中User类是一个自定义类,这里不记录代码
另外两个fragment是一样的,记录其中一个:
public class HomeMyFragment extends Fragment {
public static HomeMyFragment newInstance() {
Bundle args = new Bundle();
HomeMyFragment fragment = new HomeMyFragment();
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public void onDestroy() {
super.onDestroy();
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater,
@Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View view = inflater.inflate(R.layout.activity_home_my,container,false);
return view;
}
@Override
public void onDestroyView() {
super.onDestroyView();
}
}
三个fragment对应三个布局文件:
<?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="wrap_content"
android:orientation="vertical"
android:background="@mipmap/home"
tools:context=".MainActivity">
<android.support.v7.widget.RecyclerView
android:layout_gravity="center"
android:id="@+id/recyclerview_1"
android:layout_width="100dp"
android:layout_height="match_parent"
/>
</LinearLayout>
三个布局都差不多,只是RecyclerView的id不一样。如果有需要只用在该布局文件里面修改即可
使用的PagerAdapter继承自FragmentPagerAdapter,代码如下:
public class HomeViewPageAdapter extends FragmentPagerAdapter {
private List<Fragment> fragmentListlist;
public HomeViewPageAdapter(FragmentManager fm,List<Fragment> fragmentListlist) {
super(fm);
this.fragmentListlist = fragmentListlist;
}
@Override
public Fragment getItem(int i) {
return fragmentListlist.get(i);
}
@Override
public int getCount() {
return fragmentListlist.size();
}
}
到这里已经实现,还有对于RecyclerView的实现也需要一个继承自RecyclerView.Adapter的适配器和一个简单的布局:
RecyclerView.Adapter适配器如下:
public class HomeMainAdapterOne extends RecyclerView.Adapter {
private List<User> userList;
Context context;
public HomeMainAdapterOne(List<User> userList, Context context) {
this.userList = userList;
this.context = context;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.activity_home_main_tv,parent,false);
MyViewHolder myViewHolder = new MyViewHolder(view);
return myViewHolder;
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
User u = userList.get(position);
Log.i("adg",""+u.toString());
((MyViewHolder)holder).tv.setText(u.toString());
}
@Override
public int getItemCount() {
return userList.size();
}
static class MyViewHolder extends RecyclerView.ViewHolder{
TextView tv;
public MyViewHolder(@NonNull View view) {
super(view);
tv = view.findViewById(R.id.home_tv);
}
}
}
其中activity_home_main_tv是一个布局文件,里面有一个id为home_tv的TextView。到这里已经全部实现。
四、
RecyclerView在加载子布局的时候
子布局的加载一定要传入父布局才有效,原因是因为inflater在inflate一个xml时,需要知道parent的类型,才能生成对应的LayoutParams,才可以把xml根节点的attrs(如layout_width)读进去,代码如下:
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.activity_home_main_tv,parent,false);
activity_home_main_tv这个布局就是需要加载到RecyclerView容器中的布局文件,这样写就可以解决不居中的问题。
如果parent传进去为null,生成的View的LayoutParams为null,在RecyclerView.addView时,发现LayoutParams为null,则生成默认的LayoutParams。