Android高仿微信图片选择上传工具

源码托管地址:https://github.com/SleepyzzZ/photo-selector


话不多说,先上效果图(高仿微信图片选择器):

图片选择界面:

Android高仿微信图片选择上传工具

Android高仿微信图片选择上传工具

图片预览界面:

Android高仿微信图片选择上传工具

Android高仿微信图片选择上传工具

批量上传图片:

Android高仿微信图片选择上传工具


实现的功能介绍:

1、图片异步加载,使用Glide开源库实现加载;

2、图片的预览界面,支持左右滑动,双击放大浏览;

3、图片批量上传,使用OkHttp来实现与Servlet服务器的通信;


使用方法(Android Studio):

新建工程,File->New->Import Module导入photo-selector,记得在你的build.gradle引入Module及注册Activity;

直接在你的主Activity调用以下方法(代码托管中已经给出调用demo):

/**
     *暴露接口
     * @param context
     * @param maxSelectCount-限制的最大图片选择数量
     * @param searchPath-指定图片搜索路径(若为null-表示搜索所有图片)
     * @param url-服务器地址
     */
    public static void actionStart(Context context, int maxSelectCount, String searchPath, String url)
    {
        Intent intent = new Intent(context, PhotoPickerActivity.class);
        intent.putExtra(PhotoPickerFragment.EXTRA_SELECT_COUNT, maxSelectCount);
        intent.putExtra(PhotoPickerFragment.EXTRA_DEFAULT_SELECTED_LIST, searchPath);
        intent.putExtra(HTTP_URL, url);
        context.startActivity(intent);
    }


下面贴出关键部分代码:

图片选择和预览界面利用fragment实现,其中选择界面用GridView控件,每个Item包含加载的图片、选择标记和掩膜mask,通过回调实现图片和标记的点击事件。

其中,点击图片进入文件夹内所有图片预览界面,点击选择标记选择图片并掩膜展示图片选择后效果。

图片预览界面fragment、adapter

package com.sleepyzzz.photo_selector.fragment;

import android.app.ProgressDialog;
import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.provider.MediaStore;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.GridView;
import android.widget.PopupWindow;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.sleepyzzz.photo_selector.R;
import com.sleepyzzz.photo_selector.activity.PhotoPickerActivity;
import com.sleepyzzz.photo_selector.adapter.PhotoPickerAdapter;
import com.sleepyzzz.photo_selector.entity.ImageFolder;
import com.sleepyzzz.photo_selector.event.OnItemClickListerner;
import com.sleepyzzz.photo_selector.event.OnPhotoDirSelected;
import com.sleepyzzz.photo_selector.view.ListImageDirPopupWindow;

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

/**
 * User: datou_SleepyzzZ(SleepyzzZ19911002@126.com)
 * Date: 2016-04-14
 * Time: 15:24
 * FIXME
 */
public class PhotoPickerFragment extends Fragment {

    private final static String TAG = PhotoPickerFragment.class.getSimpleName();
    /**
     * 最大图片选择数量
     */
    public static final String EXTRA_SELECT_COUNT = "max_select_count";
    /**
     * 默认选择集
     */
    public static final String EXTRA_DEFAULT_SELECTED_LIST = "default_list";
    /**
     * 屏幕高度
     */
    public static final String EXTRA_SCREEN_HEIGHT = "screen_height";
    /**
     * 控件
     */
    private GridView mGridView;
    private Button mPreviewBtn;
    private Button mPopWindowBtn;
    private RelativeLayout mBottonLy;
    private Button mCommitBtn;
    private TextView mTopTv;
    /**
     * 当前选择的图片文件夹
     */
    private File mImgDir;
    /**
     * 第一个扫描到的文件夹
     */
    private String firstDirName;
    /**
     * 当前文件夹下图片名列表
     */
    private List<String> mImgNames;
    /**
     * 临时辅助类,用于防止同一个文件夹的多次扫描
     */
    private HashSet<String> mDirPaths = new HashSet<String>();
    /**
     * 扫描拿到所有的图片文件夹
     */
    private List<ImageFolder> mImageFolders = new ArrayList<ImageFolder>();
    /**
     * 文件夹选择popupwindow
     */
    private ListImageDirPopupWindow mDirPopupWindow;
    /**
     * 文件选择适配器
     */
    private PhotoPickerAdapter mPickerAdapter;

    private ProgressDialog mProgressDialog;

    private int mDesireSelectCount;
    private int mScreenHeight;
    private String mDesireSearchPath;

    private View rootView;

