Android自定義相冊,查看手機圖片

最近因為公司需求需要做一個自定義的相冊,因為手機自帶的相冊沒有這種可以選取多張圖片的功能,先上gif圖,看效果(功能可以看出來,不知道為什么gif這么稀爛。。。)

GIF.gif

簡單功能都實現(xiàn)了,主要點是對圖片的查詢,然后設置了兩個popupWindow來顯示小相冊和點擊放大的效果,比較簡單。(代碼里面會有一些簡單的工具類,看名字可以看出來是干什么的)

查詢手機中的圖片路徑

步驟:
1.查詢圖片的path
2.由圖片path獲取其他信息(該圖片所在文件夾的路徑,文件夾的名字,文 件夾下的圖片個數(shù))
3.定義一個圖片Model,來保存及對圖片信息的傳遞,以便展示出來
4.通過文件夾的list()方法,可以獲取每一個小相冊下的圖片文件

上代碼。。。

//獲取圖片的路徑和父路徑 及 圖片size
   private void getImages() {
       if (!Environment.getExternalStorageState().equals(
               Environment.MEDIA_MOUNTED)) {
           ViewKit.shortToast("檢測到?jīng)]有內(nèi)存卡");
           return;
       }
       showLoading();
       new Thread(new Runnable() {
           @Override
           public void run() {
               Uri mImageUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
               ContentResolver mContentResolver = GalleryActivity.this.getContentResolver();

               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_TAKEN +" DESC");//獲取圖片的cursor,按照時間倒序(發(fā)現(xiàn)沒卵用)

               while (mCursor.moveToNext()) {
                   String path = mCursor.getString(mCursor.getColumnIndex(MediaStore.Images.Media.DATA));// 1.獲取圖片的路徑
                   File parentFile = new File(path).getParentFile();
                   if (parentFile == null)
                       continue;//不獲取sd卡根目錄下的圖片
                   String parentPath = parentFile.getAbsolutePath();//2.獲取圖片的文件夾信息
                   String parentName = parentFile.getName();
                   ImageFloder imageFloder ;//自定義一個model,來保存圖片的信息  

       //這個操作,可以提高查詢的效率,將查詢的每一個圖片的文件夾的路徑保存到集合中,  
       //如果存在,就直接查詢下一個,避免對每一個文件夾進行查詢操作  
                   if (mDirPaths.contains(parentPath)) {
                       continue;
                   } else {
                       mDirPaths.add(parentPath);//將父路徑添加到集合中
                       imageFloder = new ImageFloder();
                       imageFloder.setFirstImagePath(path);
                       imageFloder.setDir(parentPath);
                       imageFloder.setName(parentName);
                   }
                   List<String>  strings = null;
                   try {
                    strings =  Arrays.asList(parentFile.list(getFileterImage()));
                   } catch (Exception e) {
                       e.printStackTrace();
                   }
                   int  picSize = strings.size();//獲取每個文件夾下的圖片個數(shù)
                   imageFloder.setCount(picSize);//傳入每個相冊的圖片個數(shù)
                   mImageFloders.add(imageFloder);//添加每一個相冊
       //獲取圖片最多的文件夾信息(父目錄對象和個數(shù),使得剛開始顯示的是最多圖片的相冊
                   if (picSize > mPicsSize) {  
                       mPicsSize = picSize;
                       mImgDir = parentFile;
                   }
               }
               mCursor.close();
               mDirPaths = null;
               mHandler.sendEmptyMessage(1);
           }
       }).start();
   }

這是Model類,貼出來,方便觀看

public class ImageFloder {
    private int count;//文件夾下的圖片個數(shù)
    private String firstImagePath;//第一張圖片的路徑 傳這個給小相冊圖片顯示
    private String dir;//文件夾路徑
    private String name;//文件夾的名字

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }

    public String getFirstImagePath() {
        return firstImagePath;
    }

    public void setFirstImagePath(String firstImagePath) {
        this.firstImagePath = firstImagePath;
    }

    public String getDir() {
        return dir;
    }

    public void setDir(String dir) {
        this.dir = dir;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

還記得上面的handler操作嗎,查詢圖片是一個耗時的操作,為了更新ui,也為了方便觀看,就使用了handler的方式,這樣代碼也比較整潔,下面這個小代碼,就是接下來的步驟了

Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            setAdapterData();//設置圖片的顯示
            cancelLoading();//取消加載框
            initListDirPopupWindw();//初始化小相冊的popupWindow
            initChekcBox();//初始化checkbox集合,防止checkBox的錯亂
        }
    };

