Android实现本地图片选择及预览缩放效果

Android实现本地图片选择及预览缩放效果,第1张

概述在做项目时经常会遇到选择本地图片的需求,以前都是懒得写直接调用系统方法来选择图片,但是这样并不能实现多选效果,最近又遇到了,所以还是写一个demo好了,以后也方便使用。还是首先来看看效果:

在做项目时经常会遇到选择本地图片的需求,以前都是懒得写直接调用系统方法来选择图片,但是这样并不能实现多选效果,最近又遇到了,所以还是写一个demo好了,以后也方便使用。还是首先来看看效果:

显示的图片使用RecyclerVIEw实现的,利用GlIDe来加载;下面d出的图片文件夹效果是采用PopupWindow实现,这里比采用PopupWindow更方便,d出显示的左边图片是这个文件夹里的第一张图片;选中的图片可以进行预览,使用网上一个大神写的来实现的;至于图片的获取是用ContentProvIDer。

看看主界面的布局文件,上面一栏是一个返回按钮和一个跳转预览界面的按钮,根据是否有选中的图片来设置它的点击和显示状态;中间就是一个用于显示图片的RecyclerVIEw,左下角是显示文件夹的名字可点击切换,右下角就是确定按钮。

<?xml version="1.0" enCoding="utf-8"?> <linearLayout xmlns:androID="http://schemas.androID.com/apk/res/androID"  xmlns:tools="http://schemas.androID.com/tools"  androID:layout_wIDth="match_parent"  androID:layout_height="match_parent"  androID:orIEntation="vertical"  tools:context="com.cdxsc.imageselect_y.ImageSelecteActivity">   <relativeLayout  androID:layout_wIDth="match_parent"  androID:layout_height="45dp"  androID:background="@androID:color/white">   <Imagebutton   androID:ID="@+ID/ib_back"   androID:layout_wIDth="wrap_content"   androID:layout_height="wrap_content"   androID:layout_centerVertical="true"   androID:layout_marginleft="10dp"   androID:background="@mipmap/action_bar_back_normal" />   <TextVIEw   androID:layout_wIDth="wrap_content"   androID:layout_height="wrap_content"   androID:layout_centerVertical="true"   androID:layout_marginleft="10dp"   androID:layout_toRightOf="@ID/ib_back"   androID:text="选择图片"   androID:textcolor="#000"   androID:textSize="16sp" />   <TextVIEw   androID:ID="@+ID/tv_prevIEw"   androID:layout_wIDth="wrap_content"   androID:layout_height="wrap_content"   androID:layout_alignParentRight="true"   androID:layout_centerVertical="true"   androID:layout_marginRight="10dp"   androID:enabled="false"   androID:text="预览"   androID:textcolor="#BEBFBF"   androID:textSize="16sp" />  </relativeLayout>   <VIEw  androID:layout_wIDth="match_parent"  androID:layout_height="0.5dp"  androID:background="#eeeeee" />   <androID.support.v7.Widget.RecyclerVIEw  androID:ID="@+ID/rv"  androID:layout_wIDth="match_parent"  androID:layout_height="0dp"  androID:layout_weight="1"></androID.support.v7.Widget.RecyclerVIEw>   <relativeLayout  androID:layout_wIDth="match_parent"  androID:layout_height="50dp">   <TextVIEw   androID:ID="@+ID/tv_allPic"   androID:layout_wIDth="wrap_content"   androID:layout_height="match_parent"   androID:layout_centerVertical="true"   androID:layout_marginleft="10dp"   androID:clickable="true"   androID:gravity="center_vertical"   androID:text="所有图片"   androID:textcolor="@androID:color/black"   androID:textSize="16sp" />   <button   androID:ID="@+ID/bt_confirm"   androID:layout_wIDth="wrap_content"   androID:layout_height="35dp"   androID:layout_alignParentRight="true"   androID:layout_centerVertical="true"   androID:layout_marginRight="10dp"   androID:background="@drawable/shape_disable"   androID:enabled="false"   androID:text="确定"   androID:textcolor="#676767"   androID:textSize="16sp" />  </relativeLayout> </linearLayout> 