    public static PhotoPickerFragment newInstance(int screenHeight, int selectCount, String searchPath) {

        Bundle args = new Bundle();
        args.putInt(EXTRA_SCREEN_HEIGHT, screenHeight);
        args.putInt(EXTRA_SELECT_COUNT, selectCount);
        args.putString(EXTRA_DEFAULT_SELECTED_LIST, searchPath);
        PhotoPickerFragment fragment = new PhotoPickerFragment();
        fragment.setArguments(args);
        return fragment;
    }

    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            mProgressDialog.dismiss();
            //为View绑定数据
            data2View();
            //初始化展示文件夹的PopupWindow
            initListDirPopupWindow();
        }
    };

    private void initListDirPopupWindow() {

        mDirPopupWindow = new ListImageDirPopupWindow(ViewGroup.LayoutParams.MATCH_PARENT,
                (int) (0.7 * mScreenHeight), mImageFolders, LayoutInflater.from(getActivity())
                .inflate(R.layout.list_folder, null));
        mDirPopupWindow.setOnDismissListener(new PopupWindow.OnDismissListener() {
            @Override
            public void onDismiss() {
                //设置背景颜色变暗
                WindowManager.LayoutParams lp = getActivity().getWindow().getAttributes();
                lp.alpha = 1.0f;
                getActivity().getWindow().setAttributes(lp);
            }
        });
        //设置选择文件夹的回调
        mDirPopupWindow.setOnPhotoDirSelected(new OnPhotoDirSelected() {
            @Override
            public void onSelected(ImageFolder folder) {
                mImgDir = new File(folder.getDir());
                mImgNames = Arrays.asList(mImgDir.list(new FilenameFilter() {
                    @Override
                    public boolean accept(File dir, String filename) {
                        if(filename.endsWith(".jpg") || filename.endsWith(".png")
                                || filename.endsWith(".jpeg"))
                            return true;
                        return false;
                    }
                }));
                mPickerAdapter = new PhotoPickerAdapter(getActivity(), mImgNames,
                        R.layout.grid_item_image, mImgDir.getAbsolutePath(), mDesireSelectCount);
                mGridView.setAdapter(mPickerAdapter);
                //item回调
                mPickerAdapter.setOnItemClickListerner(new OnItemClickListerner() {
                    @Override
                    public void onPhotoClick(View view, int position) {

                        List<String> mImgUrls = new ArrayList<String>();
                        for (int i = 0;i < mImgNames.size(); i++) {
                            mImgUrls.add(mImgDir + "/" + mImgNames.get(i));
                        }
                        int[] screenLocation = new int[2];
                        view.getLocationOnScreen(screenLocation);
                        PhotoPagerFragment fragment =
                                PhotoPagerFragment.newInstance(mImgUrls, position, mDesireSelectCount, screenLocation,
                                        view.getWidth(), view.getHeight());
                        ((PhotoPickerActivity) getActivity()).addPhotoPagerFragment(fragment);
                    }

                    @Override
                    public void onMarkClick(String path) {

                        refreshUI(path);
                    }
                });

                mPopWindowBtn.setText(folder.getName());
                mDirPopupWindow.dismiss();
            }
        });
    }

    private void refreshUI(String path) {
        if(PhotoPickerAdapter.mSelectedImage.contains(path)) {
            if(PhotoPickerAdapter.mSelectedImage.size() != 0) {
                mPreviewBtn.setEnabled(true);
                mPreviewBtn.setText(getResources().getString(R.string.preview)
                        + "(" + PhotoPickerAdapter.mSelectedImage.size() + ")");
                mCommitBtn.setEnabled(true);
                mCommitBtn.setText(String.format("%s(%d/%d)", getString(R.string.action_done)
                        , PhotoPickerAdapter.mSelectedImage.size(), mDesireSelectCount));
            } else {
                mPreviewBtn.setEnabled(false);
                mPreviewBtn.setText(R.string.preview);
                mCommitBtn.setEnabled(false);
                mCommitBtn.setText(R.string.action_done);
            }
        } else {
            if(PhotoPickerAdapter.mSelectedImage.size() == 0) {
                mPreviewBtn.setEnabled(false);
                mPreviewBtn.setText(R.string.preview);
                mCommitBtn.setEnabled(false);
                mCommitBtn.setText(R.string.action_done);
            } else {
                mPreviewBtn.setEnabled(true);
                mPreviewBtn.setText(getResources().getString(R.string.preview)
                        + "(" + PhotoPickerAdapter.mSelectedImage.size() + ")");
                mCommitBtn.setEnabled(true);
                mCommitBtn.setText(String.format("%s(%d/%d)",
                        getString(R.string.action_done), PhotoPickerAdapter.mSelectedImage.size(), mDesireSelectCount));
            }
        }
    }

    /**
     * 绑定数据
     */
    private void data2View() {

        if(mImgDir == null) {
            Toast.makeText(getActivity(), "no scanned images",
                    Toast.LENGTH_SHORT).show();
            return;
        }
        mPopWindowBtn.setText(firstDirName);
        mImgNames = Arrays.asList(mImgDir.list());
        /**
         * 文件夹路径个图片路径分开保存,减少了内存的消耗
         */
        mPickerAdapter = new PhotoPickerAdapter(getActivity(), mImgNames,
                R.layout.grid_item_image, mImgDir.getAbsolutePath(), mDesireSelectCount);
        mGridView.setAdapter(mPickerAdapter);
        //item选择回调
        mPickerAdapter.setOnItemClickListerner(new OnItemClickListerner() {
            @Override
            public void onPhotoClick(View view, int position) {

                List<String> mImgUrls = new ArrayList<String>();
                for (int i = 0;i < mImgNames.size(); i++) {
                    mImgUrls.add(mImgDir + "/" + mImgNames.get(i));
                }
                int[] screenLocation = new int[2];
                view.getLocationOnScreen(screenLocation);
                PhotoPagerFragment fragment =
                        PhotoPagerFragment.newInstance(mImgUrls, position, mDesireSelectCount, screenLocation,
                                view.getWidth(), view.getHeight());
                ((PhotoPickerActivity) getActivity()).addPhotoPagerFragment(fragment);
            }

            @Override
            public void onMarkClick(String path) {

                refreshUI(path);
            }
        });
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //选择图片数量
        mDesireSelectCount = getArguments().getInt(EXTRA_SELECT_COUNT);
        //屏幕高度
        mScreenHeight = getArguments().getInt(EXTRA_SCREEN_HEIGHT);
        //默认选择
        mDesireSearchPath = getArguments().getString(EXTRA_DEFAULT_SELECTED_LIST);
        //扫描图片
        getImages();
    }

    private void initView(View view) {

        mGridView = (GridView) view.findViewById(R.id.gd_image);
        mPopWindowBtn = (Button) view.findViewById(R.id.btn_choose_dir);
        mPreviewBtn = (Button) view.findViewById(R.id.btn_preview);
        mBottonLy = (RelativeLayout) view.findViewById(R.id.layout_bottom_actionbar);
        mCommitBtn = (Button) getActivity().findViewById(R.id.btn_commit);
        mTopTv = (TextView) getActivity().findViewById(R.id.tv_back);

        mTopTv.setText(R.string.images);
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

        //保存fragment视图状态
        rootView = getPersistentView(inflater, container, savedInstanceState, R.layout.fragment_grid_image);

        initView(rootView);
        initEvent();

        return rootView;
    }

    /**
     * 保存fragment视图状态
     * @param inflater
     * @param container
     * @param savedInstanceState
     * @param layoutId
     * @return
     */
    private View getPersistentView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState, int layoutId) {

        if(rootView == null) {

            rootView = inflater.inflate(layoutId, container, false);
        } else {

            ViewGroup parent = (ViewGroup) rootView.getParent();
            if(parent != null) {
                parent.removeView(rootView);
            }
        }
        return rootView;
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
    }

    private void initEvent() {
        mPopWindowBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mDirPopupWindow.setAnimationStyle(R.style.anim_popup_dir);
                mDirPopupWindow.showAsDropDown(mBottonLy, 0, 0);
                //设置背景颜色变暗
                WindowManager.LayoutParams lp = getActivity().getWindow().getAttributes();
                lp.alpha = .3f;
                getActivity().getWindow().setAttributes(lp);
            }
        });
        //初始化按钮
        if(PhotoPickerAdapter.mSelectedImage == null ||
                PhotoPickerAdapter.mSelectedImage.size() <= 0) {
            mPreviewBtn.setText(R.string.preview);
            mPreviewBtn.setEnabled(false);
            mCommitBtn.setText(R.string.action_done);
            mCommitBtn.setEnabled(false);
        } else {
            mPreviewBtn.setText(getResources().getString(R.string.preview)
                    + "(" + PhotoPickerAdapter.mSelectedImage.size() + ")");
            mPreviewBtn.setEnabled(true);
            mCommitBtn.setText(String.format("%s(%d/%d)", getString(R.string.action_done),
                    PhotoPickerAdapter.mSelectedImage.size(), mDesireSelectCount));
            mCommitBtn.setEnabled(true);
        }
        //监听预览按钮
        mPreviewBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                int[] screenLocation = new int[2];
                v.getLocationOnScreen(screenLocation);
                PhotoPagerFragment fragment =
                        PhotoPagerFragment.newInstance(PhotoPickerAdapter.mSelectedImage, 0, mDesireSelectCount, screenLocation,
                                v.getWidth(), v.getHeight());
                ((PhotoPickerActivity) getActivity()).addPhotoPagerFragment(fragment);
            }
        });
    }

    private String[] IMAGE_PROJECTION = {
            MediaStore.Images.Media.DATA,
            MediaStore.Images.Media.DISPLAY_NAME,
            MediaStore.Images.Media.DATE_ADDED,
            MediaStore.Images.Media.MIME_TYPE,
            MediaStore.Images.Media.SIZE,
            MediaStore.Images.Media._ID
    };

    /**
     * 扫描图片
     */
    private void getImages() {
        if(!Environment.getExternalStorageState().
                equals(Environment.MEDIA_MOUNTED)) {
            Toast.makeText(getActivity(), "no external storage", Toast.LENGTH_SHORT).show();
            return;
        }
        //显示进度条
        mProgressDialog = ProgressDialog.show(getActivity(), null, "loading...");
        new Thread(new Runnable() {
            @Override
            public void run() {
                String firstImage = null;
                Uri mImgUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
                ContentResolver mContentResolver = getActivity().getContentResolver();

                Cursor mCursor = null;
                //只查询jpeg和png图片
                if (mDesireSearchPath == null)
                {
                    mCursor = mContentResolver.query(mImgUri, IMAGE_PROJECTION,
                            IMAGE_PROJECTION[3] + "=? or "
                                    + IMAGE_PROJECTION[3] + "=?",
                            new String[]{"image/jpeg", "image/png"},
                            IMAGE_PROJECTION[2] + " DESC");
                } else
                {
                    mCursor = mContentResolver.query(mImgUri, IMAGE_PROJECTION,
                            IMAGE_PROJECTION[4] + ">0 AND " + IMAGE_PROJECTION[0]
                                    + " like '%" + mDesireSearchPath + "%'", null,
                            IMAGE_PROJECTION[2] + " DESC");
                }

                while(mCursor.moveToNext()) {
                    //获得图片路径
                    String path = mCursor.getString(mCursor.
                            getColumnIndex(MediaStore.Images.Media.DATA));
                    //拿到第一张图片的路径
                    if(firstImage == null) {
                        firstImage = path;
                    }

                    //获取该图片的父路径名
                    File parentFile = new File(path).getParentFile();
                    if(parentFile == null)
                        continue;
                    String dirPath = parentFile.getAbsolutePath();
                    ImageFolder imageFolder = null;
                    //利用一个HashSet防止多次扫描同一个文件夹
                    if(mDirPaths.contains(dirPath)) {
                        continue;
                    } else {
                        mDirPaths.add(dirPath);
                        //初始化ImageLoader
                        imageFolder = new ImageFolder();
                        imageFolder.setDir(dirPath);
                        imageFolder.setFirstImagePath(path);
                        //获取优先显示的图片父路径名
                        if(mCursor.getPosition() == 0) {
                            mImgDir = parentFile;
                            firstDirName = imageFolder.getName();
                        }
                    }

                    int picSize = parentFile.list(new FilenameFilter() {
                        @Override
                        public boolean accept(File dir, String filename) {
                            if(filename.endsWith(".jpg")
                                    || filename.endsWith(".png")
                                    || filename.endsWith("jpeg"))
                                return true;
                            return false;
                        }
                    }).length;
                    //需要显示所有图片,修改此处
                    imageFolder.setCount(picSize);
                    mImageFolders.add(imageFolder);
                }
                mCursor.close();
                //扫描完成,辅助的HashSet释放内存
                mDirPaths = null;
                mHandler.sendEmptyMessage(0x110);
            }
        }).start();
    }

    public PhotoPickerAdapter getPhotoPickerAdapter() {

        return mPickerAdapter;
    }
}

