仿微信圖片選擇器

1、概述

    圖片選擇器也是在APP開發中常見的一個功能,檢索手機本地的所有圖片以GridView的形式顯示在界面上,看起來一個簡單的功能,但是要想要儘量避免內存溢出,還想要UI操作儘可能的流暢圖片加載儘可能的快速,也不是簡單的一個setImageBitmap就可以的。    

2、運行效果

效果圖:

這裏寫圖片描述

測試手機裏存儲了近萬張漫畫圖片,每個文件夾也有上千張圖片,可以看到加載速度和運行流暢程度還是可以的。

3、代碼結構

代碼的主要思路先實現了一個異步加載圖片的ImageLoader類,通過這個類進行圖片的加載。其他界面部分的代碼就比較簡單,通過ContentResolver獲取圖片文件路徑按文件夾區分,通過ImageLoader將圖片加載到GridView中,默認最多圖片文件夾,點擊下方的layout佈局彈出一個popwindow,選擇其他文件夾,更新界面。

ImageLoader結構圖:

這裏寫圖片描述

4、具體代碼

ImageLoader.java

package com.example.sy.a20170604.utils;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.LruCache;
import android.view.ViewGroup;
import android.widget.ImageView;

import java.lang.reflect.Field;
import java.util.LinkedList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

/**
 * Created by SY on 2017/6/4.
 */

public class ImageLoader {

    private static ImageLoader mInstance;
    //圖片緩存
    private LruCache<String, Bitmap> mLruCache;
    //線程池
    private ExecutorService mThreadPool;
    private static final int DEFAULT_THREAD_COUNT = 1;
    //隊列調度方式
    private Type mType = Type.LIFO;
    //任務隊列
    private LinkedList<Runnable> mTaskQueue;
    //後臺輪詢線程
    private Thread mPoolThread;
    private Handler mPoolTheadHandler;
    //UI線程Handler
    private Handler mUIHandler;
    //mPoolTheadHandler初始化的信號量
    private Semaphore mSemaphorePoolTheadHandler = new Semaphore(0);
    //同時可並行執行線程的信號量
    private Semaphore mSemaphoreThreadPool;

    //隊列調度方式枚舉
    public enum Type {
        FIFO, LIFO;
    }

    private ImageLoader(int threadCount, Type type) {
        init(threadCount, type);
    }

    private void init(int threadCount, Type type) {
        //後臺輪詢線程
        mPoolThread = new Thread() {
            @Override
            public void run() {
                Looper.prepare();
                mPoolTheadHandler = new Handler() {

                    @Override
                    public void handleMessage(Message msg) {
                        //線程池去取出一個任務執行
                        mThreadPool.execute(getTask());
                        try {
                            mSemaphoreThreadPool.acquire();
                        } catch (InterruptedException e) {
                            Log.e("ImageLoader",e.getMessage());
                        }
                    }
                };
                //初始化完成,釋放一個信號量
                mSemaphorePoolTheadHandler.release();
                Looper.loop();
            }

        };
        mPoolThread.start();

        int maxMemory = (int) Runtime.getRuntime().maxMemory();//應用最大可用內存
        int cacheMeory = maxMemory / 4;
        mLruCache = new LruCache<String, Bitmap>(cacheMeory) {
            @Override
            protected int sizeOf(String key, Bitmap value) {

                return value.getRowBytes() * value.getHeight();
            }
        };
        //創建線程池
        mThreadPool = Executors.newFixedThreadPool(threadCount);
        mTaskQueue = new LinkedList<Runnable>();
        mType = type;

        mSemaphoreThreadPool = new Semaphore(threadCount);
    }

    //從任務隊列取出一個任務
    private Runnable getTask() {
        if (mType == Type.FIFO) {
            return mTaskQueue.removeFirst();
        } else if (mType == Type.LIFO) {
            return mTaskQueue.removeLast();
        }
        return null;
    }

    /**
     * 設置圖片
     *
     * @param path
     * @param imageView
     */
    public void loadImage(final String path, final ImageView imageView) {
        imageView.setTag(path);
        if (mUIHandler == null) {
            mUIHandler = new Handler() {
                @Override
                public void handleMessage(Message msg) {
                    //獲得圖片,爲imageview回調設置圖片
                    ImageBeanHolder holder = (ImageBeanHolder) msg.obj;
                    Bitmap bm = holder.bitmap;
                    ImageView imageView = holder.imageView;
                    String path = holder.path;
                    //將path與gettag進行比較,防止圖片錯亂
                    if (imageView.getTag().toString().equalsIgnoreCase(path)) {
                        imageView.setImageBitmap(bm);
                    }
                }
            };
        }

        Bitmap bm = getBipmapFromLruCache(path);

        if (bm != null) {
            refresashBitmap(path, imageView, bm);
        } else {
            addTasks(new Runnable() {
                @Override
                public void run() {
                    //加載圖片
                    //1、獲得圖片需要現實的大小
                    ImageSize imageSize = getImageViewSize(imageView);
                    //2、壓縮圖片
                    Bitmap bitmap = decodeSampledBitmapFromPath(path, imageSize.width, imageSize.height);
                    //3、圖片計入緩存
                    addBitmapToCache(path, bitmap);

                    refresashBitmap(path, imageView, bitmap);

                    mSemaphoreThreadPool.release();
                }
            });
        }

    }


    public void refresashBitmap(String path, ImageView imageView, Bitmap bm) {
        Message message = Message.obtain();
        ImageBeanHolder holder = new ImageBeanHolder();
        holder.bitmap = bm;
        holder.imageView = imageView;
        holder.path = path;
        message.obj = holder;
        mUIHandler.sendMessage(message);
    }

    /**
     * 圖片加入緩存
     *
     * @param path
     * @param bm
     */
    private void addBitmapToCache(String path, Bitmap bm) {
        if (getBipmapFromLruCache(path) == null) {
            if (bm != null) {
                mLruCache.put(path, bm);
            }
        }
    }

    /**
     * 壓縮圖片
     *
     * @param path
     * @param width
     * @param height
     * @return
     */
    private Bitmap decodeSampledBitmapFromPath(String path, int width, int height) {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;//圖片不加載入內存
        BitmapFactory.decodeFile(path, options);

        options.inSampleSize = caculateInSampleSize(options, width, height);

        //使用inSampleSize再次解析圖片
        options.inJustDecodeBounds = false;
        Bitmap bm = BitmapFactory.decodeFile(path, options);
        return bm;
    }

    /**
     * 根據傳入的寬高和實際寬高計算inSampleSize
     *
     * @param options
     * @param reqWidth
     * @param reqHeight
     * @return
     */
    private int caculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
        int width = options.outWidth;
        int height = options.outHeight;

        int inSampleSize = 1;