好了,现在看主界面的代码

public class ImageSelecteActivity extends AppCompatActivity {   private static final String TAG = "lzy";  @BindVIEw(R.ID.ib_back)  Imagebutton mbuttonBack;  @BindVIEw(R.ID.tv_prevIEw)  TextVIEw mTextVIEwPrevIEw;  @BindVIEw(R.ID.rv)  RecyclerVIEw mRecyclerVIEw;  @BindVIEw(R.ID.tv_allPic)  TextVIEw mTextVIEwAllPic;  @BindVIEw(R.ID.bt_confirm)  button mbuttonConfirm;  private galleryPopupWindow mPopupWindow;  //存储每个目录下的图片路径,key是文件名  private Map<String,List<String>> mGroupMap = new HashMap<>();  private List<ImageBean> List = new ArrayList<>();  //当前文件夹显示的图片路径  private List<String> ListPath = new ArrayList<>();  //所选择的图片路径集合  private ArrayList<String> ListSelectedpath = new ArrayList<>();    private Handler mHandler = new Handler() {  @OverrIDe  public voID handleMessage(Message msg) {   //扫描完成后   getgalleryList();   ListPath.clear();   ListPath.addAll(mGroupMap.get("所有图片"));   adapter.update(ListPath);   if (mPopupWindow != null)   mPopupWindow.notifyDataChanged();  }  };  private ImageSelectAdapter adapter;   @OverrIDe  protected voID onCreate(Bundle savedInstanceState) {  super.onCreate(savedInstanceState);  setContentVIEw(R.layout.activity_image_selecte);  ButterKnife.bind(this);  init();  }   private voID init() {  getimages();  mRecyclerVIEw.setLayoutManager(new GrIDLayoutManager(ImageSelecteActivity.this,3));  adapter = new ImageSelectAdapter(this,ListPath);  mRecyclerVIEw.setAdapter(adapter);  adapter.setonCheckedChangedListener(onCheckedChangedListener);  }   @OnClick({R.ID.ib_back,R.ID.tv_prevIEw,R.ID.tv_allPic,R.ID.bt_confirm})  public voID onClick(VIEw vIEw) {  switch (vIEw.getID()) {   case R.ID.ib_back:   finish();   break;   case R.ID.tv_prevIEw://跳转预览界面   Intent intent = new Intent(ImageSelecteActivity.this,ImagePrevIEwActivity.class);   //把选中的图片集合传入预览界面   intent.putStringArrayListExtra("pic",ListSelectedpath);   startActivity(intent);   break;   case R.ID.tv_allPic://选择图片文件夹   if (mPopupWindow == null) {    //把文件夹列表的集合传入显示    mPopupWindow = new galleryPopupWindow(this,List);    mPopupWindow.setonItemClickListener(new galleryPopupWindow.OnItemClickListener() {    @OverrIDe    public voID onItemClick(String filename) {     //切换了文件夹,清除之前的选择的信息     setbuttondisable();     ListPath.clear();     ListSelectedpath.clear();     //把当前选择的文件夹内图片的路径放入ListPath,更新界面     ListPath.addAll(mGroupMap.get(filename));     adapter.update(ListPath);     mTextVIEwAllPic.setText(filename);    }    });   }   mPopupWindow.showAtLocation(mRecyclerVIEw,Gravity.BottOM,dp2px(50,ImageSelecteActivity.this));   break;   case R.ID.bt_confirm://确定   for (int i = 0; i < ListSelectedpath.size(); i++) {    //这里可通过GlIDe把它转为Bitmap    GlIDe.with(this).load("file://" + ListSelectedpath.get(i)).asBitmap().into(new SimpleTarget<Bitmap>() {    @OverrIDe    public voID onResourceReady(Bitmap resource,GlIDeAnimation<? super Bitmap> glIDeAnimation) {     Log.i(TAG,"onResourceReady: " + resource);    }    });   }   break;  }  }   /**  * dp转px  */  public static int dp2px(int dp,Context context) {  return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,dp,context.getResources().getdisplayMetrics());  }   //选择图片变化的监听  private ImageSelectAdapter.OnCheckedChangedListener onCheckedChangedListener = new ImageSelectAdapter.OnCheckedChangedListener() {  @OverrIDe  public voID onChanged(boolean isChecked,String path,CheckBox cb,int position) {   if (isChecked) {//选中   if (ListSelectedpath.size() == 9) {    Toast.makeText(ImageSelecteActivity.this,"最多选择9张图片",Toast.LENGTH_SHORT).show();    //把点击变为checked的图片变为没有checked    cb.setChecked(false);    adapter.setCheckedBoxFalse(position);    return;   }   //选中的图片路径加入集合   ListSelectedpath.add(path);    } else {//取消选中   //从集合中移除   if (ListSelectedpath.contains(path))    ListSelectedpath.remove(path);   }   //如果没有选中的按钮不可点击   if (ListSelectedpath.size() == 0) {   setbuttondisable();   } else {   setbuttonEnable();   }  }  };   //选中图片时的按钮状态  private voID setbuttonEnable() {  mbuttonConfirm.setBackgroundResource(R.drawable.selector_bt);  mbuttonConfirm.setTextcolor(color.parsecolor("#ffffff"));  mbuttonConfirm.setEnabled(true);  mTextVIEwPrevIEw.setEnabled(true);  mTextVIEwPrevIEw.setTextcolor(getResources().getcolor(R.color.colorAccent));  mbuttonConfirm.setText("确定" + ListSelectedpath.size() + "/9");  }   //没有选择时按钮状态  private voID setbuttondisable() {  mbuttonConfirm.setBackgroundResource(R.drawable.shape_disable);  mbuttonConfirm.setTextcolor(color.parsecolor("#676767"));  mbuttonConfirm.setEnabled(false);  mTextVIEwPrevIEw.setEnabled(false);  mTextVIEwPrevIEw.setTextcolor(color.parsecolor("#BEBFBF"));  mbuttonConfirm.setText("确定");  }   /**  * 利用ContentProvIDer扫描手机中的图片,此方法在运行在子线程中  */  private voID getimages() {  new Thread(new Runnable() {    @OverrIDe   public voID run() {   Uri mImageUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;   ContentResolver mContentResolver = ImageSelecteActivity.this.getContentResolver();   //只查询jpeg和png的图片 //  Cursor mCursor = mContentResolver.query(mImageUri,null,//   MediaStore.Images.Media.MIME_TYPE + "=? or " //    + MediaStore.Images.Media.MIME_TYPE + "=? or " + MediaStore.Images.Media.MIME_TYPE + "=?",//   new String[]{"image/jpeg","image/png","image/jpg"},MediaStore.Images.Media.DATE_MODIFIED);   Cursor mCursor = mContentResolver.query(mImageUri,MediaStore.Images.Media.DATE_MODIFIED);   if (mCursor == null) {    return;   }   //存放所有图片的路径   List<String> ListAllPic = new ArrayList<String>();   while (mCursor.movetoNext()) {    //获取图片的路径    String path = mCursor.getString(mCursor     .getColumnIndex(MediaStore.Images.Media.DATA));     //获取该图片的父路径名    String parentname = new file(path).getParentfile().getname();    ListAllPic.add(path);     //根据父路径名将图片放入到mGruopMap中    if (!mGroupMap.containsKey(parentname)) {    List<String> chileList = new ArrayList<String>();    chileList.add(path);    mGroupMap.put(parentname,chileList);    } else {    mGroupMap.get(parentname).add(path);    }   }   //添加所有图片   mGroupMap.put("所有图片",ListAllPic);   //通知Handler扫描图片完成   mHandler.sendEmptyMessage(0);   mCursor.close();   }  }).start();   }   //获取相册文件夹列表  private voID getgalleryList() {  Iterator<Map.Entry<String,List<String>>> iterator = mGroupMap.entrySet().iterator();  while (iterator.hasNext()) {   Map.Entry<String,List<String>> next = iterator.next();   ImageBean imageBean = new ImageBean();   imageBean.setfilename(next.getKey());   imageBean.setFirstPicPath(next.getValue().get(0));   imageBean.setCount(next.getValue().size());   if (next.getKey().equals("所有图片"))   List.add(0,imageBean);   else   List.add(imageBean);  }  } } 

・mGroupMap:这个是以文件夹名为key,文件夹内的图片路径集合为value,也就是按照文件夹来分别存储了所有图片的路径。
・ListPath:保存的是当前显示在界面上的文件夹内的图片路径集合
・ListSelectedpath:保存用户选中的图片路径
・List:保存的是ImageBean的集合,ImageBean保存了文件夹名、里面首张图片的路径以及里面所包含图片的数量,当切换文件夹时用于显示
・getimages():这个方法就是用来扫描手机里图片并保存的,这是在子线程中执行的,显示这可能是一个耗时的任务。通过ContentProvIDer获取到一个包含所有图片的Cursor,然后遍历这个Cursor把所需的数据就保存在mGroupMap里面,最后利用Handler通知界面更新。
・getgalleryList():这个方法就是mGroupMap里面的数据来给List赋值,也就是产生一个现实文件夹列表所需的数据集合。
・galleryPopupWindow也就是我们用于显示文件列表的,在67--84行就是一些galleryPopupWindow的设置,调用showAtLocation方法把PopupWindow显示在距离底部50dp的位置,并设置了点击的回调,当切换了一个文件夹后要做的相关 *** 作就在这里进行。galleryPopupWindow再待会再具体看看

接下来再看看中间RecyclerVIEw的Adapter

public class ImageSelectAdapter extends RecyclerVIEw.Adapter<ImageSelectAdapter.NVIEwHolder> {   private Context context;  private List<String> List = new ArrayList<>();  private OnCheckedChangedListener onCheckedChangedListener;  private List<Boolean> ListChecked = new ArrayList<>();   public ImageSelectAdapter(Context context,List<String> List) {  this.context = context;  this.List.addAll(List);  setListCheched(List);  }   public voID update(List<String> List) {  this.List.clear();  this.List.addAll(List);  setListCheched(List);  notifyDataSetChanged();   }   /**  * 设置ListChecked的初始值  *  * @param List  */  private voID setListCheched(List<String> List) {  ListChecked.clear();  for (int i = 0; i < List.size(); i++) {   ListChecked.add(false);  }  }   //当点击超过了九张图片,再点击的设置为false  public voID setCheckedBoxFalse(int pos) {  ListChecked.set(pos,false);  }   public interface OnCheckedChangedListener {  /**   * @param isChecked 是否选中   * @param path 点击的图片路径   * @param cb 点击的CheckBox   * @param pos 点击的位置   */  voID onChanged(boolean isChecked,int pos);  }   public voID setonCheckedChangedListener(OnCheckedChangedListener onCheckedChangedListener) {  this.onCheckedChangedListener = onCheckedChangedListener;  }   @OverrIDe  public NVIEwHolder onCreateVIEwHolder(VIEwGroup parent,int vIEwType) {  return new NVIEwHolder(LayoutInflater.from(context).inflate(R.layout.item_image_select,parent,false));  }   @OverrIDe  public voID onBindVIEwHolder(final NVIEwHolder holder,final int position) {  GlIDe.with(context).load("file://" + List.get(position)).into(holder.iv);  holder.cb.setChecked(ListChecked.get(position));  holder.itemVIEw.setonClickListener(new VIEw.OnClickListener() {   @OverrIDe   public voID onClick(VIEw v) {   holder.cb.setChecked(!holder.cb.isChecked());   if (holder.cb.isChecked()) {    ListChecked.set(position,true);   } else {    ListChecked.set(position,false);   }   if (onCheckedChangedListener != null) {    onCheckedChangedListener.onChanged(holder.cb.isChecked(),List.get(position),holder.cb,position);   }   }  });  }   @OverrIDe  public int getItemCount() {  return List.size();  }   public class NVIEwHolder extends RecyclerVIEw.VIEwHolder {  @BindVIEw(R.ID.iv_itemImageSelect)  ImageVIEw iv;  @BindVIEw(R.ID.cb_itemImageSelect)  CheckBox cb;   public NVIEwHolder(VIEw itemVIEw) {   super(itemVIEw);   ButterKnife.bind(this,itemVIEw);  }  }  } 

这里Item的布局文件就是一个ImageVIEw加一个CheckBox,根据选中状态改变CheckBox的状态,这里就不贴出来了。
・ListChecked:这个集合是用来存储每个位置是否Check的,如果在onBindVIEwHolder里面不设置CheckBox的状态的话,由于复用问题会出问题,所以想出了用一个集合来保存它们状态的方法,不知道大家有没有其他更好的方法。
・OnCheckedChangedListener:向外暴露的接口,把点击的位置等参数都传到Activity中去。
・update():这个方法用来更新界面的,没有采用直接调notifyDataSetChanged方法是因为,如果数据的数量变化了那么ListChecked的数量也要发生变化才行这样才能对应,所以写了这个方法。

再接着看看galleryPopupWindow

/**  * Created by lzy on 2017/2/8.  */ public class galleryPopupWindow extends PopupWindow {  private static final String TAG = "lzy";   RecyclerVIEw mRecyclerVIEw;   private Activity activity;  private galleryPopupWindow.OnItemClickListener onItemClickListener;  private List<ImageBean> List;  private galleryAdapter adapter;    public galleryPopupWindow(Activity context,List<ImageBean> List) {  super(context);  this.activity = context;  this.List = List;  LayoutInflater inflater = (LayoutInflater) context   .getSystemService(Context.LAYOUT_INFLATER_SERVICE);  VIEw contentVIEw = inflater.inflate(R.layout.popu_gallery,null);  initVIEw(contentVIEw);   int h = context.getwindowManager().getDefaultdisplay().getHeight();  int w = context.getwindowManager().getDefaultdisplay().getWIDth();  this.setContentVIEw(contentVIEw);  this.setWIDth(w);  this.setHeight(ImageSelecteActivity.dp2px(350,context));  this.setFocusable(false);  this.setoutsIDetouchable(true);  this.update();   setBackgroundDrawable(new colorDrawable(000000000));  }   public voID notifyDataChanged() {  adapter.notifyDataSetChanged();  }   private voID initVIEw(VIEw contentVIEw) {  mRecyclerVIEw = (RecyclerVIEw) contentVIEw.findVIEwByID(R.ID.rv_gallery);  mRecyclerVIEw.setLayoutManager(new linearlayoutmanager(activity));  adapter = new galleryAdapter(List,activity);  adapter.setonItemClickListener(new galleryAdapter.OnItemClickListener() {   @OverrIDe   public voID onItemClick(String filename) {   if (onItemClickListener != null) {    onItemClickListener.onItemClick(filename);    dismiss();   }   }  });  mRecyclerVIEw.setAdapter(adapter);   }   //暴露点击的接口  public interface OnItemClickListener {  /**   * @param keyvalue   */  voID onItemClick(String keyvalue);  }   public voID setonItemClickListener(OnItemClickListener onItemClickListener) {  this.onItemClickListener = onItemClickListener;  } } 

这个PopupWindow的布局文件就是一个RecyclerVIEw,所以这里面也没什么,也就是设置RecyclerVIEw,然后向外暴露一个点击的接口,用于Activity接收是点击了哪个文件夹,所以接口参数也就是文件夹名,再看看这个PopupWindow的Adapter

/**  * Created by lzy on 2017/2/8.  */ public class galleryAdapter extends RecyclerVIEw.Adapter<galleryAdapter.NVIEwHolder> {   private Context context;  private List<ImageBean> List;  private OnItemClickListener onItemClickListener;  //用于记录是选中的哪一个文件夹  private int selectedPos;   public galleryAdapter(List<ImageBean> List,Context context) {  this.List = List;  this.context = context;  }   public interface OnItemClickListener {  voID onItemClick(String filename);  }   public voID setonItemClickListener(OnItemClickListener onItemClickListener) {  this.onItemClickListener = onItemClickListener;  }   @OverrIDe  public NVIEwHolder onCreateVIEwHolder(VIEwGroup parent,int vIEwType) {  return new NVIEwHolder(LayoutInflater.from(context).inflate(R.layout.item_gallery,false));  }   @OverrIDe  public voID onBindVIEwHolder(NVIEwHolder holder,final int position) {  holder.itemVIEw.setonClickListener(new VIEw.OnClickListener() {   @OverrIDe   public voID onClick(VIEw v) {   selectedPos = position;   notifyDataSetChanged();   if (onItemClickListener != null) {    onItemClickListener.onItemClick(List.get(position).getfilename());   }   }  });  if (position == selectedPos) {   holder.ivCheck.setVisibility(VIEw.VISIBLE);  } else {   holder.ivCheck.setVisibility(VIEw.GONE);  }  holder.tvCount.setText(List.get(position).getCount() + "张");  holder.tvname.setText(List.get(position).getfilename());  GlIDe.with(context).load("file://" + List.get(position).getFirstPicPath()).into(holder.iv);  }   @OverrIDe  public int getItemCount() {  return List.size();  }   public class NVIEwHolder extends RecyclerVIEw.VIEwHolder {  @BindVIEw(R.ID.iv_itemgallery)  ImageVIEw iv;  @BindVIEw(R.ID.tv_itemgallery_name)  TextVIEw tvname;  @BindVIEw(R.ID.tv_itemgallery_count)  TextVIEw tvCount;  @BindVIEw(R.ID.iv_itemgallery_check)  ImageVIEw ivCheck;   public NVIEwHolder(VIEw itemVIEw) {   super(itemVIEw);   ButterKnife.bind(this,itemVIEw);  }  }  } 

这里有个接口是把点击的文件名传递给PopupWindow,然后再给Activity,selectedPos是用来记录选择的是哪一个文件夹,显示对应的CheckBox。

这里就差不多完成了,感兴趣的可以下载Demo来看看。再说一下,这里显示图片都是采用的GlIDe,使用也很方便,我们获取的图片路径都是文件路径,如果要转化为Bitmap也可以直接调用GlIDe的方法就可以轻松实现,如下所示:

GlIDe.with(this).load("file://" + ListSelectedpath.get(i)).asBitmap().into(new SimpleTarget<Bitmap>() {    @OverrIDe    public voID onResourceReady(Bitmap resource,"onResourceReady: " + resource);    }    }); 

其中找寻控件都没有使用findVIEwByID,而是采用的ButterKnife,节约了大量的时间,顺便说说导入的方法
在app下面的build.gradle中加入以下:
apply plugin: 'com.neenbedankt.androID-apt' 

apt 'com.jakewharton:butterknife-compiler:8.1.0' 
    compile 'com.github.bumptech.glIDe:glIDe:3.5.2' 

项目下面的build.gradle

//添加apt插件  classpath 'com.neenbedankt.gradle.plugins:androID-apt:1.8' 

添加插件
file->Setting->Plugins  搜索zelezny,如下所示

当需要使用的时候,直接在光标移动到布局文件,点击Alt+Insert,选择Generate ButterKnife Injections

就出现如下界面,可以自动生成了


源码地址:Android图片选择及预览缩放

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程小技巧。

总结

以上是内存溢出为你收集整理的Android实现本地图片选择及预览缩放效果全部内容,希望文章能够帮你解决Android实现本地图片选择及预览缩放效果所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1146829.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-31
下一篇 2022-05-31

发表评论

登录后才能评论

评论列表(0条)

保存