package com.sleepyzzz.photo_selector.adapter;

import android.content.Context;
import android.view.View;
import android.widget.ImageView;
import android.widget.Toast;

import com.sleepyzzz.photo_selector.R;
import com.sleepyzzz.photo_selector.event.OnItemClickListerner;
import com.sleepyzzz.photo_selector.util.ViewHolder;
import com.sleepyzzz.photo_selector.view.SquaredImageView;

import java.util.LinkedList;
import java.util.List;

/**
 * User: datou_SleepyzzZ(SleepyzzZ19911002@126.com)
 * Date: 2016-04-11
 * Time: 13:22
 * FIXME
 */
public class PhotoPickerAdapter extends CommonAdapter<String> {


    private static final String TAG = PhotoPickerAdapter.class.getSimpleName();
    /**
     * 用户选择的图片,存储为图片的完整路径
     */
    public static List<String> mSelectedImage = new LinkedList<String>();
    /**
     * 文件夹路径
     */
    private String mDirPath;
    /**
     * 选择图片数量限制
     */
    private int mSelectCount;
    /**
     * 回调接口方法
     */
    private OnItemClickListerner mOnItemClickListerner = null;

    public PhotoPickerAdapter(Context context, List<String> mDatas, int itemLayoutId,
                              String dirPath, int selectCount) {
        super(context, mDatas, itemLayoutId);
        this.mDirPath = dirPath;
        this.mSelectCount = selectCount;
    }

