Android viewpager+fragment实现无限滚动,左右有前/后一页的部分,并fragment显示的内容是activity传过去的数据

      背景:最近在做app的时候碰到一个这样的需求。1,将从网络上获取的json数组数据显示出来,每页显示一个数据源,并且可以左右翻页查看;2,中间显示一个完整页,两边分别还有上下一页的一点,;3,可无限循环滑动。大致效果如下:

思考:这样的效果一下就想到用viewpager+fragment来做。本案例所有代码都有贴出来,有需要的可以自己试试看!

     1,activity向fragment传数据可以用fragment的setArguments(Bundle bundle)方法來传,数据源需要实现Serializable接口;

     2,显示两边可以用Viewpager的clipToPadding属性实现。

     3,无限循环不能用到第一页/最后一页然后改变position的方法实现,因为这样的话第一页左边会空白,最后一页右边会空白那么我这里的实现方法是用的是改变数据源的方法,即每次滑动结束过后重置fragment列表,并将当前显示的fragment放到fragment列表的中间,然后分别加上前两个与后两个fragment,然后更新adapter里面的fragment列表,并将当前currentindex设置为中间 值2

代码如下:

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"

    tools:context="cn.humanetplan.myapp.MainActivity">

    <TextView
        android:layout_marginTop="30dp"
        android:id="@+id/tv_title"
        android:padding="5dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:text="Viewpager+Fragment无限滑动" />
    <android.support.v4.view.ViewPager
        android:id="@+id/vp"
        android:layout_marginTop="15dp"
        android:layout_below="@+id/tv_title"
        android:layout_width="match_parent"
        android:paddingRight="40dp"
        android:paddingLeft="40dp"
        android:clipToPadding="false"
        android:background="@drawable/frag_bg"
        android:layout_marginBottom="150dp"
        android:layout_height="match_parent">

    </android.support.v4.view.ViewPager>
</RelativeLayout>

MainActivity代码
 

package cn.humanetplan.myapp;

import android.animation.ArgbEvaluator;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.view.ViewPager;

import android.os.Bundle;
import android.util.Log;
import android.view.ViewGroup;

import java.util.ArrayList;
import java.util.List;

import cn.humanetplan.myapp.Bases.BaseActivity;

public class MainActivity extends BaseActivity {

    ViewPager vp;
    List<DataBean> beanList = new ArrayList<>();

    //viewpager中显示的fragment的位置
    private int currentItem = 2;

    //当前fragment对应在数据源中的真实位置
    private int trueIndex = 0;

    //存放每个fragment对应数据源中的真实位置
    private List<Integer> trueIndexList = new ArrayList<>();
    //fragment集合
    private List<MyFragment> showFrag = new ArrayList<>();

    private MyFragmentPagerAdapter adapter;

    @Override
    protected int setContentLayout() {
        return R.layout.activity_main;

    }

    @Override
    protected void init() {
        vp = (ViewPager) findViewById(R.id.vp);
        TestData();
        updateViews();
    }

    private void updateViews() {
        //初始化view
        if (showFrag != null) {
            showFrag.clear();
            if (adapter != null) {
                adapter.notifyDataSetChanged();
            }
        }
        //把当前要生成/显示fragment的数据源对应的index记下来;
        RecordTrueIndex(trueIndex);

        //生成fragment
        for (int i = 0; i < trueIndexList.size(); i++) {
            showFrag.add(MyFragment.getMyFragmentInstance(beanList.get(trueIndexList.get(i))));
        }
        if (adapter != null) {
            adapter.setFragments(showFrag);
            vp.setCurrentItem(currentItem);
        } else {
            InitGv();
        }

    }

    private void InitGv() {
        adapter = new MyFragmentPagerAdapter(getSupportFragmentManager(), showFrag);
        vp.setAdapter(adapter);
        vp.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
//               通过估值器动态设置滑动时候左右page的背景色
                ChangeVpBack(positionOffset, position);

            }

            @Override
            public void onPageSelected(int position) {
                //每次切换page结束后重置fragment,将当前数据源置为中间要显示的数据源
                trueIndex = trueIndexList.get(position);

                updateViews();

            }

