Android圖片選擇器ImageEditContainer
1. 簡(jiǎn)介
本次demo中一共封裝了兩個(gè)組件:ImageEditButton 和 ImageEditContainer。其中ImageEditContainer 是在 ImageEditButton,兩個(gè)組件可單獨(dú)使用。
在demo中,實(shí)現(xiàn)了 圖片選擇(拍照+本地),裁剪,壓縮,保存本地 以及對(duì)已選擇圖片的刪除操作(如果有修改需求,也可以使用對(duì)應(yīng)方法進(jìn)行操作,該方法已添加);
還有就是 針對(duì) 6.0權(quán)限的處理問題,本次使用了第三方庫(kù) rxpermissions 進(jìn)行權(quán)限的處理。
2.項(xiàng)目主目錄結(jié)構(gòu)

3. 功能介紹
MainActivity.java 界面效果圖:


ImageEditContainer 組件初始化:
layImageContainer = (ImageEditContainer) findViewById(R.id.lay_image_container); layImageContainer.setEditListener(this); layImageContainer.setBtnImageResource(R.drawable.icon_picture_photograph); layImageContainer.setTotalImageQuantity(3);
如上代碼,設(shè)置組件的監(jiān)聽,添加按鈕展示圖,以及最多選擇圖片個(gè)數(shù)。
implements ImageEditContainer.ImageEditContainerListener 的實(shí)現(xiàn)
@Override
public void doAddImage() {
PopupWindow mCameraPop = SelectPicturePopupWindowUtils.showSelectPicturePopupWindow(this);
if (mCameraPop != null)
mCameraPop.showAtLocation(layImageContainer, Gravity.BOTTOM, 0, 0);
}
@Override
public void doEditLocalImage(ImageItem imageItem) {
if (imageItem != null) {
layImageContainer.updateEditedImageItem(imageItem);
}
}
@Override
public void doEditRemoteImage(RemoteImageItem remoteImageItem) {
if (remoteImageItem != null) {
if (remoteImageItem.isDeleted) {
layImageContainer.removeRemoteImageItem(remoteImageItem);
} else {
layImageContainer.updateRemoteImageItem(remoteImageItem);
}
}
}
當(dāng)圖片選擇數(shù)量達(dá)到最大個(gè)數(shù)時(shí),添加按鈕會(huì)消失。效果圖如下所示:

圖片裁剪 效果圖如下所示:
圖片可拖拽,縮放

