RecyclerView是Andorid 5.X中谷歌对ListView进行的一个升级,是一个强大的滑动组件,使用起来比ListView更为强大,可以很好的维护大数据集的滚动和显示。
- RecyclerView不关心Item是否显示在正确的位置,以及如何显示。(依靠LayoutManager进行RecyclerView布局的制定)
- RecyclerView不关心Item间如何间隔(使用ItemDecoration进行下划线的绘制)
- RecyclerView不关注Item增加与删除的动画效果(动画效果由ItemAnimator处理)
- RecyclerView只关注如何回收和复用View
布局、绘制、动画等方面的工作谷歌都将其差分成不同的类进行管理,因此我们可以自定义这些类来实现自己的需求。
相比于List View,RecyclerView对ViewHolder进行了封装,强制我们必须要使用ViewHolder来进行优化,因此只要实现功能就可以了。
另外注意的是Android并没有给Recycler增加点击事件,因此需要我们自己使用接口的回调机制或者直接在适配器中监听View的点击事件。
下面看一下运行效果:
Api使用的是:http://gank.io/api/data/福利/10/1(就叫做妹子Api吧O(∩_∩)O),可以去http://gank.io/api
项目结构:
自己封装的网络请求和io流转换的工具类就就不贴出来了代码比较简单
下面通过这个案例梳理一下RecyclerView的用法以加深记忆:
MyRecyclerViewAdapter.java
/**
* Created by 春水碧于天 on 2017/1/27.
*/
public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyViewHolder> {
private LayoutInflater mLayoutInflater;
private Context mContext;
private List<String> mDatas; //封装图片Url
private Random random;
//构造函数初始化数据
public MyRecyclerViewAdapter(List<String> data, Context mContext) {
mDatas = data;
this.mContext = mContext;
this.mLayoutInflater = mLayoutInflater.from(mContext);
random = new Random();
}
//返回由多少条数据
@Override
public int getItemCount() {
return mDatas.size();
}
//直接创建一个可复用的ViewHolder或者根据ViewType创建多种不同的ViewHolder
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = mLayoutInflater.inflate(R.layout.item_single_textview,parent,false);
MyViewHolder viewHolder = new MyViewHolder(view);
return viewHolder;
}
//数据和ViewHolder中的内容通过position进行绑定
@Override
public void onBindViewHolder(final MyViewHolder holder, final int position) {
Uri uri = Uri.parse(mDatas.get(position));
ViewGroup.LayoutParams params = holder.imageView.getLayoutParams();
//通过随机数生成ImageView的高度,动态设置给ImageView实现瀑布流效果的关键
params.height = random.nextInt(200)+300;
holder.imageView.setLayoutParams(params);
//通过Glide加载网络路径的图片
Glide.with(mContext).load(uri).into(holder.imageView);
//设置ImageView的点击事件
holder.imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(mContext,position+"",Toast.LENGTH_SHORT).show();
Intent intent = new Intent(mContext, DetailActivity.class);
intent.putExtra("uri",mDatas.get(position));
mContext.startActivity(intent, ActivityOptions.makeSceneTransitionAnimation((Activity) mContext,holder.imageView,"share").toBundle());
}
});
}
}
//通过继承ViewHolder这个抽象类实现View的封装
class MyViewHolder extends RecyclerView.ViewHolder{
public ImageView imageView;
public MyViewHolder(View itemView) {
super(itemView);
imageView = (ImageView) itemView.findViewById(R.id.imageView);
}
}
在ListView中ViewHolder的作用为了防止每次创建布局的时候都会调用findViewById(int ),导致ListView的性能展示缓慢,而RecyclerView则强制我们使用ViewHolder。
这里面的点击事件的逻辑直接写在了Adapter中,也可以通过回调的形式来完成。
回调的写法:
public OnItemClickListener onItemClickListener;
public void setOnItemClickListener(OnItemClickListener onItemClickListener){
this.onItemClickListener = onItemClickListener;
}
public interface OnItemClickListener{
void(View v,int position)
}
MainActivity.java
public class MainActivity extends AppCompatActivity {
private RecyclerView.Adapter myAdapter;
private RecyclerView mRecyclerView;
private Handler mHandler;
private List<String> Images;
private List<Integer> mImageHeights;
private int count = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i("ljx", "新年快乐O(∩_∩)O……");
InitUI();
InitData();
//给RecyclerView设置布局
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);
mRecyclerView.setLayoutManager(new StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL));
/**
* 系统默认的三种布局样式:
*
* new LinearLayoutManager() //线性布局管理器,默认方向垂直
* new GridLayoutManager() //创建网格布局管理器,默认方向垂直
* new LinearLayoutManager () //创建错综网格布局,默认方向锤子,可以用来实现瀑布流效果
*/
myAdapter = new MyRecyclerViewAdapter(Images, MainActivity.this); //创建适配器
mRecyclerView.setAdapter(myAdapter); //给RecyclerView绑定适配器
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
String JsonStr = (String) msg.obj;
Log.i("wk", "Handler:" + JsonStr);
getImagesFromJson(JsonStr); //解析Json
myAdapter.notifyDataSetChanged(); //更新数据
Toast.makeText(MainActivity.this, "加载到第" + count + "页", Toast.LENGTH_SHORT).show();
}
};
new Thread(new Runnable() {
@Override
public void run() {
//进行网络请求
String ResultStr = HttpHelper.GetHttpConnection("http://gank.io/api/data/%E7%A6%8F%E5%88%A9/40/1");
Message msg = new Message();
msg.obj = ResultStr;
mHandler.sendMessage(msg);
}
}).start();
//RecyclerView的滑动监听
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
//判断是否滑动到底部,用于分页加载
if (isSlideToBottom(recyclerView)) {
new Thread(new Runnable() {
@Override
public void run() {
String ResultStr = HttpHelper.GetHttpConnection("http://gank.io/api/data/%E7%A6%8F%E5%88%A9/40/" + count++);
Message msg = new Message();
msg.obj = ResultStr;
mHandler.sendMessage(msg);
}
}).start();
}
}
});
}
//解析Json数据将解析到的Image的Url添加的Images集合当中
private void getImagesFromJson(String jsonStr) {
try {
JSONObject jsonObject = new JSONObject(jsonStr);
JSONArray jsonArray = jsonObject.getJSONArray("results");
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jb = jsonArray.getJSONObject(i);
Images.add(jb.getString("url"));
}
} catch (JSONException e) {
e.printStackTrace();
} finally {
}
}
private void InitData() {
Images = new ArrayList<String>();
}
private void InitUI() {
mRecyclerView = (RecyclerView) findViewById(R.id.recyclerView);
}
//判断recycler是否滑动到底部
protected boolean isSlideToBottom(RecyclerView recyclerView) {
if (recyclerView == null) return false;
if (recyclerView.computeVerticalScrollExtent() + recyclerView.computeVerticalScrollOffset() >= recyclerView.computeVerticalScrollRange())
return true;
return false;
}
}
这边没有使用到之前提到的 ItemDecoration,ItemAnimator这两个类,后面深入的时候会对这两个类的使用进行详解,以及布局LayoutManager的自定义。
DetailActivity.java
用于显示大图
public class DetailActivity extends AppCompatActivity {
private ImageView imageView;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_detail);
imageView = (ImageView) findViewById(R.id.imageView);
String uri = getIntent().getStringExtra("uri");
Glide.with(this).load(Uri.parse(uri)).into(imageView);
}
}
布局就补不贴了,比较简单,从上面的代码也就能看出布局文件的写法了。这样一个瀑布流就实现了,相比使用ListView来实现这个效果实在简单了不少。
最后 妹子API确实挺不错的额,适合练手^_^