转载请注明出处,谢谢http://blog.csdn.net/harryweasley/article/details/51007348
始终觉得讲ui效果要先放上效果图,要不让其他人好不容易看完了,发现并不是他想要的效果,那岂不是坑了苦逼的程序员,程序员何苦为难程序员。效果图如下所示:
此应用,是viewPager结合fragment,fragment里又是一个gridView来实现的,实现向右滑动,分页加载数据的功能
文章末尾,有该应用的下载资源。
先说下该应用的功能吧,打开该应用,初始加载两个页面,第0页和第1页,当到达最后一页的时候,就会加载后一页的数据,如此一直加载下去。每个页面是一个gridView,Activity和fragment进行数据的传递。
项目的java目录如下所示:
你可能会想,这样一直加载页面出来,会不会造成oom,答案是不会。因为FragmentPagerAdapter只会保留当前页面,前一个页面和后一个页面的实例到内存,其他的都将删除。
关于Activity和fragment数据传递,因为我想要传递对象,所以我用到了bundle.putParcelableArrayList(“”,”“);这个方法,关于这个方法更多的介绍,可以查看http://www.cnblogs.com/renqingping/archive/2012/10/25/Parcelable.html
所以我的arrayList里传递的类实现了Parcelable接口,如下所示:
package com.example.viewpagerdemo;
import android.os.Parcel;
import android.os.Parcelable;
public class Model implements Parcelable {
private String index;
private String name;
public Model(String index, String name) {
this.index = index;
this.name = name;
}
// 重写describeContents方法,内容接口描述,默认返回0就可以,基本不用
@Override
public int describeContents() {
return 0;
}
// 重写writeToParcel方法,将你的对象序列化为一个Parcel对象,即:将类的数据写入外部提供的Parcel中,打包需要传递的数据到Parcel容器保存,以便从
// Parcel容器获取数据
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(index);
dest.writeString(name);
}
/**
* 其中public static
* final一个都不能少,内部对象CREATOR的名称也不能改变,必须全部大写。需重写本接口中的两个方法:createFromParcel
* (Parcel in) 实现从Parcel容器中读取传递数据值,封装成Parcelable对象返回逻辑层,newArray(int size)
* 创建一个类型为T,长度为size的数组,仅一句话即可(return new T[size]),供外部类反序列化本类数组使用。
*/
public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
@Override
public Model createFromParcel(Parcel source) {
return new Model(source.readString(), source.readString());
}
@Override
public Model[] newArray(int size) {
return new Model[size];
}
};
public String getIndex() {
return index;
}
public void setIndex(String index) {
this.index = index;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
里面已经写了注释,这里就不用再解释更多了。
MainActivity的内容,如下所示:
package com.example.viewpagerdemo;
import java.util.ArrayList;
import java.util.List;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
public class MainActivity extends FragmentActivity {
private ViewPager vp;
private List fragments;
private SimplePageAdapter pageAdapter;
/**
* 传递的数据
*/
private ArrayList modelList;
/**
* 一共有多少页
*/
private int pageCount;
private int totalCount = 18;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
vp = (ViewPager) findViewById(R.id.viewpager);
fragments = new ArrayList();
initDatas();
int size = modelList.size();
if (size % 9 == 0) {
pageCount = size / 9;
} else {
pageCount = size / 9 + 1;
}
for (int i = 0; i < pageCount; i++) {
//初始化每一个fragment
GridFragment gf = GridFragment.newInstance(i, modelList);
fragments.add(gf);
}
//初始化pageAdapter
pageAdapter = new SimplePageAdapter(getSupportFragmentManager(),
fragments);
vp.setAdapter(pageAdapter);
vp.addOnPageChangeListener(new OnPageChangeListener() {
@Override
public void onPageSelected(int arg0) {
if (arg0 == pageCount - 1) {
// 在最后一页,开始加载后一页的数据
for (int i = totalCount; i < totalCount + 9; i++) {
Model model = new Model(i + "", i + "name");
modelList.add(model);
}
totalCount += 9;
pageAdapter.addFragment(pageCount++, modelList);
pageAdapter.notifyDataSetChanged();
}
}
@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
@Override
public void onPageScrollStateChanged(int arg0) {
}
});
}
/**
* 初始化数据,刚开始有18个
*/
private void initDatas() {
modelList = new ArrayList();
for (int i = 0; i < totalCount; i++) {
Model model = new Model(i + "", i + "name");
modelList.add(model);
}
}
}
37行到41行,是确定刚开始,有几个页面。
44行是初始化GridFragment,在这里,将数据通过bundle进行了传递。
50行进行了初始化pageAdapter,同时在66行,有调用addFragment这个方法。接下来看下SimplePageAdapter里面都写了什么。
下面是SimplePageAdapter里面的内容:
package com.example.viewpagerdemo;
import java.util.ArrayList;
import java.util.List;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;
public class SimplePageAdapter extends FragmentStatePagerAdapter {
private List fragments;
public SimplePageAdapter(FragmentManager fm, List fragments) {
super(fm);
this.fragments = fragments;
}
@Override
public Fragment getItem(int arg0) {
return fragments.get(arg0);
}
@Override
public int getCount() {
return fragments.size();
}
public void addFragment(int i,ArrayList modelList){
GridFragment gf=GridFragment.newInstance(i,modelList);
fragments.add(gf);
}
}
第29行是增加新的fragment,即增加新的页面。
最后看下GridFragment里面的内容。
package com.example.viewpagerdemo;
import java.util.ArrayList;
import java.util.List;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.GridView;
import android.widget.TextView;
import android.widget.Toast;
public class GridFragment extends Fragment {
private View view;
private GridView gv;
private int index = -1;
private FragmentActivity context;
private List modelList;
private TextView no;
public static GridFragment newInstance(int index, ArrayList modelList) {
GridFragment gf = new GridFragment();
Bundle bundle = new Bundle();
bundle.putInt("index", index);
bundle.putParcelableArrayList("model", modelList);
gf.setArguments(bundle);
return gf;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (view == null) {
//防止重复加载布局
context = getActivity();
Bundle bundle = getArguments();
index = bundle.getInt("index");
modelList = bundle.getParcelableArrayList("model");
List newModels;
int last = 9 * index + 9;
if (last >= modelList.size()) {
newModels = modelList.subList((9 * index), (modelList.size()));
} else {
newModels = modelList.subList((9 * index), (last));
}
Log.i("tag", "当前页数是" + index + "view是null哦");
view = LayoutInflater.from(context).inflate(R.layout.fragment_grid,
container, false);
gv = (GridView) view.findViewById(R.id.gridview);
no = (TextView) view.findViewById(R.id.no);
no.setText("这个是第" + (index + 1) + "页");
// 这里重新开辟一个地址空间,来保存list,否则会报ConcurrentModificationException错误
final ArrayList text = new ArrayList();
text.addAll(newModels);
gv.setAdapter(new GridBaseAdapter(getActivity(), text));
gv.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView> parent, View view,
int position, long id) {
Toast.makeText(context,
"点击的item是" + text.get(position).getIndex(),
Toast.LENGTH_SHORT).show();
}
});
} else {
Log.i("tag", "当前页数是" + index + "view不不不是null哦");
ViewGroup root = (ViewGroup) view.getParent();
if (root != null) {
root.removeView(view);
}
}
Log.i("tag", "当前页数是" + index);
return view;
}
}
关于第49行到第56行,这里进行一些解释:Activity和fragment之间的数据传递,我是将所有页面的list全部保存在内存中,所以这里会根据index来确定每个页面的数据内容。
第46行的那个注释,和他下面的内容,是我目前解决ConcurrentModificationException的方法。
我想你可能对第41行的判断,81行到87行的内容有疑惑,你可以看这篇文章,http://blog.csdn.net/harryweasley/article/details/50999802
之后就是GridBaseAdapter里的内容了,这个很简单,没有很多复杂的功能,我直接贴出来,就不解释了。
package com.example.viewpagerdemo;
import java.util.List;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
public class GridBaseAdapter extends BaseAdapter {
private List modelList;
private Context context;
public GridBaseAdapter(Context context, List modelList) {
this.modelList = modelList;
this.context = context;
}
@Override
public int getCount() {
return modelList.size();
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
if (convertView == null) {
holder = new ViewHolder();
convertView = LayoutInflater.from(context).inflate(
R.layout.item_grid, parent, false);
holder.tv = (TextView) convertView.findViewById(R.id.textview);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.tv.setText(modelList.get(position).getIndex());
return convertView;
}
static class ViewHolder {
TextView tv;
}
}
其他的xml布局,我这里就不粘贴了,你可以直接下载源码查看。
参考文章:
如何更新及替换ViewPager中的Fragment,这篇文章将FragmentPagerAdapter和FragmentStatePagerAdapter的区别讲解的非常好,推荐大家去看:https://segmentfault.com/a/1190000003742057
fragment的陷阱,这篇文章说了,fragment为什么使用if (view == null) {}判断
http://blog.csdn.net/harryweasley/article/details/50999802
源码下载:
http://download.csdn.net/detail/harryweasley/9479123