最近在研究android中瀑布流视图的实现方法,我第一次看到这种视图是在一款视频App上,名叫bilibili手机客户端,非常喜欢这款App,它的界面十分漂亮,与用户的交互性很高。以下就是这款App瀑布流视图的截图
查阅相关资料,我了解到了这种瀑布流效果可以借助一款新的android控件来实现,这款控件在android-support-v7包中,大名就叫做RecyclerView。可以说,RecyclerView的确是款挺强大的控件,它不仅可以取代ListView,完成数据列表形式的展示,还能做到像瀑布流或表格这样的布局风格,巧妙的是,这些布局风格的切换仅仅需要一行代码就能实现,方便快捷。
与传统的ListView相比,RecyclerView增加了ViewHolder特性,这对于列表视图优化的实现便捷了许多。传统ListView实现优化一般是采用自己编写ViewHolder的形式,通过可复用视图(convertView)的setTag()和getTag()方法传递ViewHolder,当adapter每次创建item视图( getView() )的时候直接修改ViewHolder中已经定义好的控件的属性,避免了每次在创建item视图( getView() )时都调用findViewById(),从而达到优化的效果。而RecyclerView则自带了ViewHolder,设置起来也十分简单,所以在代码优化的方面比起ListView便捷了不少。
话不多说,以下就展示这款强大控件的使用吧!
首先是引包,因为我使用的是Android Studio,所以导包的方式为:
File-->Project Structure打开项目结构面板,然后按照下方截图所示即可导入RecyclerView包:
导好包后下面就进行代码的编写,以下是数据和RecyclerView的初始化:
private void initData() {
this.mData = new ArrayList<>();
mAdapter = new ContentViewAdapter(this.mData,getApplicationContext());
for(int i = 'A';i<'z';i++)
{
Map<String,String> map = new HashMap<>();
map.put("name",(char)i+"");
map.put("intro",i+"");
this.mData.add(map);
}
}
private void initView(RecyclerView.LayoutManager manager) {
this.contentView = (RecyclerView) this.findViewById(R.id.id_content_view);
/*设置Adapter*/
this.contentView.setAdapter(this.mAdapter);
/*设置recyclerView中item增减的动画效果*/
this.contentView.setItemAnimator(new DefaultItemAnimator());
/*设置布局*/
this.contentView.setLayoutManager(manager);
//manager = new StaggeredGridLayoutManager(2,StaggeredGridLayoutManager.VERTICAL)
}
其中,若使用第一个manager,则可以把此RecyclerView布局变成ListView的列表形式,若使用第二个,则是瀑布流布局,而第三个则是表格布局,每个布局都有方向可设置,水平或垂直。
下面就是创建RecyclerView的Adapter类。
/**
* My View Adapter
*/
public class ContentViewAdapter extends RecyclerView.Adapter<ContentViewAdapter.ContentViewHolder> {
private List<Map<String,String>> data;
private LayoutInflater inflater;
private ItemClickListener mListener;
public ContentViewAdapter(List<Map<String,String>> data,Context context)
{
this.inflater = LayoutInflater.from(context);
this.data = data;
}
public void setItemClickListener(ItemClickListener listener)
{
this.mListener = listener;
}
@Override
public ContentViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
return new ContentViewHolder(this.inflater.inflate(R.layout.layout_item,viewGroup,false));
}
@Override
public int getItemCount() {
return this.data.size();
}
/**
* 方法中获取item位置我用的是 contentViewHolder.getLayoutPosition()
* 为什么不用参数中提供的position?
* 原因是当增加或删除一个item时,使用到
* notifyItemRemoved()或notifyItemInserted()方法
* position值不会随之改变,但是getLayoutPosition()返回的是真实的item位置
*
* */
@Override
public void onBindViewHolder(final ContentViewHolder contentViewHolder, int position) {
Map<String,String> sth = this.data.get(contentViewHolder.getAdapterPosition());
contentViewHolder.setName(sth.get("name"));
contentViewHolder.setIntro(sth.get("intro"));
if(mListener!=null)
{
contentViewHolder.getItemView().setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ContentViewAdapter.this.mListener.onItemClick(v, contentViewHolder.getLayoutPosition());
}
});
contentViewHolder.getItemView().setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
ContentViewAdapter.this.mListener.onItemLongClick(v, contentViewHolder.getLayoutPosition());
return false;
}
});
}
/*随意设置item的高度,目的为了达到瀑布流的效果*/
ViewGroup.LayoutParams params = contentViewHolder.getItemView().getLayoutParams();
params.height = (int) (300 + Math.random()*(500-300+1));
}
public void insertItem()
{
Map<String,String> oneDate = new HashMap<>();
oneDate.put("name","Tom");
oneDate.put("intro", "I am tom!");
this.data.add(0, oneDate);
//记住是用这个方法而不是notifyDataSetChanged(),不然会没有动画效果
this.notifyItemInserted(0);
}
public void deleteItem(int pos)
{
this.data.remove(pos);
//规则同上
this.notifyItemRemoved(pos);
}
/**
* My View Holder
*/
class ContentViewHolder extends RecyclerView.ViewHolder {
private TextView name;
private TextView intro;
private View itemView;
public ContentViewHolder(View itemView) {
super(itemView);
this.itemView = itemView;
this.name = (TextView) itemView.findViewById(R.id.id_name);
this.intro = (TextView) itemView.findViewById(R.id.id_intro);
}
public void setName(String name) {
this.name.setText(name);
}
public void setIntro(String intro) {
this.intro.setText(intro);
}
public View getItemView()
{
return this.itemView;
}
}
/**
* 监听item点击/长点击事件
* 因为RecyclerView中没有帮我们定义item被点击后的事件监听
* 所以这需要我们自己去定义
*/
public interface ItemClickListener
{
void onItemClick(View view,int which);
void onItemLongClick(View view,int which);
}
以上就是实现RecyclerView的基本代码,下面是运行时的截图: