Android 응용 프로그램 에서 ContentProvider 를 사용 하여 로 컬 그림 을 스 캔 하고 표시 합 니 다.
다음은 이 효 과 를 실현 합 시다.우선 이미지 스 캔 이라는 항목 을 새로 만 듭 니 다.
먼저 첫 번 째 화면 을 봅 시다.핸드폰 에 있 는 그림 을 스 캔 한 다음 에 그림 이 있 는 폴 더 에 따라 분류 하고 있 는 폴 더 에 있 는 그림 과 폴 더 에 있 는 그림 개 수 를 표시 합 니 다.우 리 는 인터페이스 요소(폴 더 이름,폴 더 그림 개수,폴 더 의 그림 한 장)이 세 가지 속성 을 실체 대상 ImageBean 으로 패키지 합 니 다.
package com.example.imagescan;
/**
* GridView item
*
* @author len
*
*/
public class ImageBean{
/**
*
*/
private String topImagePath;
/**
*
*/
private String folderName;
/**
*
*/
private int imageCounts;
public String getTopImagePath() {
return topImagePath;
}
public void setTopImagePath(String topImagePath) {
this.topImagePath = topImagePath;
}
public String getFolderName() {
return folderName;
}
public void setFolderName(String folderName) {
this.folderName = folderName;
}
public int getImageCounts() {
return imageCounts;
}
public void setImageCounts(int imageCounts) {
this.imageCounts = imageCounts;
}
}
다음은 메 인 인터페이스의 레이아웃 입 니 다.위의 네 비게 이 션 바 는 제 가 넣 지 않 았 고 아래 의 GridView 만 있 습 니 다.그래서 메 인 화면 레이아웃 에는 GridView 만 있 습 니 다.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<GridView
android:id="@+id/main_grid"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:listSelector="@android:color/transparent"
android:cacheColorHint="@android:color/transparent"
android:stretchMode="columnWidth"
android:horizontalSpacing="20dip"
android:gravity="center"
android:verticalSpacing="20dip"
android:columnWidth="90dip"
android:numColumns="2" >
</GridView>
</RelativeLayout>
다음은 GridView 의 Item 레이아웃 입 니 다.위의 그림 을 보 셔 도 됩 니 다.그의 효 과 는 두 장의 그림 이 추 가 된 효과 라 고 생각 하 실 것 입 니 다.사실은 아 닙 니 다.뒤의 중첩 효 과 는 배경 그림 일 뿐 입 니 다.코드 를 먼저 붙 입 니 다.
<?xml version="1.0" encoding="UTF-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<FrameLayout
android:id="@+id/framelayout"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<com.example.imagescan.MyImageView
android:id="@+id/group_image"
android:background="@drawable/albums_bg"
android:src="@drawable/friends_sends_pictures_no"
android:paddingLeft="20dip"
android:paddingRight="20dip"
android:paddingTop="18dip"
android:paddingBottom="30dip"
android:scaleType="fitXY"
android:layout_width="fill_parent"
android:layout_height="150dip" />
<TextView
android:id="@+id/group_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/albums_icon_bg"
android:gravity="center"
android:layout_marginBottom="10dip"
android:text="5"
android:layout_gravity="bottom|center_horizontal" />
</FrameLayout>
<TextView
android:id="@+id/group_title"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_below="@id/framelayout"
android:layout_centerHorizontal="true"
android:ellipsize="end"
android:singleLine="true"
android:text="Camera"
android:textSize="16sp" />
</RelativeLayout>
위의 레이아웃 코드 를 보 셔 도 됩 니 다.위 에 사용자 정의 MyImageView 를 사용 하고 있 습 니 다.저 는 이 사용자 정의 MyImageView 의 역할 을 말 하지 않 고 잠시 후에 말씀 드 리 겠 습 니 다.코드 를 계속 보 겠 습 니 다.첫 번 째 인터페이스의 주요 코드
package com.example.imagescan;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.ContentResolver;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.provider.MediaStore;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.GridView;
public class MainActivity extends Activity {
private HashMap<String, List<String>> mGruopMap = new HashMap<String, List<String>>();
private List<ImageBean> list = new ArrayList<ImageBean>();
private final static int SCAN_OK = 1;
private ProgressDialog mProgressDialog;
private GroupAdapter adapter;
private GridView mGroupGridView;
private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case SCAN_OK:
//
mProgressDialog.dismiss();
adapter = new GroupAdapter(MainActivity.this, list = subGroupOfImage(mGruopMap), mGroupGridView);
mGroupGridView.setAdapter(adapter);
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mGroupGridView = (GridView) findViewById(R.id.main_grid);
getImages();
mGroupGridView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
List<String> childList = mGruopMap.get(list.get(position).getFolderName());
Intent mIntent = new Intent(MainActivity.this, ShowImageActivity.class);
mIntent.putStringArrayListExtra("data", (ArrayList<String>)childList);
startActivity(mIntent);
}
});
}
/**
* ContentProvider ,
*/
private void getImages() {
//
mProgressDialog = ProgressDialog.show(this, null, " ...");
new Thread(new Runnable() {
@Override
public void run() {
Uri mImageUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
ContentResolver mContentResolver = MainActivity.this.getContentResolver();
// jpeg png
Cursor mCursor = mContentResolver.query(mImageUri, null,
MediaStore.Images.Media.MIME_TYPE + "=? or "
+ MediaStore.Images.Media.MIME_TYPE + "=?",
new String[] { "image/jpeg", "image/png" }, MediaStore.Images.Media.DATE_MODIFIED);
if(mCursor == null){
return;
}
while (mCursor.moveToNext()) {
//
String path = mCursor.getString(mCursor
.getColumnIndex(MediaStore.Images.Media.DATA));
//
String parentName = new File(path).getParentFile().getName();
// mGruopMap
if (!mGruopMap.containsKey(parentName)) {
List<String> chileList = new ArrayList<String>();
chileList.add(path);
mGruopMap.put(parentName, chileList);
} else {
mGruopMap.get(parentName).add(path);
}
}
// Handler
mHandler.sendEmptyMessage(SCAN_OK);
mCursor.close();
}
}).start();
}
/**
* GridView , HashMap
* HashMap List
*
* @param mGruopMap
* @return
*/
private List<ImageBean> subGroupOfImage(HashMap<String, List<String>> mGruopMap){
if(mGruopMap.size() == 0){
return null;
}
List<ImageBean> list = new ArrayList<ImageBean>();
Iterator<Map.Entry<String, List<String>>> it = mGruopMap.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, List<String>> entry = it.next();
ImageBean mImageBean = new ImageBean();
String key = entry.getKey();
List<String> value = entry.getValue();
mImageBean.setFolderName(key);
mImageBean.setImageCounts(value.size());
mImageBean.setTopImagePath(value.get(0));//
list.add(mImageBean);
}
return list;
}
}
먼저 getImages()를 보면 이 방법 은 ContentProvider 를 사용 하여 핸드폰 에 있 는 그림 을 스 캔 하 는 것 입 니 다.저 는 핸드폰 의 외부 저장 소 에 있 는 그림 만 스 캔 했 습 니 다.핸드폰 에 많은 그림 이 존재 할 수 있 고 그림 을 스 캔 하 는 데 시간 이 걸 릴 수 있 기 때문에 우 리 는 여기 서 부분 스 레 드 를 열 어 그림 을 얻 었 습 니 다.스 캔 한 그림 은 모두 Cursor 에 저장 되 었 습 니 다.우 리 는 먼저 그림 을 폴 더 에 따라 분류 해 야 합 니 다.HashMap 을 사용 하여 분류 하고 결 과 를 mGruopMap(Key 는 폴 더 이름,Value 는 폴 더 의 그림 경로 List)에 저장 합 니 다.분류 가 끝나 면 Cursor 를 닫 고 Handler 를 이용 하여 메 인 스 레 드 를 알 립 니 다.그 다음 에 subGroupOFImage()방법 입 니 다.변경 방법 은 mGruopMap 의 데 이 터 를 List 에 조립 하고 List 에 GridView 의 모든 item 의 데이터 대상 인 ImageBean 을 저장 하 며 HashMap 대상 을 옮 겨 다 니 며 구체 적 인 논리 적 으로 코드 를 본 다음 에 GridView 에 Adapter 를 설정 하 는 것 입 니 다.
item 클릭 이 벤트 를 설정 하고 폴 더 를 클릭 하여 폴 더 그림 을 보 여 주 는 Activity 로 이동 합 니 다.폴 더 마다 그림 을 전달 하 는 경로 의 집합 이 필요 합 니 다.
GroupAdapter 의 코드 를 보기 전에 중요 한 종 류 를 보 겠 습 니 다.로 컬 이미지 로 더 Native ImageLoader
package com.example.imagescan;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Point;
import android.os.Handler;
import android.os.Message;
import android.support.v4.util.LruCache;
/**
* , , getInstance() NativeImageLoader
* loadNativeImage() ,
*/
public class NativeImageLoader {
private LruCache<String, Bitmap> mMemoryCache;
private static NativeImageLoader mInstance = new NativeImageLoader();
private ExecutorService mImageThreadPool = Executors.newFixedThreadPool(1);
private NativeImageLoader(){
//
final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
// 1/4
final int cacheSize = maxMemory / 4;
mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
//
@Override
protected int sizeOf(String key, Bitmap bitmap) {
return bitmap.getRowBytes() * bitmap.getHeight() / 1024;
}
};
}
/**
* NativeImageLoader
* @return
*/
public static NativeImageLoader getInstance(){
return mInstance;
}
/**
* ,
* @param path
* @param mCallBack
* @return
*/
public Bitmap loadNativeImage(final String path, final NativeImageCallBack mCallBack){
return this.loadNativeImage(path, null, mCallBack);
}
/**
* , mPoint ImageView , ImageView Bitmap
* , loadNativeImage(final String path, final NativeImageCallBack mCallBack)
* @param path
* @param mPoint
* @param mCallBack
* @return
*/
public Bitmap loadNativeImage(final String path, final Point mPoint, final NativeImageCallBack mCallBack){
// Bitmap
Bitmap bitmap = getBitmapFromMemCache(path);
final Handler mHander = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
mCallBack.onImageLoader((Bitmap)msg.obj, path);
}
};
// Bitmap , , Bitmap mMemoryCache
if(bitmap == null){
mImageThreadPool.execute(new Runnable() {
@Override
public void run() {
//
Bitmap mBitmap = decodeThumbBitmapForFile(path, mPoint == null ? 0: mPoint.x, mPoint == null ? 0: mPoint.y);
Message msg = mHander.obtainMessage();
msg.obj = mBitmap;
mHander.sendMessage(msg);
//
addBitmapToMemoryCache(path, mBitmap);
}
});
}
return bitmap;
}
/**
* Bitmap
*
* @param key
* @param bitmap
*/
private void addBitmapToMemoryCache(String key, Bitmap bitmap) {
if (getBitmapFromMemCache(key) == null && bitmap != null) {
mMemoryCache.put(key, bitmap);
}
}
/**
* key
* @param key
* @return
*/
private Bitmap getBitmapFromMemCache(String key) {
return mMemoryCache.get(key);
}
/**
* View( ImageView)
* @param path
* @param viewWidth
* @param viewHeight
* @return
*/
private Bitmap decodeThumbBitmapForFile(String path, int viewWidth, int viewHeight){
BitmapFactory.Options options = new BitmapFactory.Options();
// true, Bitmap ,
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, options);
//
options.inSampleSize = computeScale(options, viewWidth, viewHeight);
// false, Bitmap
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFile(path, options);
}
/**
* View( ImageView) Bitmap 。
* @param options
* @param width
* @param height
*/
private int computeScale(BitmapFactory.Options options, int viewWidth, int viewHeight){
int inSampleSize = 1;
if(viewWidth == 0 || viewWidth == 0){
return inSampleSize;
}
int bitmapWidth = options.outWidth;
int bitmapHeight = options.outHeight;
// Bitmap View ,
if(bitmapWidth > viewWidth || bitmapHeight > viewWidth){
int widthScale = Math.round((float) bitmapWidth / (float) viewWidth);
int heightScale = Math.round((float) bitmapHeight / (float) viewWidth);
// ,
inSampleSize = widthScale < heightScale ? widthScale : heightScale;
}
return inSampleSize;
}
/**
*
*
* @author xiaanming
*
*/
public interface NativeImageCallBack{
/**
* , Bitmap
* @param bitmap
* @param path
*/
public void onImageLoader(Bitmap bitmap, String path);
}
}
이 종 류 는 로 컬 이미지 불 러 오기,메모리 캐 시,재단 등 논 리 를 제공 하 는 단일 클래스 입 니 다.이 종 류 는 로 컬 그림 을 불 러 올 때 비동기 로 불 러 오 는 방식 을 사용 합 니 다.큰 그림 을 불 러 오 는 데 도 시간 이 걸 리 기 때문에 하위 스 레 드 방식 으로 불 러 옵 니 다.그림 에 대한 캐 시 체 제 는 LruCache 를 사용 합 니 다.모 바 일 로 프로그램 메모리 에 배 정 된 1/4 를 사용 하여 그림 을 캐 시 합 니 다.LruCache 캐 시 그림 을 사용 하 는 것 외 에 도 그림 을 재단 하 였 습 니 다.간단 한 예 를 들 어 우리 의 컨트롤 크기 가 100*100 이 고 우리 의 그림 은 400*400 입 니 다.우 리 는 이렇게 큰 그림 을 불 러 오 는 데 많은 메모리 가 필요 하기 때문에 우 리 는 그림 재단 을 사 용 했 습 니 다.컨트롤 의 크기 에 따라 그림 의 재단 비율 을 확정 하여 메모리 소 모 를 줄 이 고 GridView 가 미 끄 러 지 는 유창 도 를 높이 며 그 중에서 몇 가지 중요 한 방법 을 소개 합 니 다.coptute Scale()은 그림 을 재단 해 야 하 는 비율 을 계산 합 니 다.컨트롤 의 크기 와 그림 의 크기 에 따라 비례 를 정 합 니 다.그림 이 컨트롤 보다 크 면 재단 합 니 다.그렇지 않 으 면 필요 하지 않 습 니 다.
decodeThumbBitmapForFile()방법 은 그림 을 재단 한 비율 을 계산 한 후에 파일 에서 그림 을 불 러 오 는 것 입 니 다.options.inJustDecodeBounds=true 를 설정 하여 메모리 가 차지 하지 않 는 다 는 것 을 표시 합 니 다.그러나 그림 의 구체 적 인 크기 를 가 져 올 수 있 습 니 다.coptute Scale()을 이용 하여 비율 을 계산 하여 options.inJustDecodeBounds=false 를 다시 비트 맵 을 해석 합 니 다.이렇게 해서 그림 을 재단 했다.
loadNativeImage(final String path,final Point mPoint,final NativeImageCallBack mCallBack)클 라 이언 트 에서 이 방법 만 호출 하면 Bitmap 대상 을 얻 을 수 있 습 니 다.그 안의 구체 적 인 논 리 는 메모리 캐 시 LruCache 에 이 Bitmap 가 존재 하 는 지 여 부 를 판단 하고 존재 하지 않 으 면 하위 스 레 드 를 열 어 읽 습 니 다.로 컬 이미지 스 레 드 를 쉽게 관리 하기 위해 서 입 니 다.스 레 드 풀 을 사 용 했 습 니 다.풀 에 스 레 드 하나만 들 어 갈 수 있 습 니 다.로 컬 그림 을 읽 은 다음 에 Bitmap 을 LruCache 에 넣 고 저 장 된 Key 를 그림 경로 로 저장 한 다음 에 Handler 를 사용 하여 메 인 스 레 드 그림 을 불 러 왔 음 을 알 린 다음 에 Bitmap 과 경 로 를 onImageLoader(Bitmap bitmap,String path)로 되 돌 립 니 다.이 방법의 mPoint 는 컨트롤 의 너비 와 높이 를 밀봉 하 는 대상 입 니 다.
그림 을 재단 하지 않 으 면 바로 이 방법의 재 업로드 방법 loadNativeImage(final String path,final NativeImageCallBack mCallBack)를 사용 하면 됩 니 다.논 리 는 같 습 니 다.다만 이 방법 은 그림 을 재단 하지 않 습 니 다.
다음은 GridView 의 Adapter 류 코드 입 니 다.
package com.example.imagescan;
import java.util.List;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Point;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.TextView;
import com.example.imagescan.MyImageView.OnMeasureListener;
import com.example.imagescan.NativeImageLoader.NativeImageCallBack;
public class GroupAdapter extends BaseAdapter{
private List<ImageBean> list;
private Point mPoint = new Point(0, 0);// ImageView
private GridView mGridView;
protected LayoutInflater mInflater;
@Override
public int getCount() {
return list.size();
}
@Override
public Object getItem(int position) {
return list.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
public GroupAdapter(Context context, List<ImageBean> list, GridView mGridView){
this.list = list;
this.mGridView = mGridView;
mInflater = LayoutInflater.from(context);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final ViewHolder viewHolder;
ImageBean mImageBean = list.get(position);
String path = mImageBean.getTopImagePath();
if(convertView == null){
viewHolder = new ViewHolder();
convertView = mInflater.inflate(R.layout.grid_group_item, null);
viewHolder.mImageView = (MyImageView) convertView.findViewById(R.id.group_image);
viewHolder.mTextViewTitle = (TextView) convertView.findViewById(R.id.group_title);
viewHolder.mTextViewCounts = (TextView) convertView.findViewById(R.id.group_count);
// ImageView
viewHolder.mImageView.setOnMeasureListener(new OnMeasureListener() {
@Override
public void onMeasureSize(int width, int height) {
mPoint.set(width, height);
}
});
convertView.setTag(viewHolder);
}else{
viewHolder = (ViewHolder) convertView.getTag();
viewHolder.mImageView.setImageResource(R.drawable.friends_sends_pictures_no);
}
viewHolder.mTextViewTitle.setText(mImageBean.getFolderName());
viewHolder.mTextViewCounts.setText(Integer.toString(mImageBean.getImageCounts()));
// ImageView Tag,
viewHolder.mImageView.setTag(path);
// NativeImageLoader
Bitmap bitmap = NativeImageLoader.getInstance().loadNativeImage(path, mPoint, new NativeImageCallBack() {
@Override
public void onImageLoader(Bitmap bitmap, String path) {
ImageView mImageView = (ImageView) mGridView.findViewWithTag(path);
if(bitmap != null && mImageView != null){
mImageView.setImageBitmap(bitmap);
}
}
});
if(bitmap != null){
viewHolder.mImageView.setImageBitmap(bitmap);
}else{
viewHolder.mImageView.setImageResource(R.drawable.friends_sends_pictures_no);
}
return convertView;
}
public static class ViewHolder{
public MyImageView mImageView;
public TextView mTextViewTitle;
public TextView mTextViewCounts;
}
}
우선,우 리 는 모든 아 이 템 의 그림 경 로 를 이 ImageView 에 태그 한 다음 에 NativeImageLoader 를 이용 하여 로 컬 그림 을 불 러 옵 니 다.그러나 우리 가 표시 하 는 그림 의 너비 와 높이 는 GirdView item 의 ImageView 크기 보다 훨씬 클 수 있 습 니 다.따라서 메모 리 를 절약 하기 위해 서 는 그림 을 재단 해 야 합 니 다.loadNativeImage(final String path)를 이용 하여 그림 을 재단 해 야 합 니 다.final Point mPoint,final Native ImageCallBack mCallBack)방법 은 ImageView 의 너비 와 높이 를 가 져 와 야 합 니 다.하지만 getView()에서 ImageView 의 너비 와 높이 를 가 져 오 려 면 문제 가 있 습 니 다.getView()에서 아 이 템 을 처음 표시 할 때 ImageView 를 사용 합 니 다.getWidth()는 0 을 가 져 왔 습 니 다.왜 처음에 너비 와 높이 를 가 져 오지 못 했 습 니까?LayoutInflater 를 사용 하여 XML 레이아웃 파일 인 Inflater()를 View 로 만 들 때 View 는 화면 에 표시 되 지 않 았 기 때 문 입 니 다.View 에 대해 onMeasure(),onLayout(),onDraw()등 을 하지 않 았 음 을 나타 내 고 retrue convertView 를 기 다 려 야 이 item 에 대응 하 는 View 가 ListView 의 위치 에 그 려 졌 음 을 나타 낸다.이때 서 야 item 에 대응 하 는 View 에 대해 onMeasure(),onLayout(),onDraw()등 을 해 야 Item 의 너비 와 높이 를 얻 을 수 있다.그래서 나 는 사용자 정의 ImageView 를 생각 했다.onMeasure()에서 리 셋 모드 를 이용 하여 ImageView 가 측정 한 너비 와 높이 를 주동 적 으로 알려 주 었 습 니 다.그러나 이것 은 작은 문제 가 있 습 니 다.바로 GridView 의 첫 번 째 item 을 표시 할 때 얻 은 너비 와 높이 가 0 인지,두 번 째 는 정상적으로 얻 을 수 있 습 니 다.첫 번 째 너비 와 높이 는 0 입 니 다.이것 은 우리 가 첫 번 째 그림 을 재단 하지 않 았 을 뿐 효율 적 으로 도 문제 가 없습니다.여러분 에 게 좋 은 방법 이 있 는 지 모 르 겠 습 니 다.getView()에서 Item 의 한 컨트롤 의 너비 와 높이 를 가 져 올 수 있 습 니 다.
MyImageView 의 코드 를 사용자 정의 합 니 다.OnMeasure Listener 감청 만 설정 하면 MyImageView 측정 이 끝 난 후에 측정 한 너비 와 높이 를 onMeasure Size()로 조정 한 다음 에 MyImageView 의 크기 에 따라 그림 을 재단 할 수 있 습 니 다.
package com.example.imagescan;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.ImageView;
public class MyImageView extends ImageView {
private OnMeasureListener onMeasureListener;
public void setOnMeasureListener(OnMeasureListener onMeasureListener) {
this.onMeasureListener = onMeasureListener;
}
public MyImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// onMeasureSize()
if(onMeasureListener != null){
onMeasureListener.onMeasureSize(getMeasuredWidth(), getMeasuredHeight());
}
}
public interface OnMeasureListener{
public void onMeasureSize(int width, int height);
}
}
위 에 있 는 이 코드 들 은 첫 번 째 인터페이스의 기능 을 완 성 했 습 니 다.그 다음 에 GridView 의 item 을 누 르 면 다른 화면 으로 이동 하여 이 폴 더 아래 의 모든 그림 을 표시 합 니 다.기능 은 첫 번 째 화면 과 차이 가 많 지 않 고 GridView 를 사용 하여 그림 을 표시 합 니 다.두 번 째 인터페이스의 레이아웃 코드 는 붙 이지 않 고 인터페이스의 코드 를 직접 붙 입 니 다.
package com.example.imagescan;
import java.util.List;
import android.app.Activity;
import android.os.Bundle;
import android.widget.GridView;
import android.widget.Toast;
public class ShowImageActivity extends Activity {
private GridView mGridView;
private List<String> list;
private ChildAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.show_image_activity);
mGridView = (GridView) findViewById(R.id.child_grid);
list = getIntent().getStringArrayListExtra("data");
adapter = new ChildAdapter(this, list, mGridView);
mGridView.setAdapter(adapter);
}
@Override
public void onBackPressed() {
Toast.makeText(this, " " + adapter.getSelectItems().size() + " item", Toast.LENGTH_LONG).show();
super.onBackPressed();
}
}
GridView 의 item 위 에 우리 가 정의 한 MyImageView 는 그림 을 표시 하 는 데 사용 되 고,또 하나의 CheckBox 는 우리 가 선택 한 상황 을 기록 합 니 다.Adapter 의 코드 는 다음 과 같 습 니 다.
package com.example.imagescan;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Point;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.ImageView;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.GridView;
import com.example.imagescan.MyImageView.OnMeasureListener;
import com.example.imagescan.NativeImageLoader.NativeImageCallBack;
import com.nineoldandroids.animation.AnimatorSet;
import com.nineoldandroids.animation.ObjectAnimator;
public class ChildAdapter extends BaseAdapter {
private Point mPoint = new Point(0, 0);// ImageView
/**
*
*/
private HashMap<Integer, Boolean> mSelectMap = new HashMap<Integer, Boolean>();
private GridView mGridView;
private List<String> list;
protected LayoutInflater mInflater;
public ChildAdapter(Context context, List<String> list, GridView mGridView) {
this.list = list;
this.mGridView = mGridView;
mInflater = LayoutInflater.from(context);
}
@Override
public int getCount() {
return list.size();
}
@Override
public Object getItem(int position) {
return list.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
final ViewHolder viewHolder;
String path = list.get(position);
if(convertView == null){
convertView = mInflater.inflate(R.layout.grid_child_item, null);
viewHolder = new ViewHolder();
viewHolder.mImageView = (MyImageView) convertView.findViewById(R.id.child_image);
viewHolder.mCheckBox = (CheckBox) convertView.findViewById(R.id.child_checkbox);
// ImageView
viewHolder.mImageView.setOnMeasureListener(new OnMeasureListener() {
@Override
public void onMeasureSize(int width, int height) {
mPoint.set(width, height);
}
});
convertView.setTag(viewHolder);
}else{
viewHolder = (ViewHolder) convertView.getTag();
viewHolder.mImageView.setImageResource(R.drawable.friends_sends_pictures_no);
}
viewHolder.mImageView.setTag(path);
viewHolder.mCheckBox.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
// CheckBox,
if(!mSelectMap.containsKey(position) || !mSelectMap.get(position)){
addAnimation(viewHolder.mCheckBox);
}
mSelectMap.put(position, isChecked);
}
});
viewHolder.mCheckBox.setChecked(mSelectMap.containsKey(position) ? mSelectMap.get(position) : false);
// NativeImageLoader
Bitmap bitmap = NativeImageLoader.getInstance().loadNativeImage(path, mPoint, new NativeImageCallBack() {
@Override
public void onImageLoader(Bitmap bitmap, String path) {
ImageView mImageView = (ImageView) mGridView.findViewWithTag(path);
if(bitmap != null && mImageView != null){
mImageView.setImageBitmap(bitmap);
}
}
});
if(bitmap != null){
viewHolder.mImageView.setImageBitmap(bitmap);
}else{
viewHolder.mImageView.setImageResource(R.drawable.friends_sends_pictures_no);
}
return convertView;
}
/**
* CheckBox , nineoldandroids
* @param view
*/
private void addAnimation(View view){
float [] vaules = new float[]{0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.1f, 1.2f, 1.3f, 1.25f, 1.2f, 1.15f, 1.1f, 1.0f};
AnimatorSet set = new AnimatorSet();
set.playTogether(ObjectAnimator.ofFloat(view, "scaleX", vaules),
ObjectAnimator.ofFloat(view, "scaleY", vaules));
set.setDuration(150);
set.start();
}
/**
* Item position
* @return
*/
public List<Integer> getSelectItems(){
List<Integer> list = new ArrayList<Integer>();
for(Iterator<Map.Entry<Integer, Boolean>> it = mSelectMap.entrySet().iterator(); it.hasNext();){
Map.Entry<Integer, Boolean> entry = it.next();
if(entry.getValue()){
list.add(entry.getKey());
}
}
return list;
}
public static class ViewHolder{
public MyImageView mImageView;
public CheckBox mCheckBox;
}
}
두 번 째 인터페이스의 Adapter 는 첫 번 째 화면 과 차이 가 많 지 않 습 니 다.CheckBox 가 하나 더 있어 서 그림 선택 상황 을 기록 할 수 있 습 니 다.저 희 는 CheckBox 에 setOn Checked Change Listener 감청 을 설정 해 야 합 니 다.위 챗 이 선택 한 후에 CheckBox 는 애니메이션 효과 가 있 습 니 다.그래서 저 는 Ninold androids 애니메이션 라 이브 러 리 를 이용 하여 CheckBox 에 애니메이션 효 과 를 추 가 했 습 니 다.addAnimation()방법 을 직접 호출 하면 추가 할 수 있 습 니 다.getSelectItems()방법 은 우리 가 선택 한 item 의 position 를 얻 을 수 있 습 니 다.선택 한 position 를 알 게 되면 다른 정 보 는 모두 알 수 있 습 니 다.위 챗 은 그림 을 미리 보 는 기능 이 있 습 니 다.저 는 추가 하지 않 습 니 다.이 수요 가 있 으 면 스스로 추가 할 수 있 습 니 다.추천 해 드릴 게 요.https://github.com/chrisbanes/PhotoView실행 항목,효 과 는 다음 과 같 습 니 다.
보기 에는 괜 찮 은 것 같 습 니 다.비동기 로 그림 을 읽 고 그림 을 캐 시 하고 재단 하여 로 컬 그림 을 표시 하 는 데 유창 합 니 다.GridView 의 미끄럼 도 원활 하고 OOM 의 발생 을 효과적으로 피 할 수 있 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Bitrise에서 배포 어플리케이션 설정 테스트하기이 글은 Bitrise 광고 달력의 23일째 글입니다. 자체 또는 당사 등에서 Bitrise 구축 서비스를 사용합니다. 그나저나 며칠 전 Bitrise User Group Meetup #3에서 아래 슬라이드를 발표했...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.