        if (width > reqWidth || height > reqHeight) {
            int widthRadio = Math.round(width * 1.0f / reqWidth);
            int heightRadio = Math.round(height * 1.0f / reqHeight);

            inSampleSize = Math.max(widthRadio, heightRadio);

        }
        return inSampleSize;
    }

    /**
     * 根據imageview獲取適當的壓縮的圖片寬高
     *
     * @param imageView
     * @return
     */
    protected ImageSize getImageViewSize(ImageView imageView) {
        ImageSize size = new ImageSize();

        DisplayMetrics displayMetrics = imageView.getContext().getResources().getDisplayMetrics();

        ViewGroup.LayoutParams layoutParams = imageView.getLayoutParams();

        int width = imageView.getWidth();//獲取imageview實際寬度
        if (width <= 0) {
            width = layoutParams.width;//獲取image在layout裏設置的寬度
        }
        if (width <= 0) {
//            width = imageView.getMaxWidth();//檢查最大值  此方法API16以上
            width = getImageViewFieldValue(imageView,"mMaxWidth");

        }
        if (width <= 0) {
            width = displayMetrics.widthPixels;//屏幕寬度
        }

        int height = imageView.getHeight();
        if (height <= 0) {
            height = layoutParams.height;
        }
        if (height <= 0) {
//            height = imageView.getMaxHeight();
            height = getImageViewFieldValue(imageView,"mMaxHeight");

        }
        if (height <= 0) {
            height = displayMetrics.heightPixels;
        }

        size.width = width;
        size.height = height;

        return size;
    }

    /**
     * 通過反射獲取imageview的某個屬性值
     *
     * @param object
     * @param fieldName
     * @return
     */
    private static int getImageViewFieldValue(Object object, String fieldName) {
        int value = 0;

        try {
            Field field = ImageView.class.getDeclaredField(fieldName);
            field.setAccessible(true);//設置爲允許訪問
            int fieldValue = field.getInt(object);
            if (fieldValue > 0 && fieldValue < Integer.MAX_VALUE) {
                value = fieldValue;
            }
        } catch (Exception e) {
            Log.e("ImageLoader",e.getMessage());
        }


        return value;
    }


    private synchronized void addTasks(Runnable runnable) {
        mTaskQueue.add(runnable);
        try {
            if (mPoolTheadHandler == null)
                //保證mPoolTheadHandler已經初始化,如果爲null請求一個信號量,默認爲0,故停止等待mPoolTheadHandler初始化
                mSemaphorePoolTheadHandler.acquire();
        } catch (InterruptedException e) {
            Log.e("ImageLoader",e.getMessage());
        }
        mPoolTheadHandler.sendEmptyMessage(0x110);
    }

    /**
     * 根據path在緩存中獲取圖片
     *
     * @param path
     * @return
     */
    private Bitmap getBipmapFromLruCache(String path) {
        return mLruCache.get(path);
    }

    private class ImageBeanHolder {
        Bitmap bitmap;
        ImageView imageView;
        String path;
    }

    private class ImageSize {
        int width;
        int height;
    }


    public static ImageLoader getInstance() {
        if (mInstance == null) {
            synchronized (ImageLoader.class) {
                if (mInstance == null) {
                    mInstance = new ImageLoader(DEFAULT_THREAD_COUNT, Type.LIFO);
                }
            }
        }
        return mInstance;
    }
    public static ImageLoader getInstance(int threadCount, Type type) {
        if (mInstance == null) {
            synchronized (ImageLoader.class) {
                if (mInstance == null) {
                    mInstance = new ImageLoader(threadCount, type);
                }
            }
        }
        return mInstance;
    }
}

使用單例模式,給出獲得單例對象的方法getInstance();首先構造函數中執行init()初始化方法,初始化後臺輪詢線程,初始化後臺輪詢線程Handler和線程池和任務隊列。接着看loadImage()方法,傳入圖片路徑和一個imageview,通過getBipmapFromLruCache()方法在LruCache里根據路徑url尋找圖片,如果找到執行refresashBitmap()方法,設置圖片到imageview。如果在LruCache裏沒有該圖片,則新建一個Runnable任務 Task通過addTask()方法將任務加入到TaskQueue裏,並通過mPoolTheadHandler發送消息通知後臺輪詢線程,後臺輪詢線程收到消息後從TaskQueue裏取出任務放入從線程池中取出的子線程裏執行。Task任務Runnable的run方法裏執行具體的加載圖片方法。通過getImageViewSize()方法獲得圖片適合大小,根據傳進來的圖片url路徑用decodeSampledBitmapFromPath()壓縮並且BitmapFactory.decodeFile()得到圖片的Bitmap對象,接着將圖片放入LruCache緩存,最後調用refresashBitmap()方法設置圖片到imageview。除此之外,代碼中使用了信號量類Semaphore,來保證在addTask()方法中發送消息時mPoolTheadHandler已經初始化,若未初始化則線程無法獲取到信號量線程暫停,直到後臺輪詢線程初始化完成mPoolTheadHandler釋放信號量。同樣在後臺輪詢線程在任務隊列中拿去任務時同樣需要使用信號量控制同時並行執行的線程數量,來實現任務隊列TaskQueue的隊列不同調度方式。

MainActivity.java

package com.example.sy.a20170604;

