Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android 圖片選擇器 圖片預覽

android 圖片選擇器 圖片預覽

編輯:關於Android編程

 

需求:近段時間公司有要求寫一個類似於微信發送圖片時,用來選擇照片的一個圖片浏覽器,本來想在網上找一個直接拿來用,找尋無果,只能自己寫了。相信有很多網頁也有這樣的需求,這裡我將寫好的源碼打包成library工程分享給大家!!

 

 

 

 

說明:

①本來打算自己寫圖片異步加載代碼,後來因為趕時間,就改成直接引用開源框架universal-image-loader,一個 android上知名度很高的圖片加載框架。

②預覽圖片的時候,使用到了一個開源框架,忘了叫什麼啦,只記得包名叫polites.android,這裡直接引入了源 碼,對不住作者了 - _ - 。

③為了兼容低版本,library以及測試項目的開發平台均為android2.3.3。

④點擊查看照片時,為了防止手機上照片太對,使用bundle在activity之間傳遞會導致崩潰,所以使用進入預覽 界面之後重新從本地讀取圖片信息。

⑤項目中使用了一個PhotoModel實體類,用來存放照片的路徑信息,以及照片被選中的狀態。

 

 

簡單入門:

大家只需要引入library工程,並在清單文件中注冊兩個activity以及加入讀取SD卡權限即可,使用例子以及源碼放在文章最後

 

 

功能介紹:

大致實現了圖片選擇、預覽、切換相冊、拍照。並將選中的照片信息返回。

 

 

預覽效果:

\

照片選擇

\

預覽

\

相冊選擇

 

關鍵實現:

〇:首先要說明的是如何使用我的源碼,引入library,並在你自己的清單文件中加入讀取SD卡權限,以及注冊兩個activity。

 





 

①首先,一進入照片選擇界面,需要將最近照片顯示出來,使用ContentResolver查詢最近照片,這裡我采用了異步加載的方式獲取數據,並調用主界面的回調函數對適配器adapter進行更新。

說明:過濾掉小於10kb的照片

 

/** 獲取最近照片列表 */
public List getCurrent() {
	Cursor cursor = resolver.query(Media.EXTERNAL_CONTENT_URI, new String[] { ImageColumns.DATA,
			ImageColumns.DATE_ADDED, ImageColumns.SIZE }, null, null, ImageColumns.DATE_ADDED);
	if (cursor == null || !cursor.moveToNext())
		return new ArrayList();
	List photos = new ArrayList();
	cursor.moveToLast();
	do {
		if (cursor.getLong(cursor.getColumnIndex(ImageColumns.SIZE)) > 1024 * 10) {
			PhotoModel photoModel = new PhotoModel();
			photoModel.setOriginalPath(cursor.getString(cursor.getColumnIndex(ImageColumns.DATA)));
			photos.add(photoModel);
		}
	} while (cursor.moveToPrevious());
	return photos;
}
public void getReccent(final OnLocalReccentListener listener) {
	final Handler handler = new Handler() {
		@SuppressWarnings(unchecked)
		@Override
		public void handleMessage(Message msg) {
			listener.onPhotoLoaded((List) msg.obj);
		}
	};
	new Thread(new Runnable() {
		@Override
		public void run() {
			List photos = albumController.getCurrent();
			Message msg = new Message();
			msg.obj = photos;
			handler.sendMessage(msg);
		}
	}).start();
}
private OnLocalReccentListener reccentListener = new OnLocalReccentListener() {
	@Override
	public void onPhotoLoaded(List photos) {
		if (tvAlbum.getText().equals(RECCENT_PHOTO))
			photos.add(0, new PhotoModel());
		photoAdapter.update(photos);
		gvPhotos.smoothScrollToPosition(0); // 滾動到頂端
		reset();
	}
};

 

②在圖片選擇界面,新建一個ArrayList集合變量selected用來存放當前選中的照片信息。

接著將獲取到的照片顯示在GridView上,這裡我對GridView的每一個Item進行了封裝,大致就是一個ImageView上面浮著一個CheckBox。在每一個CheckBox狀態改變時,調用回調函數往集合中插入當前選中照片的信息。

 

@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
	if (!isCheckAll) {
		listener.onCheckedChanged(photo, buttonView, isChecked); // 調用主界面回調函數
	}
	// 讓圖片變暗或者變亮
	if (isChecked) {
		setDrawingable();
		ivPhoto.setColorFilter(Color.GRAY, PorterDuff.Mode.MULTIPLY);
	} else {
		ivPhoto.clearColorFilter();
	}
	photo.setChecked(isChecked);
}

 

 

private ArrayList selected;

 

@Override
/** 照片選中狀態改變之後 */
public void onCheckedChanged(PhotoModel photoModel, CompoundButton buttonView, boolean isChecked) {
	if (isChecked) {
		selected.add(photoModel);
		tvPreview.setEnabled(true);
	} else {
		selected.remove(photoModel);
	}
	tvPreview.setText(預覽( + selected.size() + ));  //修改預覽數量

	if (selected.isEmpty()) {
		tvPreview.setEnabled(false);
		tvPreview.setText(預覽);
	}
}

