<Android 开源库> PhotoPicker从头到脚

1. 简介

PhotoPicker, 是一款开源的图片选择器。效果上和微信相似。

2. 使用方法

2.1 添加依赖

1
2
3
4
5
6
7
8
9
dependencies {
compile 'me.iwf.photopicker:PhotoPicker:0.9.5@aar'
compile 'com.android.support:appcompat-v7:23.4.0'
compile 'com.android.support:recyclerview-v7:23.4.0'
compile 'com.android.support:design:23.4.0'
compile 'com.nineoldandroids:library:2.4.0'
compile 'com.github.bumptech.glide:glide:3.7.0'
}
  • appcompat-v7version >= 23.0.0

或者使用download源码,然后使用module依赖,我平时使用是这种方式。

1
2
3
4
5
dependencies {
...
compile project(':PhotoPicker')
...
}

2.2 代码集成

如下内容来自Github介绍

  • Pick Photo

    1
    2
    3
    4
    5
    6
    PhotoPicker.builder()
    .setPhotoCount(9)
    .setShowCamera(true)
    .setShowGif(true)
    .setPreviewEnabled(false)
    .start(this, PhotoPicker.REQUEST_CODE);
  • Preview Photo

    1
    2
    3
    4
    5
    6
    7
    ArrayList<String> photoPaths = ...;
    PhotoPreview.builder()
    .setPhotos(selectedPhotos)
    .setCurrentItem(position)
    .setShowDeleteButton(false)
    .start(MainActivity.this);
  • onActivityResult

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (resultCode == RESULT_OK && requestCode == PhotoPicker.REQUEST_CODE) {
    if (data != null) {
    ArrayList<String> photos =
    data.getStringArrayListExtra(PhotoPicker.KEY_SELECTED_PHOTOS);
    }
    }
    }
  • AndroidManifest.xml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
    >
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.CAMERA" />
    <application
    ...
    >
    ...
    <activity android:name="me.iwf.photopicker.PhotoPickerActivity"
    android:theme="@style/Theme.AppCompat.NoActionBar"
    />
    <activity android:name="me.iwf.photopicker.PhotoPagerActivity"
    android:theme="@style/Theme.AppCompat.NoActionBar"/>
    </application>
    </manifest>
  • Custom Style

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <style name="actionBarTheme" parent="ThemeOverlay.AppCompat.Dark.ActionBar">
    <item name="android:textColorPrimary">@android:color/primary_text_light</item>
    <item name="actionBarSize">@dimen/actionBarSize</item>
    </style>
    <style name="customTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="actionBarTheme">@style/actionBarTheme</item>
    <item name="colorPrimary">#FFA500</item>
    <item name="actionBarSize">@dimen/actionBarSize</item>
    <item name="colorPrimaryDark">#CCa500</item>
    </style>
  • ProGuard

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    # Glide
    -keep public class * implements com.bumptech.glide.module.GlideModule
    -keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
    **[] $VALUES;
    public *;
    }
    # nineoldandroids
    -keep interface com.nineoldandroids.view.** { *; }
    -dontwarn com.nineoldandroids.**
    -keep class com.nineoldandroids.** { *; }
    # support-v7-appcompat
    -keep public class android.support.v7.widget.** { *; }
    -keep public class android.support.v7.internal.widget.** { *; }
    -keep public class android.support.v7.internal.view.menu.** { *; }
    -keep public class * extends android.support.v4.view.ActionProvider {
    public <init>(android.content.Context);
    }
    # support-design
    -dontwarn android.support.design.**
    -keep class android.support.design.** { *; }
    -keep interface android.support.design.** { *; }
    -keep public class android.support.design.R$* { *; }

3. 源码分析

3.1 代码结构

这里写图片描述

  • 类说明(按照功能)
类名 描述
PhotoPicker 内部类PhotoPickerBuilder是关键,设置图片选择参数,启动PhotoPickerActivity均在此
PhotoPickerActivity 图片选择界面,两个Fragment:PhotoPickerFragment,ImagePagerFragment,一个用来图片选择,一个用来预览图片
PhotoPagerActivity 图片预览界面,和PhotoPickerActivity使用同样的布局文件,但是只有一个Fragment,ImagePagerFragment
PhotoPreview 内部类PhotoPreviewBuilder是关键,设置预览参数,启动PhotoPagerActivity均在此
PhotoPickerFragment 图片选择Fragment,在PhotoPickerActivity中使用到,Toolbar + RecyclerView + ListPopupWindow
ImagePagerFragment 图片预览Framgment,在PhotoPickerActivity中如果支持预览,点击图片后就会切换到此Fragment,单独使用PhotoPreview自然也是用的ImagePagerFragment
ImageCaptureManager 拍照管理类,当PhotoPicker中setShowCamera设为true后,点击拍照项,会调用系统相机拍照,相关方法实现均在ImageCaptureManager
PhotoGridAdapter 图片选择界面RecyclerView的 Adapter,瀑布流,主要因为它继承SelectableAdapter,平时开发有相同需求可以借鉴一些这个实现
PopupDirectoryListAdapter 底部图片分类文件夹ListPopupWindow的Adapter
MediaStoreHelper 图片数据查找Helper类,单独拿出来看,Loader的使用
SelectableAdapter 自定义用于选择的RecyclerView.Adapter,支持toggleSelection
Selectable Selectable接口,支持toggleSelection
PhotoPagerAdapter ImagePagerFragment中用于预览的ViewPager的Adapter
PhotoDirectory 图片目录对象,在PopupDirectoryListAdapter中使用到
Photo 图片对象,存放id和Path,分别对应数据库中图片_ID字段和DATA字段
OnItemCheckListener 图片选择框的点击事件接口
OnPhotoClickListener 图片点击事件接口,应该只有在图片选择器支持预览的情况下使用
AndroidLifecycleUtils 判断是否可以加载图片
FileUtils 文件处理工具类,只有一个判断文件是否存在的方法
PermissionsConstant 关于权限请求的部分常量
PermissionsUtils 权限请求工具类
PhotoDirectoryLoader 继承CursorLoader,从数据库中读取数据
SquareItemLayout 图片选择器Item布局
TouchImageView 预览图片自定义元件