import android.app.ProgressDialog;
import android.content.ContentResolver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.provider.MediaStore;
import android.support.annotation.Size;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.WindowManager;
import android.widget.GridView;
import android.widget.PopupWindow;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.example.sy.a20170604.adapter.ImageListAdapter;
import com.example.sy.a20170604.bean.FolderBean;

import java.io.File;
import java.io.FilenameFilter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class MainActivity extends AppCompatActivity {

    private GridView mGridView;
    private RelativeLayout mBottomLy;
    private TextView mDirName;
    private TextView mDirCount;

    private List<String> mImages ;
    private File mCurrentDir;
    private int mMaxCount;
    private ImageListAdapter adapter;

    private ProgressDialog progressDialog;
    private List<FolderBean> folderBeans = new ArrayList<FolderBean>();
    private ListImageDirPopupWindow popupWindow;

    private Handler mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            if (msg.what == 0x110) {
                progressDialog.dismiss();
                data2View();
                initDirPopupWindow();
            }
        }
    };

    private void initDirPopupWindow() {
        popupWindow = new ListImageDirPopupWindow(this, folderBeans);
        popupWindow.setOnDismissListener(new PopupWindow.OnDismissListener() {
            @Override
            public void onDismiss() {
                lightOn();
            }
        });
        popupWindow.setOnDirSelectedListener(new ListImageDirPopupWindow.OnDirSelectedListener() {
            @Override
            public void onSelected(FolderBean folderBean) {
                //更新adapter
                mCurrentDir = new File(folderBean.getDir());
                mImages = Arrays.asList(mCurrentDir.list(new FilenameFilter() {
                    @Override
                    public boolean accept(File file, String filename) {
                        if (filename.endsWith(".jpg") || filename.endsWith(".png") ||
                                filename.endsWith(".jepg")){
                            return true;
                        }
                        return false;
                    }
                }));

                adapter = new ImageListAdapter(MainActivity.this, mImages, mCurrentDir.getAbsolutePath());
                mGridView.setAdapter(adapter);
                Log.e("Size",mImages.size() + "");
                mDirCount.setText(mImages.size() + "");
                mDirName.setText(mCurrentDir.getName());
                popupWindow.dismiss();
            }
        });
    }

    private void data2View() {
        if (mCurrentDir == null) {
            Toast.makeText(this, "未掃描到任何圖片", Toast.LENGTH_SHORT).show();
            return;
        }
        mImages = Arrays.asList(mCurrentDir.list(new FilenameFilter() {
            @Override
            public boolean accept(File file, String filename) {
                if (filename.endsWith(".jpg") || filename.endsWith(".png") ||
                        filename.endsWith(".jepg")){
                    return true;
                }
                return false;
            }
        }));
        setGridViewAdapter();
    }

    private void lightOn() {
        WindowManager.LayoutParams lp = getWindow().getAttributes();
        lp.alpha = 1.0f;
        getWindow().setAttributes(lp);
    }
    private void lightOff() {
        WindowManager.LayoutParams lp = getWindow().getAttributes();
        lp.alpha = 0.3f;
        getWindow().setAttributes(lp);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        initDatas();
        initEvent();
    }

    private void initEvent() {
        mBottomLy.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                popupWindow.setAnimationStyle(R.style.dir_popupwindow_anim);
                popupWindow.showAsDropDown(mBottomLy, 0, 0);
                lightOff();
            }
        });
    }

    /**
     * 利用ContentProvider掃描手機中的所有圖片
     */
    private void initDatas() {
        if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
            Toast.makeText(getApplicationContext(), "當前存儲卡不可用!", Toast.LENGTH_SHORT).show();
            return;
        }
        progressDialog = ProgressDialog.show(this, null, "正在加載...");

       new Thread() {
            @Override
            public void run() {
                Uri uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
                ContentResolver contentResolver = MainActivity.this.getContentResolver();
                String select = MediaStore.Images.Media.MIME_TYPE + " = ? or " + MediaStore.Images.Media.MIME_TYPE + " = ?";
                Cursor cursor = contentResolver.query(uri, null, select, new String[]{"image/jpeg", "image/png"}, MediaStore.Images.Media.DATE_MODIFIED);
                Set<String> mDirPaths = new HashSet<String>();
                while (cursor.moveToNext()) {
                    String path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
                    File parentFile = new File(path).getParentFile();
                    if (parentFile == null) {
                        continue;
                    }
                    String dirPath = parentFile.getAbsolutePath();
                    FolderBean bean = null;
                    if (mDirPaths.contains(dirPath)) {
                        continue;
                    } else {
                        mDirPaths.add(dirPath);
                        bean = new FolderBean();
                        bean.setDir(dirPath);
                        bean.setFirstImgPath(path);
                    }
                    if (parentFile.list() == null) {
                        continue;
                    }
                    int picSize = parentFile.list(new FilenameFilter() {
                        @Override
                        public boolean accept(File dir, String filename) {
                            if (filename.endsWith(".jpg") || filename.endsWith(".png") ||
                                    filename.endsWith(".jepg")){
                                return true;
                            }
                            return false;
                        }
                    }).length;
                    bean.setCount(picSize);
                    folderBeans.add(bean);
                    if (picSize > mMaxCount) {
                        mMaxCount = picSize;
                        mCurrentDir = parentFile;
                    }
                }
                cursor.close();
                //通知 掃描圖片完成
                mHandler.sendEmptyMessage(0x110);
            }
        }.start();
    }

    private void initView() {
        mGridView = (GridView) findViewById(R.id.id_gridview);
        mBottomLy = (RelativeLayout) findViewById(R.id.id_bottom_rl);
        mDirName = (TextView) findViewById(R.id.id_dir_name);
        mDirCount = (TextView) findViewById(R.id.id_dir_count);
    }

    private void setGridViewAdapter() {
        adapter = new ImageListAdapter(this, mImages, mCurrentDir.getAbsolutePath());
        mGridView.setAdapter(adapter);
        mDirCount.setText(mMaxCount + "");
        mDirName.setText(mCurrentDir.getName());
    }
}