圖片選擇好后,進(jìn)行圖片壓縮:
private void compressImage(String path) {
if (TextUtils.isEmpty(path)) {
return;
}
compressImage = compressImage + 1;
ImageItem imageItem = new ImageItem();
imageItem.storedPath = path;
File file = new File(FilePathUtils.getImageSavePath());
if (!file.exists()) {
file.mkdirs();
}
String filePath = FilePathUtils.getImageSavePath() + System.currentTimeMillis() + ".jpg";
new Thread(new MyThread(imageItem, path, filePath)).start();
List<String> imagePaths = new ArrayList<>();
imagePaths.add(path);
layImageContainer.addNewImageItem(imageItem);
}
圖片壓縮比較慢,要開啟個(gè) 線程進(jìn)行壓縮:
public class MyThread implements Runnable {
private String imgPath;
private String outPath;
private ImageItem imageItem;
public MyThread(ImageItem imageItem, String imgPath, String outPath) {
this.imageItem = imageItem;
this.imgPath = imgPath;
this.outPath = outPath;
}
public void run() {
try {
BitmapUtil.compressAndGenImage(imgPath, outPath, 500, false);
compressImage = compressImage - 1;
imageItem.storedPath = outPath;
} catch (IOException e) {
compressImage = compressImage - 1;
e.printStackTrace();
}
}
}
使用的壓縮方法:
/**
* Compress by quality, and generate image to the path specified
*
* @param imgPath
* @param outPath
* @param maxSize target will be compressed to be smaller than this size.(kb)
* @param needsDelete Whether delete original file after compress
* @throws IOException
*/
public static void compressAndGenImage(String imgPath, String outPath, int maxSize, boolean needsDelete) throws IOException {
compressAndGenImage(getBitmap(imgPath), outPath, maxSize);
// Delete original file
if (needsDelete) {
File file = new File(imgPath);
if (file.exists()) {
file.delete();
}
}
}
組件 ImageEditContainer 添加圖片方法介紹:
可添加本地和網(wǎng)絡(luò)圖片
/**
* 添加本地圖片
* List<String> storePaths 本地圖片路徑數(shù)組
*/
public void addNewImages(List<String> storePaths) {
}
/**
* 添加本地圖片
*/
public void addNewImageItem(ImageItem imageItem) {
}
/**
* 添加網(wǎng)絡(luò)圖片
*/
public void addRemoteImageItem(RemoteImageItem remoteImageItem) {
}
組件 ImageEditContainer 其他方法介紹:
/**
* 設(shè)置組件中 選擇按鈕的寬高
*/
public void setImvHeightAndWidth(int height, int width) {
}
/**
* 設(shè)置圖片最大數(shù)量
*/
public void setTotalImageQuantity(int totalImageQuantity) {
}
/**
* 設(shè)置圖片展示圖
*/
public void setBtnImageResource(int resid) {
}
/**
* 獲取組件中所有圖片對(duì)象(本地+網(wǎng)絡(luò))
*/
public List<Object> getAllImageItems() {
}
public void updateEditedImageItem(ImageItem imageItem) {
}
/**
* 更新網(wǎng)絡(luò)圖片
*/
public void updateRemoteImageItem(RemoteImageItem remoteImageItem) {
}
/**
* 刪除網(wǎng)絡(luò)圖片
*/
public void removeRemoteImageItem(RemoteImageItem remoteImageItem) {
}
4. 組件代碼
1.ImageEditButton.java
/**
* Created by dingzuoqiang on 2017/6/20.
* Email: 530858106@qq.com
*/
public class ImageEditButton extends RelativeLayout {
private final static String TAG = "ImageEditButton";
private ImageView imvAddImage;
private ImageView imvEdit;
private int imvHeight;
private int imvWidth;
public ImageEditButtonListener editButtonListener;
public ImageEditButton(Context context) {
this(context, null);
}
public ImageEditButton(Context context, AttributeSet attrs) {
super(context, attrs);
LayoutInflater.from(context).inflate(R.layout.image_edit_button_view, this, true);
imvHeight = CommonUtil.dip2px(getContext(), 70);
imvWidth = imvHeight;
imvAddImage = (ImageView) findViewById(R.id.imv_add_image);
imvEdit = (ImageView) findViewById(R.id.imv_edit);
setImvHeightAndWidth(imvHeight, imvWidth);
imvAddImage.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
doEditImage();
}
});
imvEdit.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
doEditImage2();
}
});
}
public void setImvHeightAndWidth(int height, int width) {
this.imvHeight = height;
this.imvWidth = width;
ViewGroup.LayoutParams layoutParams = imvAddImage.getLayoutParams();
layoutParams.width = imvHeight;
layoutParams.height = imvWidth;
imvAddImage.setLayoutParams(layoutParams);
}
public int getImvHeight() {
return imvHeight;
}
public int getImvWidth() {
return imvWidth;
}
public void setPadding2(int left, int top, int right, int bottom) {
this.setPadding(left, top, right, bottom);
}
public void setBtnImageResource(int resid) {
imvAddImage.setImageResource(resid);
// ImageLoaderUtils.loadImageFromDrawable(resid, imvAddImage, null);
}
public void reset() {
imvEdit.setVisibility(GONE);
}
public void setEditButtonListener(ImageEditButtonListener editButtonListener) {
this.editButtonListener = editButtonListener;
}
public BaseImageItem getImageItem() {
Object object = this.getTag();
if (object instanceof BaseImageItem) return (BaseImageItem) object;
return null;
}
public void displayUI() {
//
Object object = this.getTag();
if (object == null) return;
if (object instanceof ImageItem) {
ImageItem imageItem = (ImageItem) object;
if (TextUtils.isEmpty(imageItem.storedPath))
return;
File file = new File(imageItem.storedPath);
if (file.exists()) {
// 其實(shí)Glide加載本地圖片和加載網(wǎng)絡(luò)圖片調(diào)用的方法是一樣的,唯一的區(qū)別是說加載SD卡的圖片需要SD卡的權(quán)限,加載網(wǎng)絡(luò)需要網(wǎng)絡(luò)權(quán)限
Glide.with(getContext()).load(file).crossFade().into(imvAddImage);
}
} else if (object instanceof RemoteImageItem) {
// 如果是 remoteImageItem 則需要從讀取圖片,同時(shí)不可以裁剪
RemoteImageItem remoteImageItem = (RemoteImageItem) object;
Glide.with(getContext()).load(remoteImageItem.thumbUrl).centerCrop().crossFade().into(imvAddImage);
}
// TODO
BaseImageItem baseImageItem = (BaseImageItem) object;
displayNoteIcons(baseImageItem);
}
private void displayNoteIcons(BaseImageItem baseImageItem) {
imvEdit.setVisibility(VISIBLE);
}
private void doEditImage() {
if (editButtonListener == null) return;
Object object = this.getTag();
if (object == null) {
// add image
editButtonListener.doAddImage();
} else {
//
if (object instanceof ImageItem) {
editButtonListener.doEditLocalImage((ImageItem) object);
} else if (object instanceof RemoteImageItem) {
editButtonListener.doEditRemoteImage((RemoteImageItem) object);
}
}
}
private void doEditImage2() {
if (editButtonListener == null) return;
Object object = this.getTag();
if (object != null) {
//
if (object instanceof ImageItem) {
ImageItem imageItem = (ImageItem) object;
imageItem.isDeleted = true;
editButtonListener.doEditLocalImage(imageItem);
} else if (object instanceof RemoteImageItem) {
RemoteImageItem remoteImageItem = (RemoteImageItem) object;
remoteImageItem.isDeleted = true;
editButtonListener.doEditRemoteImage(remoteImageItem);
}
}
}
public interface ImageEditButtonListener {
public void doAddImage();
public void doEditLocalImage(ImageItem imageItem1);
public void doEditRemoteImage(RemoteImageItem remoteImageItem);
}
}
2.ImageEditContainer.java
/**
* Created by dingzuoqiang on 2017/6/20.
* Email: 530858106@qq.com
*/
public class ImageEditContainer extends HorizontalScrollView implements ImageEditButton.ImageEditButtonListener {
private final static String TAG = "ImageEditContainer";
public ImageEditContainerListener mEditListener;
private int idValue = 0;
ImageEditButton imbAddImage;
ViewGroup buttonsContainer;
private int totalImageQuantity = 3;// 總添加數(shù)量
private int mBtnBgResid = 0;
public ImageEditContainer(Context context) {
//super(context);
this(context, null);
}
public ImageEditContainer(Context context, AttributeSet attrs) {
super(context, attrs);
//
LayoutInflater.from(context).inflate(R.layout.image_edit_container, this, true);
imbAddImage = (ImageEditButton) findViewById(R.id.imb_add_image);
imbAddImage.setEditButtonListener(this);
//
buttonsContainer = (ViewGroup) findViewById(R.id.lay_container);
setHorizontalScrollBarEnabled(false);
setHorizontalFadingEdgeEnabled(false);
}
public void setImvHeightAndWidth(int height, int width) {
for (int i = 0; i < buttonsContainer.getChildCount(); i++) {
ImageEditButton imageEditButton = (ImageEditButton) buttonsContainer.getChildAt(i);
if (imageEditButton == null) continue;
imageEditButton.setImvHeightAndWidth(height, width);
}
}
public void setTotalImageQuantity(int totalImageQuantity) {
if (totalImageQuantity > 0)
this.totalImageQuantity = totalImageQuantity;
}
public void setBtnImageResource(int resid) {
mBtnBgResid = resid;
imbAddImage.setBtnImageResource(mBtnBgResid);
}
public List<Object> getAllImageItems() {
List<Object> allItems = new ArrayList<>();
for (int i = 0; i < buttonsContainer.getChildCount(); i++) {
ImageEditButton imageEditButton = (ImageEditButton) buttonsContainer.getChildAt(i);
if (imageEditButton == null) continue;
if (imageEditButton.getTag() == null) continue;
allItems.add(imageEditButton.getTag());
}
return allItems;
}
/**
* 添加本地圖片
*/
public void addNewImages(List<String> storePaths) {
for (int i = 0; i < storePaths.size(); i++) {
String path = storePaths.get(i);
ImageItem imageItem = new ImageItem();
imageItem.storedPath = path;
imageItem.id = idValue++;
Log.i(TAG, "index=" + i + " id=" + imageItem.id);
imageItem.index = (buttonsContainer.getChildCount() - 1);
addBaseImageItemToContainer(imageItem);
}
}
/**
* 添加本地圖片
*/
public void addNewImageItem(ImageItem imageItem) {
if (imageItem == null) return;
imageItem.id = idValue++;
imageItem.index = (buttonsContainer.getChildCount() - 1);
addBaseImageItemToContainer(imageItem);
}
public void updateEditedImageItem(ImageItem imageItem) {
ImageEditButton imageEditButton = getImageEditButtonForImageItemById(imageItem);
if (imageEditButton == null) {
return;
}
Object originObj = imageEditButton.getTag();
if (!(originObj instanceof ImageItem)) {
if (originObj instanceof RemoteImageItem) {
RemoteImageItem remoteItem = (RemoteImageItem) originObj;
if (remoteItem.index == imageItem.index) {
imageEditButton.setTag(imageItem);
imageEditButton.displayUI();
return;
}
reorderForImageItem(imageItem);
}
return;
}
ImageItem originImageItem = (ImageItem) originObj;
if (imageItem.isDeleted) {
removeButtonContainImageItem(imageItem);
resetImageItemIndex();
return;
} else {
if (originImageItem.index == imageItem.index) {
imageEditButton.setTag(imageItem);
imageEditButton.displayUI();
return;
}
reorderForImageItem(imageItem);
}
}
/**
* 添加網(wǎng)絡(luò)圖片
*/
public void addRemoteImageItem(RemoteImageItem remoteImageItem) {
addBaseImageItemToContainer(remoteImageItem);
}
/**
* 更新網(wǎng)絡(luò)圖片
*/
public void updateRemoteImageItem(RemoteImageItem remoteImageItem) {
ImageEditButton imageEditButton = getImageEditButtonForImageItemById(remoteImageItem);
if (imageEditButton == null) {
if (getAllImageItems().size() > 0) {
List<Object> objectList = getAllImageItems();
for (int i = 0; i < objectList.size(); i++) {
BaseImageItem baseImageItem = (BaseImageItem) objectList.get(i);
removeButtonContainImageItem(baseImageItem);
}
//
objectList.add(0, remoteImageItem);
for (int i = 0; i < objectList.size(); i++) {
addRemoteImageItem((RemoteImageItem) objectList.get(i));
}
//
} else {
addRemoteImageItem(remoteImageItem);
}
return;
}
BaseImageItem baseImageItem = (BaseImageItem) imageEditButton.getTag();
if (baseImageItem instanceof ImageItem) return;
RemoteImageItem originRemoteItem = (RemoteImageItem) baseImageItem;
if (remoteImageItem.index == originRemoteItem.index) {
// index 相同 只是update
imageEditButton.setTag(remoteImageItem);
imageEditButton.displayUI();
return;
}
reorderForImageItem(remoteImageItem);
}
/**
* 刪除網(wǎng)絡(luò)圖片
*/
public void removeRemoteImageItem(RemoteImageItem remoteImageItem) {
ImageEditButton imageEditButton = getImageEditButtonForImageItemById(remoteImageItem);
if (null != imageEditButton && null != imageEditButton.getTag()) {
BaseImageItem baseImageItem = (BaseImageItem) imageEditButton.getTag();
if (baseImageItem instanceof ImageItem) return;
RemoteImageItem originRemoteItem = (RemoteImageItem) baseImageItem;
removeButtonContainImageItem(remoteImageItem);
resetImageItemIndex();
}
}
private void reorderForImageItem(BaseImageItem imageItem) {
removeButtonContainImageItem(imageItem);
List<BaseImageItem> imageItems = new ArrayList<>();
imageItems.add(imageItem);
int count = buttonsContainer.getChildCount();
for (int i = imageItem.index; i < count; i++) {
ImageEditButton button = (ImageEditButton) buttonsContainer.getChildAt(i);
if (button == null) continue;
BaseImageItem imageItem1 = (BaseImageItem) button.getTag();
if (imageItem1 == null) continue;
imageItems.add(imageItem1);
}
for (int i = 0; i < imageItems.size(); i++) {
BaseImageItem item = imageItems.get(i);
removeButtonContainImageItem(item);
}
//
for (int i = 0; i < imageItems.size(); i++) {
addBaseImageItemToContainer(imageItems.get(i));
}
}
private void resetImageItemIndex() {
for (int i = 0; i < buttonsContainer.getChildCount(); i++) {
try {
ImageEditButton button = (ImageEditButton) buttonsContainer.getChildAt(i);
if (button == null) continue;
BaseImageItem imageItem = (BaseImageItem) button.getTag();
if (imageItem == null) continue;
imageItem.index = i;
} catch (Exception ignored) {
}
}
}
private ImageEditButton getImageEditButtonForImageItemById(BaseImageItem imageItem) {
for (int i = 0; i < buttonsContainer.getChildCount(); i++) {
ImageEditButton imageEditButton = (ImageEditButton) buttonsContainer.getChildAt(i);
if (imageEditButton == null) continue;
if (imageEditButton.getImageItem() == null) continue;
BaseImageItem searchedImageItem = imageEditButton.getImageItem();
if (imageItem.id.longValue() == searchedImageItem.id.longValue()) {
return imageEditButton;
}
}
return null;
}
/*
刪除一個(gè) ImageItem
*/
private void removeButtonContainImageItem(BaseImageItem imageItem) {
ImageEditButton imageEditButton = getImageEditButtonForImageItemById(imageItem);
if (imageEditButton == null) return;
buttonsContainer.removeView(imageEditButton);
resetImageItemIndex();
imbAddImage.setVisibility(buttonsContainer.getChildCount() <= totalImageQuantity ? VISIBLE : GONE);
}
private void addBaseImageItemToContainer(BaseImageItem imageItem) {
buttonsContainer.removeView(imbAddImage);
ImageEditButton imageEditButton = new ImageEditButton(getContext());
if (mBtnBgResid != 0)
imageEditButton.setBtnImageResource(mBtnBgResid);
imageEditButton.setTag(imageItem);
imageEditButton.setEditButtonListener(this);
// buttonsContainer.addView(imageEditButton, buttonsContainer.getChildCount(), new RelativeLayout.LayoutParams(nSize, imbAddImage.getHeight()));
buttonsContainer.addView(imageEditButton, buttonsContainer.getChildCount());
LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) imageEditButton.getLayoutParams();
layoutParams.rightMargin = CommonUtil.dip2px(getContext(), 5);
imageEditButton.setLayoutParams(layoutParams);
imageEditButton.setImvHeightAndWidth(imbAddImage.getImvHeight(), imbAddImage.getImvWidth());
imageEditButton.displayUI();
//
buttonsContainer.addView(imbAddImage, buttonsContainer.getChildCount());
//
imbAddImage.setVisibility(buttonsContainer.getChildCount() <= totalImageQuantity ? VISIBLE : GONE);
resetImageItemIndex();
}
/*
ImageEditButton listener
*/
public void doAddImage() {
if (mEditListener != null) {
mEditListener.doAddImage();
}
}
public void doEditLocalImage(ImageItem imageItem) {
if (mEditListener != null) {
mEditListener.doEditLocalImage(imageItem);
}
}
public void doEditRemoteImage(RemoteImageItem remoteImageItem) {
if (mEditListener != null) {
mEditListener.doEditRemoteImage(remoteImageItem);
}
}
// -----
public void setEditListener(ImageEditContainerListener editListener) {
this.mEditListener = editListener;
}
//
public interface ImageEditContainerListener {
public void doAddImage();
public void doEditLocalImage(ImageItem imageItem1);
public void doEditRemoteImage(RemoteImageItem remoteImageItem);
}
項(xiàng)目下載:ImageEditContainer
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
深入淺析Android手機(jī)衛(wèi)士保存密碼時(shí)進(jìn)行md5加密
一般的手機(jī)沒有root權(quán)限,進(jìn)不去data/data目錄,當(dāng)手機(jī)刷機(jī)了后,擁有root權(quán)限,就可以進(jìn)入data/data目錄,查看我們保存的密碼文件,因此我們需要對(duì)存入的密碼進(jìn)行MD5加密,接下來通過本文給大家介紹Android手機(jī)衛(wèi)士保存密碼時(shí)進(jìn)行md5加密,需要的朋友一起學(xué)習(xí)吧2016-04-04
Android Okhttp斷點(diǎn)續(xù)傳面試深入解析
這篇文章主要給大家介紹了關(guān)于Android Okhttp斷點(diǎn)續(xù)傳面試的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Android具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-06-06
Android編程實(shí)現(xiàn)只顯示圖片一部分的方法
這篇文章主要介紹了Android編程實(shí)現(xiàn)只顯示圖片一部分的方法,涉及Android針對(duì)圖片的局部顯示操作技巧,需要的朋友可以參考下2016-10-10
Android動(dòng)畫之補(bǔ)間動(dòng)畫(Tween Animation)基礎(chǔ)學(xué)習(xí)
補(bǔ)間動(dòng)畫是指定開始和結(jié)束的圖像狀態(tài),自動(dòng)生成需要顯示的過度圖像的動(dòng)畫。補(bǔ)間動(dòng)畫又分為四種:移動(dòng),縮放,旋轉(zhuǎn),通明度等。下面就來給大家一篇關(guān)于Android中補(bǔ)間動(dòng)畫的基礎(chǔ)知識(shí),有需要的可以參考學(xué)習(xí)。2016-09-09
Android WebView實(shí)現(xiàn)全屏播放視頻
WebView是Android系統(tǒng)中的原生控件,其主要功能與前端頁(yè)面進(jìn)行響應(yīng)交互,快捷省時(shí)地實(shí)現(xiàn)如期的功能,相當(dāng)于增強(qiáng)版的內(nèi)置瀏覽器。這篇文章主要介紹的是利用WebView實(shí)現(xiàn)全屏播放視頻的功能,感興趣的小伙伴可以了解一下2021-12-12
Android編程雙重單選對(duì)話框布局實(shí)現(xiàn)與事件監(jiān)聽方法示例
這篇文章主要介紹了Android編程雙重單選對(duì)話框布局實(shí)現(xiàn)與事件監(jiān)聽方法,涉及Android雙重單選對(duì)話框的界面布局與事件監(jiān)聽、響應(yīng)等相關(guān)操作技巧,需要的朋友可以參考下2017-10-10
Android自定義View實(shí)現(xiàn)抽獎(jiǎng)轉(zhuǎn)盤
這篇文章主要為大家詳細(xì)介紹了Android自定義View實(shí)現(xiàn)抽獎(jiǎng)轉(zhuǎn)盤,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-12-12
淺談Android IPC機(jī)制之Binder的工作機(jī)制
IPC機(jī)制即為跨進(jìn)程通信,是inter-Process Communication的縮寫。是指兩個(gè)進(jìn)程之間進(jìn)行通信。在說進(jìn)程通信之前,我們的弄明白什么是線程,什么是進(jìn)程。進(jìn)程和線程是兩個(gè)截然不同的概念。本文將介紹Android IPC機(jī)制之Binder的工作機(jī)制。2021-06-06
Android實(shí)現(xiàn)倒計(jì)時(shí)的方案梳理
這篇文章主要介紹了Android實(shí)現(xiàn)倒計(jì)時(shí)的方案梳理,下面文章圍繞主題展開Android倒計(jì)時(shí)方案,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-08-08

