編輯:關於Android編程
說明:
①本來打算自己寫圖片異步加載代碼,後來因為趕時間,就改成直接引用開源框架universal-image-loader,一個 android上知名度很高的圖片加載框架。
②預覽圖片的時候,使用到了一個開源框架,忘了叫什麼啦,只記得包名叫polites.android,這裡直接引入了源 碼,對不住作者了 - _ - 。
③為了兼容低版本,library以及測試項目的開發平台均為android2.3.3。
④點擊查看照片時,為了防止手機上照片太對,使用bundle在activity之間傳遞會導致崩潰,所以使用進入預覽 界面之後重新從本地讀取圖片信息。
⑤項目中使用了一個PhotoModel實體類,用來存放照片的路徑信息,以及照片被選中的狀態。
簡單入門:
大家只需要引入library工程,並在清單文件中注冊兩個activity以及加入讀取SD卡權限即可,使用例子以及源碼放在文章最後
功能介紹:
大致實現了圖片選擇、預覽、切換相冊、拍照。並將選中的照片信息返回。
預覽效果:

照片選擇

預覽

相冊選擇
關鍵實現:
〇:首先要說明的是如何使用我的源碼,引入library,並在你自己的清單文件中加入讀取SD卡權限,以及注冊兩個activity。
①首先,一進入照片選擇界面,需要將最近照片顯示出來,使用ContentResolver查詢最近照片,這裡我采用了異步加載的方式獲取數據,並調用主界面的回調函數對適配器adapter進行更新。
說明:過濾掉小於10kb的照片
/** 獲取最近照片列表 */ public ListgetCurrent() { 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 ArrayListselected;
@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);
}
}
}
說明:這裡的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 ListgetAlbum(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();
}
}
/** 完成 */
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();
}
說明:這裡的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());
}
}
}
轉載請注明出處:http://blog.csdn.net/a740169405/article/details/41622025
android使用自定義字體
前言 Android有自己的默認字體,但是有時候我們並不想使用它的默認字體,我們想使用諸如楷體,隸書等字體,那麼該怎麼去做呢?本文就是說明該如何使用
Android事件總線(二)EventBus3.0源碼解析
前言上一篇我們講到了EventBus3.0的用法,這一篇我們來講一下EventBus3.0的源碼以及它的利與弊。1.構造函數當我們要調用EventBus的功能時,比如注冊
Android的Bitmap和BitmapDrawable類解析-android學習之旅(六十)
使用簡單圖片使用Drawable對象bitmap和BitmapDrawable對象package peng.liu.test;import android.app.Act
Android百度定位導航之基於百度地圖移動獲取位置和自動定位
一、問題描述使用百度地圖實現如圖所示應用,首先自動定位當前我起始位置(小圓點位置),並跟隨移動不斷自動定位我的當前位置百度Api不同版本使用會有些差異,本例中加入lib如