上路傳送眼:
Android練手小項(xiàng)目(KTReader)基于mvp架構(gòu)(四)
GIthub地址: https://github.com/yiuhet/KTReader
上篇文章中我們完成了豆瓣模塊。
而這次我們要做的的就是圖片模塊。
效果圖奉上:
總覽一下圖片模塊我們完成的功能有:
- 圖片瀏覽(三種排序方式)
- 圖片關(guān)鍵字搜索
- 圖片詳情查看
- 圖片下載(可查看和選擇圖片質(zhì)量)
- 下拉刷新,上拉加載
所用到的一些知識(shí)點(diǎn)有:
- Rxjava2 + Retrofit2 + OKhttp3 實(shí)現(xiàn)網(wǎng)絡(luò)請(qǐng)求
- 下載文件的FileOutputStream用法
- 下載文件的大小獲取回調(diào)
- AlertDialog的適配器視圖和Items視圖
- Spinner的簡(jiǎn)單使用
- RecycleView的瀑布流布局實(shí)現(xiàn)和踩坑(item重排)
- SwipeRefreshLayout布局
可完善和加強(qiáng)的內(nèi)容或功能有:
- 收藏圖片
- 圖片詳情頁的美化
- 下載列表的實(shí)現(xiàn)
- 下載圖片時(shí)通知欄的進(jìn)度提醒
- 隨意推薦一張圖片
大體上介紹完畢之后,下面就說說具體的實(shí)現(xiàn):
1. API的獲取
想要做一個(gè)圖片模塊,數(shù)據(jù)是必不可少的,這里我們直接使用免費(fèi)的api就行了,話說我百度出來的圖片api為啥都是美女圖啊喂,雖然很福利!為嘛找個(gè)綜合圖片的api那么麻煩啊,總之找了好久終于找到了個(gè)好用的api,分享給大家:Unsplash(唯一的不足就是沒有中文的開發(fā)者文檔,不過其實(shí)里面的英語挺好懂的,實(shí)在不行還可以劃詞翻譯嘛)。
另外附上我找資源時(shí)發(fā)現(xiàn)的一個(gè)好東西,以后找api時(shí)可以直接先在這搜:
總之,注冊(cè)好開發(fā)者賬號(hào)和看了開發(fā)者文檔后就可以直接寫接口了。
api.TupianApi
public interface TupianApi {
/*
*Get a single page from the list of all photos.
* 參數(shù)分別為appId,頁碼,每頁個(gè)數(shù),排序規(guī)則 (Valid values: latest, oldest, popular; default: latest)
*/
@GET("photos")
Observable<List<UnsplashPhotosList>> getUnsplashPhotosList
(@Query("client_id") String clientId,@Query("page") int page,@Query("per_page") int perPage,
@Query("order_by") String orderBy);
@GET("/search/photos")
Observable<UnsplashPhotoSearch> getSearchUnsplashPhotosList
(@Query("client_id") String clientId,@Query("query") String query,@Query("page") int page,
@Query("per_page") int perPage);
@GET("photos/random")
Observable<UnsplashPhoto> getUnsplashRandomPhoto(@Query("client_id") String clientId);
@GET("photos/{id}")
Observable<UnsplashPhoto> getUnsplashPhoto
(@Path("id") String id, @Query("client_id") String clientId);
@GET("photos/{id}/download")
Observable<UnsplashUrl> getPhotoDownloadUrl(
@Path("id") String id, @Query("client_id") String clientId);
@GET
Observable<ResponseBody> getPhotoDownload(@Url String url);
}
然后在RetrofitManager類里添加個(gè)獲取圖片服務(wù)的方法
utils.RetrofitManager
private TupianApi tupianApi;
public TupianApi getTupianService(String url) {
if (tupianApi == null) {
tupianApi = new Retrofit.Builder()
.baseUrl(url) //必須以‘/’結(jié)尾
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())//使用RxJava2作為CallAdapter
.client(client)//如果沒有添加,那么retrofit2會(huì)自動(dòng)給我們添加了一個(gè)。
.addConverterFactory(GsonConverterFactory.create())//Retrofit2可以幫我們自動(dòng)解析返回?cái)?shù)據(jù),
.build().create(TupianApi.class);
}
return tupianApi;
}
2. 實(shí)現(xiàn)M層
實(shí)體類老規(guī)矩直接GsonFormat生成,不過Unsplash返回的直接是數(shù)組類型,以至于工具生成的實(shí)體類為數(shù)組里的具體項(xiàng),因此我們?cè)趯慳pi接口時(shí)類型要為L(zhǎng)ist類型,這樣才能解析出列表數(shù)據(jù)。
-
M層的接口
我們需要的功能為加載查詢的關(guān)鍵字圖片數(shù)據(jù)和默認(rèn)加載數(shù)據(jù)
model.UnsplashPhotoListModel
public interface UnsplashPhotoListModel {
void loadSearchPhotoList(OnUnsplashPhotoListListener listener,String query);
void loadPhotoList(OnUnsplashPhotoListListener listener);
}
-
M層的實(shí)現(xiàn)類
實(shí)現(xiàn)類里我們定義了挺多變量,是為了控制獲取的數(shù)據(jù)數(shù)量和類型。
分別有頁碼,每頁圖片數(shù)量,和排序方式等。
model.UnsplashPhotoListModelImp1
public class UnsplashPhotoListModelImp1 implements UnsplashPhotoListModel{
private static final String UNSPLASH_APPLICATION_ID = "nideapplicationidya233";
private static final String UNSPLASH_BASE_URL = "https://api.unsplash.com/";
private int PAGE = 1;
private int PAGE_SEARCH = 1;
private int PER_PAGE = 10;
private String[] ORDERBY = {"latest", "oldest", "popular"};
//排序方式 ,0,1,2分別為"latest", "oldest", "popular"。
private int STATE = 0;
private TupianApi mTupianApi;
public UnsplashPhotoListModelImp1() {
mTupianApi = RetrofitManager
.getInstence()
.getTupianService(UNSPLASH_BASE_URL);
}
public void setState(int state) {
STATE = state;
}
@Override
public void loadSearchPhotoList(final OnUnsplashPhotoListListener listener, String query) {
if (mTupianApi != null) {
mTupianApi.getSearchUnsplashPhotosList(UNSPLASH_APPLICATION_ID, query, PAGE_SEARCH, PER_PAGE)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<UnsplashPhotoSearch>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
}
@Override
public void onNext(@NonNull UnsplashPhotoSearch unsplashPhotosLists) {
Log.d("testquery","onNext");
listener.onLoadSearchPhotoListSuccess(unsplashPhotosLists);
PAGE_SEARCH ++;
}
@Override
public void onError(@NonNull Throwable e) {
Log.d("testquery",e.toString());
listener.onLoadDataError(e.toString());
}
@Override
public void onComplete() {
}
});
}
}
@Override
public void loadPhotoList(final OnUnsplashPhotoListListener listener) {
if (mTupianApi != null) {
mTupianApi.getUnsplashPhotosList(UNSPLASH_APPLICATION_ID, PAGE, PER_PAGE, ORDERBY[STATE])
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<List<UnsplashPhotosList>>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
}
@Override
public void onNext(@NonNull List<UnsplashPhotosList> unsplashPhotosLists) {
listener.onLoadPhotoListSuccess(unsplashPhotosLists);
PAGE++;
}
@Override
public void onError(@NonNull Throwable e) {
listener.onLoadDataError(e.toString());
}
@Override
public void onComplete() {
}
});
}
}
}
3. 實(shí)現(xiàn)V層
首先確定我們要實(shí)現(xiàn)的功能,大致分為4種:
- 開始獲取數(shù)據(jù)
- 獲取默認(rèn)數(shù)據(jù)成功
- 獲取查詢數(shù)據(jù)成功
- 獲取數(shù)據(jù)失敗
詳情代碼如下
view.UnsplashPhotoListView
public interface UnsplashPhotoListView {
void onStartGetData();
void onGetPhotoSuccess(List<UnsplashPhotosList> photosList);
void onGetSearchPhotoSuccess(UnsplashPhotoSearch photosList);
void onGetDataFailed(String error);
}
然后可以寫具體的界面
這里我們同樣分析一下界面需要如何實(shí)現(xiàn):
首先我們需要個(gè)搜索欄和選擇欄,然后再來個(gè)recycleview來加載圖片,為了美觀我們采用瀑布流的布局,當(dāng)內(nèi)容拉到底部時(shí),我們要加載更多的圖片,這是我們就需要個(gè)變量標(biāo)識(shí)我們需要加載更多的是用戶自己搜索的圖片還是默認(rèn)加載的圖片(哪種排序方式),同時(shí)這個(gè)標(biāo)識(shí)用于傳遞給P層通知它要加載的數(shù)據(jù)類型。
分析完成后就是具體代碼的實(shí)現(xiàn):
ui.fragment.UnsplashListFragment
public class UnsplashListFragment extends BaseFragment<UnsplashPhotoListView, UnsplashPhotoListPresenterImp1> implements UnsplashPhotoListView, SwipeRefreshLayout.OnRefreshListener {
private UnsplashListAdapter unsplashListAdapter;
private int STATE = 0;//當(dāng)前的狀態(tài)
//擁有的狀態(tài) :latest", "oldest", "popular",搜索狀態(tài)。
private final int STATE_LATEST = 0;
private final int STATE_OLDEST = 1;
private final int STATE_POPULAR = 2;
private final int STATE_SEARCH = 3;
//記錄搜索狀態(tài)下的搜索項(xiàng)
private String Query;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View rootView = super.onCreateView(inflater, container, savedInstanceState);
unbinder = ButterKnife.bind(this, rootView);
init();
return rootView;
}
private void init() {
initRecycleView();
//監(jiān)聽 SwipeRefreshLayout 事件 上拉就調(diào)用ReLoad方法。
mContentSwipe.setOnRefreshListener(this);
//監(jiān)聽 SearchView 事件
mSvPhoto.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
Query = query;
if (query != null){
STATE = STATE_SEARCH;
} else {
STATE = STATE_LATEST;
}
ReLoad(query);
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
return false;
}
});
//初始化加載數(shù)據(jù) Spinner 開始選擇latest
mSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
STATE = position;
ReLoad("");
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
}
private void initRecycleView() {
contentRecycle.setLayoutManager(new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL));
contentRecycle.setHasFixedSize(true);
contentRecycle.setItemAnimator(new DefaultItemAnimator());
unsplashListAdapter = new UnsplashListAdapter(getContext());
unsplashListAdapter.setOnItemClickListener(mOnItemClickListener);
SpacesItemDecoration decoration = new SpacesItemDecoration(12);
contentRecycle.addItemDecoration(decoration);
contentRecycle.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)) {
if (STATE == STATE_SEARCH) {
mPresenter.getSearchPhotoList(Query);
} else {
mPresenter.getPhotoList(STATE);
}
}
}
});
contentRecycle.setAdapter(unsplashListAdapter);
}
//判斷RecycleView是否到底部
public static boolean isSlideToBottom(RecyclerView recyclerView) {
if (recyclerView.computeVerticalScrollExtent() + recyclerView.computeVerticalScrollOffset()
>= recyclerView.computeVerticalScrollRange()){
return true;
}
return false;
}
//RecycleView的item監(jiān)聽事件 點(diǎn)擊item,跳轉(zhuǎn)到相應(yīng)的activity
private UnsplashListAdapter.OnItemClickListener mOnItemClickListener = new UnsplashListAdapter.OnItemClickListener() {
@Override
public void onItemClick(String id,View view) {
Intent intent = new Intent(getActivity(), UnsplashPhotoActivity.class);
intent.putExtra("PHOTOID", id);
CircularAnimUtil.startActivity(getActivity(), intent, view,
R.color.colorPrimary);
toast("you touch me,my id:" + id);
}
};
//重新加載數(shù)據(jù) ,首先清空數(shù)據(jù),然后根據(jù)當(dāng)前狀態(tài)獲取數(shù)據(jù)
public void ReLoad(String query) {
unsplashListAdapter.clearData();
if (STATE == STATE_SEARCH) {
mPresenter.getSearchPhotoList(query);
} else {
mPresenter.getPhotoList(STATE);
}
}
@Override
public void onStartGetData() {
if (mContentSwipe != null) {
mContentSwipe.setRefreshing(true);
}
}
@Override
public void onGetPhotoSuccess(List<UnsplashPhotosList> photosList) {
if (mContentSwipe != null && mContentSwipe.isRefreshing()) {
mContentSwipe.setRefreshing(false);
}
unsplashListAdapter.addData(photosList);
}
@Override
public void onGetSearchPhotoSuccess(UnsplashPhotoSearch photosList) {
if (mContentSwipe != null && mContentSwipe.isRefreshing()) {
mContentSwipe.setRefreshing(false);
}
unsplashListAdapter.addData(photosList.results);
}
@Override
public void onGetDataFailed(String error) {
if (mContentSwipe != null && mContentSwipe.isRefreshing()) {
mContentSwipe.setRefreshing(false);
}
toast(error);
}
@Override
protected int getLayoutRes() {
return R.layout.fragment_unsplash;
}
@Override
protected UnsplashPhotoListPresenterImp1 createPresenter() {
return new UnsplashPhotoListPresenterImp1(this);
}
@Override
public void onDestroyView() {
super.onDestroyView();
unbinder.unbind();
}
@Override
public void onRefresh() {
ReLoad("");
}
}
這里有個(gè)坑,當(dāng)RecycleView設(shè)置為StaggeredGridLayoutManager布局方式時(shí),我們會(huì)發(fā)現(xiàn)RecycleView的item項(xiàng)會(huì)變位置,原來是每次其高度都隨機(jī)導(dǎo)致,這里我們?cè)赼dapter內(nèi)部維護(hù)一個(gè)高度數(shù)組,讓內(nèi)部的item有著不變的隨機(jī)高度。
其具體實(shí)現(xiàn)代碼我也貼出 如下:
adapter.UnsplashListAdapter
public class UnsplashListAdapter extends RecyclerView.Adapter<UnsplashListAdapter.PhotoViewHolder>{
private List<UnsplashPhotosList> mPhotoList;
private Context mContext;
private OnItemClickListener mItemClickListener;
//用于每個(gè)item的布局
private LayoutInflater mInflater;
//瀑布流控制高度
private List<Integer> mHeights;
private int currentPos = 0;
public UnsplashListAdapter(Context context) {
mContext = context;
mPhotoList = new ArrayList<>();
mInflater = LayoutInflater.from(context);
mHeights = new ArrayList<Integer>();
}
public void addData(List<UnsplashPhotosList> unsplashPhotosList) {
currentPos += mPhotoList.size();
for (UnsplashPhotosList photosList:unsplashPhotosList){
mPhotoList.add(photosList);
}
for (int i = 0;i<unsplashPhotosList.size();i++){
mHeights.add((int) (300+Math.random()*300));
}
//應(yīng)該局部 刷新 ,有個(gè)bug TODO: 2017/6/11 bug
//notifyItemRangeChanged(currentPos,unsplashPhotosList.size());
notifyDataSetChanged();
}
//清空數(shù)據(jù)
public void clearData() {
currentPos = 0;
mPhotoList.clear();
notifyDataSetChanged();
}
@Override
public PhotoViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = mInflater.inflate(R.layout.item_photo, parent, false);
PhotoViewHolder photoViewHolder = new PhotoViewHolder(view);
return photoViewHolder;
}
@Override
public void onBindViewHolder(final PhotoViewHolder holder, final int position) {
ViewGroup.LayoutParams layoutParams = holder.itemView.getLayoutParams();
layoutParams.height = mHeights.get(position);
holder.itemView.setLayoutParams(layoutParams);
Glide.with(mContext)
.load(mPhotoList.get(position).urls.small)
.diskCacheStrategy(DiskCacheStrategy.SOURCE)
.centerCrop()
.into(holder.mImage);
holder.mImage.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mItemClickListener != null) {
mItemClickListener.onItemClick(mPhotoList.get(position).id,holder.itemView);
}
}
});
}
@Override
public int getItemCount() {
return mPhotoList == null ? 0:mPhotoList.size();
}
class PhotoViewHolder extends RecyclerView.ViewHolder{
@BindView(R.id.iv_photo)
ImageView mImage;
@BindView(R.id.tv_title)
TextView mTitle;
public PhotoViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
public interface OnItemClickListener {
void onItemClick(String id,View view);
}
public void setOnItemClickListener(OnItemClickListener listener) {
mItemClickListener = listener;
}
}
4. 實(shí)現(xiàn)P層
P層提供兩個(gè)供V層調(diào)用的方法
- getPhotoList(int state)
- getSearchPhotoList(String query)
M層在P層的回調(diào)接口
presenter.listener.OnUnsplashPhotoListListener
public interface OnUnsplashPhotoListListener {
void onLoadPhotoListSuccess(List<UnsplashPhotosList> photosList);
void onLoadSearchPhotoListSuccess(UnsplashPhotoSearch photosList);
void onLoadDataError(String error);
}
P層接口
presenter.UnsplashPhotoListPresenter
public interface UnsplashPhotoListPresenter {
void getPhotoList(int state);
void getSearchPhotoList(String query);
}
P層實(shí)現(xiàn)類
presenter.imp1.UnsplashPhotoListPresenterImp1
public class UnsplashPhotoListPresenterImp1 extends BasePresenter<UnsplashPhotoListView> implements UnsplashPhotoListPresenter,OnUnsplashPhotoListListener{
private UnsplashPhotoListView mUnsplashPhotoListView;
private UnsplashPhotoListModelImp1 mUnsplashPhotoListModelImp1;
public UnsplashPhotoListPresenterImp1(UnsplashPhotoListView unsplashPhotoListView) {
mUnsplashPhotoListView = unsplashPhotoListView;
mUnsplashPhotoListModelImp1 = new UnsplashPhotoListModelImp1();
}
@Override
public void getPhotoList(int state) {
mUnsplashPhotoListView.onStartGetData();
mUnsplashPhotoListModelImp1.setState(state);
mUnsplashPhotoListModelImp1.loadPhotoList(this);
}
@Override
public void getSearchPhotoList(String query) {
mUnsplashPhotoListView.onStartGetData();
mUnsplashPhotoListModelImp1.loadSearchPhotoList(this,query);
}
@Override
public void onLoadPhotoListSuccess(List<UnsplashPhotosList> photosList) {
mUnsplashPhotoListView.onGetPhotoSuccess(photosList);
}
@Override
public void onLoadSearchPhotoListSuccess(UnsplashPhotoSearch photosList) {
mUnsplashPhotoListView.onGetSearchPhotoSuccess(photosList);
}
@Override
public void onLoadDataError(String error) {
mUnsplashPhotoListView.onGetDataFailed(error);
}
}
5. 圖片詳情界面
繁瑣的MVP各層代碼這里就不貼了,參照上面代碼實(shí)現(xiàn),這只寫下具體的一些方法。
-
下載圖片
下載圖片的功能寫在M層的實(shí)現(xiàn)類里。
具體實(shí)現(xiàn)是兩個(gè)方法:downloadPhoto(final OnUnsplashPhotoListener listener, String id, final String photoName)
傳的參數(shù)分別為回調(diào)接口,圖片下載url,保存文件名。DownloadImage(ResponseBody body,OnUnsplashPhotoListener listener,String photoName)
傳的參數(shù)分別為網(wǎng)絡(luò)請(qǐng)求返回?cái)?shù)據(jù),回調(diào)接口,保存文件名。方法內(nèi)部實(shí)現(xiàn)了將返回的字節(jié)流寫入文件的功能。
model.UnsplashPhotoModelImp1
public void downloadPhoto(final OnUnsplashPhotoListener listener, String id, final String photoName) {
if (mTupianApi != null) {
mTupianApi.getPhotoDownload(id)
.subscribeOn(Schedulers.io())
.map(new Function<ResponseBody, Boolean>() {
@Override
public Boolean apply(@NonNull ResponseBody responseBody) throws Exception {
return DownloadImage(responseBody,listener,photoName);
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Boolean>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
}
@Override
public void onNext(@NonNull Boolean aBoolean) {
if (aBoolean) {
listener.onDownloadSuccess();
}
}
@Override
public void onError(@NonNull Throwable e) {
listener.onLoadDataError(e.toString());
}
@Override
public void onComplete() {
}
});
}
}
private boolean DownloadImage(ResponseBody body,OnUnsplashPhotoListener listener,String photoName) {
try {
InputStream in;
in = null;
FileOutputStream out = null;
try {
in = body.byteStream();
//String dir = Environment.getExternalStorageDirectory() + "/KTReader/";
out = new FileOutputStream(MyApplication.getAppCacheDir()+ File.separator + photoName + ".jpg");
byte[] buf = new byte[1024];
while ((in.read(buf)) != -1) {
out.write(buf);
}
}
catch (IOException e) {
return false;
}
finally {
if (in != null) {
in.close();
}
if (out != null) {
out.close();
}
}
return true;
} catch (IOException e) {
listener.onLoadDataError(e.toString());
return false;
}
}
在model層的實(shí)現(xiàn)類里還有一個(gè)獲取圖片大小的方法:
使用了Rxjava2的異步調(diào)用。
public void getPhotoSize(final OnUnsplashPhotoListener listener, final String urlString, final int pos) {
Flowable.just(urlString)
.subscribeOn(Schedulers.io())
.map(new Function<String, Integer>() {
@Override
public Integer apply(@NonNull String s) throws Exception {
int size = -1;
try {
URL url = new URL(urlString);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
size = connection.getContentLength();
return size;
}catch (Exception e) {
e.printStackTrace();
}
return size;
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<Integer>() {
@Override
public void accept(@NonNull Integer s) throws Exception {
listener.onLoadSizeSuccess(s, pos);
}
});
}
這里最終返回的大小會(huì)在View層的彈出框中呈現(xiàn),使得用戶可以根據(jù)自身需求下載不同質(zhì)量的圖片。
下面就說說view層的彈出框的寫法:
我們想要的功能是彈出對(duì)話框,然后呈現(xiàn)不同質(zhì)量圖片的大小,這就需要在對(duì)話框create之后更新視圖,這里我們選擇setAdapter的做法(還有一種我知道的是setView,然后更新view里的Textview等子布局),首先我們寫個(gè)簡(jiǎn)單的adapter:
private String[] itemsSize = { "raw (大小正在計(jì)算中)","full (大小正在計(jì)算中)","regularl (大小正在計(jì)算中)","small (大小正在計(jì)算中)" };
private String[] items = { "raw","full","regular","small" };
ArrayAdapter<String> adapter;
final Context dialogContext = new ContextThemeWrapper(this,
android.R.style.Theme_Light);
final LayoutInflater dialogInflater = (LayoutInflater) dialogContext
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
adapter = new ArrayAdapter<String>(this,
R.layout.item_dialog_list, itemsSize) {
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = dialogInflater.inflate(
R.layout.item_dialog_list, parent, false);
}
final TextView text1 = (TextView) convertView
.findViewById(R.id.tv);
final String display = this.getItem(position);
text1.setText(display);
return convertView;
}
};
然后構(gòu)建AlertDialog時(shí)傳進(jìn)adapter:
AlertDialog.Builder listDialog = new AlertDialog.Builder(this)
.setTitle("選擇要下載的圖片質(zhì)量:")
.setAdapter(adapter, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
toast("已添加進(jìn)下載任務(wù),圖片質(zhì)量" + itemsSize[which] );
switch (which) {
case 0:
mPresenter.downLoadPhoto(mUnsplashPhoto.urls.raw,
mUnsplashPhoto.id + "(" + items[which] + ")");
break;
case 1:
mPresenter.downLoadPhoto(mUnsplashPhoto.urls.full,
mUnsplashPhoto.id + "(" + items[which] + ")");
break;
case 2:
mPresenter.downLoadPhoto(mUnsplashPhoto.urls.regular,
mUnsplashPhoto.id + "(" + items[which] + ")");
break;
case 3:
mPresenter.downLoadPhoto(mUnsplashPhoto.urls.small,
mUnsplashPhoto.id + "(" + items[which] + ")");
break;
default:
break;
}
}
})
.setPositiveButton("取消下載", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
});
listDialog.show();
以上AlertDialog的構(gòu)建我們封裝為方法showListDialog()以方便調(diào)用;
最后我們?cè)谙鄳?yīng)的下載布局添加點(diǎn)擊事件讓P層調(diào)用M層的獲取大小方法并返回,然后更新AlertDialog的數(shù)據(jù):
@OnClick({R.id.button_collect, R.id.button_detail, R.id.button_download})
public void onViewClicked(View view) {
switch (view.getId()) {
case R.id.button_download:
mPresenter.getPhotoSize(mUnsplashPhoto.urls.raw,0);
mPresenter.getPhotoSize(mUnsplashPhoto.urls.full,1);
mPresenter.getPhotoSize(mUnsplashPhoto.urls.regular,2);
mPresenter.getPhotoSize(mUnsplashPhoto.urls.small,3);
showListDialog();
break;
}
}
最后我們?cè)诔晒卣{(diào)的函數(shù)里改變adapter的數(shù)據(jù),然后更新adapter:
@Override
public void onGetSizeSuccess(int size,int pos) {
itemsSize[pos] = String.format(items[pos] + " (圖片大約" + size/1024 + "K)");;
adapter.notifyDataSetChanged();
}
至此,我們的下載選擇彈出框功能就完成了。
而圖片的詳細(xì)內(nèi)容顯示我們?yōu)榱朔奖阃瑯邮褂肁lertDialog完成,這次簡(jiǎn)單的使用他的setItems方法,然后傳進(jìn)對(duì)應(yīng)數(shù)據(jù)就可以簡(jiǎn)單顯示了。
private void showPhotoDetail() {
String[] detailItems = {
// "標(biāo)題: " + mUnsplashPhoto.location.title,
// "作者: " + mUnsplashPhoto.location.name,
"拍攝時(shí)間: " + mUnsplashPhoto.createdAt,
"拍攝設(shè)備: " + mUnsplashPhoto.exif.make,
"寬度: " + mUnsplashPhoto.width,
"高度: " + mUnsplashPhoto.height,
"保存路徑: " + MyApplication.getAppCacheDir()+ File.separator + mUnsplashPhoto.id + ".jpg"};
AlertDialog.Builder builder = new AlertDialog.Builder(this)
.setTitle("Photo 詳情")
.setItems(detailItems, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
})
.setPositiveButton("確定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
});
builder.show();
}
以上,便是KTReader的圖片模塊,功能略單一,代碼也只是小白水平,如有批評(píng)建議,歡迎指正。