    @Override
    public void convert(final ViewHolder helper, final String item) {

        //设置图片
        helper.setImageResource(R.id.siv_image, R.drawable.default_error);
        helper.setImageResource(R.id.iv_checkmark, R.drawable.btn_unselected);
        helper.setImageByUrl(R.id.siv_image, mDirPath + "/" + item);

        final SquaredImageView mImageView = helper.getView(R.id.siv_image);
        final ImageView mCheckMark = helper.getView(R.id.iv_checkmark);
        final View mask = helper.getView(R.id.mask);

        mask.setVisibility(View.GONE);
        //设置Mark的点击事件
        mCheckMark.setOnClickListener(new View.OnClickListener() {
            //选择,则将图片变暗,反之则反之
            @Override
            public void onClick(View v) {
                //已经选择过该图片
                if (mSelectedImage.contains(mDirPath + "/" + item)) {

                    mSelectedImage.remove(mDirPath + "/" + item);
                    mOnItemClickListerner.onMarkClick(mDirPath + "/" +item);    //回调
                    mCheckMark.setImageResource(R.drawable.btn_unselected);
                    mask.setVisibility(View.GONE);
                } else {
                    //未选择该图片
                    if (mSelectedImage.size() == mSelectCount) {
                        Toast.makeText(mContext, R.string.msg_amount_limit,
                                Toast.LENGTH_SHORT).show();
                        return;
                    }
                    mSelectedImage.add(mDirPath + "/" + item);
                    mOnItemClickListerner.onMarkClick(mDirPath + "/" +item);    //回调
                    mCheckMark.setImageResource(R.drawable.btn_selected);
                    mask.setVisibility(View.VISIBLE);
                }
            }
        });

        //已经选择过的图片,显示出选择效果
        if (mSelectedImage.contains(mDirPath + "/" + item)) {

            mCheckMark.setImageResource(R.drawable.btn_selected);
            mask.setVisibility(View.VISIBLE);
        }

        //设置photo的点击事件
        mImageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                mOnItemClickListerner.onPhotoClick(v, helper.getPosition());
            }
        });
    }

    /**
     * 回调方法
     * @param onItemClickListerner
     */
    public void setOnItemClickListerner(OnItemClickListerner onItemClickListerner) {

        this.mOnItemClickListerner = onItemClickListerner;
    }

    public List<String> getmSelectedImage() {

        return mSelectedImage;
    }

    @Override
    public void setSelectIndex(int i) {

    }

    @Override
    public int getSetlectIndex() {

        return 0;
    }
}

