国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

Android實現本地圖片選擇及預覽縮放效果

2019-12-12 03:30:32
字體:
來源:轉載
供稿:網友

在做項目時經常會遇到選擇本地圖片的需求,以前都是懶得寫直接調用系統方法來選擇圖片,但是這樣并不能實現多選效果,最近又遇到了,所以還是寫一個demo好了,以后也方便使用。還是首先來看看效果:

顯示的圖片使用RecyclerView實現的,利用Glide來加載;下面彈出的圖片文件夾效果是采用PopupWindow實現,這里比采用PopupWindow更方便,彈出顯示的左邊圖片是這個文件夾里的第一張圖片;選中的圖片可以進行預覽,使用網上一個大神寫的來實現的;至于圖片的獲取是用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, 0, 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, null, null, null,    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, String path, CheckBox cb, 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, parent, 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, GlideAnimation<? super Bitmap> glideAnimation) {     Log.i(TAG, "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圖片選擇及預覽縮放

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 军事| 图木舒克市| 五寨县| 襄汾县| 抚远县| 珠海市| 兴义市| 台北县| 诸城市| 搜索| 巢湖市| 高青县| 阆中市| 徐闻县| 侯马市| 灵石县| 长寿区| 佳木斯市| 忻州市| 泰州市| 应城市| 兴和县| 嵩明县| 棋牌| 平潭县| 台湾省| 阿鲁科尔沁旗| 海南省| 楚雄市| 平罗县| 怀安县| 宿松县| 涞水县| 保德县| 香格里拉县| 阳城县| 齐齐哈尔市| 南丰县| 望江县| 西峡县| 林周县|