在onCreate()方法裏initView()方法初始化界面控件;initDatas()方法裏new子線程在裏面通過使用ContentResolver獲取圖片文件信息,將圖片文件夾信息封裝到一個FolderBean裏,獲取圖片信息結束後通過Handler發送消息,通知主線程執行data2View()方法加載圖片顯示到界面的GridView裏,並且初始化更換文件夾的popwindow;最後initEvent()方法裏設置了點擊下方的layout彈出popwindow的事件。
FolderBean.java

package com.example.sy.a20170604.bean;

/**
 * Created by SY on 2017/6/4.
 */
public class FolderBean {
    private String dir;//文件夾路徑
    private String firstImgPath;
    private int count;
    private String name;//文件夾名稱


    public String getDir() {
        return dir;
    }

    public void setDir(String dir) {
        this.dir = dir;
        int lastIndexof = this.dir.lastIndexOf("/");
        this.name = this.dir.substring(lastIndexof);
    }

    public String getFirstImgPath() {
        return firstImgPath;
    }

    public void setFirstImgPath(String firstImgPath) {
        this.firstImgPath = firstImgPath;
    }

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

ImageListAdapter.java

package com.example.sy.a20170604.adapter;

import android.content.Context;
import android.graphics.Color;
import android.util.DisplayMetrics;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.BaseAdapter;
import android.widget.ImageButton;
import android.widget.ImageView;


import com.example.sy.a20170604.R;
import com.example.sy.a20170604.utils.ImageLoader;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class ImageListAdapter extends BaseAdapter {

        private static Set<String> mSelectImgs = new HashSet<String>();
        private List<String> mDatas;
        private String dirPath;
        private LayoutInflater inflater;
        private int mScreenWidth;

        public ImageListAdapter(Context context, List<String> mDatas, String dirPath) {
            this.mDatas = mDatas;
            this.dirPath = dirPath;
            this.inflater = LayoutInflater.from(context);

            WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
            DisplayMetrics metrics = new DisplayMetrics();
            manager.getDefaultDisplay().getMetrics(metrics);
            mScreenWidth = metrics.widthPixels;//獲取屏幕寬度
        }

        @Override
        public int getCount() {
            return mDatas.size();
        }

        @Override
        public Object getItem(int position) {
            return mDatas.get(position);
        }

        @Override
        public long getItemId(int position) {
            return position;
        }

        @Override
        public View getView(final int position, View convertView, ViewGroup parent) {
            final ViewHolder viewHolder ;
            if (convertView == null) {
                convertView = inflater.inflate(R.layout.item_gridview, parent, false);
                viewHolder = new ViewHolder();
                viewHolder.imageView = (ImageView) convertView.findViewById(R.id.id_item_img);
                viewHolder.imageButton = (ImageButton) convertView.findViewById(R.id.id_item_select);
                convertView.setTag(viewHolder);
            } else {
                viewHolder = (ViewHolder) convertView.getTag();
            }
            //重置狀態
            viewHolder.imageView.setImageResource(R.mipmap.icon_default_img);
            viewHolder.imageView.setColorFilter(null);
            viewHolder.imageButton.setImageResource(R.mipmap.icon_file_check_off_grid);
            viewHolder.imageView.setMaxWidth(mScreenWidth / 3);//ImageLoader 進行圖片壓縮的時候可能會用到 減少內存使用
            ImageLoader.getInstance(3, ImageLoader.Type.LIFO).loadImage(dirPath + "/" + mDatas.get(position),
                    viewHolder.imageView);

            final  String filePath = dirPath + "/" + mDatas.get(position);
            viewHolder.imageView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (mSelectImgs.contains(filePath)) {
                        mSelectImgs.remove(filePath);
                        viewHolder.imageView.setColorFilter(null);
                        viewHolder.imageButton.setImageResource(R.mipmap.icon_file_check_off_grid);
                    }else {
                        mSelectImgs.add(filePath);
                        viewHolder.imageView.setColorFilter(Color.parseColor("#77000000"));
                        viewHolder.imageButton.setImageResource(R.mipmap.icon_file_check_on_grid);
                    }
                }
            });
            if (mSelectImgs.contains(filePath)) {
                viewHolder.imageView.setColorFilter(Color.parseColor("#77000000"));
                viewHolder.imageButton.setImageResource(R.mipmap.icon_file_check_on_grid);
            }
            return convertView;
        }


        private class ViewHolder {
            ImageView imageView;
            ImageButton imageButton;
        }

}

