本文文字稍多,源碼下載地址在最后。
01 效果圖
主頁.png
選擇相冊.png
圖片預覽.png
02 用到的技術點
LoaderManager、Glide圖片加載框架、ButterKnife注解、easypermissions、RecyclerView、PopupWindow、ViewPager
03 一小部分關鍵代碼
圖片預覽的ViewPager public class PreviewViewPager extends ViewPager { private boolean mScrolling; private float touchDownY; private int mTouchSlop; public PreviewViewPager(Context context) { this(context, null); } public PreviewViewPager(Context context, AttributeSet attrs) { super(context, attrs); mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); } // 由于ViewPager Adapter的Item都有添加點擊事件,為了避免上下滑動和點擊事件的沖突做如下處理。 // 上下滑動時攔截事件,只有真正的點擊時才執行Item的點擊事件。 @Override public boolean onInterceptTouchEvent(MotionEvent ev) { boolean isBeingDragged = super.onInterceptTouchEvent(ev); switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: touchDownY = ev.getY(); mScrolling = false; break; case MotionEvent.ACTION_MOVE: if (Math.abs(touchDownY - ev.getY()) gt;= mTouchSlop) { mScrolling = true; } else{ mScrolling = false; } break; case MotionEvent.ACTION_UP: mScrolling = false; break; } return isBeingDragged ? isBeingDragged : mScrolling; } }
相冊主頁的Fragment public class AlbumFragment extends BaseFragment implements ImageLoaderListener, View.OnClickListener, BaseRecyclerAdapter.OnItemClickListener{ @BindView(R.id.rv_image) RecyclerView mContentView; @BindView(R.id.btn_title_select) Button mSelectFolderView; @BindView(R.id.iv_title_select) ImageView mSelectFolderIcon; @BindView(R.id.toolbar) View mToolbar; private LoaderListener mCursorLoader; private ImageFolderAdapter mImageFolderAdapter; private ImageAdapter mImageAdapter; private ImageFolderPopupWindow mFolderPopupWindow; private String[] mImageSources; @Override protected int getLayoutId() { return R.layout.fragment_select_image; } @Override protected void initWidget(View root) { super.initWidget(root); mContentView.setLayoutManager(new GridLayoutManager(getActivity(), 4)); mContentView.addItemDecoration(new SpaceGridItemDecoration((int) DeviceUtil.dipToPx(getResources(), 1))); mImageAdapter = new ImageAdapter(getContext(), this); mImageFolderAdapter = new ImageFolderAdapter(getContext(), this); mContentView.setAdapter(mImageAdapter); mContentView.setItemAnimator(null); mImageAdapter.setOnItemClickListener(this); } @Override protected void initData() { super.initData(); mCursorLoader = new LoaderListener(); getLoaderManager().initLoader(0, null, mCursorLoader); } @Override public void displayImage(ImageView iv, String path) { // Load image getImgLoader().load(path) .asBitmap() .centerCrop() .error(R.mipmap.ic_split_graph) .into(iv); } @OnClick({R.id.btn_title_select}) @Override public void onClick(View v) { switch (v.getId()) { case R.id.btn_title_select: showPopupFolderList(); break; } } /** * 創建彈出的相冊 */ private void showPopupFolderList() { if (mFolderPopupWindow == null) { ImageFolderPopupWindow popupWindow = new ImageFolderPopupWindow(getContext(), new ImageFolderPopupWindow.Callback() { @Override public void onSelect(ImageFolder imageFolder) { addImagesToAdapter(imageFolder.getImages()); } @Override public void onDismiss() { mSelectFolderIcon.setImageResource(R.mipmap.ic_arrow_bottom); } @Override public void onShow() { mSelectFolderIcon.setImageResource(R.mipmap.ic_arrow_top); } }); popupWindow.setAdapter(mImageFolderAdapter); mFolderPopupWindow = popupWindow; } mFolderPopupWindow.showAsDropDown(mToolbar); } @Override public void onItemClick(int position) { ImageGalleryActivity.show(getContext(), mImageSources, position); } private class LoaderListener implements LoaderManager.LoaderCallbackslt;Cursorgt; { private final String[] IMAGE_PROJECTION = { MediaStore.Images.Media.DATA, MediaStore.Images.Media.DISPLAY_NAME, MediaStore.Images.Media.DATE_ADDED, MediaStore.Images.Media._ID, MediaStore.Images.Media.MINI_THUMB_MAGIC, MediaStore.Images.Media.BUCKET_DISPLAY_NAME}; @Override public Loaderlt;Cursorgt; onCreateLoader(int id, Bundle args) { if (id == 0) { //數據庫光標加載器 return new CursorLoader(getContext(), MediaStore.Images.Media.EXTERNAL_CONTENT_URI, IMAGE_PROJECTION, null, null, IMAGE_PROJECTION[2] quot; DESCquot;); } return null; } @Override public void onLoadFinished(Loaderlt;Cursorgt; loader, Cursor data) { if (data != null) { final ArrayListlt;Imagegt; images = new ArrayListlt;gt;(); final Listlt;ImageFoldergt; imageFolders = new ArrayListlt;gt;(); final ImageFolder defaultFolder = new ImageFolder(); defaultFolder.setName(quot;全部照片quot;); defaultFolder.setPath(quot;quot;); imageFolders.add(defaultFolder); int count = data.getCount(); if (count gt; 0) { data.moveToFirst(); do { String path = data.getString(data.getColumnIndexOrThrow(IMAGE_PROJECTION[0])); String name = data.getString(data.getColumnIndexOrThrow(IMAGE_PROJECTION[1])); long dateTime = data.getLong(data.getColumnIndexOrThrow(IMAGE_PROJECTION[2])); int id = data.getInt(data.getColumnIndexOrThrow(IMAGE_PROJECTION[3])); String thumbPath = data.getString(data.getColumnIndexOrThrow(IMAGE_PROJECTION[4])); String bucket = data.getString(data.getColumnIndexOrThrow(IMAGE_PROJECTION[5])); Image image = new Image(); image.setPath(path); image.setName(name); image.setDate(dateTime); image.setId(id); image.setThumbPath(thumbPath); image.setFolderName(bucket); images.add(image); File imageFile = new File(path); File folderFile = imageFile.getParentFile(); ImageFolder folder = new ImageFolder(); folder.setName(folderFile.getName()); folder.setPath(folderFile.getAbsolutePath()); if (!imageFolders.contains(folder)) { folder.getImages().add(image); folder.setAlbumPath(image.getPath());//默認相冊封面 imageFolders.add(folder); } else { // 更新 ImageFolder f = imageFolders.get(imageFolders.indexOf(folder)); f.getImages().add(image); } } while (data.moveToNext()); } addImagesToAdapter(images); defaultFolder.getImages().addAll(images); defaultFolder.setAlbumPath(images.size() gt; 0 ? images.get(0).getPath() : null); mImageFolderAdapter.resetItem(imageFolders); } } @Override public void onLoaderReset(Loaderlt;Cursorgt; loader) { } } private void addImagesToAdapter(ArrayListlt;Imagegt; images) { mImageAdapter.resetItem(images); mImageSources = toArray(images); } private static String[] toArray(Listlt;Imagegt; images) { if (images == null) return null; int len = images.size(); if (len == 0) return null; String[] strings = new String[len]; int i = 0; for (Image image : images) { strings[i] = image.getPath(); i ; } return strings; } }
圖片文件夾選擇(PopupWindow) public class ImageFolderPopupWindow extends PopupWindow implements View.OnAttachStateChangeListener, BaseRecyclerAdapter.OnItemClickListener{ private ImageFolderAdapter mAdapter; private RecyclerView mFolderView; private Callback mCallback; public ImageFolderPopupWindow(Context context, Callback callback) { super(LayoutInflater.from(context).inflate(R.layout.popup_window_folder, null), ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); mCallback = callback; // init setAnimationStyle(R.style.popup_anim_style_alpha); setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); setOutsideTouchable(true); setFocusable(true); // content View content = getContentView(); content.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { dismiss(); } }); content.addOnAttachStateChangeListener(this); mFolderView = (RecyclerView) content.findViewById(R.id.rv_popup_folder); mFolderView.setLayoutManager(new LinearLayoutManager(context)); } public void setAdapter(ImageFolderAdapter adapter) { this.mAdapter = adapter; mFolderView.setAdapter(adapter); mAdapter.setOnItemClickListener(this); } @Override public void onItemClick(int position) { if (mCallback != null) mCallback.onSelect(mAdapter.getItem(position)); dismiss(); } @Override public void onViewAttachedToWindow(View v) { if(mCallback != null) mCallback.onShow(); } @Override public void onViewDetachedFromWindow(View v) { if(mCallback != null) mCallback.onDismiss(); } public interface Callback { void onSelect(ImageFolder imageFolder); void onDismiss(); void onShow(); } }
04 源碼
源碼 下載地址 。
05 PhotoAlbum apk
PhotoAlbum apk 下載地址 。
Tags: 安卓開發
文章來源:http://www.jianshu.com/p/aba7e513dfa4