手把手教你做開源專案MyMeiZi 二(使用RecyclerView+Glide打造瀑布流)
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可以傳
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,看起來效果還是不錯的,本章內容就到此為止啦