            @Override
            public void onPageScrollStateChanged(int state) {
            }
        });
        vp.setCurrentItem(currentItem);


    }

    /**
     * 通过估值器动态渐变背景色
     *
     * @param positionOffset
     * @param position
     */
    private void ChangeVpBack(float positionOffset, int position) {
        ArgbEvaluator evaluator = new ArgbEvaluator();

        int c2 = 0xff3F51B5;
        int c1 = 0x643F51B5;

        int evaluate;
        if (position % 2 == 0) {
            evaluate = (Integer) evaluator.evaluate(positionOffset, c2, c1);
        } else {
            evaluate = (Integer) evaluator.evaluate(positionOffset, c1, c2);
        }
        
        //动态改变shape的背景色
        GradientDrawable vpdrawable = (GradientDrawable) vp.getBackground();
        vpdrawable.setColor(evaluate);
    }


    /**
     * 记下当前要生成fragment的数据源对应的index记下来;
     * 生成5个fragment,当前要显示的放到中间,前后各加两个
     *
     * @param trueIndex 要显示的fragment对应的数据源的真实位置
     */
    private void RecordTrueIndex(int trueIndex) {

        int frag0 = trueIndex - 2;//前2,也就是fragment list中的第一个,index 0
        int frag1 = trueIndex - 1;//前1,也就是fragment list中的第2个,index 1
        int frag3 = trueIndex + 1;//后1,也就是fragment list中的第4个,index 3
        int frag4 = trueIndex + 2;//后2,也就是fragment list中的第5个,index 4
        if (frag0 < 0) {//负值几,就从最后一个往前数几个
            frag0 = beanList.size() + frag0;
        }
        if (frag1 < 0) {//负值几,就从最后一个往前数几个
            frag1 = beanList.size() + frag1;
        }
        if (frag3 >= beanList.size()) {//超过数据源几个,就从第0个加上超过的数,也就是还有+0,省略
            frag3 = frag3 - beanList.size();
        }
        if (frag4 >= beanList.size()) {//超过数据源几个,就从第0个加上超过的数,也就是还有+0,省略
            frag4 = frag4 - beanList.size();
        }
        if (trueIndexList != null) {
            trueIndexList.clear();
        }

        trueIndexList.add(frag0);
        trueIndexList.add(frag1);
        trueIndexList.add(trueIndex);
        trueIndexList.add(frag3);
        trueIndexList.add(frag4);
    }

    //初始化测试数据
    private void TestData() {
        beanList.add(new DataBean(R.mipmap.girl1, "第一张图片"));
        beanList.add(new DataBean(R.mipmap.girl2, "第二张图片"));
        beanList.add(new DataBean(R.mipmap.girl3, "第三张图片"));
        beanList.add(new DataBean(R.mipmap.girl4, "第四张图片"));
    }

    public class MyFragmentPagerAdapter extends FragmentStatePagerAdapter {

        private List<MyFragment> mlist;
        private FragmentManager fm;

        public MyFragmentPagerAdapter(FragmentManager fm, List<MyFragment> list) {
            super(fm);
            this.mlist = list;
            this.fm = fm;
        }

        @Override
        public Fragment getItem(int arg0) {
            return mlist.get(arg0);//显示第几个页面
        }

        @Override
        public int getCount() {
            return mlist.size();//有几个页面
        }

        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            super.destroyItem(container, position, object);
        }

        public void setFragments(List<MyFragment> fragments) {
            if (this.mlist != null) {
                FragmentTransaction ft = fm.beginTransaction();
                for (Fragment f : this.mlist) {
                    ft.remove(f);
                }
                ft.commit();
                ft = null;
                fm.executePendingTransactions();
            }
            this.mlist = fragments;
            notifyDataSetChanged();
        }

        @Override
        public int getItemPosition(Object object) {
            return POSITION_NONE;
        }


    }


}


DataBean代码
 

package cn.humanetplan.myapp;

import java.io.Serializable;

/**
 * Created by xiaobo on 2018/7/18.
 */

public class DataBean implements Serializable{
    private int resourceId;
    private String tips;

    public DataBean(int resourceId, String tips) {
        this.resourceId = resourceId;
        this.tips = tips;
    }

    public int getResourceId() {
        return resourceId;
    }

    public void setResourceId(int resourceId) {
        this.resourceId = resourceId;
    }

    public String getTips() {
        return tips;
    }

    public void setTips(String tips) {
        this.tips = tips;
    }
}

frag_mine.xml代码
 

<?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">
    <ImageView
        android:layout_marginTop="20dp"
        android:id="@+id/iv_girl"
        android:src="@mipmap/girl4"
        android:layout_gravity="center_horizontal"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <TextView
        android:id="@+id/tv_tips"
        android:layout_width="wrap_content"
        android:layout_marginTop="20dp"
        android:textColor="#fff"
        android:textSize="16sp"
        android:layout_gravity="center_horizontal"
        android:text="标题一"
        android:layout_height="wrap_content" />

</LinearLayout>

MyFragment代码
 

package cn.humanetplan.myapp;

import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;

import cn.humanetplan.myapp.Bases.BaseFragment;

/**
 * Created by xiaobo on 2018/7/18.
 */

public class MyFragment extends BaseFragment {

    ImageView iv;
    TextView tv;



    @Override
    protected int setContentLayout() {
        return R.layout.frag_mine;
    }