图片预览界面可以通过右下角选择按钮,添加或删除图片选择项

图片预览界面fragmenty、adapter

package com.sleepyzzz.photo_selector.fragment;

import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.view.ViewPager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.nineoldandroids.animation.Animator;
import com.nineoldandroids.animation.ObjectAnimator;
import com.nineoldandroids.view.ViewHelper;
import com.nineoldandroids.view.ViewPropertyAnimator;
import com.sleepyzzz.photo_selector.R;
import com.sleepyzzz.photo_selector.adapter.PhotoPagerAdapter;
import com.sleepyzzz.photo_selector.adapter.PhotoPickerAdapter;
import com.sleepyzzz.photo_selector.event.OnPagerCLickListener;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * User: datou_SleepyzzZ(SleepyzzZ19911002@126.com)
 * Date: 2016-04-15
 * Time: 20:47
 * FIXME
 */
public class PhotoPagerFragment extends Fragment {

    public final static String ARG_PATH = "PATHS";
    public final static String ARG_POSITION = "CURRENT_POSITION";
    public final static String ARG_MAXCOUNT = "MAX_SELECT_COUNT";

    private ArrayList<String> mPaths;
    private ViewPager mViewPager;
    private PhotoPagerAdapter mPagerAdapter;

    private RelativeLayout mBottombar;
    private ImageView mSelectMark;
    private Button mSelectBtn;
    private Button mCommitBtn;
    private TextView mToptv;

    private boolean isShowBottomBar = true;

    public final static long ANIM_DURATION = 200L;

    public final static String ARG_THUMBNAIL_TOP = "THUMBNAIL_TOP";
    public final static String ARG_THUMBNAIL_LEFT = "THUMBNAIL_LEFT";
    public final static String ARG_THUMBNAIL_WIDTH = "THUMBNAIL_WIDTH";
    public final static String ARG_THUMBNAIL_HEIGHT = "THUMBNAIL_HEIGHT";
    public final static String ARG_HAS_ANIM = "HAS_ANIM";

    private int thumbnailTop = 0;
    private int thumbnailLeft = 0;
    private int thumbnailWidth = 0;
    private int thumbnailHeight = 0;

    private boolean hasAnim = false;

    private final ColorMatrix colorizerMatrix = new ColorMatrix();

    private int currentPosition = 0;

    private int mDesireSelectCount;

    public static PhotoPagerFragment newInstance(List<String> paths, int position, int maxSelectCount) {

        PhotoPagerFragment fragment = new PhotoPagerFragment();

        Bundle args = new Bundle();
        args.putStringArray(ARG_PATH, paths.toArray(new String[paths.size()]));
        args.putInt(ARG_POSITION, position);
        args.putBoolean(ARG_HAS_ANIM, false);
        args.putInt(ARG_MAXCOUNT, maxSelectCount);
        fragment.setArguments(args);

        return fragment;
    }

