Android 手寫手機(jī)圖片選擇器

效果圖

photo.png

需求: 獲取手機(jī)內(nèi)存中的所有圖片摔敛,以及拍照?qǐng)D片柄粹。

首頁(yè)布局RecyclerView投放,就不上布局代碼了。

  • 直接上整體首頁(yè)代碼
public class PhotoListActivity extends AppCompatActivity implements View.OnClickListener {

    private RecyclerView recycManager;
    private LoaderManager.LoaderCallbacks<Cursor> loaderCallbacks;//圖片加載器
    private Activity mActivity = null;
    private ArrayList<PhotoInfo> photoInfoList = new ArrayList<>();
    private PhotoAdapter photoAdapter;
    private File path;
    private TextView textNumber;
    private TextView textEnter;
    private ArrayList<String> resultList = new ArrayList<>();//返回首頁(yè)的集合

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_photo_list);
        initView();
        initListener();
        initPhoto();
        initRecycler();
    }

    private void initView() {
        mActivity = this;
        recycManager = (RecyclerView) findViewById(R.id.recycManager);
        textNumber = (TextView) findViewById(R.id.textNumber);
        textEnter = (TextView) findViewById(R.id.textEnter);
        textNumber.setText("(" + 0 + "/9" + ")");
    }

    private void initListener() {
        textEnter.setOnClickListener(this);
    }

    private File createCreamePath;

    private void initRecycler() {
        GridLayoutManager gridLayoutManager = new GridLayoutManager(mActivity, 3);
        recycManager.setLayoutManager(gridLayoutManager);
        photoAdapter = new PhotoAdapter(mActivity, photoInfoList);
        recycManager.setAdapter(photoAdapter);

        photoAdapter.getPhoto(new PhotoAdapter.getPhoto() {
            @Override
            public void getTakeCreame(View v) {
                Intent intentPhone = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                createCreamePath = createTmpFile(mActivity, "/Edreamoon/Pictures");
                intentPhone.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(createCreamePath));
                intentPhone.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
                startActivityForResult(intentPhone, 100);
            }
        });

        photoAdapter.getSelectPhoto(new PhotoAdapter.getSelectPhoto() {
            @Override
            public void getListPhoto(List<String> photoPath) {
                resultList.clear();
                int size = photoPath.size();
                textNumber.setText("(" + size + "/9" + ")");
                if (size > 0) {
                    textEnter.setVisibility(View.VISIBLE);
                } else {
                    textEnter.setVisibility(View.GONE);
                }

                //獲取選擇集合賦值給 返回MAIN集合
                for (String path : photoPath) {
                    if (resultList.contains(path)) {
                        resultList.remove(path);
                    } else {
                        resultList.add(path);
                    }
                }
            }
        });
    }

private void initPhoto() {
    loaderCallbacks = new LoaderManager.LoaderCallbacks<Cursor>() {
        private final String[] IMAGE_PROJECT = {
                MediaStore.Images.Media.DATA,
                MediaStore.Images.Media.DISPLAY_NAME,
                MediaStore.Images.Media.DATE_ADDED,
                MediaStore.Images.Media._ID,
                MediaStore.Images.Media.SIZE,
        };

        @Override
        public Loader<Cursor> onCreateLoader(int id, Bundle args) {
            if (id == 0) {
                return new CursorLoader(mActivity, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, IMAGE_PROJECT, null, null, IMAGE_PROJECT[2] + " DESC");

            } else if (id == 1) {
                return new CursorLoader(mActivity, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, IMAGE_PROJECT, IMAGE_PROJECT[0] + "like '%" + args.getString("path") + "%'", null, IMAGE_PROJECT[2] + " DESC");
            }
            return null;
        }

        @Override
        public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
            if (data != null) {
                photoInfoList.clear();
                int count = data.getCount();
                data.moveToFirst();
                if (count > 0) {
                    do {
                        String path = data.getString(data.getColumnIndexOrThrow(IMAGE_PROJECT[0]));
                        String name = data.getString(data.getColumnIndexOrThrow(IMAGE_PROJECT[1]));
                        long time = data.getLong(data.getColumnIndexOrThrow(IMAGE_PROJECT[2]));
                        int size = data.getInt(data.getColumnIndexOrThrow(IMAGE_PROJECT[4]));
                        PhotoInfo photoInfo = new PhotoInfo(path, name, time, false);
                        Boolean isSize5k = size > 1024 * 5;
                        if (isSize5k) {
                            photoInfoList.add(photoInfo);
                        }
                    } while (data.moveToNext());
                }
            }
        }

        @Override
        public void onLoaderReset(Loader<Cursor> loader) {

        }
    };
    getSupportLoaderManager().restartLoader(0, null, loaderCallbacks);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == 100 && resultCode == RESULT_OK) {
        resultList.clear();
        String absolutePath = createCreamePath.getAbsolutePath();
        resultList.add(absolutePath);
        Intent intent = new Intent(mActivity, MainActivity.class);
        intent.putExtra("resultPath", resultList);
        setResult(200, intent);
        finish();
    }
}
    /**
     * 創(chuàng)建文件
     *
     * @param context  context
     * @param filePath 文件路徑
     * @return file
     */
    public static File createTmpFile(Context context, String filePath) {

        String timeStamp = new SimpleDateFormat("yyyyMMddHHmmss", Locale.CHINA).format(new Date());

        String externalStorageState = Environment.getExternalStorageState();

        File dir = new File(Environment.getExternalStorageDirectory() + filePath);

        if (externalStorageState.equals(Environment.MEDIA_MOUNTED)) {
            if (!dir.exists()) {
                dir.mkdirs();
            }
            return new File(dir, timeStamp + ".jpg");
        } else {
            File cacheDir = context.getCacheDir();
            return new File(cacheDir, timeStamp + ".jpg");
        }

    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.textEnter:
                Intent intent = new Intent(mActivity, MainActivity.class);
                intent.putExtra("resultPath", resultList);
                setResult(200, intent);
                finish();
                break;
        }
    }
}
  • adapter代碼