ListImageDirPopupWindow.java

package com.example.sy.a20170604;

import android.content.Context;
import android.graphics.drawable.BitmapDrawable;
import android.util.DisplayMetrics;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.PopupWindow;
import android.widget.TextView;

import com.example.sy.a20170604.bean.FolderBean;
import com.example.sy.a20170604.utils.ImageLoader;

import java.util.List;


/**
 * Created by SY on 2017/6/4.
 */
public class ListImageDirPopupWindow extends PopupWindow {

    private int width;
    private int height;
    private View mConvertView;
    private ListView mListView;
    private List<FolderBean> mDatas;

    public interface OnDirSelectedListener {
        void onSelected(FolderBean folderBean);
    }


    private OnDirSelectedListener listener;

    public void setOnDirSelectedListener(OnDirSelectedListener listener) {
        this.listener = listener;
    }

    public ListImageDirPopupWindow(Context context, List<FolderBean> mDatas) {
        super(context);
        this.mDatas = mDatas;
        calWidthAndHeight(context);
        mConvertView = LayoutInflater.from(context).inflate(R.layout.popup_main, null);

        setContentView(mConvertView);
        setWidth(width);
        setHeight(height);
        setFocusable(true);
        setTouchable(true);
        setOutsideTouchable(true);
        setBackgroundDrawable(new BitmapDrawable());
        setTouchInterceptor(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
                    dismiss();
                    return true;
                }
                return false;
            }
        });

        initViews(context);
        initEvent();
    }

    private void initViews(Context context) {
        mListView = (ListView) mConvertView.findViewById(R.id.id_dir_list);
        mListView.setAdapter(new ListDirAdapter(context, mDatas));
    }

    private void initEvent() {
        mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                if(listener!=null) {
                    listener.onSelected(mDatas.get(position));
                }
            }
        });

    }

    /**
     * 計算高度和寬度
     * 寬度和屏幕一樣
     * 高度是75%的屏幕
     * @param context
     */
    private void calWidthAndHeight(Context context) {
        WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics displayMetrics = new DisplayMetrics();
        windowManager.getDefaultDisplay().getMetrics(displayMetrics);
        width = displayMetrics.widthPixels;
        height = (int) (displayMetrics.heightPixels * 0.75 );
    }


    private class ListDirAdapter extends ArrayAdapter<FolderBean> {

        private LayoutInflater inflater;

        public ListDirAdapter(Context context, List<FolderBean> objects) {
            super(context, 0, objects);
            inflater = LayoutInflater.from(context);
        }


        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            ViewHolder viewHolder =null;
            if (convertView == null) {
                viewHolder = new ViewHolder();
                convertView = inflater.inflate(R.layout.item_popup, parent, false);
                viewHolder.imageView = (ImageView) convertView.findViewById(R.id.id_dir_item_image);
                viewHolder.nameTv = (TextView) convertView.findViewById(R.id.id_dir_item_name);
                viewHolder.countTv = (TextView) convertView.findViewById(R.id.id_dir_item_count);
                convertView.setTag(viewHolder);
            }else {
                viewHolder = (ViewHolder) convertView.getTag();
            }
            FolderBean bean = getItem(position);
            viewHolder.imageView.setImageResource(R.mipmap.icon_default_img);
            ImageLoader.getInstance(3, ImageLoader.Type.LIFO).loadImage(bean.getFirstImgPath(), viewHolder.imageView);
            viewHolder.nameTv.setText(bean.getName());
            viewHolder.countTv.setText(bean.getCount() + "");
            return convertView;
        }

        private class ViewHolder {
            ImageView imageView;
            TextView nameTv;
            TextView countTv;
        }
    }

}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<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"
    tools:context=".MainActivity">

    <GridView
        android:id="@+id/id_gridview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:numColumns="3"
        android:stretchMode="columnWidth"
        android:cacheColorHint="@android:color/transparent"
        android:listSelector="@android:color/transparent"
        android:horizontalSpacing="3dp"
        android:verticalSpacing="3dp">

    </GridView>
    <RelativeLayout
        android:id="@+id/id_bottom_rl"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:layout_alignParentBottom="true"
        android:background="#ee000000"
        android:clipChildren="true">
        <TextView
            android:id="@+id/id_dir_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:layout_centerVertical="true"
            android:paddingLeft="10dp"
            android:textColor="@android:color/white"
            android:text="所有圖片"/>
        <TextView
            android:id="@+id/id_dir_count"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:layout_centerVertical="true"
            android:paddingRight="10dp"
            android:textColor="@android:color/white"
            android:text="0"/>
    </RelativeLayout>
</RelativeLayout>

item_popup.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="5dp">


    <ImageView
        android:id="@+id/id_dir_item_image"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_alignParentLeft="true"
        android:paddingLeft="12dp"
        android:paddingRight="12dp"
        android:paddingBottom="17dp"
        android:paddingTop="9dp"
        android:scaleType="fitXY"
        android:src="@mipmap/icon_default_img"/>

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:layout_centerVertical="true"
        android:layout_toRightOf="@id/id_dir_item_image"
        android:orientation="vertical">
        <TextView
            android:id="@+id/id_dir_item_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="12sp"
            android:text="文件夾"/>
        <TextView
            android:id="@+id/id_dir_item_count"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:textSize="10sp"
            android:textColor="#444"
            android:text="1112"/>
    </LinearLayout>

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"
        android:layout_marginRight="20dp"
        android:src="@mipmap/icon_file_check_off_grid"/>

</RelativeLayout>

5、參考資料

Android 超高仿微信圖片選擇器 圖片該這麼加載 - Hongyang - 博客頻道 - CSDN.NET
http://blog.csdn.net/lmj623565791/article/details/39943731

Android-仿微信圖片選擇器-慕課網
http://www.imooc.com/learn/489

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章