    public static PhotoPagerFragment newInstance(List<String> paths, int position, int maxSelectCount, int[] screenLocation, int thumbnailWidth, int thumbnailHeight) {

        PhotoPagerFragment fragment = newInstance(paths, position, maxSelectCount);

        fragment.getArguments().putInt(ARG_THUMBNAIL_LEFT, screenLocation[0]);
        fragment.getArguments().putInt(ARG_THUMBNAIL_TOP, screenLocation[1]);
        fragment.getArguments().putInt(ARG_THUMBNAIL_WIDTH, thumbnailWidth);
        fragment.getArguments().putInt(ARG_THUMBNAIL_HEIGHT, thumbnailHeight);
        fragment.getArguments().putBoolean(ARG_HAS_ANIM, true);

        return fragment;
    }

    public void setPhotos(List<String> paths, int position) {

        this.mPaths.clear();
        this.mPaths.addAll(paths);
        this.currentPosition = position;

        mViewPager.setCurrentItem(position);
        mViewPager.getAdapter().notifyDataSetChanged();
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mPaths = new ArrayList<>();

        Bundle bundle = getArguments();
        if (bundle != null) {
            String[] pathArr = bundle.getStringArray(ARG_PATH);
            mPaths.clear();
            if (pathArr != null) {
                mPaths = new ArrayList<>(Arrays.asList(pathArr));
            }

            hasAnim = bundle.getBoolean(ARG_HAS_ANIM);
            currentPosition = bundle.getInt(ARG_POSITION);
            mDesireSelectCount = bundle.getInt(ARG_MAXCOUNT);
            thumbnailTop = bundle.getInt(ARG_THUMBNAIL_TOP);
            thumbnailLeft = bundle.getInt(ARG_THUMBNAIL_LEFT);
            thumbnailWidth = bundle.getInt(ARG_THUMBNAIL_WIDTH);
            thumbnailHeight = bundle.getInt(ARG_THUMBNAIL_HEIGHT);
        }

        mPagerAdapter = new PhotoPagerAdapter(getActivity(), mPaths);
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

        View rootView = inflater.inflate(R.layout.fragment_photo_pager, container, false);

        mViewPager = (ViewPager) rootView.findViewById(R.id.vp_photos);
        mViewPager.setAdapter(mPagerAdapter);
        mViewPager.setCurrentItem(currentPosition);
        mViewPager.setOffscreenPageLimit(5);

        mBottombar = (RelativeLayout) rootView.findViewById(R.id.ly_bottom_bar);
        mSelectMark = (ImageView) rootView.findViewById(R.id.iv_select_box);
        mSelectBtn = (Button) rootView.findViewById(R.id.btn_selectbox);
        mCommitBtn = (Button) getActivity().findViewById(R.id.btn_commit);
        mToptv = (TextView) getActivity().findViewById(R.id.tv_back);

        //更新第一张预览图片的selectbox
        if (PhotoPickerAdapter.mSelectedImage.contains(
                mPaths.get(currentPosition)))
        {
            mSelectMark.setImageResource(R.drawable.selectbox_marked);
        }
        //进入pager显示Top TextView(eg:2/19)
        mToptv.setText(String.format("%d/%d", currentPosition+1,
                mPaths.size()));

        if (savedInstanceState == null && hasAnim) {

            ViewTreeObserver observer = mViewPager.getViewTreeObserver();
            observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
                @Override
                public boolean onPreDraw() {

                    mViewPager.getViewTreeObserver().removeOnPreDrawListener(this);

                    int[] screenLocation = new int[2];
                    mViewPager.getLocationOnScreen(screenLocation);
                    thumbnailLeft = thumbnailLeft - screenLocation[0];
                    thumbnailTop = thumbnailTop - screenLocation[1];

                    runEnterAnimation();

                    return true;
                }
            });
        }

        mPagerAdapter.setOnPagerCLickListener(new OnPagerCLickListener() {
            @Override
            public void onPagerClick() {

                if(isShowBottomBar)
                {
                    mBottombar.setVisibility(View.GONE);
                    isShowBottomBar = !isShowBottomBar;
                } else
                {
                    mBottombar.setVisibility(View.VISIBLE);
                    isShowBottomBar = !isShowBottomBar;
                }
            }
        });

        mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

            }

            @Override
            public void onPageSelected(int position) {

                hasAnim = currentPosition == position;
                if (PhotoPickerAdapter.mSelectedImage.
                        contains(mPaths.get(position)))
                {
                    mSelectMark.setImageResource(R.drawable.selectbox_marked);
                } else
                {
                    mSelectMark.setImageResource(R.drawable.selectbox_n);
                }
                mToptv.setText(String.format("%d/%d", position+1,
                        mPaths.size()));
            }

            @Override
            public void onPageScrollStateChanged(int state) {

            }
        });

        mSelectBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                int pos = mViewPager.getCurrentItem();
                if (PhotoPickerAdapter.mSelectedImage.
                        contains(mPaths.get(pos)))
                {
                    mSelectMark.setImageResource(R.drawable.selectbox_n);
                    PhotoPickerAdapter.mSelectedImage.remove(mPaths.get(pos));
                    if (PhotoPickerAdapter.mSelectedImage.size() == 0)
                    {
                        mCommitBtn.setEnabled(false);
                        mCommitBtn.setText(R.string.action_done);
                    } else
                    {
                        mCommitBtn.setText(String.format("%s(%d/%d)", getString(R.string.action_done)
                                , PhotoPickerAdapter.mSelectedImage.size(), mDesireSelectCount));
                    }
                } else
                {
                    if (PhotoPickerAdapter.mSelectedImage.size() < mDesireSelectCount)
                    {
                        mSelectMark.setImageResource(R.drawable.selectbox_marked);
                        PhotoPickerAdapter.mSelectedImage.add(mPaths.get(pos));
                        mCommitBtn.setEnabled(true);
                        mCommitBtn.setText(String.format("%s(%d/%d)", getString(R.string.action_done)
                                , PhotoPickerAdapter.mSelectedImage.size(), mDesireSelectCount));
                    } else
                    {
                        Toast.makeText(getActivity().getApplicationContext(),
                                R.string.msg_amount_limit, Toast.LENGTH_SHORT).show();
                    }
                }
            }
        });

        return rootView;
    }

    private void runEnterAnimation() {

        final long duration = ANIM_DURATION;

        ViewHelper.setPivotX(mViewPager, 0);
        ViewHelper.setPivotY(mViewPager, 0);
        ViewHelper.setScaleX(mViewPager, (float) thumbnailWidth / mViewPager.getWidth());
        ViewHelper.setScaleY(mViewPager, (float) thumbnailHeight / mViewPager.getHeight());
        ViewHelper.setTranslationX(mViewPager, thumbnailLeft);
        ViewHelper.setTranslationY(mViewPager, thumbnailTop);

        ViewPropertyAnimator.animate(mViewPager)
                .setDuration(duration)
                .scaleX(1)
                .scaleY(1)
                .translationX(0)
                .translationY(0)
                .setInterpolator(new DecelerateInterpolator());

        ObjectAnimator bgAnim = ObjectAnimator.ofInt(mViewPager.getBackground(),
                "alpha", 0, 255);
        bgAnim.setDuration(duration);
        bgAnim.start();

        ObjectAnimator colorizer = ObjectAnimator.ofFloat(PhotoPagerFragment.this,
                "saturation", 0, 1);
        colorizer.setDuration(duration);
        colorizer.start();
    }

    public void runExitAnimation(final Runnable endAction) {

        if (!getArguments().getBoolean(ARG_HAS_ANIM, false) || !hasAnim) {
            endAction.run();
            return;
        }

        final long duration = ANIM_DURATION;
        ViewPropertyAnimator.animate(mViewPager)
                .setDuration(duration)
                .setInterpolator(new AccelerateInterpolator())
                .scaleX((float) thumbnailWidth / mViewPager.getWidth())
                .scaleY((float) thumbnailHeight / mViewPager.getHeight())
                .translationX(thumbnailLeft)
                .translationY(thumbnailTop)
                .setListener(new Animator.AnimatorListener() {
                    @Override
                    public void onAnimationStart(Animator animation) {

                    }

                    @Override
                    public void onAnimationEnd(Animator animation) {
                        endAction.run();
                    }

                    @Override
                    public void onAnimationCancel(Animator animation) {

                    }

                    @Override
                    public void onAnimationRepeat(Animator animation) {

                    }
                });

        ObjectAnimator bgAnim =
                ObjectAnimator.ofInt(mViewPager.getBackground(), "alpha", 0);
        bgAnim.setDuration(duration);
        bgAnim.start();

        ObjectAnimator colorizer =
                ObjectAnimator.ofFloat(PhotoPagerFragment.this, "saturation", 1, 0);
        colorizer.setDuration(duration);
        colorizer.start();
    }

    public void setSaturation(float value) {

        colorizerMatrix.setSaturation(value);
        ColorMatrixColorFilter colorizerFilter = new ColorMatrixColorFilter(colorizerMatrix);
        mViewPager.getBackground().setColorFilter(colorizerFilter);
    }

    public ViewPager getViewPager() {

        return mViewPager;
    }

    public ArrayList<String> getPaths() {

        return mPaths;
    }

    public int getCurrentPosition() {

        return mViewPager.getCurrentItem();
    }
}

