在做项目时经常会遇到选择本地图片的需求,以前都是懒得写直接调用系统方法来选择图片,但是这样并不能实现多选效果,最近又遇到了,所以还是写一个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实现本地图片选择及预览缩放效果所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)