設置適配器(采用的RecycleVIew,自己做的封裝)

    //設置適配器數(shù)據(jù)
private void setAdapterData() {
    if (mImgDir == null) {
        ViewKit.shortToast("沒有查詢到圖片");
        return;
    }
    tv_pop_gallery.setText(mImgDir.getName());
    try {
        mImgs = Arrays.asList(mImgDir.list(getFileterImage()));//獲取文件夾下的圖片集合
    }catch (Exception e){
        e.printStackTrace();
    }
    //查詢出來的圖片是正序的,為了讓圖片按照時間倒序顯示,對其倒序操作
    Collections.sort(mImgs, new Comparator<String>() {
        @Override
        public int compare(String lhs, String rhs) {
            return -1;
        }
    });

    mAdapter = new GalleryAdapter(gallery_recycleView, mImgs, R.layout.item_gallery_camera);
    gallery_recycleView.setLayoutManager(new GridLayoutManager(this, 3));
    gallery_recycleView.addItemDecoration(new DividerGridItemDecoration(this));
    gallery_recycleView.setAdapter(mAdapter);
}

適配器:

//適配器
    private class GalleryAdapter extends BaseRecyclerAdapter<String> {
        List<String> datas;
        String picPath;
        ImageView iv_gallery;
        CheckBox cb_gallery;

        public GalleryAdapter(RecyclerView v, List<String> datas, int itemLayoutId) {
            super(v, datas, itemLayoutId);
            this.datas = datas;
        }

        @Override
        public void convert(final RecyclerHolder holder, String item, final int position) {
            iv_gallery = holder.getView(R.id.iv_gallery);
            cb_gallery = holder.getView(R.id.cb_gallery);
            iv_gallery.setLayoutParams(new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, DensityKit.getScreenW() / 3));
            picPath = mImgDir.getAbsolutePath() + "/" + datas.get(position);
            BitmapKit.loadLocalImage(iv_gallery, picPath);//這里采用的是Glide為ImageVIew加載圖片,很方便,這里對Glide進行了工具類的封裝

            //顯示大圖
            iv_gallery.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    initBigPicPopupWindw(mImgDir.getAbsolutePath() + "/" + datas.get(position));
                }
            });

            //checkBox
            cb_gallery.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    CheckBox checkBox = (CheckBox) v;
                    if (realCount >= 9 && !selectList.get(position)) {
                        ViewKit.shortToast("最多可以選擇9張圖片");
                        selectList.put(position, false);
                    } else{
                        selectList.put(position, !selectList.get(position));
                    }

                    for (Map.Entry<Integer, Boolean> entry : selectList.entrySet()) {
                        entry.getKey();
                        Boolean value = entry.getValue();
                        if (value) {
                            checkCount++;
                        }
                    }
                    tv_count_gallery.setText("(" + checkCount + ")");
                    tv_confirm_gallery.setVisibility(checkCount>0?View.VISIBLE:View.GONE);
                    realCount = checkCount;
                    checkCount = 0;
                    checkBox.setChecked(selectList.get(position));
                }
            });
            if(selectList!=null)
                cb_gallery.setChecked(selectList.get(position));
        }
    }
}

左側(cè)popupWindow小相冊的定義

//設置相冊PopupWindow
   private void initListDirPopupWindw() {
       mListImageDirPopupWindow = new ListImageDirPopupWindow(this, mImageFloders);
       mListImageDirPopupWindow.setOnDismissListener(new PopupWindow.OnDismissListener() {
           @Override
           public void onDismiss() {
               setToRightDrawable(R.drawable.arrow_bottom);
           }
       });
       mListImageDirPopupWindow.setOnImageDirSelected(new ListImageDirPopupWindow.OnImageDirSelected() {  
         //點擊item之后的回調(diào)
           @Override
           public void selected(ImageFloder floder) {
               mListImageDirPopupWindow.showAtDropDownCenter(tv_confirm_gallery);
               setToRightDrawable(R.drawable.arrow_bottom);
               realCount = 0;
               tv_pop_gallery.setText(floder.getName());
               tv_count_gallery.setText("(0)");
               tv_confirm_gallery.setVisibility(View.GONE);
               File file = new File(floder.getDir());
               List<String> picFileList = null;
               try {
                   picFileList =   Arrays.asList(file.list(getFileterImage()));
               } catch (Exception e) {
                   e.printStackTrace();
               }

               Collections.sort(picFileList, new Comparator<String>() {
                   @Override
                   public int compare(String lhs, String rhs) {
                       return -1;
                   }
               });
             //重新設置數(shù)據(jù)和checkBox初始化
               mImgDir = file;
               mImgs = picFileList;
               initChekcBox();
               mAdapter = new GalleryAdapter(gallery_recycleView, picFileList, R.layout.item_gallery_camera);
               gallery_recycleView.setAdapter(mAdapter);
           }
       });
   }

