看完这一篇你应该学会:如何展示照片墙,并且保存图片到本地。效果图:
上一篇讲的是:知乎日报板块的实现
这一篇的知识点有:Okhttp,Picasso,CardView,动态请求权限,创建文件,文件夹,保存图片。
先来布局:
material-design,用得CardView,使用CardView记得添加
com.android.support:cardview-v7:27.0.2 依赖
主代码:
public class MeiriFragment extends Fragment {
private final String TAG = "MeiriFragment";
private RecyclerView mRecyclerView;
private int cur = 1;
private MeiriAdapter mMeiriAdapter;
private boolean isFirstEnter = true; //标志是否第一次进入
boolean isGettingPre = false; //标识是否正在获取之前的图片
boolean isEnd = false; //标志是否图片到底
private List imgUrls;
// private ThumbnailDownloader mThumbnailDownloader;
public static Fragment newInstance() {
return new MeiriFragment();
}
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what == 0x123) {
Log.d("MeiriFragment", "Handler接受到消息");
String url = (String) msg.obj;
Log.d("message===>", url);
}
}
};
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mMeiriAdapter = new MeiriAdapter();
AsyncTask> task = new AsyncTask>() {
@Override
protected List doInBackground(Object... objects) {
return Connect.getMeiriImgUrls(getActivity(), String.valueOf(cur));
}
@Override
protected void onPostExecute(List imgs) {
super.onPostExecute(imgs);
imgUrls = imgs;
mRecyclerView.setAdapter(mMeiriAdapter);
}
};
task.execute();
/* Handler responseHandler = new Handler();
mThumbnailDownloader = new ThumbnailDownloader<>(responseHandler);
mThumbnailDownloader.setTThumbnailDownloadListener(new ThumbnailDownloader.ThumbnailDownloadListener() {
@Override
public void onThumbnailDownloaded(MeiriAdapter.MeiriHolder target, Bitmap thumbnail) {
// target.mImageView.setImageBitmap(thumbnail);
}
});
mThumbnailDownloader.start();
mThumbnailDownloader.getLooper();
Log.i(TAG,"background thread started");*/
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.wangyifragmennt, container, false);
mRecyclerView = v.findViewById(R.id.recyler_view);
final LinearLayoutManager manager = new LinearLayoutManager(getActivity());
mRecyclerView.setLayoutManager(manager);
BitmapFactory.Options options = new BitmapFactory.Options();
//mBitmap = CalculateInSampleSize.decodeSampleBitmapFromRes(getResources(),R.drawable.wangyiimg,600,600);
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
Log.i(TAG, "itemCount==> " + manager.getItemCount() + "\n current item position==> " + manager.findLastVisibleItemPosition());
// Log.i(TAG,"isEnd==> "+isEnd);
if (recyclerView.computeVerticalScrollExtent() + recyclerView.computeVerticalScrollOffset()
>= recyclerView.computeVerticalScrollRange() && isEnd) {
Toast.makeText(getActivity(), "没有更多的图片啦", Toast.LENGTH_SHORT).show();
}
if (isGettingPre) {
return;
}
if (manager.getItemCount() - manager.findLastVisibleItemPosition() < 3) {
final int preLength = imgUrls.size();
isGettingPre = true;
AsyncTask task = new AsyncTask() {
@Override
protected Object doInBackground(Object[] objects) {
return Connect.getPreMeiriUrls(String.valueOf(++cur));
}
@Override
protected void onPostExecute(Object o) {
super.onPostExecute(o);
imgUrls = (List) o;
if (preLength == imgUrls.size()) {
isEnd = true;
return;
}
mMeiriAdapter.notifyDataSetChanged();
isGettingPre = false;
}
};
task.execute();
}
}
});
return v;
}
private class MeiriAdapter extends RecyclerView.Adapter {
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(getActivity()).inflate(R.layout.meiri_layout, parent, false);
return new MeiriHolder(v);
}
@Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {
//((MeiriHolder)holder).mImageView.setImageBitmap(mBitmap);
// Message msg = mHandler.obtainMessage(0x123,imgUrls.get(position));
// mHandler.sendMessage(msg);
// mThumbnailDownloader.queueThumbnail((MeiriHolder) holder,imgUrls.get(position));
// Picasso.with(getActivity()).setIndicatorsEnabled(true); //用于显示图片从哪里加载【网络,内存,磁盘】
Picasso.with(getActivity()).load(Uri.parse(imgUrls.get(position))).fit().centerCrop().into(((MeiriHolder) holder).mImageView);
/*
* 为什么在这加了fit(),和centerCrop()
*
*/
((MeiriHolder) holder).mImageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Toast.makeText(getActivity(),"点击照片",Toast.LENGTH_SHORT).show();
View view = LayoutInflater.from(getActivity()).inflate(R.layout.bigimg, null);
ImageView imageView = view.findViewById(R.id.img_container);
Log.i(TAG, "拿到的URI是==》:" + imgUrls.get(position));
Picasso.with(getActivity()).load(Uri.parse(imgUrls.get(position))).into(imageView);
AlertDialog dialog = new AlertDialog.Builder(getActivity(), R.style.Dialog_Fullscreen).setView(view)
.setPositiveButton("保存", null)
.setNegativeButton("返回", null).create();
//这里如果加了.fit()和centerCrop()会不显示图片
imageView.setOnTouchListener(new OnDoubleClickListener(new OnDoubleClickListener.DoubleClickCallback() {
@Override
public void onDoubleClcik() {
saveImg(position);
}
}));
imageView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
Log.i(TAG, "url is ==> " + imgUrls.get(position));
saveImg(position);
return true;
}
});
dialog.show();
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//Toast.makeText(getActivity(),"保存",Toast.LENGTH_SHORT).show();
saveImg(position);
}
});
if (isFirstEnter) {
Toast.makeText(getActivity(), "长按图片可以保存哟", Toast.LENGTH_SHORT).show();
isFirstEnter = false;
}
}
});
}
@Override
public int getItemCount() {
return imgUrls.size();
}
public class MeiriHolder extends RecyclerView.ViewHolder {
public ImageView mImageView;
public MeiriHolder(View itemView) {
super(itemView);
mImageView = itemView.findViewById(R.id.iv_meiri);
}
}
}
@Override
public void onDestroy() {
super.onDestroy();
// mThumbnailDownloader.clearQueue();
}
public void saveImg(final int position) {
if (SaveImg.hasPermission(getActivity())) {
Picasso.with(getActivity()).load(imgUrls.get(position)).into(new Target() {
@Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
Log.i(TAG, "load from==>" + from);
boolean hasSaved = SaveImg.saveImg(bitmap, "每日看看-" + String.valueOf(position) + ".jpeg", getActivity());
if (hasSaved) {
Toast.makeText(getActivity(), "已保存至相册^.^", Toast.LENGTH_SHORT).show();
}
}
@Override
public void onBitmapFailed(Drawable errorDrawable) {
}
@Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
}
});
} else {
Log.i(TAG,"无权限");
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 0);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case 0: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(getActivity(), "已获取权限,可以保存图片", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(getActivity(), "您拒绝了写文件权限,无法保存图片", Toast.LENGTH_SHORT).show();
}
return;
}
}
}
}
说下逻辑吧:
创建fragment时,会返回包含CardView的布局,在onCreate里面先去用AsyncTask联网加载数据,这些数据以json格式返回,此时我用JsonObject解析,拿到json里面每张图片的url,接着讲url都放到一个list集合里面,返回,设置adapter,
adapter里面的bindView会去显示每一个子item,然后用Picasso框架去获取url对应的图片并显示在ImageView里面。
Picasso使用起来很方面,可以链式调用Picasson.with(Context).load(url).fit().centerCrop().into(imageview).
保存图片:
为item设置侦听,点击子项时弹出一个全屏的dialog,点击保存时会先检查是否能够读写sd卡权限,如果没有权限则动态申请
我另外博客有写:
保存bitmap到本地
动态请求权限
ok...