今天,有一个需求,就是做一个瀑布流。第一反应,相当简单,RecyclerView实现瀑布流的方便快捷,早已如雷贯耳,博文遍地了。于是,我踩上了这个惊天大坑了。
我还以为RecyclerView 会为每个item 动态设置高度,然而,呵呵( ̄ ̄)"。想得美。
然后,更让人无语的是,网上这么多博文,竟然都是靠随机高度来解决这一个问题,面对这么草率的解决办法,我是拒绝的。特此发表博文,用另外一种方式,动态改变item的宽高。
思路
因为瀑布流都会一般都会有图片展示,我举得根据每一张图片的不同的宽高比例,去实现瀑布流。
拿到每一个item里面的ImageView的宽度 计算方式:
屏幕宽度/列数 - item的左边距 - item 的右边距 (如果有内边距则再减掉左右两边的Padding)
/**
* Created by Jin on 2016/6/20.
*/
public class DetailsAdapter extends RecyclerView.Adapter<DetailsAdapter.DetailsViewHolder> {
private final LayoutInflater mInflater;
private List<ItemDetails.Details> mLists = new ArrayList<>();
private int mItemWidth;
public DetailsAdapter(Context context) {
mInflater = LayoutInflater.from(context);
mItemWidth = AppUtil.getDisplayMetrics(context).widthPixels / 2 - AppUtil.dip2px(10) - AppUtil.dip2px(5);
}
在Adapter 的onBindViewHolder()方法中,获取ImageView的bitmap,并计算按比率缩小后的bitmap的高度,有了imageview的宽高,后面就so easy了
//填充onCreateViewHolder方法返回的holder中的控件
@Overridepublic void onBindViewHolder(final DetailsViewHolder holder, final int position) {
ItemDetails.Details details = mLists.get(position);
holder.tvLikeCount.setText(String.valueOf(details.getLikeCount()));
ImageLoader.getInstance().load(holder.ivPic, details.getPorposeUrl());
ImageLoader.getInstance().load(details.getPorposeUrl(), new ImageLoader.OnLoadByteListener() {
@Override
public void onLoad(Bitmap resource) {
int height = ImageUtil.getHeight(resource, mItemWidth);
resource.recycle();//算完高度,回收bitmap,释放内存
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(mItemWidth, height);
holder.ivPic.setLayoutParams(params);
}
});
holder.ivPic.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
T.showShort("你点击了第" + position + "张图片");
}
});
}
根据宽度计算等比例的高度的方法
public static int getHeight(Bitmap btm,int newWidth){
float btmW=btm.getWidth();
float btmH=btm.getHeight();
float scale=btmH/btmW;
return (int) (newWidth*scale);
}
2016.06.23 填坑
1.经过测试,当图片多的时候,出现很明显的卡顿,通过内存检测,内存占用很大,忽略了内存的问题了。具体原因是,因为Adapter 的onBindViewHolder方法会重复调用,而我方法里面只是为了拿个宽高,而每次去创建一个bitmap,虽然有及时recycle,但是内存的抖动还是很大的,所以就会一卡一卡的了。我的想法了,后台在得到图片的时候,顺便计算高度,并存入数据库中,每次获取时,我们只要根据图片的后台宽高数据,来惊醒Item中ImageView的宽高设置即可。经过检测,使用这个方法,可以让RecyclerView滚动很顺畅,具体的修改如下:
1)Adapter onBindViewHolder方法的改动
//填充onCreateViewHolder方法返回的holder中的控件
@Override
public void onBindViewHolder(final DetailsViewHolder holder, final int position) {
ItemDetails.Details details = mLists.get(position);
holder.tvLikeCount.setText(String.valueOf(details.getLikeCount()));
int height=ImageUtil.getNewHeight(details.getWidth(),details.getHeight(),mItemWidth);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(mItemWidth, height);
holder.ivPic.setLayoutParams(params);
ImageLoader.getInstance().load(holder.ivPic, details.getPorposeUrl());
holder.ivPic.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
T.showShort("你点击了第" + position + "张图片");
}
});
}
- 新的高度计算方法
public static int getNewHeight(int oldw,int oldh,int newWidth){
float scale=(float)oldh/oldw;
return (int) (newWidth*scale);
}