相冊PopupWIndow的代碼:

public class ListImageDirPopupWindow extends PopupWindow {
   RecyclerView recycl_camera_list;
   public ListImageDirPopupWindow(Context context, List<ImageFloder> mImageFloders) {
       View conentView = LayoutInflater.from(context).inflate(R.layout.view_dir_camera, null);
       recycl_camera_list = (RecyclerView) conentView.findViewById(R.id.recycl_camera_list);
       setContentView(conentView);

       ListAdapter listAdapter = new ListAdapter(recycl_camera_list, mImageFloders, R.layout.item_list_camera);
       recycl_camera_list.setLayoutManager(new LinearLayoutManager(context));//設置垂直
       recycl_camera_list.addItemDecoration(new DividerItemDecoration(context, DividerItemDecoration.VERTICAL));
       recycl_camera_list.setAdapter(listAdapter);
       listAdapter.setOnItemClickListener(new BaseRecyclerAdapter.OnItemClickListener() {
           @Override
           public void onItemClick(View view, Object data, int position) {
               if (data instanceof ImageFloder) {
                   ImageFloder imageFloder = (ImageFloder) data;
                   onImageDirSelected.selected(imageFloder);
               }
           }
       });
       setAnimationStyle(R.style.popup_camera);
       setFocusable(true);
       setTouchable(true);

       setOutsideTouchable(true);
       ColorDrawable background = new ColorDrawable(0xffffff);
       setBackgroundDrawable(background);
       setWidth((int) (DensityKit.getScreenW()/2));
       setHeight(DensityKit.getScreenH()/3);

   }


   class ListAdapter extends BaseRecyclerAdapter<ImageFloder> {

       public ListAdapter(RecyclerView v, List<ImageFloder> datas, int itemLayoutId) {
           super(v, datas, itemLayoutId);
       }

       @Override
       public void convert(RecyclerHolder holder, final ImageFloder imageFloder, int position) {
           ImageView iv_first_image = holder.getView(R.id.iv_first_image);
           TextView tv_count_list = holder.getView(R.id.tv_count_list);
           TextView tv_name_list = holder.getView(R.id.tv_name_list);

           BitmapKit.loadLocalImage(iv_first_image, imageFloder.getFirstImagePath());
           tv_count_list.setText("(" + imageFloder.getCount() + ")");
           tv_name_list.setText(imageFloder.getName());

       }
   }

   public void showAtDropDownCenter(View parent) {
       if (!isShowing()) {
           setAnimationStyle(R.style.popup_camera);
           int[] location = new int[2];
           parent.getLocationOnScreen(location);//獲取以屏幕為原點的位置
           showAtLocation(parent,Gravity.TOP|Gravity.LEFT,0,location[1]-getHeight());
//            showAtLocation(parent,Gravity.TOP,(location[0]-getWidth())/2, location[1]-getHeight());
//            showAtLocation(parent, Gravity.NO_GRAVITY, location[0], location[1]-getHeight()); 三種方式都可以 原理是一樣的
       } else {
           dismiss();
       }
   }
   //點擊之后的接口回調(diào)
   private OnImageDirSelected onImageDirSelected;
   public void setOnImageDirSelected(OnImageDirSelected onImageDirSelected) {
       this.onImageDirSelected = onImageDirSelected;
   }
   public interface OnImageDirSelected {
       void selected(ImageFloder floder);
   }
}

