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

被折叠的 条评论
为什么被折叠?



