a亚洲精品_精品国产91乱码一区二区三区_亚洲精品在线免费观看视频_欧美日韩亚洲国产综合_久久久久久久久久久成人_在线区

首頁 > 系統 > Android > 正文

Android應用中使用ContentProvider掃描本地圖片并顯示

2019-12-12 06:41:03
字體:
來源:轉載
供稿:網友

之前群里面有朋友問我,有沒有關于本地圖片選擇的Demo,類似微信的效果,他說網上沒有這方面的Demo,問我能不能寫一篇關于這個效果的Demo,于是我研究了下微信的本地圖片選擇的Demo,自己仿照的寫了下分享給大家,希望對以后有這樣子需求的朋友有一點幫助吧,主要使用的是ContentProvider掃描手機中的圖片,并用GridView將圖片顯示出來,關于GridView和ListView顯示圖片的問題,一直是一個很頭疼的問題,因為我們手機的內存有限,手機給每個應用程序分配的內存也有限,所以圖片多的情況下很容易伴隨著OOM的發生,不過現在也有很多的開源的圖片顯示框架,對顯示很多圖片進行了優化,大家有興趣的可以去了解了解,今天我的這篇文章使用的是LruCache這個類以及對圖片進行相對應的裁剪,這樣也可以盡量的避免OOM的發生,我們先看下微信的效果吧

201645151626071.png (480×854)

201645151655089.png (480×854)

接下來我們就來實現這些效果吧,首先我們新建一個項目,取名ImageScan
首先我們先看第一個界面吧,使用將手機中的圖片掃描出來,然后根據圖片的所在的文件夾將其分類出來,并顯示所在文件夾里面的一張圖片和文件夾中圖片個數,我們根據界面元素(文件夾名, 文件夾圖片個數,文件夾中的一張圖片)使用一個實體對象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的布局,看上面的圖也行你會認為他的效果是2張圖片添加的效果,其實不是,后面的疊加效果只是一張背景圖片而已,代碼先貼上來

<?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的代碼之前,我們先看一個比較重要的類,本地圖片加載器NativeImageLoader
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滑動的流暢度,介紹里面幾個比較重要的方法
computeScale()計算圖片需要裁剪的比例,根據控件的大小和圖片的大小確定比例,如果圖片比控件大,我們就進行裁剪,否則不需要。
decodeThumbBitmapForFile()方法是根據計算好了圖片裁剪的比例之后從文件中加載圖片,我們先設置options.inJustDecodeBounds = true表示解析不占用內存,但是我們能獲取圖片的具體大小,利用computeScale()計算好比例,在將options.inJustDecodeBounds=false,再次解析Bitmap,這樣子就對圖片進行了裁剪。
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;   }     } 
首先我們將每個item的圖片路徑設置Tag到該ImageView上面,然后利用NativeImageLoader來加載本地圖片,但是我們顯示的圖片的寬和高可能遠大于GirdView item中ImageView的大小,于是為了節省內存,我們需要對圖片進行裁剪,需要對圖片裁剪我們利用loadNativeImage(final String path, final Point mPoint, final NativeImageCallBack mCallBack)方法,我們就必須要獲取ImageView的寬和高了
但是我們想在getView()中獲取ImageView的寬和高存在問題,在getView()里面剛開始顯示item的時候利用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的代碼,我們只需要設置OnMeasureListener監聽,當MyImageView測量完畢之后,就會將測量的寬和高回調到onMeasureSize()中,然后我們可以根據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設置setOnCheckedChangeListener監聽,微信的選中之后CheckBox有一個動畫效果,所以我利用nineoldandroids動畫庫也給CheckBox加了一個動畫效果,直接調用addAnimation()方法就能添加了,getSelectItems()方法就能獲取我們選中的item的position了,知道了選中的position,其他的信息就都知道了,微信有對圖片進行預覽的功能,我這里就不添加了,如果有這個需求可以自行添加,給大家推薦一個https://github.com/chrisbanes/PhotoView

運行項目,效果如下

看起來還不錯吧,采用的是異步讀取圖片,對圖片進行了緩存和裁剪,使得在顯示本地圖片方面比較流暢,GridView滑動也挺流暢的,也有效的避免OOM的產生。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 精品久久久网站 | 日本精品视频在线 | 欧美性一区二区 | 欧美在线视频网站 | 香蕉在线视频免费 | 91一区二区在线 | 亚洲欧美在线视频 | 97久久精品人人澡人人爽 | 黄网站在线播放 | 午夜欧美 | av网站免费观看 | 亚洲电影在线观看 | 久久久www| 九九九色 | 91精品国产91久久综合桃花 | 2020天天操| 欧美一区二区 | 久久久精品亚洲 | 操视频网站 | 国产精品毛片一区二区 | 亚洲成人福利 | 九九视频这里只有精品 | 日韩aⅴ影视 | 黄色毛片免费看 | 成人一级 | 中文字幕亚洲欧美日韩在线不卡 | 久久久久久成人精品 | 婷婷激情五月 | 成人av一区二区三区 | 天堂a| 91麻豆精品国产91久久久久久久久 | 精品免费国产视频 | 中字幕视频在线永久在线观看免费 | 狠狠综合| 国产黄色在线免费看 | 三级电影网址 | 国产乱码精品一区二区三区忘忧草 | 黄色大片视频网站 | 国产一区二区三区免费 | 三区在线 | 在线不卡小视频 |