雜⑦雜⑧的代碼,懶的搞了,都貼出來(都有小注釋)

 //設置大圖片的PopupWindow
   private void initBigPicPopupWindw(String path) {
       BigImagePopup bigImagePopup = new BigImagePopup(this);
       bigImagePopup.setUrl(path);
       bigImagePopup.showAtDropDownCenter(tv_confirm_gallery);
   }


   //導航欄點擊事件
   @Override
   public void onClick(View v) {
       int i = v.getId();
       if (i == R.id.tv_pop_gallery) {
          setToRightDrawable(R.drawable.arrow_up);
           mListImageDirPopupWindow.showAtDropDownCenter(tv_confirm_gallery);
       } else if (i == R.id.tv_confirm_gallery) {

           ArrayList<String> pathList = new ArrayList<>();
           for (Map.Entry<Integer, Boolean> entry : selectList.entrySet()) {
               Boolean isChecked = entry.getValue();
               if (isChecked) {
                   Integer position = entry.getKey();
                   String checkPath = mImgDir.getAbsolutePath() + "/" + mImgs.get(position);
                   pathList.add(checkPath);
               }
           }
           backUrl(pathList);
       }
   }


   //intent
   public static Intent createIntent(Context context) {
       Intent intent = new Intent(context, GalleryActivity.class);
       intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
       return intent;
   }


   //返回的圖片路徑集合
   private void backUrl(ArrayList<String> pathList) {
       Intent intent = new Intent();
       intent.putStringArrayListExtra("imageUrl", pathList);
       setResult(RESULT_OK, intent);
       finish();
   }


   // 初始化 設置所有checkbox都為未選擇
   private void initChekcBox() {
       selectList = new HashMap<Integer, Boolean>();
       if (mImgs != null && mImgs.size() > 0) {
           for (int i = 0; i < mImgs.size(); i++) {
               selectList.put(i, false);
           }
       }
   }


   //動態(tài)改變text的toRightDrawable
   private void setToRightDrawable(int drawalbeId){
       Drawable drawable= getResources().getDrawable(drawalbeId);
       drawable.setBounds(0, 0, drawable.getMinimumWidth(), drawable.getMinimumHeight());
       tv_pop_gallery.setCompoundDrawables(null,null,drawable,null);
   }


   //設置popWindow的背景----不要設置  會透視。。。
   public void setBg_popup() {
       WindowManager.LayoutParams lp = getWindow().getAttributes();
       lp.alpha = 1.0f;
       getWindow().setAttributes(lp);
   }

   //圖片篩選器,過濾無效圖片
   private FilenameFilter getFileterImage(){
       FilenameFilter filenameFilter = new FilenameFilter() {
           @Override
           public boolean accept(File dir, String filename) {
               if (filename.endsWith(".jpg")
                       || filename.endsWith(".png")
                       || filename.endsWith(".jpeg"))
                   return true;
               return false;
           }
       };
       return filenameFilter;
   }

點擊放大的popupWIndow

public class BigImagePopup extends PopupWindow {
    ImageView iv_big_picture;

    public BigImagePopup(Activity context) {
        View conentView = LayoutInflater.from(context).inflate(R.layout.view_bigpic, null);
        setContentView(conentView);

        LinearLayout linearLayout = (LinearLayout) conentView.findViewById(R.id.ll_picture);
        iv_big_picture = (ImageView) conentView.findViewById(R.id.iv_big_picture);

        linearLayout.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                dismiss();
            }
        });
        iv_big_picture.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                dismiss();
            }
        });
        setAnimationStyle(R.style.big_popup_camera);
        setFocusable(true);
        setTouchable(true);
        setOutsideTouchable(true);
        ColorDrawable background = new ColorDrawable(0xffffff);
        setBackgroundDrawable(background);
        setWidth(LinearLayout.LayoutParams.MATCH_PARENT);
        setHeight(LinearLayout.LayoutParams.MATCH_PARENT);
    }

    public void setUrl(String url){
        BitmapKit.loadLocalImage(iv_big_picture, url);
    }

    public void showAtDropDownCenter(View parent) {
        if (!isShowing()) {
            setAnimationStyle(R.style.big_popup_camera);
            showAtLocation(parent, Gravity.BOTTOM, 0, 0);
        } else {
            dismiss();
        }
    }
}

寫個這樣的博客都這么累。。。。。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,321評論 6 543
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,559評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,442評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,835評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,581評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,922評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,931評論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,096評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,639評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 41,374評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,591評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,104評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,789評論 3 349
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,196評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,524評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,322評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,554評論 2 379

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,740評論 25 708
  • 發(fā)現(xiàn) 關注 消息 iOS 第三方庫、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關注 2017.06.26 09:4...
    肇東周閱讀 12,176評論 4 61
  • ¥開啟¥ 【iAPP實現(xiàn)進入界面執(zhí)行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開一個線程,因...
    小菜c閱讀 6,494評論 0 17
  • 離婚 少年 兄弟 媽媽
    鄺鑒萍閱讀 133評論 0 2
  • 人的這一生要經(jīng)歷很多的人很多的事,有時一個轉(zhuǎn)身無論是朋友還是某個機會錯過了就真的錯過了。 準備考研之際,沒有座位于...
    萬萬是我閱讀 237評論 0 1