package com.sleepyzzz.photo_selector.adapter;

import android.content.Context;
import android.support.v4.view.PagerAdapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;

import com.bumptech.glide.Glide;
import com.sleepyzzz.photo_selector.R;
import com.sleepyzzz.photo_selector.event.OnPagerCLickListener;

import java.util.ArrayList;
import java.util.List;

/**
 * User: datou_SleepyzzZ(SleepyzzZ19911002@126.com)
 * Date: 2016-04-15
 * Time: 20:58
 * FIXME
 */
public class PhotoPagerAdapter extends PagerAdapter {

    private List<String> mPaths = new ArrayList<>();
    private Context mContext;
    private LayoutInflater mInflater;

    private OnPagerCLickListener mOnPagerCLickListener;

    public void setOnPagerCLickListener(OnPagerCLickListener onPagerCLickListener) {
        mOnPagerCLickListener = onPagerCLickListener;
    }

    public PhotoPagerAdapter(Context context, List<String> paths) {
        mPaths = paths;
        mContext = context;
        mInflater = LayoutInflater.from(mContext);
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {

        View itemView = mInflater.inflate(R.layout.item_pager, container, false);

        ImageView imageView = (ImageView) itemView.findViewById(R.id.iv_pager);

        //自定义图片异步加载类(大图片存在OOM)
        /*ImageLoader.getInstance(3, ImageLoader.Type.LIFO)
                .loadImage(mPaths.get(position), imageView);*/
        /*Glide.with(mContext)
                .load(mPaths.get(position))
                .thumbnail(0.1f)
                .dontAnimate()
                .dontTransform()
                .override(800, 800)
                .placeholder(R.drawable.ic_photo_black_48dp)
                .error(R.drawable.ic_broken_image_black_48dp)
                .into(imageView);*/
        Glide.with(mContext)
                .load(mPaths.get(position))
                .thumbnail(0.1f)        //先显示.1的缩略图
                .dontAnimate()
                .dontTransform()
                .override(800, 800)     //尺寸
                .placeholder(R.drawable.ic_photo_black_48dp)
                .error(R.drawable.ic_broken_image_black_48dp)
                .into(imageView);

        imageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                mOnPagerCLickListener.onPagerClick();
            }
        });
        /*imageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(mContext instanceof PhotoPickerActivity) {
                    if(!((Activity) mContext).isFinishing()) {
                        ((Activity) mContext).onBackPressed();
                    }
                }
            }
        });*/
        container.addView(itemView);

        return itemView;
    }

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

    @Override
    public boolean isViewFromObject(View view, Object object) {
        return view == object;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        container.removeView((View) object);
    }

    @Override
    public int getItemPosition(Object object) {
        return POSITION_NONE;
    }
}