public class PhotoAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    private Context mContext;
    private List<PhotoInfo> list;
    private LayoutInflater inflater;
    private getPhoto getPhoto;
    private List<String> selectPhoto = new ArrayList<>();
    private getSelectPhoto getSelectPhoto;

    public PhotoAdapter(Context mContext, List<PhotoInfo> list) {
        this.mContext = mContext;
        this.list = list;
        inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        selectPhoto.clear();
    }

    public void getPhoto(getPhoto getPhoto) {
        this.getPhoto = getPhoto;
    }

    public void getSelectPhoto(getSelectPhoto getSelectPhoto) {
        this.getSelectPhoto = getSelectPhoto;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if (viewType == 0) {//顯示的第一張圖片的布局 , 就是調(diào)用攝像頭拍照的布局哪痰。
            return new MyViewHolder(inflater.inflate(R.layout.item_photo_adapter_first, parent, false));
        }//之后的圖片顯示的布局泽论。
        return new MyViewHolder(inflater.inflate(R.layout.item_photo_adapter, parent, false));
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
        holder.setIsRecyclable(false);
        ViewGroup.LayoutParams params = holder.itemView.getLayoutParams();
        params.height = getScreenWidth(mContext) / 3;
        params.width = getScreenWidth(mContext) / 3;
        holder.itemView.setLayoutParams(params);//重設(shè)item大小

        if (getItemViewType(position) == 0) {
            holder.itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    //因?yàn)榕恼找祷貐?shù)夺蛇,所以接口回調(diào)方式將事件處理交給activity處理
                    getPhoto.getTakeCreame(v);
                }
            });
            return;
        }

        final MyViewHolder myViewHolder = (MyViewHolder) holder;
        final PhotoInfo photoInfo = list.get(position - 1);
        Glide.with(mContext).load(photoInfo.path).into(myViewHolder.image);

        myViewHolder.image.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (selectPhoto.size() < 9) {
                    //selectPhoto為選中的集合鸭廷。
                    if (selectPhoto.contains(photoInfo.path)) {
                        selectPhoto.remove(photoInfo.path);
                        photoInfo.setChecked(false);
                        myViewHolder.checkBox.setButtonDrawable(R.mipmap.uncheck);

                    } else {
                        selectPhoto.add(photoInfo.path);
                        photoInfo.setChecked(true);
                        myViewHolder.checkBox.setButtonDrawable(R.mipmap.checked);
                    }
                    myViewHolder.checkBox.setChecked(photoInfo.getChecked());
                    getSelectPhoto.getListPhoto(selectPhoto);
                } else {
                    if (selectPhoto.contains(photoInfo.path)) {
                        selectPhoto.remove(photoInfo.path);
                        photoInfo.setChecked(false);
                        myViewHolder.checkBox.setButtonDrawable(R.mipmap.uncheck);

                    } else {
                        Toast.makeText(mContext, "最多選擇9張", Toast.LENGTH_SHORT).show();
                    }
                }
            }
        });
        if (photoInfo.getChecked()) {
            myViewHolder.checkBox.setChecked(photoInfo.getChecked());
            myViewHolder.checkBox.setButtonDrawable(R.mipmap.checked);
        } else {
            myViewHolder.checkBox.setButtonDrawable(R.mipmap.uncheck);
        }
    }

    @Override
    public int getItemViewType(int position) {
        if (position == 0) {
            return 0;
        }
        return 1;
    }

    @Override
    public int getItemCount() {
        return list.size();
    }

    class MyViewHolder extends RecyclerView.ViewHolder {
        private ImageView image;
        private CheckBox checkBox;

        public MyViewHolder(View itemView) {
            super(itemView);
            image = (ImageView) itemView.findViewById(R.id.image);
            checkBox = (CheckBox) itemView.findViewById(R.id.checkbox);
        }
    }

    /**
     * 獲得屏幕高度
     *
     * @param context context
     * @return 屏幕高度
     */
    public int getScreenWidth(Context context) {
        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics outMetrics = new DisplayMetrics();
        wm.getDefaultDisplay().getMetrics(outMetrics);
        return outMetrics.widthPixels;
    }

    //獲取拍照后的照片
    public interface getPhoto {
        void getTakeCreame(View v);
    }

    public interface getSelectPhoto {
        void getListPhoto(List<String> photoPath);
    }
}

  • 模型類
