Glide
一个专注于平滑滚动的图片加载和缓存库,相信大家也不会陌生,话说我以前一直使用的是Fresco,这次也是为了学习使用了Glide,谁上谁下这个不好区分,但是Glide更轻量级,究竟选择哪个还要看各位自己了
在Github上我们可以看到关于Glide的用法。
// For a simple view:
@Override public void onCreate(Bundle savedInstanceState) {
...
ImageView imageView = (ImageView) findViewById(R.id.my_image_view);
Glide.with(this).load("http://goo.gl/gEgYUd").into(imageView);
}
// For a simple image list:
@Override public View getView(int position, View recycled, ViewGroup container) {
final ImageView myImageView;
if (recycled == null) {
myImageView = (ImageView) inflater.inflate(R.layout.my_image_view, container, false);
} else {
myImageView = (ImageView) recycled;
}
String url = myUrls.get(position);
Glide
.with(myFragment)
.load(url)
.centerCrop()
.placeholder(R.drawable.loading_spinner)
.crossFade()
.into(myImageView);
return myImageView;
}
非常的简单,with里面可以传Activity,Fragment,Glide会自动根据你的生命周期来判断暂停和加载,load可以传
centerCrop和fitCenter就和设置ImageView的scaleType一样,into就是你的ImageView控件了。
RecyclerView
更加灵活的ListView,拔插式的设计能轻而易举的完成许多效果(拖动排序,滑动删除),而且使用StaggeredGridLayoutManager可以轻松的完成瀑布流样式
我们今天的主题就是使用Glide+RecyclerView完成MyMeiZi中的老司机界面
关于从网上用RxJava和Retrofit拿数据我们上一章已经讲过了这一次我们直接开始完成UI吧.手把手教你做开源项目MyMeiZi 一( RxJava + Retrofit)
既然RecyclerView自带瀑布流我们就轻轻松松的完成吧!
@Override
protected ItemHolder onAdapterCreateViewHolder(ViewGroup viewGroup, int viewType) {
DriverView driverView = new DriverView(mContext);
ItemHolder itemHolder = new ItemHolder(driverView);
return itemHolder;
}
@Override
protected void onAdapterBindViewHolder(ItemHolder viewHolder, int position) {
viewHolder.driverView.setData(mData.get(position));
}
因为图片高度不一样所以才能完成瀑布流样式,那么我们该怎么判断Item适当的高度呢,因为Item的宽度是固定的,所以我们可以根据宽度得到适当的高度(这叫自问自答).
<android.support.v7.widget.CardView
android:id="@+id/view_card_feed"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:scrollbars="vertical"
app:cardCornerRadius="5dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/view_img_feed"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="centerCrop"
/>
</RelativeLayout>
</android.support.v7.widget.CardView>
用Glide override和asBitmap的方法得到一个宽度为Item宽度高度为原始尺寸的图片
Glide.with(getContext()).load(data.getUrl()).asBitmap().fitCenter().override(mBinding.viewImgFeed.getWidth(), BitmapImageViewTarget.SIZE_ORIGINAL).into(new DriverViewTarget(mBinding.viewImgFeed));
在BitmapImageViewTarget中对Item进行宽高的调整
private class DriverViewTarget extends BitmapImageViewTarget {
public DriverViewTarget(ImageView view) {
super(view);
}
@Override
public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) {
int viewWidth = mBinding.viewImgFeed.getWidth();
float scale = resource.getWidth() / (viewWidth * 1.0f);
int viewHeight = (int) (resource.getHeight() * scale);
setCardViewLayoutParams(viewWidth, viewHeight);
super.onResourceReady(resource, glideAnimation);
}
}
恩,完美,运行一下!
看上去是没啥问题,瀑布流的样子也都出来了,不过慢滑和快滑时明显有一个重新排列的过程,这是因为每次划出来时会从缓存或者网上重新填充,而这个填充快慢就不一定了,可能Item填充顺序和第一次加载完毕时不一样,高度的计算顺序也不一样,这也就导致了如图中的效果,几个Item会不断的变换位置~
果然什么事都没有那么简单啊,不过我们已经知道这是因为高度计算的问题,那么我们可以新建立一个SizeModel类,来存储我们第一次加载时计算的高度,以后判断这个SizeModel如果存在可以直接用width和Height而不用再根据Bitmap重新计算一次,这也是本章的核心内容!!!!
public class SizeModel {
private String url;
private int height;
private int width;
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public boolean isNull() {
return height == 0 || width == 0;
}
public void setSize(int width, int height) {
this.width = width;
this.height = height;
}
}
使用方法,首先在获取到网络数据时,把图片的url传给SizeModel,然后传给Adapter
@Override
public void onNext(GankIoModel.ResultsEntity resultsEntity) {
mData.add(resultsEntity);
SizeModel sizeModel = new SizeModel();
sizeModel.setUrl(resultsEntity.getUrl());
mSizeData.add(sizeModel);
feedAdapter.setSizeModel(mSizeData);
feedAdapter.notifyAdapterItemInserted(mData.size());
}
然后再由Adapter传给我们的控件
@Override
protected void onAdapterBindViewHolder(ItemHolder viewHolder, int position) {
viewHolder.driverView.setData(mData.get(position), mSizeModel.get(position));
}
最后我们在控件中做处理判断
if (!mSizeModel.isNull()) {
setCardViewLayoutParams(mSizeModel.getWidth(), mSizeModel.getHeight());
}
private void setCardViewLayoutParams(int width, int height) {
ViewGroup.LayoutParams layoutParams = mBinding.viewImgFeed.getLayoutParams();
layoutParams.width = width;
layoutParams.height = height;
mBinding.viewImgFeed.setLayoutParams(layoutParams);
}
@Override
public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) {
if (mSizeModel.isNull()) {
int viewWidth = mBinding.viewImgFeed.getWidth();
float scale = resource.getWidth() / (viewWidth * 1.0f);
int viewHeight = (int) (resource.getHeight() * scale);
setCardViewLayoutParams(viewWidth, viewHeight);
mSizeModel.setSize(viewWidth, viewHeight);
}
super.onResourceReady(resource, glideAnimation);
}
再次运行~
ok,看起来效果还是不错的,本章内容就到此为止啦