这里也给出了服务器端批量接收图片测试代码:

package com.sleepyzzz.server;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Date;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadBase.FileSizeLimitExceededException;
import org.apache.commons.fileupload.FileUploadBase.SizeLimitExceededException;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

/**
 * Servlet implementation class DetectionServlet
 */
@WebServlet("/DetectionServlet")
public class DetectionServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
	private final static long MAX_FILE_SIZE = 50 * 1024 * 1024;
	
	private final static String[] allowedExt = new String[]
			{"jpg", "JPG", "JPEG", "jpeg"};
	
	private String result;
	
	private DiskFileItemFactory factory;
	
	private ServletFileUpload upload;
	
	private PrintWriter writer;
	
	private ArrayList<FileItem> list;
	
	private String clientIP;
	
    /**
     * @see HttpServlet#HttpServlet()
     */
    public DetectionServlet() {
        super();
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		doPost(request, response);
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
response.setContentType("text/html;charset=utf-8");
		
		this.clientIP = request.getRemoteAddr();
		
		factory = new DiskFileItemFactory();
		factory.setSizeThreshold(2*1024*1024);		//缓冲区
		factory.setRepository(new File(request.getSession()		//临时存放文件目录
				.getServletContext()
				.getRealPath("/")
				+ "UploadTemp"));
		
		upload = new ServletFileUpload(factory);		//用硬盘文件工厂实例化上传组件
		upload.setFileSizeMax(MAX_FILE_SIZE);		//最大上传尺寸
		
		writer = response.getWriter();
		result = "Upload sucess";
		
		try {
			
			list = (ArrayList<FileItem>) upload.parseRequest(request);
		} catch (FileUploadException e) {
			// TODO Auto-generated catch block
			if(e instanceof FileSizeLimitExceededException) {
				
				result = "File size exceeds a predetermined size: " + MAX_FILE_SIZE + "bytes";
				return;
			}
			e.printStackTrace();
		}
		
		if(list == null || list.size() == 0) {
			
			result = "Please select images to upload";
			return;
		}
		
		String fileName;
		Date now = new Date();
		DateFormat dateFormat = DateFormat.getDateInstance();
		String date = dateFormat.format(now);
		String destDirName = request.getSession()
									.getServletContext()
									.getRealPath("/")
									+ "RawImages\\" + date;
		File dir = new File(destDirName);
		if(!dir.exists() && !dir.isDirectory()) {
			
			dir.mkdirs();
		}
		/*if(!dir.mkdirs()) {
			
			result = "The server creates image folder failed";
			return;
		}*/
		
		for(FileItem item : list) {
			
			fileName = clientIP + "-" + item.getName();
			try {
				
				File file = new File(destDirName, fileName);
				if(file.exists()) {
					continue;
				}
					
				item.write(new File(destDirName, fileName));
			} catch (Exception e) {
				// TODO Auto-generated catch block
				result = e.getMessage();
				e.printStackTrace();
			}
		}
	
		writer.print(result);
	}

}

Android高仿微信图片选择上传工具

上一篇:IOS 即时通讯 + 微信聊天框架 + 源码


下一篇:玩转微信营销和推广的10种方法和技巧