③因為使用了圖片加載框架,需要在使用之前進行配置。使用該框架加載圖片的代碼很簡潔。

因為對GridView的每一個Item進行了封裝,同一時刻加載太多個會導致內存崩潰,這裡我采用在一定時間內隨機選擇一個時間進行加載,這也是為什麼有時候後面的Item會先加載完成(不排除小圖片先加載完成的可能)

 

DisplayImageOptions defaultDisplayImageOptions = new DisplayImageOptions.Builder() //
		.considerExifParams(true) // 調整圖片方向
		.resetViewBeforeLoading(true) // 載入之前重置ImageView
		.showImageOnLoading(R.drawable.ic_picture_loading) // 載入時圖片設置為黑色
		.showImageOnFail(R.drawable.ic_picture_loadfailed) // 加載失敗時顯示的圖片
		.delayBeforeLoading(0) // 載入之前的延遲時間
		.build(); //
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getApplicationContext())
		.defaultDisplayImageOptions(defaultDisplayImageOptions).memoryCacheExtraOptions(480, 800)
		.threadPoolSize(5).build();
ImageLoader.getInstance().init(config);

 

 

new Handler().postDelayed(new Runnable() {
	@Override
	public void run() {
		ImageLoader.getInstance().displayImage(file:// + photo.getOriginalPath(), ivPhoto);
	}
}, new Random().nextInt(10));


 

④點擊照片與選中對對張照片之後進行預覽都會開啟預覽界面,但是傳遞給預覽界面的數據是不一樣的,這裡需要進行處理。

說明:CommonUtils是我封裝的一個常用工具類。

 

/** 預覽照片 */
private void priview() {
	Bundle bundle = new Bundle();
	bundle.putSerializable(photos, selected);
	CommonUtils.launchActivity(this, PhotoPreviewActivity.class, bundle);
}

@Override
/** 點擊查看照片 */
public void onItemClick(int position) {
	Bundle bundle = new Bundle();
	if (tvAlbum.getText().toString().equals(RECCENT_PHOTO))
		bundle.putInt(position, position - 1);
	else
		bundle.putInt(position, position);
	bundle.putString(album, tvAlbum.getText().toString());
	CommonUtils.launchActivity(this, PhotoPreviewActivity.class, bundle);
}

@SuppressWarnings(unchecked)
protected void init(Bundle extras) {
	if (extras == null)
		return;

	if (extras.containsKey(photos)) { // 預覽圖片
		photos = (List) extras.getSerializable(photos);
		current = extras.getInt(position, 0);
		updatePercent();
		bindData();
	} else if (extras.containsKey(album)) { // 點擊圖片查看
		String albumName = extras.getString(album); // 相冊
		this.current = extras.getInt(position);
		if (!CommonUtils.isNull(albumName) && albumName.equals(PhotoSelectorActivity.RECCENT_PHOTO)) {
			photoSelectorDomain.getReccent(this);
		} else {
			photoSelectorDomain.getAlbum(albumName, this);
		}
	}
}

⑤相冊選擇界面我采用的是一個ListView進行顯示,並采用動畫的形式彈出和收回。相冊信息同樣是使用ContentResolver進行獲取,這裡同樣是采用異步回去數據,接著調用主界面回調函數對adapter適配器進行更新

 

說明:這裡的AnimationUtil是我封裝的一個用來顯示動畫的工具類,具體代碼可以看源代碼。

 

/** 彈出相冊列表 */
private void popAlbum() {
	layoutAlbum.setVisibility(View.VISIBLE);
	new AnimationUtil(getApplicationContext(), R.anim.translate_up_current).setLinearInterpolator().startAnimation(
			layoutAlbum);
}

/** 隱藏相冊列表 */
private void hideAlbum() {
	new AnimationUtil(getApplicationContext(), R.anim.translate_down).setLinearInterpolator().startAnimation(
			layoutAlbum);
	layoutAlbum.setVisibility(View.GONE);
}

private OnLocalAlbumListener albumListener = new OnLocalAlbumListener() {
	@Override
	public void onAlbumLoaded(List albums) {
		albumAdapter.update(albums);
	}
};
/** 獲取所有相冊列表 */
public List getAlbums() {
	List albums = new ArrayList();
	Map map = new HashMap();
	Cursor cursor = resolver.query(Media.EXTERNAL_CONTENT_URI, new String[] { ImageColumns.DATA,
			ImageColumns.BUCKET_DISPLAY_NAME, ImageColumns.SIZE }, null, null, null);
	if (cursor == null || !cursor.moveToNext())
		return new ArrayList();
	cursor.moveToLast();
	AlbumModel current = new AlbumModel(最近照片, 0, cursor.getString(cursor.getColumnIndex(ImageColumns.DATA)), true); // 最近照片相冊
	albums.add(current);
	do {
		if (cursor.getInt(cursor.getColumnIndex(ImageColumns.SIZE)) < 1024 * 10)
			continue;

		current.increaseCount();
		String name = cursor.getString(cursor.getColumnIndex(ImageColumns.BUCKET_DISPLAY_NAME));
		if (map.keySet().contains(name))
			map.get(name).increaseCount();
		else {
			AlbumModel album = new AlbumModel(name, 1, cursor.getString(cursor.getColumnIndex(ImageColumns.DATA)));
			map.put(name, album);
			albums.add(album);
		}
	} while (cursor.moveToPrevious());
	return albums;
}
/** 獲取對應相冊下的照片 */
public List getAlbum(String name) {
	Cursor cursor = resolver.query(Media.EXTERNAL_CONTENT_URI, new String[] { ImageColumns.BUCKET_DISPLAY_NAME,
			ImageColumns.DATA, ImageColumns.DATE_ADDED, ImageColumns.SIZE }, bucket_display_name = ?,
			new String[] { name }, ImageColumns.DATE_ADDED);
	if (cursor == null || !cursor.moveToNext())
		return new ArrayList();
	List photos = new ArrayList();
	cursor.moveToLast();
	do {
		if (cursor.getLong(cursor.getColumnIndex(ImageColumns.SIZE)) > 1024 * 10) {
			PhotoModel photoModel = new PhotoModel();
			photoModel.setOriginalPath(cursor.getString(cursor.getColumnIndex(ImageColumns.DATA)));
			photos.add(photoModel);
		}
	} while (cursor.moveToPrevious());
	return photos;
}

⑥最後,如果不想選擇圖庫裡的照片,可以使用拍照獲取照片並返回。這裡的拍照按鈕在適配器裡進行了處理。

 

 

@Override
public View getView(int position, View convertView, ViewGroup parent) {
	PhotoItem item = null;
	TextView tvCamera = null;
	if (position == 0 && CommonUtils.isNull(models.get(position).getOriginalPath())) { // 當時第一個時,顯示按鈕
		if (convertView == null || !(convertView instanceof TextView)) {
			tvCamera = (TextView) LayoutInflater.from(context).inflate(R.layout.view_camera, null);
			tvCamera.setHeight(itemWidth);
			tvCamera.setWidth(itemWidth);
			convertView = tvCamera;
		}
		convertView.setOnClickListener(cameraListener);
	} else { // 顯示圖片
		if (convertView == null || !(convertView instanceof PhotoItem)) {
			item = new PhotoItem(context, listener);
			item.setLayoutParams(itemLayoutParams);
			convertView = item;
		} else {
			item = (PhotoItem) convertView;
		}
		item.setImageDrawable(models.get(position));
		item.setSelected(models.get(position).isChecked());
		item.setOnClickListener(mCallback, position);
	}
	return convertView;
}

/** 拍照 */
private void catchPicture() {
	CommonUtils.launchActivityForResult(this, new Intent(MediaStore.ACTION_IMAGE_CAPTURE), REQUEST_CAMERA);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
	if (requestCode == REQUEST_CAMERA && resultCode == RESULT_OK) {
		PhotoModel photoModel = new PhotoModel(CommonUtils.query(getApplicationContext(), data.getData()));
		selected.clear();
		selected.add(photoModel);
		ok();
	}
}

⑦接著,就是將選中或者拍攝的照片路徑信息返回,這裡我采用setResult的方式放回,所以在使用時需要在需要在調用照片選擇器的Activity重寫onActivityResult函數。

 

 

/** 完成 */
private void ok() {
	if (selected.isEmpty()) {
		setResult(RESULT_CANCELED);
	} else {
		Intent data = new Intent();
		Bundle bundle = new Bundle();
		bundle.putSerializable(photos, selected);
		data.putExtras(bundle);
		setResult(RESULT_OK, data);
	}
	finish();
}

⑧最後,如何調用照片選擇器以及在調用照片選擇器的界面重寫onActivityResult函數接受照片信息。

 

說明:這裡的tvPath是我寫的Demo項目裡,一個用來顯示照片路徑的TextView。

 

@Override
public void onClick(View v) {
	//CommonUtils是library中的一個工具類
	CommonUtils.launchActivityForResult(this, PhotoSelectorActivity.class, 0);
	tvPath.setText();
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
	super.onActivityResult(requestCode, resultCode, data);
	if (requestCode == 0 && resultCode == RESULT_OK) {
		if (data != null && data.getExtras() != null) {
			@SuppressWarnings(unchecked)
			List photos = (List) data.getExtras().getSerializable(photos);
			if (photos == null || photos.isEmpty())
				return;
			StringBuffer sb = new StringBuffer();
			for (PhotoModel photo : photos) {
				sb.append(photo.getOriginalPath() + 
);
			}
			tvPath.setText(sb.toString());
		}
		
	}
}

附上源碼:library以及Demo

 

轉載請注明出處:http://blog.csdn.net/a740169405/article/details/41622025

 

 

 

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved