源码托管地址:https://github.com/SleepyzzZ/photo-selector
话不多说,先上效果图(高仿微信图片选择器):
图片选择界面:
图片预览界面:
批量上传图片:
实现的功能介绍:
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); } }