public class PhotoInfo {

    public String name;                 // 圖片名
    public String path;                 // 圖片路徑
    public long time;                   // 圖片添加時(shí)間
    public Boolean checked;             //checkbox  選中狀態(tài)

    public PhotoInfo(String path, String name, long time ,Boolean checked) {
        this.path = path;
        this.name = name;
        this.time = time;
        this.checked =checked;
    }


    public Boolean getChecked() {
        return checked;
    }

    public void setChecked(Boolean checked) {
        this.checked = checked;
    }

    @Override
    public String toString() {
        return "PhotoInfo{" +
                "name='" + name + '\'' +
                ", path='" + path + '\'' +
                ", time=" + time +
                '}';
    }

    @Override
    public boolean equals(Object object) {
        try {
            PhotoInfo other = (PhotoInfo) object;
            return this.path.equalsIgnoreCase(other.path);
        } catch (ClassCastException e) {
            e.printStackTrace();
        }
        return super.equals(object);
    }


    public String getName() {
        return name;
    }

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

    public String getPath() {
        return path;
    }

    public void setPath(String path) {
        this.path = path;
    }

    public long getTime() {
        return time;
    }

    public void setTime(long time) {
        this.time = time;
    }
}
  • 具體思路
    1-寫一個(gè)模型類儲(chǔ)存自己想要的數(shù)據(jù): 路徑枣抱,文件名,時(shí)間
    2-涉及到recyclerView復(fù)用套checkbox的問題辆床,所以在模型類中加了Boolean類型顯示checkbox狀態(tài)
    3-通過LoaderManager.LoaderCallbacks<Cursor> 獲取內(nèi)存圖片
    4-書寫adapter :由于調(diào)用本地拍照需返回佳晶,所以adapter寫接口,講事件處理交給activity
    5-加部分細(xì)節(jié)讼载,比如只能只能9張 轿秧,等。
    6-activityResult回調(diào)處理咨堤,我將路徑全都存到了集合中菇篡,可直接拿來(lái)路徑上傳服務(wù)器等或別的操作

csdn
https://blog.csdn.net/binbinxiaoz

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市一喘,隨后出現(xiàn)的幾起案子驱还,更是在濱河造成了極大的恐慌,老刑警劉巖凸克,帶你破解...
    沈念sama閱讀 222,104評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件议蟆,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡萎战,警方通過查閱死者的電腦和手機(jī)咐容,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)蚂维,“玉大人戳粒,你說(shuō)我怎么就攤上這事〕嫔叮” “怎么了蔚约?”我有些...
    開封第一講書人閱讀 168,697評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)涂籽。 經(jīng)常有香客問我苹祟,道長(zhǎng),這世上最難降的妖魔是什么又活? 我笑而不...
    開封第一講書人閱讀 59,836評(píng)論 1 298
  • 正文 為了忘掉前任苔咪,我火速辦了婚禮,結(jié)果婚禮上柳骄,老公的妹妹穿的比我還像新娘团赏。我一直安慰自己,他們只是感情好耐薯,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評(píng)論 6 397
  • 文/花漫 我一把揭開白布舔清。 她就那樣靜靜地躺著丝里,像睡著了一般。 火紅的嫁衣襯著肌膚如雪体谒。 梳的紋絲不亂的頭發(fā)上杯聚,一...
    開封第一講書人閱讀 52,441評(píng)論 1 310
  • 那天,我揣著相機(jī)與錄音抒痒,去河邊找鬼幌绍。 笑死,一個(gè)胖子當(dāng)著我的面吹牛故响,可吹牛的內(nèi)容都是我干的傀广。 我是一名探鬼主播,決...
    沈念sama閱讀 40,992評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼彩届,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼伪冰!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起樟蠕,我...
    開封第一講書人閱讀 39,899評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤贮聂,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后寨辩,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體吓懈,經(jīng)...
    沈念sama閱讀 46,457評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評(píng)論 3 341
  • 正文 我和宋清朗相戀三年捣染,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了骄瓣。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片停巷。...
    茶點(diǎn)故事閱讀 40,664評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡耍攘,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出畔勤,到底是詐尸還是另有隱情蕾各,我是刑警寧澤,帶...
    沈念sama閱讀 36,346評(píng)論 5 350
  • 正文 年R本政府宣布庆揪,位于F島的核電站式曲,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏缸榛。R本人自食惡果不足惜吝羞,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評(píng)論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望内颗。 院中可真熱鬧钧排,春花似錦、人聲如沸均澳。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至糟袁,卻和暖如春判族,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背项戴。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工形帮, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人周叮。 一個(gè)月前我還...
    沈念sama閱讀 49,081評(píng)論 3 377
  • 正文 我出身青樓沃缘,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親则吟。 傳聞我的和親對(duì)象是個(gè)殘疾皇子槐臀,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評(píng)論 2 359

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