    @Override
    protected void init(View view) {
        iv= (ImageView) view.findViewById(R.id.iv_girl);
        tv= (TextView) view.findViewById(R.id.tv_tips);
        InitData();

    }

    /**
     * 接收Fragment传过来的参数,更新视图
     */
    private void InitData() {
        DataBean bean=null;
        if (getArguments()!=null){
            bean= (DataBean) getArguments().getSerializable("dataBean");
            if (bean!=null){
                iv.setImageResource(bean.getResourceId());
                tv.setText(TextUtils.isEmpty(bean.getTips())?"这张图片还没有添加任何说明":bean.getTips());
            }
        }

    }

    /**
     * 带参数新建fragment
     * @param dataBean 需要传过来的参数DataBean
     * @return
     */
    public static MyFragment getMyFragmentInstance(DataBean dataBean){
        MyFragment myFragment=new MyFragment();
        Bundle bundle=new Bundle();
        bundle.putSerializable("dataBean",dataBean);
        myFragment.setArguments(bundle);
        return myFragment;
    }


}

再贴一下BaseActivity与BaseFragment以及shape画的圆角背景的代码
BaseActivity
 

package cn.humanetplan.myapp.Bases;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.RadioButton;
import android.widget.Toast;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;


public abstract class BaseActivity extends AppCompatActivity {
    public static int IsFirstToClassfy = 0;
    public ProgressDialog loginDialog;
    public List<Activity> logActivityList = new ArrayList<>();

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        //设置软件盘弹出后不挡住输入框
        getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
        setContentView(setContentLayout());
        initState();

        loginDialog = new ProgressDialog(this);
        loginDialog.setTitle("提示:");
        loginDialog.setMessage("正在加载中...请稍后");
        loginDialog.setCancelable(true);
        init();

    }

    protected abstract int setContentLayout();

    protected abstract void init();

    protected void showToast(String msg) {
        Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            View v = getCurrentFocus();
            if (isShouldHideInput(v, ev)) {

                InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
                if (imm != null) {
                    imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
                }
            }
            return super.dispatchTouchEvent(ev);
        }
        // 必不可少,否则所有的组件都不会有TouchEvent了
        if (getWindow().superDispatchTouchEvent(ev)) {
            return true;
        }
        return onTouchEvent(ev);
    }

    public boolean isShouldHideInput(View v, MotionEvent event) {
        if (v != null && (v instanceof EditText)) {
            int[] leftTop = {0, 0};
            //获取输入框当前的location位置
            v.getLocationInWindow(leftTop);
            int left = leftTop[0];
            int top = leftTop[1];
            int bottom = top + v.getHeight();
            int right = left + v.getWidth();
            if (event.getX() > left && event.getX() < right
                    && event.getY() > top && event.getY() < bottom) {
                // 点击的是输入框区域,保留点击EditText的事件
                return false;
            } else {
                return true;
            }
        }
        return false;
    }


    @Override
    protected void onDestroy() {
        super.onDestroy();

    }

    /**
     * 动态的设置状态栏  实现沉浸式状态栏
     */
    private void initState() {

        //当系统版本为4.4或者4.4以上时可以使用沉浸式状态栏
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            //透明状态栏
            getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
            //透明导航栏
            getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);

        }
    }

    /**
     * 通过反射的方式获取状态栏高度
     *
     * @return
     */
    private int getStatusBarHeight() {
        try {
            Class<?> c = Class.forName("com.android.internal.R$dimen");
            Object obj = c.newInstance();
            Field field = c.getField("status_bar_height");
            int x = Integer.parseInt(field.get(obj).toString());
            return getResources().getDimensionPixelSize(x);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }


}

BaseFragment
 

package cn.humanetplan.myapp.Bases;

import android.app.ProgressDialog;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;

public abstract class BaseFragment extends Fragment {
    protected View mView;
    public ProgressDialog loginDialog;

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        mView = inflater.inflate(setContentLayout(), null);
//        ButterKnife.bind(this,mView);
        return mView;
    }
    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        loginDialog=new ProgressDialog(getActivity());
        loginDialog.setTitle("提示:");
        loginDialog.setMessage("正在加载数据,请稍后");

        init(view);
    }
    protected abstract int setContentLayout();

    protected abstract void init(View view);

    protected void showToast(String msg) {
        Toast.makeText(getContext(), msg, Toast.LENGTH_SHORT).show();
    }

    //界面是否可见
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if (isVisibleToUser){//可见

        }else {//不可见

        }
    }
}

drawable画的背景frag_bg.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="#3F51B5" />
    <corners android:radius="10dp" />

</shape>
总结:这样就将上述功能基本实现了,基本上代码都贴出来了,也有相应的注释。建好相应的文件,将代买粘上,替换掉几张图片就可以运行了。上述是我的思路和实现,希望大家有什么好的方法和建议的话,能够一起分享,共同进步!

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值