3.2 源码设计思路

从代码结构和使用方法上来看,PhotoPicker是将图片选择作为一个单独的功能模块解耦出来,以Activity的形式进行PhotoPicker或者是PhotoPreview,在合适的位置创建Intent显示启动PhotoPagerAcitivty(预览)或者是PhotoPickerActivity(选择图片)。针对图片选择的场景,通过onActivityResult得到所选图片的Path。


这里写图片描述


  • PhotoPicker
方法 参数 描述
setPhotoCount(int photoCount) EXTRA_MAX_COUNT(“MAX_COUNT”) 设置可选的最大图片数量
setShowCamera(boolean showCamera) EXTRA_SHOW_CAMERA(“SHOW_CAMERA”) 是否显示拍照
setShowGif(boolean showGif) EXTRA_SHOW_GIF(“SHOW_GIF”) 是否显示gif图
setGridColumnCount(int columnCount) EXTRA_GRID_COLUMN(“column”) 设置图片选择网格的列数
setSelected(ArrayList< String> imagesUri) EXTRA_ORIGINAL_PHOTOS(“ORIGINAL_PHOTOS”) 已选照片
setPreviewEnabled(boolean previewEnabled) EXTRA_PREVIEW_ENABLED(“PREVIEW_ENABLED”) 图片网格视图中是否支持预览
参数 描述
KEY_SELECTED_PHOTOS(“SELECTED_PHOTOS”) 所选图片Path 列表

  • PhotoPreview
方法 参数 描述
setCurrentItem(int currentItem) EXTRA_CURRENT_ITEM(“current_item”) 设置预览界面当前显示图片序号
setPhotos(ArrayList< String> photoPaths) EXTRA_PHOTOS(“photos”) 设置预览图片列表,图片Path的ArrayList
setShowDeleteButton(boolean showDeleteButton) EXTRA_SHOW_DELETE(“show_delete”) 是否显示删除按钮

  • Build设计模式
    PhotoPicker和PhotoPreview都是采用的Build设计模式。利用构建者模式,可以清晰的管理参数,层次清晰,增加代码的可读性,Android源码系统中也有此模式的大量使用,如AlertDialog.Builder等等。
    PhotoPickerBuilder和PhotoPreviewBuilder正式采用的这种设计模式。

  • Loader机制
    loader机制,包括LoaderManager,Loader,LoaderCallbacks三部分,
    LoaderManager 来管理我们的laoder实例,获取来初始化,重启一个loader,
    Loader 来执行我们的异步操作,有开始,完成,后台等接口实现
    LoaderCallbacks 来执行我们的loader回调,主要是绑定分发Loader,完成加载,重置数据等
    MediaStoreHelper中只有一个方法getPhotoDirs,方法中使用
    activity.getSupportLoaderManager()
    .initLoader(0, args,
    new PhotoDirLoaderCallbacks(activity, resultCallback));
    的方式初始化Loader,然后在
    PhotoDirLoaderCallbacks实现
    LoaderManager.LoaderCallbacks< Cursor>接口。onCreateLoader方法中创建PhotoDirectoryLoader并传入参数,onLoadFinished返回后台数据库查询结果。

4. 备注

PhotoPicker,可以满足日常开发需求,代码结构非常清晰,可以直接根据自己的需求在源码上进行定制修改。感谢大神的开源精神。


个人微信公众号:Learning_Of_ALL,欢迎大家扫码关注,Android技术交流。


这里写图片描述

文章目录
  1. 1. 1. 简介
  2. 2. 2. 使用方法
    1. 2.1. 2.1 添加依赖
    2. 2.2. 2.2 代码集成
  3. 3. 3. 源码分析
    1. 3.1. 3.1 代码结构
    2. 3.2. 3.2 源码设计思路
  4. 4. 4. 备注
|