ViewPager+PagerAdapter+Fragment实现首页滑动效果

一、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。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值