├── application
├── .gitignore
├── src
│ └── main
│ │ ├── res
│ │ ├── values
│ │ │ └── strings.xml
│ │ └── layout
│ │ │ └── layout_example_activity.xml
│ │ ├── java
│ │ └── com
│ │ │ └── iknow
│ │ │ └── imageselect
│ │ │ └── application
│ │ │ └── ExampleActivity.java
│ │ └── AndroidManifest.xml
├── build.gradle
└── proguard-rules.pro
├── business
├── .gitignore
├── src
│ └── main
│ │ ├── res
│ │ └── values
│ │ │ └── strings.xml
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ └── rawe
│ │ └── gordon
│ │ └── com
│ │ └── business
│ │ └── ZApplication.java
├── build.gradle
└── proguard-rules.pro
├── image-selector
├── .gitignore
├── src
│ └── main
│ │ ├── AndroidManifest.xml
│ │ ├── res
│ │ ├── drawable-hdpi
│ │ │ ├── icon_back.png
│ │ │ ├── video_icon.png
│ │ │ ├── ic_launcher.png
│ │ │ ├── img_pic_selected.png
│ │ │ └── img_pic_unselected.png
│ │ ├── values
│ │ │ ├── strings.xml
│ │ │ ├── dimens.xml
│ │ │ ├── colors.xml
│ │ │ ├── styles.xml
│ │ │ └── attrs.xml
│ │ ├── drawable
│ │ │ ├── ic_arrow_back.xml
│ │ │ ├── ic_play_circle.xml
│ │ │ ├── ic_choosable.xml
│ │ │ ├── ic_radio_button_unchecked.xml
│ │ │ ├── ic_chosen.xml
│ │ │ └── ic_radio_button_checked.xml
│ │ └── layout
│ │ │ ├── layout_photo_view_item.xml
│ │ │ ├── image_select_item.xml
│ │ │ ├── ablum_list_view_item.xml
│ │ │ ├── abs_image_select_layout.xml
│ │ │ └── layout_browse_detail_activity.xml
│ │ └── java
│ │ └── com
│ │ └── iknow
│ │ └── imageselect
│ │ ├── view
│ │ └── IImageChooseView.java
│ │ ├── core
│ │ └── CoreActivity.java
│ │ ├── model
│ │ ├── AlbumInfo.java
│ │ └── MediaInfo.java
│ │ ├── utils
│ │ ├── DrawableUtil.java
│ │ ├── DeviceInforHelper.java
│ │ ├── CacheBean.java
│ │ ├── PhotoDraweeViewUtil.java
│ │ ├── ImageFilePathUtil.java
│ │ └── MediaFileUtil.java
│ │ ├── presenter
│ │ ├── IImageChoosePresenter.java
│ │ └── ImageChoosePresenterCompl.java
│ │ ├── photodraweeview
│ │ ├── OnScaleChangeListener.java
│ │ ├── OnViewTapListener.java
│ │ ├── OnPhotoTapListener.java
│ │ ├── OnScaleDragGestureListener.java
│ │ ├── IAttacher.java
│ │ ├── DefaultOnDoubleTapListener.java
│ │ ├── PhotoDraweeView.java
│ │ ├── ScaleDragDetector.java
│ │ └── Attacher.java
│ │ ├── ImageSelectContextHolder.java
│ │ ├── widget
│ │ ├── SpacesItemDecoration.java
│ │ ├── PicItemCheckedView.java
│ │ └── TitleView.java
│ │ ├── adapter
│ │ └── AlbumListAdapter.java
│ │ ├── configs
│ │ └── ImagePipelineConfigFactory.java
│ │ └── activities
│ │ ├── MultiSelectImageActivity.java
│ │ ├── SingleSelectImageActivity.java
│ │ ├── AbsImageSelectActivity.java
│ │ └── BrowseDetailActivity.java
├── proguard-rules.pro
└── build.gradle
├── settings.gradle
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── .gitignore
├── README.md
├── shared.gradle
├── gradle.properties
├── gradlew.bat
├── gradlew
└── LICENSE
/application/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/business/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/image-selector/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':image-selector', ':application', ':business'
2 |
--------------------------------------------------------------------------------
/image-selector/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/business/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Business
3 |
4 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iKnown/AndroidImagePicker/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/workspace.xml
5 | /.idea/libraries
6 | .DS_Store
7 | /build
8 | /captures
9 | .idea
10 | build
11 |
--------------------------------------------------------------------------------
/image-selector/src/main/res/drawable-hdpi/icon_back.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iKnown/AndroidImagePicker/HEAD/image-selector/src/main/res/drawable-hdpi/icon_back.png
--------------------------------------------------------------------------------
/image-selector/src/main/res/drawable-hdpi/video_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iKnown/AndroidImagePicker/HEAD/image-selector/src/main/res/drawable-hdpi/video_icon.png
--------------------------------------------------------------------------------
/image-selector/src/main/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iKnown/AndroidImagePicker/HEAD/image-selector/src/main/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/image-selector/src/main/res/drawable-hdpi/img_pic_selected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iKnown/AndroidImagePicker/HEAD/image-selector/src/main/res/drawable-hdpi/img_pic_selected.png
--------------------------------------------------------------------------------
/image-selector/src/main/res/drawable-hdpi/img_pic_unselected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iKnown/AndroidImagePicker/HEAD/image-selector/src/main/res/drawable-hdpi/img_pic_unselected.png
--------------------------------------------------------------------------------
/image-selector/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | 确认
3 | 选择
4 | 原图
5 |
6 |
--------------------------------------------------------------------------------
/image-selector/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 52dp
4 | 14dp
5 |
--------------------------------------------------------------------------------
/application/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Pop Chooser
3 | please click to choose a picture...
4 |
5 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | ### 本项目是一个类似Android微信图片选择的项目
3 | ### 使用到的相关库和代码结构
4 | * MVP设计模式
5 | * fresco图片加载库
6 | * 图片和视频的查询操作
7 |
8 |
9 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Dec 28 10:00:20 PST 2015
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip
7 |
--------------------------------------------------------------------------------
/image-selector/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #2B3131
4 | #2B3131
5 | #FF4081
6 | #2B3131
7 |
8 |
--------------------------------------------------------------------------------
/business/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/image-selector/src/main/java/com/iknow/imageselect/view/IImageChooseView.java:
--------------------------------------------------------------------------------
1 | package com.iknow.imageselect.view;
2 |
3 | /**
4 | * Author: J.Chou
5 | * Email: who_know_me@163.com
6 | * Created: 2016年04月06日 6:40 PM
7 | * Description:
8 | */
9 |
10 | public interface IImageChooseView {
11 | void reloadData();
12 | }
13 |
--------------------------------------------------------------------------------
/application/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | apply from: rootDir.path + '/shared.gradle'
3 |
4 | android {
5 | defaultConfig {
6 | applicationId 'org.iknown'
7 | }
8 | }
9 |
10 | dependencies {
11 | compile fileTree(dir: 'libs', include: ['*.jar'])
12 | compile project(':business')
13 | }
14 |
--------------------------------------------------------------------------------
/image-selector/src/main/java/com/iknow/imageselect/core/CoreActivity.java:
--------------------------------------------------------------------------------
1 | package com.iknow.imageselect.core;
2 |
3 | import android.support.v7.app.AppCompatActivity;
4 |
5 | /**
6 | * Author: Jason.Chou
7 | * Email: who_know_me@163.com
8 | * Created: 2016年04月26日 5:08 PM
9 | * Description:
10 | */
11 | public class CoreActivity extends AppCompatActivity {
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/image-selector/src/main/java/com/iknow/imageselect/model/AlbumInfo.java:
--------------------------------------------------------------------------------
1 | package com.iknow.imageselect.model;
2 |
3 | import java.util.ArrayList;
4 |
5 | /**
6 | * Author: J.Chou
7 | * Email: who_know_me@163.com
8 | * Created: 2016年04月06日 4:27 PM
9 | * Description:相册专辑类
10 | */
11 |
12 | public class AlbumInfo extends MediaInfo {
13 | public ArrayList medias;
14 | }
15 |
--------------------------------------------------------------------------------
/image-selector/src/main/res/drawable/ic_arrow_back.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/image-selector/src/main/res/drawable/ic_play_circle.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/image-selector/src/main/res/drawable/ic_choosable.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/image-selector/src/main/res/drawable/ic_radio_button_unchecked.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/image-selector/src/main/java/com/iknow/imageselect/utils/DrawableUtil.java:
--------------------------------------------------------------------------------
1 | package com.iknow.imageselect.utils;
2 |
3 | import android.content.Context;
4 | import android.graphics.drawable.Drawable;
5 | import android.support.v7.widget.AppCompatDrawableManager;
6 |
7 | /**
8 | * Created by gordon on 5/9/16.
9 | */
10 | public class DrawableUtil {
11 | public static Drawable decodeFromVector(Context context, int resId) {
12 | return AppCompatDrawableManager.get().getDrawable(context, resId);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/image-selector/src/main/res/drawable/ic_chosen.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/image-selector/src/main/java/com/iknow/imageselect/presenter/IImageChoosePresenter.java:
--------------------------------------------------------------------------------
1 | package com.iknow.imageselect.presenter;
2 |
3 | import com.iknow.imageselect.model.MediaInfo;
4 | import java.util.ArrayList;
5 |
6 | /**
7 | * Author: J.Chou
8 | * Email: who_know_me@163.com
9 | * Created: 2016年04月06日 6:37 PM
10 | * Description:
11 | */
12 |
13 | public interface IImageChoosePresenter {
14 | void doCancel();
15 | String takePhotos();
16 | void doSendAction();
17 | void doPreview(ArrayList hasCheckedImages);
18 | }
19 |
--------------------------------------------------------------------------------
/image-selector/src/main/res/drawable/ic_radio_button_checked.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/shared.gradle:
--------------------------------------------------------------------------------
1 | android {
2 | compileSdkVersion 23
3 | buildToolsVersion "23.0.2"
4 |
5 | android {
6 | defaultConfig {
7 | minSdkVersion 14
8 | targetSdkVersion 23
9 | versionCode 1
10 | versionName "1.0"
11 | }
12 |
13 | lintOptions {
14 | abortOnError false
15 | checkReleaseBuilds = false
16 | }
17 | }
18 |
19 | buildTypes {
20 | release {
21 | minifyEnabled false
22 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
23 | }
24 | }
25 | }
--------------------------------------------------------------------------------
/image-selector/src/main/java/com/iknow/imageselect/photodraweeview/OnScaleChangeListener.java:
--------------------------------------------------------------------------------
1 | package com.iknow.imageselect.photodraweeview;
2 |
3 | /**
4 | * Interface definition for callback to be invoked when attached ImageView scale changes
5 | *
6 | * @author Marek Sebera
7 | */
8 | public interface OnScaleChangeListener {
9 | /**
10 | * Callback for when the scale changes
11 | *
12 | * @param scaleFactor the scale factor
13 | * @param focusX focal point X position
14 | * @param focusY focal point Y position
15 | */
16 | void onScaleChange(float scaleFactor, float focusX, float focusY);
17 | }
18 |
--------------------------------------------------------------------------------
/business/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 23
5 | buildToolsVersion "23.0.2"
6 |
7 | defaultConfig {
8 | minSdkVersion 14
9 | targetSdkVersion 23
10 | versionCode 1
11 | versionName "1.0"
12 | }
13 | buildTypes {
14 | release {
15 | minifyEnabled false
16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
17 | }
18 | }
19 | }
20 |
21 | dependencies {
22 | compile fileTree(dir: 'libs', include: ['*.jar'])
23 | compile project(':image-selector')
24 | compile 'com.android.support:appcompat-v7:23.3.0'
25 | }
26 |
--------------------------------------------------------------------------------
/business/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/gordon/Space/sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/application/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/gordon/Space/sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/image-selector/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/choujason/AndroidStudioSDK/android-sdk-macosx/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/image-selector/src/main/java/com/iknow/imageselect/photodraweeview/OnViewTapListener.java:
--------------------------------------------------------------------------------
1 | package com.iknow.imageselect.photodraweeview;
2 |
3 | import android.view.View;
4 |
5 | /**
6 | * Interface definition for a callback to be invoked when the ImageView is tapped with a single
7 | * tap.
8 | *
9 | * @author Chris Banes
10 | */
11 | public interface OnViewTapListener {
12 | /**
13 | * A callback to receive where the user taps on a ImageView. You will receive a callback if
14 | * the user taps anywhere on the view, tapping on 'whitespace' will not be ignored.
15 | *
16 | * @param view - View the user tapped.
17 | * @param x - where the user tapped from the left of the View.
18 | * @param y - where the user tapped from the top of the View.
19 | */
20 | void onViewTap(View view, float x, float y);
21 | }
--------------------------------------------------------------------------------
/image-selector/src/main/java/com/iknow/imageselect/ImageSelectContextHolder.java:
--------------------------------------------------------------------------------
1 | package com.iknow.imageselect;
2 |
3 | import android.content.Context;
4 |
5 | /**
6 | * Created by gordon on 8/1/16.
7 | */
8 | public class ImageSelectContextHolder {
9 | private Context context;
10 |
11 | private ImageSelectContextHolder() {
12 | }
13 |
14 | private static class Holder {
15 | private static ImageSelectContextHolder instance = new ImageSelectContextHolder();
16 | }
17 |
18 | public static ImageSelectContextHolder getInstance() {
19 | return Holder.instance;
20 | }
21 |
22 | public void init(Context context) {
23 | this.context = context;
24 | }
25 |
26 | public Context getContext() {
27 | return context;
28 | }
29 |
30 | public void setContext(Context context) {
31 | this.context = context;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
--------------------------------------------------------------------------------
/business/src/main/java/rawe/gordon/com/business/ZApplication.java:
--------------------------------------------------------------------------------
1 | package rawe.gordon.com.business;
2 |
3 | import android.app.Application;
4 | import com.facebook.drawee.backends.pipeline.Fresco;
5 | import com.iknow.imageselect.ImageSelectContextHolder;
6 | import com.iknow.imageselect.configs.ImagePipelineConfigFactory;
7 |
8 | /**
9 | * Author: Jason.Chou
10 | * Email: who_know_me@163.com
11 | * Created: 2016年04月26日 4:54 PM
12 | * Description:
13 | */
14 | public class ZApplication extends Application{
15 |
16 | private static ZApplication mApplication;
17 | public static ZApplication getApplication() {
18 | return mApplication;
19 | }
20 |
21 | @Override public void onCreate() {
22 | super.onCreate();
23 | mApplication = this;
24 | Fresco.initialize(this, ImagePipelineConfigFactory.getImagePipelineConfig(this));
25 | ImageSelectContextHolder.getInstance().init(getApplicationContext());
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/image-selector/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply from: rootDir.path + '/shared.gradle'
3 | apply plugin: 'com.novoda.bintray-release'
4 |
5 |
6 | publish {
7 | artifactId = 'image-selector'//模块名称
8 | userOrg = rootProject.userOrg
9 | groupId = rootProject.groupId
10 | uploadName = rootProject.uploadName //模块上传后所在的文件夹名称
11 | publishVersion = rootProject.publishVersion//模块版本号
12 | desc = rootProject.description//模块的描述
13 | website = rootProject.website //模块的网站
14 | licences = rootProject.licences //模块的licences
15 | }
16 |
17 | dependencies {
18 | compile fileTree(dir: 'libs', include: ['*.jar'])
19 | compile 'com.android.support:appcompat-v7:23.3.0'
20 | compile 'com.android.support:recyclerview-v7:23.3.0'
21 | compile 'com.android.support:cardview-v7:23.3.0'
22 | compile 'com.facebook.fresco:fresco:0.10.0'
23 | compile 'com.github.chrisbanes:PhotoView:1.2.6'
24 | }
25 |
--------------------------------------------------------------------------------
/image-selector/src/main/java/com/iknow/imageselect/photodraweeview/OnPhotoTapListener.java:
--------------------------------------------------------------------------------
1 | package com.iknow.imageselect.photodraweeview;
2 |
3 | import android.view.View;
4 |
5 | /**
6 | * Interface definition for a callback to be invoked when the Photo is tapped with a single
7 | * tap.
8 | *
9 | * @author Chris Banes
10 | */
11 | public interface OnPhotoTapListener {
12 |
13 | /**
14 | * A callback to receive where the user taps on a photo. You will only receive a callback if
15 | * the user taps on the actual photo, tapping on 'whitespace' will be ignored.
16 | *
17 | * @param view - View the user tapped.
18 | * @param x - where the user tapped from the of the Drawable, as percentage of the
19 | * Drawable width.
20 | * @param y - where the user tapped from the top of the Drawable, as percentage of the
21 | * Drawable height.
22 | */
23 | void onPhotoTap(View view, float x, float y);
24 | }
25 |
--------------------------------------------------------------------------------
/application/src/main/res/layout/layout_example_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
14 |
15 |
21 |
22 |
--------------------------------------------------------------------------------
/image-selector/src/main/java/com/iknow/imageselect/widget/SpacesItemDecoration.java:
--------------------------------------------------------------------------------
1 | package com.iknow.imageselect.widget;
2 |
3 | import android.graphics.Rect;
4 | import android.support.v7.widget.RecyclerView;
5 | import android.view.View;
6 |
7 | /**
8 | * Author: Jason.Chou
9 | * Email: who_know_me@163.com
10 | * Created: 2016年05月04日 11:27 AM
11 | * Description:
12 | */
13 | public class SpacesItemDecoration extends RecyclerView.ItemDecoration{
14 |
15 | private int halfSpace;
16 |
17 | public SpacesItemDecoration(int space) {
18 | this.halfSpace = space / 2;
19 | }
20 |
21 | @Override
22 | public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
23 |
24 | if (parent.getPaddingLeft() != halfSpace) {
25 | parent.setPadding(halfSpace, halfSpace, halfSpace, halfSpace);
26 | parent.setClipToPadding(false);
27 | }
28 |
29 | outRect.top = halfSpace;
30 | outRect.bottom = halfSpace;
31 | outRect.left = halfSpace;
32 | outRect.right = halfSpace;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/application/src/main/java/com/iknow/imageselect/application/ExampleActivity.java:
--------------------------------------------------------------------------------
1 | package com.iknow.imageselect.application;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 | import android.support.annotation.Nullable;
6 | import android.support.v7.app.AppCompatActivity;
7 | import android.view.View;
8 |
9 | import com.iknow.imageselect.activities.MultiSelectImageActivity;
10 |
11 | /**
12 | * Created by gordon on 5/10/16.
13 | */
14 | public class ExampleActivity extends AppCompatActivity implements View.OnClickListener {
15 |
16 | @Override
17 | protected void onCreate(@Nullable Bundle savedInstanceState) {
18 | super.onCreate(savedInstanceState);
19 | setContentView(R.layout.layout_example_activity);
20 | findViewById(R.id.card).setOnClickListener(this);
21 | }
22 |
23 | @Override
24 | public void onClick(View view) {
25 | if (view.getId() == R.id.card) {
26 | Intent intent = new Intent(this, MultiSelectImageActivity.class);
27 | startActivity(intent);
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/image-selector/src/main/java/com/iknow/imageselect/model/MediaInfo.java:
--------------------------------------------------------------------------------
1 | package com.iknow.imageselect.model;
2 |
3 | import java.io.Serializable;
4 |
5 | /**
6 | * Author: J.Chou
7 | * Email: who_know_me@163.com
8 | * Created: 2016年04月06日 3:17 PM
9 | * Description:
10 | */
11 |
12 | public class MediaInfo implements Serializable,Cloneable {
13 |
14 | public long fileId;
15 | /** 图片显示的名称 */
16 | public String name = "";
17 | /** 作者名称 */
18 | public String author = "";
19 | /** 图片描述信息 */
20 | public String description = "";
21 |
22 | public String filePath;//图片所在文件夹的路径
23 |
24 | public String createTime;
25 |
26 | public String thumbPath;//缩略图路径
27 |
28 | public String fileName;//图片全路径,包含图片文件名的路径信息
29 |
30 | public int rotate;
31 |
32 | public String lat;
33 |
34 | public String lon;
35 |
36 | public int mediaType;
37 |
38 | public static MediaInfo obtain(String path){
39 | MediaInfo imageInfo = new MediaInfo();
40 | imageInfo.fileName = path;
41 | return imageInfo;
42 | }
43 |
44 | public static MediaInfo buildOneImage(String path){
45 |
46 | return null;
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/image-selector/src/main/res/layout/layout_photo_view_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
10 |
11 |
18 |
19 |
29 |
--------------------------------------------------------------------------------
/image-selector/src/main/java/com/iknow/imageselect/utils/DeviceInforHelper.java:
--------------------------------------------------------------------------------
1 | package com.iknow.imageselect.utils;
2 |
3 | import android.util.DisplayMetrics;
4 | import android.util.TypedValue;
5 |
6 | import com.iknow.imageselect.ImageSelectContextHolder;
7 |
8 | /**
9 | * Author: Jason.Chou
10 | * Email: who_know_me@163.com
11 | * Created: 2016年04月26日 4:13 PM
12 | * Description:
13 | */
14 | public class DeviceInforHelper {
15 |
16 | public static int getPixelFromDip(float f) {
17 | return getPixelFromDip(ImageSelectContextHolder.getInstance().getContext().getResources().getDisplayMetrics(), f);
18 | }
19 |
20 | public static int getPixelFromDip(DisplayMetrics dm, float dip) {
21 | return (int) (TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip, dm) + 0.5f);
22 | }
23 |
24 | public static int getScreenWidth() {
25 | return ImageSelectContextHolder.getInstance().getContext().getResources().getDisplayMetrics().widthPixels;
26 | }
27 |
28 | public static int getScreenHeight() {
29 | return ImageSelectContextHolder.getInstance().getContext().getResources().getDisplayMetrics().heightPixels;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/image-selector/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
15 |
16 |
20 |
24 |
25 |
29 |
30 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/image-selector/src/main/java/com/iknow/imageselect/photodraweeview/OnScaleDragGestureListener.java:
--------------------------------------------------------------------------------
1 | package com.iknow.imageselect.photodraweeview;
2 |
3 | /**
4 | * ****************************************************************************
5 | * Copyright 2011, 2012 Chris Banes.
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | * *****************************************************************************
19 | */
20 |
21 | public interface OnScaleDragGestureListener {
22 | void onDrag(float dx, float dy);
23 |
24 | void onFling(float startX, float startY, float velocityX, float velocityY);
25 |
26 | void onScale(float scaleFactor, float focusX, float focusY);
27 |
28 | void onScaleEnd();
29 | }
30 |
--------------------------------------------------------------------------------
/image-selector/src/main/java/com/iknow/imageselect/utils/CacheBean.java:
--------------------------------------------------------------------------------
1 | package com.iknow.imageselect.utils;
2 |
3 | import java.util.HashMap;
4 | import java.util.Map;
5 |
6 | public class CacheBean {
7 |
8 | private static Map cacheBeanMap = new HashMap();
9 |
10 | private static Map> paramMap = new HashMap>();
11 |
12 | public static void putParam(String token, String key, Object value) {
13 | Map params = paramMap.get(token);
14 | if (params == null) {
15 | params = new HashMap();
16 | }
17 | params.put(key, value);
18 | paramMap.put(token, params);
19 | }
20 |
21 | public static Object getParam(String token, String key) {
22 | Map params = paramMap.get(token);
23 | if (params == null) {
24 | return null;
25 | }
26 | return params.get(key);
27 | }
28 |
29 | public static void clean(String token) {
30 | cacheBeanMap.remove(token);
31 | paramMap.remove(token);
32 | }
33 |
34 | public static CacheBean get(String token) {
35 | CacheBean commonCacheBean = cacheBeanMap.get(token);
36 | if (commonCacheBean == null) {
37 | commonCacheBean = new CacheBean();
38 | cacheBeanMap.put(token, commonCacheBean);
39 | }
40 | return commonCacheBean;
41 | }
42 |
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/image-selector/src/main/java/com/iknow/imageselect/utils/PhotoDraweeViewUtil.java:
--------------------------------------------------------------------------------
1 | package com.iknow.imageselect.utils;
2 |
3 | import android.graphics.drawable.Animatable;
4 | import android.net.Uri;
5 |
6 | import com.facebook.drawee.backends.pipeline.Fresco;
7 | import com.facebook.drawee.backends.pipeline.PipelineDraweeControllerBuilder;
8 | import com.facebook.drawee.controller.BaseControllerListener;
9 | import com.facebook.imagepipeline.image.ImageInfo;
10 |
11 | import com.iknow.imageselect.photodraweeview.PhotoDraweeView;
12 |
13 | /**
14 | * Created by gordon on 5/9/16.
15 | */
16 | public class PhotoDraweeViewUtil {
17 | public static void display(final PhotoDraweeView draweeView, Uri uri) {
18 | PipelineDraweeControllerBuilder controller = Fresco.newDraweeControllerBuilder();
19 | controller.setUri(uri);
20 | controller.setOldController(draweeView.getController());
21 | controller.setControllerListener(new BaseControllerListener() {
22 | @Override
23 | public void onFinalImageSet(String id, ImageInfo imageInfo, Animatable animatable) {
24 | super.onFinalImageSet(id, imageInfo, animatable);
25 | if (imageInfo == null || draweeView == null) {
26 | return;
27 | }
28 | draweeView.update(imageInfo.getWidth(), imageInfo.getHeight());
29 | }
30 | });
31 | draweeView.setController(controller.build());
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/image-selector/src/main/res/layout/image_select_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
13 |
14 |
21 |
29 |
37 |
38 |
39 |
48 |
--------------------------------------------------------------------------------
/application/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
15 |
16 |
21 |
22 |
27 |
28 |
34 |
35 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/image-selector/src/main/res/layout/ablum_list_view_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
17 |
18 |
26 |
27 |
35 |
36 |
43 |
44 |
45 |
52 |
53 |
61 |
62 |
--------------------------------------------------------------------------------
/image-selector/src/main/java/com/iknow/imageselect/photodraweeview/IAttacher.java:
--------------------------------------------------------------------------------
1 | package com.iknow.imageselect.photodraweeview;
2 |
3 | import android.view.GestureDetector;
4 | import android.view.View;
5 |
6 | /**
7 | * ****************************************************************************
8 | * Copyright 2011, 2012 Chris Banes.
9 | *
10 | * Licensed under the Apache License, Version 2.0 (the "License");
11 | * you may not use this file except in compliance with the License.
12 | * You may obtain a copy of the License at
13 | *
14 | * http://www.apache.org/licenses/LICENSE-2.0
15 | *
16 | * Unless required by applicable law or agreed to in writing, software
17 | * distributed under the License is distributed on an "AS IS" BASIS,
18 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 | * See the License for the specific language governing permissions and
20 | * limitations under the License.
21 | * *****************************************************************************
22 | */
23 |
24 | public interface IAttacher {
25 |
26 | public static final float DEFAULT_MAX_SCALE = 3.0f;
27 | public static final float DEFAULT_MID_SCALE = 1.75f;
28 | public static final float DEFAULT_MIN_SCALE = 1.0f;
29 | public static final long ZOOM_DURATION = 200L;
30 |
31 | float getMinimumScale();
32 |
33 | float getMediumScale();
34 |
35 | float getMaximumScale();
36 |
37 | void setMaximumScale(float maximumScale);
38 |
39 | void setMediumScale(float mediumScale);
40 |
41 | void setMinimumScale(float minimumScale);
42 |
43 | float getScale();
44 |
45 | void setScale(float scale);
46 |
47 | void setScale(float scale, boolean animate);
48 |
49 | void setScale(float scale, float focalX, float focalY, boolean animate);
50 |
51 | void setZoomTransitionDuration(long duration);
52 |
53 | void setAllowParentInterceptOnEdge(boolean allow);
54 |
55 | void setOnDoubleTapListener(GestureDetector.OnDoubleTapListener listener);
56 |
57 | void setOnScaleChangeListener(OnScaleChangeListener listener);
58 |
59 | void setOnLongClickListener(View.OnLongClickListener listener);
60 |
61 | void setOnPhotoTapListener(OnPhotoTapListener listener);
62 |
63 | void setOnViewTapListener(OnViewTapListener listener);
64 |
65 | OnPhotoTapListener getOnPhotoTapListener();
66 |
67 | OnViewTapListener getOnViewTapListener();
68 |
69 | void update(int imageInfoWidth, int imageInfoHeight);
70 | }
71 |
--------------------------------------------------------------------------------
/image-selector/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/image-selector/src/main/java/com/iknow/imageselect/presenter/ImageChoosePresenterCompl.java:
--------------------------------------------------------------------------------
1 | package com.iknow.imageselect.presenter;
2 |
3 | import android.app.Activity;
4 | import android.content.Intent;
5 | import android.net.Uri;
6 | import android.os.Environment;
7 | import android.provider.MediaStore;
8 | import android.text.format.DateFormat;
9 | import android.widget.Toast;
10 |
11 | import com.iknow.imageselect.ImageSelectContextHolder;
12 | import com.iknow.imageselect.activities.AbsImageSelectActivity;
13 | import com.iknow.imageselect.activities.BrowseDetailActivity;
14 | import com.iknow.imageselect.model.MediaInfo;
15 | import com.iknow.imageselect.view.IImageChooseView;
16 | import java.io.File;
17 | import java.util.ArrayList;
18 | import java.util.Calendar;
19 | import java.util.Locale;
20 |
21 | /**
22 | * Author: J.Chou
23 | * Email: who_know_me@163.com
24 | * Created: 2016年04月06日 6:38 PM
25 | * Description:
26 | */
27 |
28 | public class ImageChoosePresenterCompl implements IImageChoosePresenter {
29 |
30 | Activity context;
31 | IImageChooseView imageChooseView;
32 | String mCameraImagePath;
33 |
34 | public ImageChoosePresenterCompl(Activity context, IImageChooseView chooseView) {
35 | this.context = context;
36 | this.imageChooseView = chooseView;
37 | }
38 |
39 | @Override
40 | public void doCancel() {
41 | context.finish();
42 | }
43 |
44 | @Override
45 | public String takePhotos() {
46 | try {
47 | final Intent intent = new Intent();
48 | final String dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).getAbsolutePath() + "/";
49 | final File f = new File(dir);
50 | if (!f.exists()) {
51 | f.mkdir();
52 | }
53 |
54 | mCameraImagePath = dir + DateFormat.format("yyyyMMdd_hhmmss", Calendar.getInstance(Locale.CHINA)) + ".jpg";
55 | final File f1 = new File(mCameraImagePath);
56 | final Uri uri = Uri.fromFile(f1);
57 |
58 | intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
59 | intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
60 | if (intent.resolveActivity(ImageSelectContextHolder.getInstance().getContext().getPackageManager()) != null) {
61 | context.startActivityForResult(intent, AbsImageSelectActivity.PHOTO_REQUEST_CAMERA);
62 | }
63 | } catch (Throwable e) {
64 | e.printStackTrace();
65 | Toast.makeText(context, "启动相机失败,请重试", Toast.LENGTH_LONG).show();
66 | }
67 |
68 | return mCameraImagePath;
69 | }
70 |
71 | @Override public void doSendAction() {
72 |
73 | }
74 |
75 | @Override public void doPreview(ArrayList hasCheckedImages) {
76 | if(hasCheckedImages.isEmpty())
77 | return;
78 | BrowseDetailActivity.goToBrowseDetailActivitySelected(context,hasCheckedImages);
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/image-selector/src/main/java/com/iknow/imageselect/photodraweeview/DefaultOnDoubleTapListener.java:
--------------------------------------------------------------------------------
1 | package com.iknow.imageselect.photodraweeview;
2 |
3 | import android.graphics.RectF;
4 | import android.view.GestureDetector;
5 | import android.view.MotionEvent;
6 |
7 | import com.facebook.drawee.generic.GenericDraweeHierarchy;
8 | import com.facebook.drawee.view.DraweeView;
9 |
10 | public class DefaultOnDoubleTapListener implements GestureDetector.OnDoubleTapListener {
11 |
12 | private Attacher mAttacher;
13 |
14 | public DefaultOnDoubleTapListener(Attacher attacher) {
15 | setPhotoDraweeViewAttacher(attacher);
16 | }
17 |
18 | @Override public boolean onSingleTapConfirmed(MotionEvent e) {
19 |
20 | if (mAttacher == null) {
21 | return false;
22 | }
23 | DraweeView draweeView = mAttacher.getDraweeView();
24 | if (draweeView == null) {
25 | return false;
26 | }
27 |
28 | if (mAttacher.getOnPhotoTapListener() != null) {
29 | final RectF displayRect = mAttacher.getDisplayRect();
30 |
31 | if (null != displayRect) {
32 | final float x = e.getX(), y = e.getY();
33 | if (displayRect.contains(x, y)) {
34 | float xResult = (x - displayRect.left) / displayRect.width();
35 | float yResult = (y - displayRect.top) / displayRect.height();
36 | mAttacher.getOnPhotoTapListener().onPhotoTap(draweeView, xResult, yResult);
37 | return true;
38 | }
39 | }
40 | }
41 |
42 | if (mAttacher.getOnViewTapListener() != null) {
43 | mAttacher.getOnViewTapListener().onViewTap(draweeView, e.getX(), e.getY());
44 | return true;
45 | }
46 |
47 | return false;
48 | }
49 |
50 | @Override public boolean onDoubleTap(MotionEvent event) {
51 | if (mAttacher == null) {
52 | return false;
53 | }
54 |
55 | try {
56 | float scale = mAttacher.getScale();
57 | float x = event.getX();
58 | float y = event.getY();
59 |
60 | if (scale < mAttacher.getMediumScale()) {
61 | mAttacher.setScale(mAttacher.getMediumScale(), x, y, true);
62 | } else if (scale >= mAttacher.getMediumScale() && scale < mAttacher.getMaximumScale()) {
63 | mAttacher.setScale(mAttacher.getMaximumScale(), x, y, true);
64 | } else {
65 | mAttacher.setScale(mAttacher.getMinimumScale(), x, y, true);
66 | }
67 | } catch (Exception e) {
68 | // Can sometimes happen when getX() and getY() is called
69 | }
70 | return true;
71 | }
72 |
73 | @Override public boolean onDoubleTapEvent(MotionEvent event) {
74 | return false;
75 | }
76 |
77 | public void setPhotoDraweeViewAttacher(Attacher attacher) {
78 | mAttacher = attacher;
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/image-selector/src/main/java/com/iknow/imageselect/widget/PicItemCheckedView.java:
--------------------------------------------------------------------------------
1 | package com.iknow.imageselect.widget;
2 |
3 | import android.content.Context;
4 | import android.graphics.Bitmap;
5 | import android.graphics.drawable.Drawable;
6 | import android.util.AttributeSet;
7 | import android.view.LayoutInflater;
8 | import android.view.View;
9 | import android.widget.Checkable;
10 | import android.widget.FrameLayout;
11 | import android.widget.ImageView;
12 | import android.widget.RelativeLayout;
13 | import com.facebook.drawee.view.SimpleDraweeView;
14 | import com.iknow.imageselect.R;
15 | import com.iknow.imageselect.utils.DeviceInforHelper;
16 |
17 | public class PicItemCheckedView extends RelativeLayout implements Checkable {
18 |
19 | private Context mContext;
20 | private boolean mChecked;
21 | private SimpleDraweeView mImgView = null;
22 | private ImageView mSelectView,mUnSelectView,mVideoIcon;
23 | private View mSelectPanelView;
24 |
25 | private static final int columnNum = 3;
26 |
27 | public PicItemCheckedView(Context context,boolean isHide) {
28 | this(context, null, 0,isHide);
29 | }
30 |
31 | public PicItemCheckedView(Context context) {
32 | this(context, null, 0,false);
33 | }
34 |
35 | public PicItemCheckedView(Context context, AttributeSet attrs) {
36 | this(context, attrs, 0,false);
37 | }
38 |
39 | public PicItemCheckedView(Context context, AttributeSet attrs, int defStyle,boolean isHide) {
40 | super(context, attrs, defStyle);
41 | mContext = context;
42 | LayoutInflater.from(mContext).inflate(R.layout.image_select_item, this);
43 | mImgView = (SimpleDraweeView) findViewById(R.id.img_view);
44 | mVideoIcon = (ImageView) findViewById(R.id.video_icon);
45 |
46 | int size = DeviceInforHelper.getScreenWidth()/ columnNum;
47 | FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) mImgView.getLayoutParams();
48 | params.width = size;
49 | params.height = size;
50 | mImgView.setLayoutParams(params);
51 |
52 | mSelectView = (ImageView) findViewById(R.id.select);
53 | mUnSelectView = (ImageView) findViewById(R.id.unselect);
54 | if(isHide) {
55 | mUnSelectView.setVisibility(View.GONE);
56 | }
57 |
58 | mSelectPanelView = findViewById(R.id.album_pic_select_panel);
59 | }
60 |
61 | @Override
62 | public void setChecked(boolean checked) {
63 | mChecked = checked;
64 | mSelectView.setVisibility(checked ? View.VISIBLE : View.GONE);
65 | mUnSelectView.setVisibility(checked ? View.GONE : View.VISIBLE);
66 | }
67 |
68 | @Override
69 | public boolean isChecked() {
70 | return mChecked;
71 | }
72 |
73 | @Override
74 | public void toggle() {
75 | setChecked(!mChecked);
76 | }
77 |
78 | public void setImgResId(int resId) {
79 | if (mImgView != null) {
80 | mImgView.setBackgroundResource(resId);
81 | }
82 | }
83 |
84 | public void setImageView(Bitmap bp){
85 | if(mImgView != null){
86 | mImgView.setImageBitmap(bp);
87 | }
88 | }
89 |
90 | public void setImageView(Drawable db){
91 | if(mImgView != null){
92 | mImgView.setImageDrawable(db);
93 | }
94 | }
95 |
96 | public ImageView getVideoIcon() {
97 | return mVideoIcon;
98 | }
99 |
100 | public SimpleDraweeView getImageView(){
101 | return mImgView;
102 | }
103 |
104 | public View getSelectPanelView(){
105 | return mSelectPanelView;
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/image-selector/src/main/java/com/iknow/imageselect/utils/ImageFilePathUtil.java:
--------------------------------------------------------------------------------
1 | package com.iknow.imageselect.utils;
2 |
3 | import android.text.TextUtils;
4 | import java.io.File;
5 | import java.io.IOException;
6 | import java.security.NoSuchAlgorithmException;
7 |
8 | /**
9 | * Author: J.Chou
10 | * Email: who_know_me@163.com
11 | * Created: 2016年04月06日 3:46 PM
12 | * Description:
13 | */
14 |
15 | public class ImageFilePathUtil {
16 | public static final String DESTINATION_CACHE_FOLDER = android.os.Environment.getExternalStorageDirectory()
17 | .getPath() + "/Android/data/com.iknow.imageselect/";
18 |
19 | public static String getImgUrl(String url){
20 |
21 | if(TextUtils.isEmpty(url) || url.length() < 5){
22 | return "";
23 | }
24 |
25 | if (url.substring(0, 4).equalsIgnoreCase("http")) {
26 | String filePath = getLocalImagePath(url);
27 | File f = new File(filePath);
28 | if (f.exists()) {
29 | url = "file:///"+ filePath;
30 | }
31 | } else {
32 | String filePath2 = getLocalImagePath(url);
33 | File f = new File(filePath2);
34 | if (f.exists()) {
35 | url = "file:///"+ filePath2;
36 | } else{
37 | url = "file:///" + url;
38 | }
39 |
40 | }
41 | return url;
42 | }
43 |
44 | public static final String getCacheImagePath() {
45 | String path = DESTINATION_CACHE_FOLDER + "image/";
46 | initPath(path);
47 |
48 | createNoMediaScanFile(path);
49 |
50 | return path;
51 | }
52 |
53 | /**
54 | * 创建nomedia文件,防止图库扫描
55 | *
56 | * @param path
57 | */
58 | private static void createNoMediaScanFile(String path) {
59 | File noMediaFile = new File(path + "nomedia");
60 | if (!noMediaFile.exists()) {
61 | try {
62 | noMediaFile.createNewFile();
63 | } catch (IOException e) {
64 | e.printStackTrace();
65 | }
66 | }
67 | }
68 |
69 | public static final String getCacheDbPath() {
70 | String path = DESTINATION_CACHE_FOLDER + "data/";
71 | initPath(path);
72 | return path;
73 | }
74 |
75 | public static final String getImagePath(String url){
76 |
77 | if(TextUtils.isEmpty(url)){
78 | return "";
79 | }
80 |
81 | int index = url.lastIndexOf("?");
82 |
83 | if(index == -1){
84 | return url;
85 | }
86 |
87 | return url.substring(0, index);
88 | }
89 |
90 | public static final String getLocalFileUri(String filePath){
91 | File f = new File(filePath);
92 | return "file://"+f.getAbsolutePath();
93 | }
94 |
95 | public static final String getLocalImagePath(String url) {
96 | return getCacheImagePath() + getLocalImageFileName(url);
97 | }
98 |
99 | public static final String getLocalImageFileName(String url) {
100 | return getMD5(url.getBytes());
101 | }
102 |
103 | private static void initPath(String path) {
104 | File file = new File(path);
105 | if (!file.exists()) {
106 | file.mkdirs();
107 | }
108 | }
109 |
110 | public static String getMD5(byte[] source) {
111 | StringBuilder sb = new StringBuilder();
112 | java.security.MessageDigest md5 = null;
113 | try {
114 | md5 = java.security.MessageDigest.getInstance("MD5");
115 | md5.update(source);
116 | }
117 | catch (NoSuchAlgorithmException e) {
118 | }
119 | if (md5 != null) {
120 | for (byte b : md5.digest()) {
121 | sb.append(String.format("%02X", b));
122 | }
123 | }
124 | return sb.toString();
125 | }
126 | }
127 |
--------------------------------------------------------------------------------
/image-selector/src/main/res/layout/abs_image_select_layout.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
11 |
12 |
16 |
26 |
38 |
39 |
40 |
47 |
53 |
60 |
61 |
62 |
63 |
64 |
65 |
72 |
82 |
83 |
96 |
97 |
98 |
--------------------------------------------------------------------------------
/image-selector/src/main/java/com/iknow/imageselect/adapter/AlbumListAdapter.java:
--------------------------------------------------------------------------------
1 | package com.iknow.imageselect.adapter;
2 |
3 | import android.content.Context;
4 | import android.net.Uri;
5 | import android.text.TextUtils;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 | import android.widget.BaseAdapter;
10 | import android.widget.ImageView;
11 | import android.widget.TextView;
12 | import com.facebook.drawee.backends.pipeline.Fresco;
13 | import com.facebook.drawee.backends.pipeline.PipelineDraweeController;
14 | import com.facebook.drawee.view.SimpleDraweeView;
15 | import com.facebook.imagepipeline.common.ResizeOptions;
16 | import com.facebook.imagepipeline.request.ImageRequest;
17 | import com.facebook.imagepipeline.request.ImageRequestBuilder;
18 | import com.iknow.imageselect.R;
19 | import com.iknow.imageselect.model.AlbumInfo;
20 | import com.iknow.imageselect.model.MediaInfo;
21 | import com.iknow.imageselect.utils.DrawableUtil;
22 | import com.iknow.imageselect.utils.ImageFilePathUtil;
23 | import java.util.LinkedList;
24 |
25 | /**
26 | * Author: Jason.Chou
27 | * Email: who_know_me@163.com
28 | * Created: 2016年04月12日 3:26 PM
29 | * Description:
30 | */
31 | public class AlbumListAdapter extends BaseAdapter{
32 | private LinkedList adapterListData;
33 | private Context context;
34 | private String hasChooseItemName;
35 | public AlbumListAdapter(Context context,LinkedList dataList,String itemName) {
36 | super();
37 | this.context = context;
38 | this.adapterListData = dataList;
39 | this.hasChooseItemName = itemName;
40 | }
41 |
42 | @Override public int getCount() {
43 | return adapterListData.size();
44 | }
45 |
46 | @Override public Object getItem(int id) {
47 | return adapterListData.get(id);
48 | }
49 |
50 | @Override public long getItemId(int id) {
51 | return id;
52 | }
53 |
54 | @Override public View getView(int position, View convertView, ViewGroup viewGroup) {
55 | ViewHolder h;
56 | AlbumInfo albumInfo = (AlbumInfo) getItem(position);
57 | if(null == convertView){
58 | convertView = LayoutInflater.from(context).inflate(R.layout.ablum_list_view_item, null);
59 | h = new ViewHolder();
60 | h.albumCover = (SimpleDraweeView) convertView.findViewById(R.id.album_cover);
61 | h.albumName = (TextView) convertView.findViewById(R.id.album_name);
62 | h.albumNumber = (TextView) convertView.findViewById(R.id.album_count);
63 | h.chooseIcon = (ImageView) convertView.findViewById(R.id.icon_item_choosen);
64 | convertView.setTag(h);
65 | }else{
66 | h = (ViewHolder) convertView.getTag();
67 | }
68 |
69 | MediaInfo imageInfo = albumInfo.medias.get(0);
70 | String path = imageInfo.fileName;
71 | if(!TextUtils.isEmpty(imageInfo.thumbPath)){
72 | path = imageInfo.thumbPath;
73 | }
74 |
75 | ImageRequest request = ImageRequestBuilder.newBuilderWithSource(Uri.parse(ImageFilePathUtil.getImgUrl(path)))
76 | .setResizeOptions(new ResizeOptions(100, 100)).build();
77 |
78 | PipelineDraweeController controller = (PipelineDraweeController) Fresco.newDraweeControllerBuilder()
79 | .setOldController(h.albumCover.getController())
80 | .setImageRequest(request)
81 | .build();
82 | h.albumCover.setController(controller);
83 |
84 | h.albumName.setText(albumInfo.name);
85 | h.albumNumber.setText(""+albumInfo.medias.size());
86 | if(hasChooseItemName.equals(albumInfo.name)) {
87 | h.chooseIcon.setImageDrawable(DrawableUtil.decodeFromVector(context, R.drawable.ic_radio_button_checked));
88 | h.chooseIcon.setVisibility(View.VISIBLE);
89 | }else
90 | h.chooseIcon.setVisibility(View.GONE);
91 | return convertView;
92 | }
93 |
94 | static class ViewHolder{
95 | SimpleDraweeView albumCover;
96 | TextView albumName,albumNumber;
97 | ImageView chooseIcon;
98 | }
99 | }
100 |
101 |
--------------------------------------------------------------------------------
/image-selector/src/main/java/com/iknow/imageselect/configs/ImagePipelineConfigFactory.java:
--------------------------------------------------------------------------------
1 | package com.iknow.imageselect.configs;
2 |
3 | import android.content.Context;
4 | import android.os.Build;
5 | import android.os.Environment;
6 | import com.facebook.cache.disk.DiskCacheConfig;
7 | import com.facebook.common.internal.Supplier;
8 | import com.facebook.common.util.ByteConstants;
9 | import com.facebook.imagepipeline.cache.MemoryCacheParams;
10 | import com.facebook.imagepipeline.core.ImagePipelineConfig;
11 | import java.io.File;
12 |
13 | /**
14 | * Author: Jason.Chou
15 | * Email: who_know_me@163.com
16 | * Created: 2016年04月27日 11:13 AM
17 | * Description:
18 | */
19 | public class ImagePipelineConfigFactory {
20 |
21 | private static final String IMAGE_PIPELINE_CACHE_DIR = "imagepipeline_cache";
22 |
23 | private static ImagePipelineConfig sImagePipelineConfig;
24 | // private static ImagePipelineConfig sOkHttpImagePipelineConfig;
25 |
26 | private static final int MAX_HEAP_SIZE = (int) Runtime.getRuntime().maxMemory();
27 |
28 | public static final int MAX_DISK_CACHE_SIZE = 300 * ByteConstants.MB;
29 | public static final int MAX_MEMORY_CACHE_SIZE = MAX_HEAP_SIZE / 3;
30 |
31 | /**
32 | * Creates config using android http stack as network backend.
33 | */
34 | public static ImagePipelineConfig getImagePipelineConfig(Context context) {
35 | if (sImagePipelineConfig == null) {
36 | ImagePipelineConfig.Builder configBuilder = ImagePipelineConfig.newBuilder(context);
37 | configureCaches(configBuilder, context);
38 | sImagePipelineConfig = configBuilder.build();
39 | }
40 | return sImagePipelineConfig;
41 | }
42 |
43 | /**
44 | * Creates config using OkHttp as network backed.
45 | */
46 | /* public static ImagePipelineConfig getOkHttpImagePipelineConfig(Context context) {
47 | if (sOkHttpImagePipelineConfig == null) {
48 | OkHttpClient okHttpClient = new OkHttpClient();
49 | ImagePipelineConfig.Builder configBuilder =
50 | OkHttpImagePipelineConfigFactory.newBuilder(context, okHttpClient);
51 | configureCaches(configBuilder, context);
52 | sOkHttpImagePipelineConfig = configBuilder.build();
53 | }
54 | return sOkHttpImagePipelineConfig;
55 | }*/
56 |
57 | /**
58 | * Configures disk and memory cache not to exceed common limits
59 | */
60 | private static void configureCaches(ImagePipelineConfig.Builder configBuilder, Context context) {
61 | final MemoryCacheParams bitmapCacheParams = new MemoryCacheParams(
62 | MAX_MEMORY_CACHE_SIZE, // Max total size of elements in the cache
63 | Integer.MAX_VALUE, // Max entries in the cache
64 | MAX_MEMORY_CACHE_SIZE, // Max total size of elements in eviction queue
65 | Integer.MAX_VALUE, // Max length of eviction queue
66 | Integer.MAX_VALUE); // Max cache entry size
67 | configBuilder
68 | .setBitmapMemoryCacheParamsSupplier(
69 | new Supplier() {
70 | public MemoryCacheParams get() {
71 | return bitmapCacheParams;
72 | }
73 | })
74 | .setMainDiskCacheConfig(DiskCacheConfig.newBuilder(context)
75 | .setBaseDirectoryPath(getExternalCacheDir(context))
76 | .setBaseDirectoryName(IMAGE_PIPELINE_CACHE_DIR)
77 | .setMaxCacheSize(MAX_DISK_CACHE_SIZE)
78 | .build())
79 | .setDownsampleEnabled(true)
80 | .setSmallImageDiskCacheConfig(DiskCacheConfig.newBuilder(context)
81 | .setBaseDirectoryPath(getExternalCacheDir(context))
82 | .setBaseDirectoryName(IMAGE_PIPELINE_CACHE_DIR)
83 | .setMaxCacheSize(MAX_DISK_CACHE_SIZE)
84 | .build() );
85 | }
86 |
87 | public static File getExternalCacheDir(final Context context) {
88 | if (hasExternalCacheDir())
89 | return context.getExternalCacheDir();
90 |
91 | // Before Froyo we need to construct the external cache dir ourselves
92 | final String cacheDir = "/Android/data/" + context.getPackageName() + "/cache/";
93 | return createFile(Environment.getExternalStorageDirectory().getPath() + cacheDir, "");
94 | }
95 |
96 | public static boolean hasExternalCacheDir() {
97 | return Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO;
98 | }
99 |
100 | public static File createFile(String folderPath, String fileName) {
101 | File destDir = new File(folderPath);
102 | if (!destDir.exists()) {
103 | destDir.mkdirs();
104 | }
105 | return new File(folderPath, fileName);
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/image-selector/src/main/java/com/iknow/imageselect/activities/MultiSelectImageActivity.java:
--------------------------------------------------------------------------------
1 | package com.iknow.imageselect.activities;
2 |
3 | import android.content.Intent;
4 | import android.graphics.Color;
5 | import android.net.Uri;
6 | import android.os.Bundle;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 | import android.widget.TextView;
10 | import com.facebook.drawee.backends.pipeline.Fresco;
11 | import com.facebook.drawee.backends.pipeline.PipelineDraweeController;
12 | import com.facebook.imagepipeline.common.ResizeOptions;
13 | import com.facebook.imagepipeline.request.ImageRequest;
14 | import com.facebook.imagepipeline.request.ImageRequestBuilder;
15 | import com.iknow.imageselect.R;
16 | import com.iknow.imageselect.model.MediaInfo;
17 | import com.iknow.imageselect.utils.ImageFilePathUtil;
18 | import com.iknow.imageselect.widget.PicItemCheckedView;
19 | import com.iknow.imageselect.widget.TitleView;
20 |
21 | /**
22 | * Author: Jason.Chou
23 | * Email: who_know_me@163.com
24 | * Created: 2016年04月12日 5:02 PM
25 | * Description:
26 | */
27 | public class MultiSelectImageActivity extends AbsImageSelectActivity{
28 |
29 | private TextView mSendBtn,mPreviewBtn;
30 |
31 | @Override
32 | protected void initTitleView(TitleView titleView) {
33 | mSendBtn = (TextView) titleView.getRBtnView();
34 | mSendBtn.setOnClickListener(new View.OnClickListener() {
35 | @Override public void onClick(View pView) {
36 | imageChoosePresenter.doSendAction();
37 | }
38 | });
39 | }
40 |
41 | @Override protected void initBottomView(View bottomView) {
42 | mPreviewBtn = (TextView) bottomView.findViewById(R.id.preview_btn);
43 | mPreviewBtn.setOnClickListener(new View.OnClickListener() {
44 | @Override public void onClick(View pView) {
45 | imageChoosePresenter.doPreview(hasCheckedImages);
46 | }
47 | });
48 | }
49 |
50 | @Override protected void onBindViewHolderToChild(MediaInfo model,ImageSelectViewHolder holder, int position) {
51 | ImageRequest request = ImageRequestBuilder.newBuilderWithSource(Uri.parse(ImageFilePathUtil.getImgUrl(model.fileName)))
52 | .setResizeOptions(new ResizeOptions(100, 100)).build();
53 |
54 | PipelineDraweeController controller = (PipelineDraweeController) Fresco.newDraweeControllerBuilder()
55 | .setOldController(holder.picImageView.getController())
56 | .setImageRequest(request)
57 | .build();
58 | holder.picImageView.setController(controller);
59 |
60 | holder.videoIcon.setVisibility(model.mediaType == 3 ? View.VISIBLE:View.GONE);
61 | }
62 |
63 | @Override public View getRecyclerItemView(ViewGroup parentView, int position) {
64 | return new PicItemCheckedView(this);
65 | }
66 |
67 |
68 | @Override
69 | protected void onImageSelectItemClick(View view, int position) {
70 | if(view instanceof PicItemCheckedView){
71 | PicItemCheckedView item = (PicItemCheckedView)view;
72 | boolean isChecked = item.isChecked();
73 | item.setChecked(!isChecked);
74 | if(isChecked && hasCheckedImages.contains(allMedias.get(position)))
75 | hasCheckedImages.remove(allMedias.get(position));
76 | else if(!isChecked && !hasCheckedImages.contains(allMedias.get(position))){
77 | hasCheckedImages.add(allMedias.get(position));
78 | }
79 |
80 | if(hasCheckedImages.size() > 0 ) {
81 | mSendBtn.setTextAppearance(mContext,R.style.text_16_ffffff);
82 | mSendBtn.setEnabled(true);
83 | mPreviewBtn.setEnabled(true);
84 | mPreviewBtn.setText("预览"+"("+hasCheckedImages.size()+")");
85 | mPreviewBtn.setTextColor(Color.parseColor("#ffffff"));
86 | }else {
87 | mSendBtn.setEnabled(false);
88 | mPreviewBtn.setEnabled(false);
89 | mPreviewBtn.setText("预览");
90 | mSendBtn.setTextAppearance(mContext,R.style.gray_text_16);
91 | mPreviewBtn.setTextAppearance(mContext,R.style.gray_text_16);
92 | }
93 |
94 | }
95 | }
96 |
97 | @Override
98 | protected void onImageItemClick(View view, int position) {
99 | BrowseDetailActivity.goToBrowseDetailActivity(this,allMedias,position);
100 | }
101 |
102 | @Override protected void onCameraActivityResult(String path) {
103 | Bundle bd = new Bundle();
104 | hasCheckedImages.clear();
105 | hasCheckedImages.add(MediaInfo.buildOneImage(path));
106 | bd.putSerializable("ImageData",hasCheckedImages);
107 | Intent intent = new Intent();
108 | intent.putExtras(bd);
109 | MultiSelectImageActivity.this.setResult(RESULT_OK, intent);
110 | MultiSelectImageActivity.this.finish();
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/image-selector/src/main/java/com/iknow/imageselect/photodraweeview/PhotoDraweeView.java:
--------------------------------------------------------------------------------
1 | package com.iknow.imageselect.photodraweeview;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.support.annotation.NonNull;
6 | import android.util.AttributeSet;
7 | import android.view.GestureDetector;
8 | import android.view.MotionEvent;
9 | import com.facebook.drawee.generic.GenericDraweeHierarchy;
10 | import com.facebook.drawee.view.SimpleDraweeView;
11 |
12 | public class PhotoDraweeView extends SimpleDraweeView implements IAttacher {
13 |
14 | private Attacher mAttacher;
15 |
16 | public PhotoDraweeView(Context context, GenericDraweeHierarchy hierarchy) {
17 | super(context, hierarchy);
18 | init();
19 | }
20 |
21 | public PhotoDraweeView(Context context) {
22 | super(context);
23 | init();
24 | }
25 |
26 | public PhotoDraweeView(Context context, AttributeSet attrs) {
27 | super(context, attrs);
28 | init();
29 | }
30 |
31 | public PhotoDraweeView(Context context, AttributeSet attrs, int defStyle) {
32 | super(context, attrs, defStyle);
33 | init();
34 | }
35 |
36 | protected void init() {
37 | if (mAttacher == null || mAttacher.getDraweeView() == null) {
38 | mAttacher = new Attacher(this);
39 | }
40 | }
41 |
42 | @Override public boolean onTouchEvent(MotionEvent event) {
43 |
44 | return super.onTouchEvent(event);
45 | }
46 |
47 | @Override protected void onDraw(@NonNull Canvas canvas) {
48 | int saveCount = canvas.save();
49 | canvas.concat(mAttacher.getDrawMatrix());
50 | super.onDraw(canvas);
51 | canvas.restoreToCount(saveCount);
52 | }
53 |
54 | @Override protected void onAttachedToWindow() {
55 | init();
56 | super.onAttachedToWindow();
57 | }
58 |
59 | @Override protected void onDetachedFromWindow() {
60 | mAttacher.onDetachedFromWindow();
61 | super.onDetachedFromWindow();
62 | }
63 |
64 | @Override public float getMinimumScale() {
65 | return mAttacher.getMinimumScale();
66 | }
67 |
68 | @Override public float getMediumScale() {
69 | return mAttacher.getMediumScale();
70 | }
71 |
72 | @Override public float getMaximumScale() {
73 | return mAttacher.getMaximumScale();
74 | }
75 |
76 | @Override public void setMinimumScale(float minimumScale) {
77 | mAttacher.setMinimumScale(minimumScale);
78 | }
79 |
80 | @Override public void setMediumScale(float mediumScale) {
81 | mAttacher.setMediumScale(mediumScale);
82 | }
83 |
84 | @Override public void setMaximumScale(float maximumScale) {
85 | mAttacher.setMaximumScale(maximumScale);
86 | }
87 |
88 | @Override public float getScale() {
89 | return mAttacher.getScale();
90 | }
91 |
92 | @Override public void setScale(float scale) {
93 | mAttacher.setScale(scale);
94 | }
95 |
96 | @Override public void setScale(float scale, boolean animate) {
97 | mAttacher.setScale(scale, animate);
98 | }
99 |
100 | @Override public void setScale(float scale, float focalX, float focalY, boolean animate) {
101 | mAttacher.setScale(scale, focalX, focalY, animate);
102 | }
103 |
104 | @Override public void setZoomTransitionDuration(long duration) {
105 | mAttacher.setZoomTransitionDuration(duration);
106 | }
107 |
108 | @Override public void setAllowParentInterceptOnEdge(boolean allow) {
109 | mAttacher.setAllowParentInterceptOnEdge(allow);
110 | }
111 |
112 | @Override public void setOnDoubleTapListener(GestureDetector.OnDoubleTapListener listener) {
113 | mAttacher.setOnDoubleTapListener(listener);
114 | }
115 |
116 | @Override public void setOnScaleChangeListener(OnScaleChangeListener listener) {
117 | mAttacher.setOnScaleChangeListener(listener);
118 | }
119 |
120 | @Override public void setOnLongClickListener(OnLongClickListener listener) {
121 | mAttacher.setOnLongClickListener(listener);
122 | }
123 |
124 | @Override public void setOnPhotoTapListener(OnPhotoTapListener listener) {
125 | mAttacher.setOnPhotoTapListener(listener);
126 | }
127 |
128 | @Override public void setOnViewTapListener(OnViewTapListener listener) {
129 | mAttacher.setOnViewTapListener(listener);
130 | }
131 |
132 | @Override public OnPhotoTapListener getOnPhotoTapListener() {
133 | return mAttacher.getOnPhotoTapListener();
134 | }
135 |
136 | @Override public OnViewTapListener getOnViewTapListener() {
137 | return mAttacher.getOnViewTapListener();
138 | }
139 |
140 | @Override public void update(int imageInfoWidth, int imageInfoHeight) {
141 | mAttacher.update(imageInfoWidth, imageInfoHeight);
142 | }
143 | }
144 |
--------------------------------------------------------------------------------
/image-selector/src/main/res/layout/layout_browse_detail_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
14 |
15 |
24 |
25 |
30 |
31 |
36 |
37 |
38 |
42 |
43 |
51 |
52 |
56 |
57 |
63 |
64 |
74 |
75 |
76 |
77 |
78 |
86 |
87 |
93 |
94 |
98 |
99 |
107 |
108 |
109 |
113 |
114 |
120 |
121 |
125 |
126 |
134 |
135 |
136 |
137 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/image-selector/src/main/java/com/iknow/imageselect/activities/SingleSelectImageActivity.java:
--------------------------------------------------------------------------------
1 | package com.iknow.imageselect.activities;
2 |
3 | import android.app.Activity;
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 | import android.widget.ImageView;
9 | import android.widget.TextView;
10 |
11 | import com.iknow.imageselect.R;
12 | import com.iknow.imageselect.model.MediaInfo;
13 | import com.iknow.imageselect.widget.PicItemCheckedView;
14 | import com.iknow.imageselect.widget.TitleView;
15 | import java.util.ArrayList;
16 |
17 | /**
18 | * Author: Jason.Chou
19 | * Email: who_know_me@163.com
20 | * Created: 2016年04月12日 5:03 PM
21 | * Description:
22 | */
23 | public class SingleSelectImageActivity extends AbsImageSelectActivity {
24 |
25 | // ===========================================================
26 | // Constants
27 | // ===========================================================
28 |
29 | // ===========================================================
30 | // Fields
31 | // ===========================================================
32 | private ArrayList hasCheckedView = new ArrayList<>();
33 | private View mCameraIv;
34 | private TextView mPreviewBtn;
35 | // ===========================================================
36 | // Constructors
37 | // ===========================================================
38 | public static void startActivityForResult(Activity context){
39 | context.startActivityForResult(new Intent(context,SingleSelectImageActivity.class),
40 | SINGLE_PIC_SELECT_REQUEST);
41 | }
42 | // ===========================================================
43 | // Getter & Setter
44 | // ===========================================================
45 |
46 | // ===========================================================
47 | // Methods for/from SuperClass/Interfaces
48 | // ===========================================================
49 | @Override
50 | protected void initTitleView(TitleView titleView) {
51 | this.mCameraIv = titleView.getRBtnView();
52 | titleView.setOnRightBtnClickListener(new TitleView.OnRightBtnClickListener() {
53 | @Override public void onRBtnClick(View v) {
54 | mTakeCameraImagePath = imageChoosePresenter.takePhotos();
55 | }
56 | });
57 | titleView.setOnLeftBtnClickListener(new TitleView.OnLeftBtnClickListener() {
58 | @Override public void onRBtnClick(View v) {
59 | imageChoosePresenter.doCancel();
60 | }
61 | });
62 |
63 | }
64 |
65 | @Override protected void initBottomView(View bottomView) {
66 | mPreviewBtn = (TextView) bottomView.findViewById(R.id.preview_btn);
67 | mPreviewBtn.setTextAppearance(mContext,R.style.gray_text_18_style);
68 | mPreviewBtn.setEnabled(false);
69 | mPreviewBtn.setOnClickListener(new View.OnClickListener() {
70 | @Override public void onClick(View pView) {
71 | Bundle bd = new Bundle();
72 | imageChoosePresenter.doPreview(hasCheckedImages);
73 | }
74 | });
75 | }
76 |
77 | @Override protected void onBindViewHolderToChild(MediaInfo model,
78 | ImageSelectViewHolder holder, int position) {
79 |
80 | }
81 |
82 | @Override
83 | protected View getRecyclerItemView(ViewGroup parentView, int position) {
84 | if (parentView == null) {
85 | parentView = new PicItemCheckedView(this,true);
86 | }
87 |
88 | try {
89 | PicItemCheckedView view = ((PicItemCheckedView) parentView);
90 | long picId = allMedias.get(position).fileId;
91 | if (picId < 0) {
92 | throw new RuntimeException("the pic id is not num");
93 | }
94 |
95 | final ImageView iv = view.getImageView();
96 | iv.setScaleType(ImageView.ScaleType.FIT_XY);
97 |
98 |
99 | //if (hasCheckedImages.contains(allMedias.get(position))) {
100 | // view.setChecked(true);
101 | //} else {
102 | // view.setChecked(false);
103 | //}
104 | } catch (Exception e) {
105 | e.printStackTrace();
106 | }
107 | return parentView;
108 | }
109 |
110 | @Override
111 | protected void onImageSelectItemClick(View view, int position) {
112 | if(view instanceof PicItemCheckedView){
113 |
114 | PicItemCheckedView item = (PicItemCheckedView)view;
115 | boolean isChecked = item.isChecked();
116 |
117 | if(isChecked) {
118 | hasCheckedImages.remove(allMedias.get(position));
119 | item.setChecked(false);
120 | }
121 | else{
122 | resetImagesChecked();
123 | hasCheckedView.add(item);
124 | hasCheckedImages.add(allMedias.get(position));
125 | item.setChecked(true);
126 | }
127 |
128 | if(hasCheckedImages.size() > 0 ) {
129 | mPreviewBtn.setTextAppearance(mContext,R.style.text_18_ffffff);
130 | mPreviewBtn.setEnabled(true);
131 | }else {
132 | mPreviewBtn.setTextAppearance(mContext,R.style.gray_text_18_style);
133 | mPreviewBtn.setEnabled(false);
134 | }
135 | }
136 | }
137 |
138 | @Override
139 | protected void onImageItemClick(View view, int position) {
140 |
141 | }
142 |
143 | @Override protected void onCameraActivityResult(String path) {
144 | Bundle bd = new Bundle();
145 | hasCheckedImages.clear();
146 | hasCheckedImages.add(MediaInfo.buildOneImage(path));
147 | bd.putSerializable("ImageData",hasCheckedImages);
148 | Intent intent = new Intent();
149 | intent.putExtras(bd);
150 | SingleSelectImageActivity.this.setResult(RESULT_OK, intent);
151 | SingleSelectImageActivity.this.finish();
152 | }
153 |
154 | // ===========================================================
155 | // Methods
156 | // ===========================================================
157 | private void resetImagesChecked(){
158 | if(hasCheckedView.size()>0){
159 | hasCheckedView.get(0).setChecked(false);
160 | hasCheckedView.clear();
161 | hasCheckedImages.clear();
162 | }
163 | }
164 | // ===========================================================
165 | // Inner and Anonymous Classes
166 | // ===========================================================
167 | }
168 |
--------------------------------------------------------------------------------
/image-selector/src/main/java/com/iknow/imageselect/photodraweeview/ScaleDragDetector.java:
--------------------------------------------------------------------------------
1 | package com.iknow.imageselect.photodraweeview;
2 |
3 | import android.content.Context;
4 | import android.support.v4.view.MotionEventCompat;
5 | import android.view.MotionEvent;
6 | import android.view.ScaleGestureDetector;
7 | import android.view.VelocityTracker;
8 | import android.view.ViewConfiguration;
9 |
10 | /**
11 | * ****************************************************************************
12 | * Copyright 2011, 2012 Chris Banes.
13 | *
14 | * Licensed under the Apache License, Version 2.0 (the "License");
15 | * you may not use this file except in compliance with the License.
16 | * You may obtain a copy of the License at
17 | *
18 | * http://www.apache.org/licenses/LICENSE-2.0
19 | *
20 | * Unless required by applicable law or agreed to in writing, software
21 | * distributed under the License is distributed on an "AS IS" BASIS,
22 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23 | * See the License for the specific language governing permissions and
24 | * limitations under the License.
25 | * *****************************************************************************
26 | */
27 | public class ScaleDragDetector implements ScaleGestureDetector.OnScaleGestureListener {
28 |
29 | private static final int INVALID_POINTER_ID = -1;
30 |
31 | private final float mTouchSlop;
32 | private final float mMinimumVelocity;
33 | private final ScaleGestureDetector mScaleDetector;
34 | private final OnScaleDragGestureListener mScaleDragGestureListener;
35 |
36 | private VelocityTracker mVelocityTracker;
37 | private boolean mIsDragging;
38 | float mLastTouchX;
39 | float mLastTouchY;
40 | private int mActivePointerId = INVALID_POINTER_ID;
41 | private int mActivePointerIndex = 0;
42 |
43 | public ScaleDragDetector(Context context, OnScaleDragGestureListener scaleDragGestureListener) {
44 | mScaleDetector = new ScaleGestureDetector(context, this);
45 | mScaleDragGestureListener = scaleDragGestureListener;
46 |
47 | final ViewConfiguration configuration = ViewConfiguration.get(context);
48 | mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
49 | mTouchSlop = configuration.getScaledTouchSlop();
50 | }
51 |
52 | @Override public boolean onScale(ScaleGestureDetector detector) {
53 | float scaleFactor = detector.getScaleFactor();
54 |
55 | if (Float.isNaN(scaleFactor) || Float.isInfinite(scaleFactor)) {
56 | return false;
57 | }
58 |
59 | mScaleDragGestureListener.onScale(scaleFactor, detector.getFocusX(), detector.getFocusY());
60 | return true;
61 | }
62 |
63 | @Override public boolean onScaleBegin(ScaleGestureDetector detector) {
64 | return true;
65 | }
66 |
67 | @Override public void onScaleEnd(ScaleGestureDetector detector) {
68 | mScaleDragGestureListener.onScaleEnd();
69 | }
70 |
71 | public boolean isScaling() {
72 | return mScaleDetector.isInProgress();
73 | }
74 |
75 | public boolean isDragging() {
76 | return mIsDragging;
77 | }
78 |
79 | private float getActiveX(MotionEvent ev) {
80 | try {
81 | return MotionEventCompat.getX(ev, mActivePointerIndex);
82 | } catch (Exception e) {
83 | return ev.getX();
84 | }
85 | }
86 |
87 | private float getActiveY(MotionEvent ev) {
88 | try {
89 | return MotionEventCompat.getY(ev, mActivePointerIndex);
90 | } catch (Exception e) {
91 | return ev.getY();
92 | }
93 | }
94 |
95 | public boolean onTouchEvent(MotionEvent ev) {
96 | mScaleDetector.onTouchEvent(ev);
97 | final int action = MotionEventCompat.getActionMasked(ev);
98 | onTouchActivePointer(action, ev);
99 | onTouchDragEvent(action, ev);
100 | return true;
101 | }
102 |
103 | private void onTouchActivePointer(int action, MotionEvent ev) {
104 | switch (action) {
105 | case MotionEvent.ACTION_DOWN:
106 | mActivePointerId = ev.getPointerId(0);
107 | break;
108 | case MotionEvent.ACTION_CANCEL:
109 | case MotionEvent.ACTION_UP:
110 | mActivePointerId = INVALID_POINTER_ID;
111 | break;
112 | case MotionEvent.ACTION_POINTER_UP:
113 | final int pointerIndex = MotionEventCompat.getActionIndex(ev);
114 | final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex);
115 | if (pointerId == mActivePointerId) {
116 | final int newPointerIndex = (pointerIndex == 0) ? 1 : 0;
117 | mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex);
118 | mLastTouchX = MotionEventCompat.getX(ev, newPointerIndex);
119 | mLastTouchY = MotionEventCompat.getY(ev, newPointerIndex);
120 | }
121 |
122 | break;
123 | }
124 |
125 | mActivePointerIndex = MotionEventCompat.findPointerIndex(ev,
126 | mActivePointerId != INVALID_POINTER_ID ? mActivePointerId : 0);
127 | }
128 |
129 | private void onTouchDragEvent(int action, MotionEvent ev) {
130 | switch (action) {
131 | case MotionEvent.ACTION_DOWN: {
132 | mVelocityTracker = VelocityTracker.obtain();
133 | if (null != mVelocityTracker) {
134 | mVelocityTracker.addMovement(ev);
135 | }
136 |
137 | mLastTouchX = getActiveX(ev);
138 | mLastTouchY = getActiveY(ev);
139 | mIsDragging = false;
140 | break;
141 | }
142 |
143 | case MotionEvent.ACTION_MOVE: {
144 | final float x = getActiveX(ev);
145 | final float y = getActiveY(ev);
146 | final float dx = x - mLastTouchX, dy = y - mLastTouchY;
147 |
148 | if (!mIsDragging) {
149 | mIsDragging = Math.sqrt((dx * dx) + (dy * dy)) >= mTouchSlop;
150 | }
151 |
152 | if (mIsDragging) {
153 | mScaleDragGestureListener.onDrag(dx, dy);
154 | mLastTouchX = x;
155 | mLastTouchY = y;
156 |
157 | if (null != mVelocityTracker) {
158 | mVelocityTracker.addMovement(ev);
159 | }
160 | }
161 | break;
162 | }
163 |
164 | case MotionEvent.ACTION_CANCEL: {
165 | if (null != mVelocityTracker) {
166 | mVelocityTracker.recycle();
167 | mVelocityTracker = null;
168 | }
169 | break;
170 | }
171 |
172 | case MotionEvent.ACTION_UP: {
173 | if (mIsDragging) {
174 | if (null != mVelocityTracker) {
175 | mLastTouchX = getActiveX(ev);
176 | mLastTouchY = getActiveY(ev);
177 |
178 | mVelocityTracker.addMovement(ev);
179 | mVelocityTracker.computeCurrentVelocity(1000);
180 |
181 | final float vX = mVelocityTracker.getXVelocity(), vY =
182 | mVelocityTracker.getYVelocity();
183 |
184 | if (Math.max(Math.abs(vX), Math.abs(vY)) >= mMinimumVelocity) {
185 | mScaleDragGestureListener.onFling(mLastTouchX, mLastTouchY, -vX, -vY);
186 | }
187 | }
188 | }
189 | if (null != mVelocityTracker) {
190 | mVelocityTracker.recycle();
191 | mVelocityTracker = null;
192 | }
193 | break;
194 | }
195 | }
196 | }
197 | }
198 |
--------------------------------------------------------------------------------
/image-selector/src/main/java/com/iknow/imageselect/activities/AbsImageSelectActivity.java:
--------------------------------------------------------------------------------
1 | package com.iknow.imageselect.activities;
2 |
3 | import android.app.Activity;
4 | import android.content.Intent;
5 | import android.net.Uri;
6 | import android.os.Bundle;
7 | import android.support.v7.app.AppCompatActivity;
8 | import android.support.v7.widget.GridLayoutManager;
9 | import android.support.v7.widget.RecyclerView;
10 | import android.text.TextUtils;
11 | import android.view.View;
12 | import android.view.ViewGroup;
13 | import android.widget.AdapterView;
14 | import android.widget.ImageView;
15 | import android.widget.ListView;
16 | import android.widget.TextView;
17 | import android.widget.Toast;
18 | import com.facebook.drawee.view.SimpleDraweeView;
19 | import com.iknow.imageselect.ImageSelectContextHolder;
20 | import com.iknow.imageselect.R;
21 | import com.iknow.imageselect.adapter.AlbumListAdapter;
22 | import com.iknow.imageselect.core.CoreActivity;
23 | import com.iknow.imageselect.model.AlbumInfo;
24 | import com.iknow.imageselect.model.MediaInfo;
25 | import com.iknow.imageselect.presenter.IImageChoosePresenter;
26 | import com.iknow.imageselect.presenter.ImageChoosePresenterCompl;
27 | import com.iknow.imageselect.utils.MediaFileUtil;
28 | import com.iknow.imageselect.view.IImageChooseView;
29 | import com.iknow.imageselect.widget.PicItemCheckedView;
30 | import com.iknow.imageselect.widget.SpacesItemDecoration;
31 | import com.iknow.imageselect.widget.TitleView;
32 | import java.io.File;
33 | import java.util.ArrayList;
34 | import java.util.LinkedList;
35 |
36 | /**
37 | * Author: J.Chou
38 | * Email: who_know_me@163.com
39 | * Created: 2016年04月06日 3:16 PM
40 | * Description:
41 | */
42 |
43 | public abstract class AbsImageSelectActivity extends CoreActivity implements IImageChooseView,
44 | View.OnClickListener {
45 | // ===========================================================
46 | // Constants
47 | // ===========================================================
48 | public static final int PHOTO_REQUEST_CAMERA = 0x007;
49 | public static final int MULTI_PIC_SELECT_REQUEST = 0x008;
50 | public static final int SINGLE_PIC_SELECT_REQUEST = 0x009;
51 | private static final String ALL_VIDEO = "所有视频";
52 | private static final String PIC_AND_VIDEO = "图片和视频";
53 | // ===========================================================
54 | // Fields
55 | // ===========================================================
56 | protected AppCompatActivity mContext;
57 | protected String mTakeCameraImagePath;
58 | private boolean showAlbumList = false;
59 | private ListView albumListView;
60 | private View albumView;
61 | protected TextView allImagesTv;
62 | protected TitleView gsTitleView;
63 | protected ArrayList allMedias = new ArrayList<>();
64 | protected ArrayList imageAndVideoAlbums = new ArrayList<>();
65 | protected ArrayList hasCheckedImages = new ArrayList<>();
66 | private AlbumInfo allAlbumInfo = new AlbumInfo();
67 | private AlbumInfo videoAlbumInfo = new AlbumInfo();
68 | private LinkedList albumLinkedList = new LinkedList<>();
69 | protected IImageChoosePresenter imageChoosePresenter;
70 | private RecyclerAdapter imageGridAdapter;
71 | private RecyclerView recyclerView;
72 |
73 | protected abstract void initTitleView(TitleView titleView);
74 | protected abstract void initBottomView(View bottomView);
75 | protected abstract void onBindViewHolderToChild(MediaInfo model,ImageSelectViewHolder holder,int position);
76 | protected abstract View getRecyclerItemView(ViewGroup parentView, int position);
77 | protected abstract void onImageSelectItemClick(View view, int position);
78 | protected abstract void onImageItemClick(View view, int position);
79 | protected abstract void onCameraActivityResult(String path);
80 |
81 | // ===========================================================
82 | // Constructors
83 | // ===========================================================
84 |
85 | // ===========================================================
86 | // Getter & Setter
87 | // ===========================================================
88 |
89 | // ===========================================================
90 | // Methods for/from SuperClass/Interfaces
91 | // ===========================================================
92 | @Override
93 | public void onCreate(Bundle savedInstanceState) {
94 | super.onCreate(savedInstanceState);
95 | this.mContext = this;
96 | setContentView(R.layout.abs_image_select_layout);
97 | allMedias = MediaFileUtil.getAllMediaFiles(ImageSelectContextHolder.getInstance().getContext());
98 | imageAndVideoAlbums = (ArrayList) allMedias.clone();
99 | videoAlbumInfo.medias = MediaFileUtil.getAllVideoFiles(ImageSelectContextHolder.getInstance().getContext());
100 | imageChoosePresenter = new ImageChoosePresenterCompl(this, this);
101 | initTitleView(gsTitleView = (TitleView) this.findViewById(R.id.titlebar));
102 | initBottomView(this.findViewById(R.id.bottomView));
103 | initContentView();
104 | }
105 |
106 |
107 | @Override public void onActivityResult(int requestCode, int resultCode, Intent data) {
108 | if (resultCode == Activity.RESULT_OK) {
109 |
110 |
111 | if (requestCode == PHOTO_REQUEST_CAMERA) {//拍照返回
112 | if (TextUtils.isEmpty(mTakeCameraImagePath)) {
113 | return;
114 | }
115 |
116 | final File f = new File(mTakeCameraImagePath);
117 | if (f == null || !f.exists()) {
118 | Toast.makeText(ImageSelectContextHolder.getInstance().getContext(), "照相失败", Toast.LENGTH_SHORT).show();
119 | return;
120 | }
121 |
122 | try {
123 | Intent scanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
124 | scanIntent.setData(Uri.fromFile(f));
125 | AbsImageSelectActivity.this.sendBroadcast(scanIntent);
126 |
127 | onCameraActivityResult(mTakeCameraImagePath);
128 | } catch (Throwable e) {
129 | Toast.makeText(AbsImageSelectActivity.this, "照相失败", Toast.LENGTH_SHORT).show();
130 | e.printStackTrace();
131 | }
132 |
133 | }
134 | }
135 | super.onActivityResult(requestCode, resultCode, data);
136 | }
137 |
138 | @Override public void onClick(View view) {
139 | if(R.id.all_album_tv == view.getId()) {
140 | if(!showAlbumList) {
141 | showAlbumListView();
142 | try {
143 | albumLinkedList.clear();
144 | allAlbumInfo.medias = imageAndVideoAlbums;
145 | if(!allAlbumInfo.medias.isEmpty()){
146 | allAlbumInfo.name = PIC_AND_VIDEO;
147 | albumLinkedList.add(allAlbumInfo);
148 | }else {
149 | allAlbumInfo.medias = MediaFileUtil.getAllMediaFiles(ImageSelectContextHolder.getInstance().getContext());
150 | allAlbumInfo.name = PIC_AND_VIDEO;
151 | albumLinkedList.add(allAlbumInfo);
152 | }
153 |
154 | if(!videoAlbumInfo.medias.isEmpty()) {
155 | videoAlbumInfo.name = ALL_VIDEO;
156 | albumLinkedList.add(videoAlbumInfo);
157 | }else{
158 | videoAlbumInfo.medias = MediaFileUtil.getAllVideoFiles(ImageSelectContextHolder.getInstance().getContext());
159 | videoAlbumInfo.name = ALL_VIDEO;
160 | albumLinkedList.add(videoAlbumInfo);
161 | }
162 |
163 | albumLinkedList.addAll(MediaFileUtil.getThumbnailsPhotosInfo(this));
164 | albumListView.setAdapter(new AlbumListAdapter(this, albumLinkedList,allImagesTv.getText().toString()));
165 | }catch(Exception e) {
166 | e.printStackTrace();
167 | }
168 | }else{
169 | hideAlbumListView();
170 | }
171 | }else if(R.id.empty_place == view.getId()) {
172 | hideAlbumListView();
173 | }
174 | }
175 |
176 | @Override
177 | public void reloadData() {
178 | }
179 |
180 | @Override
181 | protected void onDestroy() {
182 | super.onDestroy();
183 | allMedias = null;
184 | imageAndVideoAlbums = null;
185 | albumLinkedList = null;
186 | }
187 |
188 | // ===========================================================
189 | // Methods
190 | // ===========================================================
191 | private void initContentView() {
192 |
193 | findViewById(R.id.empty_place).setOnClickListener(this);
194 | albumView = findViewById(R.id.albumView);
195 | albumListView = (ListView) findViewById(R.id.all_album_list);
196 | albumListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
197 | @Override public void onItemClick(AdapterView> adapterView, View view, int position, long id) {
198 | AlbumInfo albumInfo = (AlbumInfo) adapterView.getItemAtPosition(position);
199 | allMedias = albumInfo.medias;
200 | recyclerView.setAdapter(imageGridAdapter = new RecyclerAdapter(albumInfo.medias));
201 | allImagesTv.setText(albumInfo.name);
202 | gsTitleView.setTitleText(albumInfo.name);
203 | hideAlbumListView();
204 | }
205 | });
206 |
207 | allImagesTv = (TextView) findViewById(R.id.all_album_tv);
208 | allImagesTv.setOnClickListener(this);
209 |
210 | recyclerView = (RecyclerView) this.findViewById(R.id.album_pic_recyclerview);
211 | GridLayoutManager manager = new GridLayoutManager(this, 3);
212 | recyclerView.addItemDecoration(new SpacesItemDecoration(5));
213 | recyclerView.setHasFixedSize(true);
214 | recyclerView.setAdapter(imageGridAdapter = new RecyclerAdapter(allMedias));
215 | recyclerView.setLayoutManager(manager);
216 | }
217 |
218 | private void showAlbumListView() {
219 | showAlbumList = true;
220 | albumView.setVisibility(View.VISIBLE);
221 | }
222 |
223 | private void hideAlbumListView() {
224 | albumView.setVisibility(View.INVISIBLE);
225 | showAlbumList = false;
226 | }
227 |
228 | // ===========================================================
229 | // Inner and Anonymous Classes
230 | // ===========================================================
231 |
232 | public class RecyclerAdapter extends RecyclerView.Adapter {
233 |
234 | private ArrayList albumMedias;
235 |
236 | public RecyclerAdapter(ArrayList allMedias) {
237 | this.albumMedias = allMedias;
238 | }
239 |
240 | @Override public ImageSelectViewHolder onCreateViewHolder(ViewGroup parent, int position) {
241 | View view = getRecyclerItemView(parent,position);
242 | return new ImageSelectViewHolder(view);
243 | }
244 |
245 | @Override
246 | public void onBindViewHolder(ImageSelectViewHolder holder, final int position) {
247 | MediaInfo mediaInfo = albumMedias.get(position);
248 | onBindViewHolderToChild(mediaInfo,holder,position);
249 | }
250 |
251 | @Override public int getItemCount() {
252 | return albumMedias.size();
253 | }
254 |
255 | }
256 |
257 | public class ImageSelectViewHolder extends RecyclerView.ViewHolder {
258 | public SimpleDraweeView picImageView;
259 | public View panelView;
260 | public ImageView videoIcon;
261 |
262 | public ImageSelectViewHolder(final View itemView) {
263 | super(itemView);
264 | if(itemView instanceof PicItemCheckedView){
265 | picImageView = ((PicItemCheckedView) itemView).getImageView();
266 | videoIcon = ((PicItemCheckedView) itemView).getVideoIcon();
267 | panelView = ((PicItemCheckedView) itemView).getSelectPanelView();
268 | panelView.setOnClickListener(new View.OnClickListener() {
269 | @Override public void onClick(View pView) {
270 | onImageSelectItemClick(itemView,getAdapterPosition());
271 | }
272 | });
273 | picImageView.setOnClickListener(new View.OnClickListener() {
274 | @Override
275 | public void onClick(View view) {
276 | onImageItemClick(view,getAdapterPosition());
277 |
278 | }
279 | });
280 | }
281 | }
282 | }
283 | }
284 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/image-selector/src/main/java/com/iknow/imageselect/activities/BrowseDetailActivity.java:
--------------------------------------------------------------------------------
1 | package com.iknow.imageselect.activities;
2 |
3 | import android.app.Activity;
4 | import android.content.Intent;
5 | import android.net.Uri;
6 | import android.os.Bundle;
7 | import android.support.annotation.Nullable;
8 | import android.support.v4.view.PagerAdapter;
9 | import android.support.v4.view.ViewPager;
10 | import android.support.v7.app.AppCompatActivity;
11 | import android.util.Log;
12 | import android.view.View;
13 | import android.view.ViewGroup;
14 | import android.widget.ImageView;
15 | import android.widget.TextView;
16 |
17 | import com.bumptech.glide.Glide;
18 | import com.iknow.imageselect.R;
19 | import com.iknow.imageselect.model.MediaInfo;
20 | import com.iknow.imageselect.utils.CacheBean;
21 | import com.iknow.imageselect.utils.DrawableUtil;
22 | import com.iknow.imageselect.utils.ImageFilePathUtil;
23 | import com.iknow.imageselect.utils.PhotoDraweeViewUtil;
24 |
25 | import java.io.Serializable;
26 | import java.util.ArrayList;
27 | import java.util.List;
28 |
29 | import com.iknow.imageselect.photodraweeview.PhotoDraweeView;
30 |
31 | /**
32 | * Created by gordon on 5/9/16.
33 | */
34 | public class BrowseDetailActivity extends AppCompatActivity implements View.OnClickListener {
35 |
36 | public static final String TOKEN = "BrowseDetailActivity";
37 | public static final String ALL_MEDIA_LIST = "all_media_list";
38 | public static final String MEDIA_KEY = "MEDIA_KEY";
39 | public static final String CHOOSEN_PICS = "CHOOSEN_PICS";
40 | public static final int CODE_BROWSE_AND_CHOOSE = 0x1128;
41 |
42 | public static final String TYPE_SELECTED = "TYPE_SELECTED";
43 | public static final String TYPE_EMPTY = "TYPE_EMPTY";
44 | public static String ENTRY_TYPE = "ENTRY_TYPE";
45 | public static String CURRENT_INDEX = "CURRENT_INDEX";
46 |
47 | private String fromType = TYPE_EMPTY;
48 |
49 | private ImageView backImage, orginalImage, chooseImage;
50 | private View send, backArea, originalArea, chooseArea;
51 | private TextView navigationText;
52 | private ViewPager viewPager;
53 | private List medias;
54 | private int count = 0;
55 |
56 | @Override
57 | protected void onCreate(@Nullable Bundle savedInstanceState) {
58 | super.onCreate(savedInstanceState);
59 | prepareData();
60 | setContentView(R.layout.layout_browse_detail_activity);
61 | findViews();
62 | addIcons();
63 | addListeners();
64 | initialize();
65 | }
66 |
67 | private void findViews() {
68 | navigationText = (TextView) findViewById(R.id.nav_text);
69 | backArea = findViewById(R.id.back_container);
70 | backImage = (ImageView) findViewById(R.id.back_image);
71 | orginalImage = (ImageView) findViewById(R.id.radio_original);
72 | chooseImage = (ImageView) findViewById(R.id.radio_choose);
73 | originalArea = findViewById(R.id.original_container);
74 | chooseArea = findViewById(R.id.choose_container);
75 | send = findViewById(R.id.send);
76 | viewPager = (ViewPager) findViewById(R.id.view_pager);
77 | }
78 |
79 | private void prepareData() {
80 | medias = new ArrayList<>();
81 | Intent fromIntent = getIntent();
82 | if (fromIntent.getExtras() != null) {
83 | currentIndex = fromIntent.getExtras().getInt(CURRENT_INDEX);
84 | fromType = fromIntent.getExtras().getString(ENTRY_TYPE);
85 | List pass = (ArrayList) CacheBean.getParam(TOKEN, ALL_MEDIA_LIST);
86 | if (pass == null) {
87 | //Say something
88 | pass = new ArrayList<>();
89 | }
90 | CacheBean.clean(TOKEN);
91 | for (MediaInfo info : pass) {
92 | medias.add(fromType.equals(TYPE_EMPTY) ? new BrowseDetailModel(info) : new BrowseDetailModel(true, info));
93 | }
94 |
95 | }
96 | // medias.addAll(Arrays.asList(new BrowseDetailModel(new MediaInfo()), new BrowseDetailModel(new MediaInfo()), new BrowseDetailModel(new MediaInfo())));
97 | count = medias.size();
98 | }
99 |
100 | public void initialize() {
101 | viewPager.setAdapter(new CycleBrowseAdapter());
102 | viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
103 | @Override
104 | public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
105 |
106 | }
107 |
108 | @Override
109 | public void onPageSelected(int position) {
110 | setCurrentIndex(position);
111 | }
112 |
113 | @Override
114 | public void onPageScrollStateChanged(int state) {
115 |
116 | }
117 | });
118 | viewPager.setCurrentItem(currentIndex);
119 | setNavigationText((currentIndex + 1) + "/" + count);
120 | }
121 |
122 | private void addIcons() {
123 | backImage.setImageDrawable(DrawableUtil.decodeFromVector(getApplicationContext(), R.drawable.ic_arrow_back));
124 | orginalImage.setImageDrawable(DrawableUtil.decodeFromVector(getApplicationContext(), R.drawable.ic_radio_button_unchecked));
125 | chooseImage.setImageDrawable(DrawableUtil.decodeFromVector(getApplicationContext(), R.drawable.ic_choosable));
126 | }
127 |
128 | private void addListeners() {
129 | send.setOnClickListener(this);
130 | backArea.setOnClickListener(this);
131 | chooseArea.setOnClickListener(this);
132 | originalArea.setOnClickListener(this);
133 | }
134 |
135 | /**
136 | * variables
137 | */
138 | private int currentIndex = 0;
139 | private boolean isOriginal = false;
140 |
141 | public void setCurrentIndex(int currentIndex) {
142 | this.currentIndex = currentIndex;
143 | refreshState();
144 | }
145 |
146 | private void refreshState() {
147 | setChosen(medias.get(currentIndex).isSelected());
148 | setNavigationText((currentIndex + 1) + "/" + count);
149 | }
150 |
151 | private void setNavigationText(String navigation) {
152 | this.navigationText.setText(navigation);
153 | }
154 |
155 | public boolean isChosen() {
156 | return medias.get(currentIndex).isSelected();
157 | }
158 |
159 | public void setChosen(boolean chosen) {
160 | medias.get(currentIndex).setSelected(chosen);
161 | chooseImage.setImageDrawable(chosen ? DrawableUtil.decodeFromVector(getApplicationContext(),
162 | R.drawable.ic_chosen) : DrawableUtil.decodeFromVector(getApplicationContext(), R.drawable.ic_choosable));
163 | }
164 |
165 | public boolean isOriginal() {
166 | return isOriginal;
167 | }
168 |
169 | public void setOriginal(boolean original) {
170 | isOriginal = original;
171 | orginalImage.setImageDrawable(original ? DrawableUtil.decodeFromVector(getApplicationContext(),
172 | R.drawable.ic_radio_button_checked) : DrawableUtil.decodeFromVector(getApplicationContext(), R.drawable.ic_radio_button_unchecked));
173 | }
174 |
175 | @Override
176 | public void onClick(View view) {
177 | int id = view.getId();
178 | if (id == R.id.choose_container) {
179 | setChosen(!isChosen());
180 | } else if (id == R.id.original_container) {
181 | setOriginal(!isOriginal());
182 | } else if (id == R.id.back_container) {
183 | handleBackAction();
184 | } else if (id == R.id.send) {
185 | handleSureAction();
186 | }
187 | }
188 |
189 | class CycleBrowseAdapter extends PagerAdapter {
190 |
191 | private List views;
192 |
193 | public CycleBrowseAdapter() {
194 | views = new ArrayList<>();
195 | for (BrowseDetailModel model : medias) {
196 | views.add(getLayoutInflater().inflate(R.layout.layout_photo_view_item, viewPager, false));
197 | }
198 | Log.d("gordon", "views count ->" + views.size());
199 | }
200 |
201 | @Override
202 | public int getCount() {
203 | return medias.size();
204 | }
205 |
206 | @Override
207 | public boolean isViewFromObject(View view, Object object) {
208 | return view == object;
209 | }
210 |
211 | @Override
212 | public Object instantiateItem(ViewGroup container, int position) {
213 | View itemView;
214 | container.addView(itemView = views.get(position));
215 | ImageView videoIcon = (ImageView) itemView.findViewById(R.id.video_icon);
216 | TextView videoSizeTv = (TextView) itemView.findViewById(R.id.video_size_tv);
217 | final MediaInfo mediaInfo = medias.get(position).media;
218 |
219 | if (mediaInfo.mediaType == 3) {
220 | originalArea.setVisibility(View.GONE);
221 | videoIcon.setOnClickListener(new View.OnClickListener() {
222 | @Override
223 | public void onClick(View pView) {
224 | playVideo(mediaInfo);
225 | }
226 | });
227 | }
228 | videoIcon.setVisibility(mediaInfo.mediaType == 3 ? View.VISIBLE : View.GONE);
229 | videoSizeTv.setVisibility(mediaInfo.mediaType == 3 ? View.VISIBLE : View.GONE);
230 |
231 | PhotoDraweeViewUtil.display((PhotoDraweeView) itemView.findViewById(R.id.photo_view), Uri.parse(ImageFilePathUtil.getImgUrl(medias.get(position).getMedia().fileName)));
232 | return itemView;
233 | }
234 |
235 | @Override
236 | public int getItemPosition(Object object) {
237 | return super.getItemPosition(object);
238 | }
239 |
240 | @Override
241 | public void destroyItem(ViewGroup container, int position, Object object) {
242 | Glide.clear(((View) object).findViewById(R.id.photo_view));
243 | container.removeView((View) object);
244 | }
245 | }
246 |
247 | private void playVideo(MediaInfo pMediaInfo) {
248 | Uri uri = Uri.parse(pMediaInfo.fileName);
249 | Intent intent = new Intent(Intent.ACTION_VIEW);
250 | intent.setDataAndType(uri, "video/*");
251 | startActivity(intent);
252 | }
253 |
254 | class BrowseDetailModel implements Serializable {
255 | private boolean isSelected = false;
256 | private MediaInfo media;
257 |
258 | public BrowseDetailModel(boolean isChosen, MediaInfo media) {
259 | this.isSelected = isChosen;
260 | this.media = media;
261 | }
262 |
263 | public BrowseDetailModel(MediaInfo media) {
264 | this.media = media;
265 | }
266 |
267 | public boolean isSelected() {
268 | return isSelected;
269 | }
270 |
271 | public void setSelected(boolean selected) {
272 | isSelected = selected;
273 | }
274 |
275 | public MediaInfo getMedia() {
276 | return media;
277 | }
278 |
279 | public void setMedia(MediaInfo media) {
280 | this.media = media;
281 | }
282 | }
283 |
284 | private void handleSureAction() {
285 | Bundle bundle = new Bundle();
286 | bundle.putSerializable(CHOOSEN_PICS, (Serializable) getValidModels(medias));
287 | Intent intent = new Intent();
288 | intent.putExtras(bundle);
289 | setResult(RESULT_OK, intent);
290 | finish();
291 | }
292 |
293 | private void handleBackAction() {
294 | finish();
295 | }
296 |
297 | public static List getValidModels(List models) {
298 | List res = new ArrayList<>();
299 | for (BrowseDetailModel model : models) {
300 | if (model.isSelected()) res.add(model.getMedia());
301 | }
302 | return res;
303 | }
304 |
305 | public static void goToBrowseDetailActivity(Activity from, List mediaInfos, int index) {
306 | Intent intent = new Intent(from, BrowseDetailActivity.class);
307 | Bundle bundle = new Bundle();
308 | bundle.putInt(CURRENT_INDEX, index);
309 | bundle.putString(ENTRY_TYPE, TYPE_EMPTY);
310 | intent.putExtras(bundle);
311 | CacheBean.putParam(BrowseDetailActivity.TOKEN, BrowseDetailActivity.ALL_MEDIA_LIST, mediaInfos);
312 | from.startActivityForResult(intent, CODE_BROWSE_AND_CHOOSE);
313 | }
314 |
315 | public static void goToBrowseDetailActivitySelected(Activity from, List mediaInfos) {
316 | Bundle bundle = new Bundle();
317 | CacheBean.putParam(BrowseDetailActivity.TOKEN, BrowseDetailActivity.ALL_MEDIA_LIST, mediaInfos);
318 | bundle.putString(ENTRY_TYPE, TYPE_SELECTED);
319 | bundle.putInt(CURRENT_INDEX, 0);
320 | Intent intent = new Intent(from, BrowseDetailActivity.class);
321 | intent.putExtras(bundle);
322 | from.startActivityForResult(intent, CODE_BROWSE_AND_CHOOSE);
323 | }
324 | }
325 |
--------------------------------------------------------------------------------
/image-selector/src/main/java/com/iknow/imageselect/widget/TitleView.java:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | */
4 | package com.iknow.imageselect.widget;
5 |
6 | import android.app.Activity;
7 | import android.content.Context;
8 | import android.content.res.TypedArray;
9 | import android.graphics.Color;
10 | import android.graphics.drawable.Drawable;
11 | import android.support.v4.view.ViewCompat;
12 | import android.text.TextUtils;
13 | import android.util.AttributeSet;
14 | import android.view.Gravity;
15 | import android.view.KeyEvent;
16 | import android.view.View;
17 | import android.view.ViewGroup;
18 | import android.widget.FrameLayout;
19 | import android.widget.RelativeLayout;
20 | import android.widget.TextView;
21 | import com.iknow.imageselect.R;
22 | import com.iknow.imageselect.core.CoreActivity;
23 | import com.iknow.imageselect.utils.DeviceInforHelper;
24 |
25 | public class TitleView extends RelativeLayout implements View.OnClickListener{
26 |
27 | // ===========================================================
28 | // Constants
29 | // ===========================================================
30 | private static final int Left_Btn_View_Id = 0x1001;
31 | private static final int Title_View_Id = 0x1002;
32 | private static final int Right_Btn_View_Id = 0x1003;
33 | private static final int DEFAULT_TITLE_HEIGHT = DeviceInforHelper.getPixelFromDip(50);
34 | private static final int DEFAULT_ICON_SIZE = DeviceInforHelper.getPixelFromDip(24);
35 |
36 | private static final int TITLE_TEXT_DEFAULT_STYLE = R.style.text_18_ffffff;
37 | private static final int BTN_TEXT_DEFAULT_STYLE = R.style.text_16_ffffff;
38 | // ===========================================================
39 | // Fields
40 | // ===========================================================
41 | private TextView mTitleTextView;
42 | private TextView mSubTitleTextView;
43 | private String mTitleText;
44 | private int mTitleStyle;
45 |
46 | private View mLeftBtnTextView;
47 | private View mLeftBtnImgView;
48 | private String mLeftBtnText;
49 | private Drawable mLBtnDrawable;
50 | private int mLBtnStyle;
51 | private boolean isShowLBtn;
52 |
53 | private View mRightBtnTextView;
54 | private View mRightBtnImgView;
55 | private String mRightBtnText;
56 | private Drawable mRBtnBgDrawable;
57 | private int mRBtnStyle;
58 | private boolean isShowRBtn;
59 |
60 | private OnTitleClickListener mOnTitleClickListener;
61 | private OnRightBtnClickListener mOnRightBtnClickListener;
62 | private OnLeftBtnClickListener mOnLeftBtnClickListener;
63 |
64 | // ===========================================================
65 | // Constructors
66 | // ===========================================================
67 |
68 | // ===========================================================
69 | // Getter & Setter
70 | // ===========================================================
71 |
72 | // ===========================================================
73 | // Methods for/from SuperClass/Interfaces
74 | // ===========================================================
75 | public TitleView(Context context){
76 | this(context,null);
77 | }
78 |
79 | public TitleView(Context context, AttributeSet attrs) {
80 | super(context, attrs);
81 | initView(context,attrs);
82 | setupView(context);
83 | }
84 |
85 | private void initView(Context context, AttributeSet attrs) {
86 | if (attrs != null){
87 | TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TitleView);
88 | mTitleText = a.getString(R.styleable.TitleView_title_text);
89 | mTitleStyle = a.getResourceId(R.styleable.TitleView_title_text_appearance, -1);
90 |
91 | isShowLBtn = a.getBoolean(R.styleable.TitleView_is_show_left_button, true);
92 | if(isShowLBtn){
93 | mLeftBtnText = a.getString(R.styleable.TitleView_title_btn_left_text);
94 | mLBtnStyle = a.getResourceId(R.styleable.TitleView_title_btn_left_text_appearance, -1);
95 | mLBtnDrawable = a.getDrawable(R.styleable.TitleView_title_btn_left_drawable);
96 | if(mLBtnDrawable == null)
97 | mLBtnDrawable = getResources().getDrawable(R.drawable.icon_back);
98 | }
99 |
100 | isShowRBtn = a.getBoolean(R.styleable.TitleView_is_show_right_button, true);
101 | if(isShowRBtn){
102 | mRightBtnText = a.getString(R.styleable.TitleView_title_btn_right_text);
103 | mRBtnStyle = a.getResourceId(R.styleable.TitleView_title_btn_right_text_appearance, -1);
104 | mRBtnBgDrawable = a.getDrawable(R.styleable.TitleView_title_btn_right_drawable);
105 | }
106 |
107 | a.recycle();
108 | if (getBackground() == null) {
109 | setBackgroundResource(android.R.color.white);
110 | }
111 | //this.setVisibility(View.GONE);
112 | }
113 | }
114 |
115 | private void setupView(Context context) {
116 | // final DisplayMetrics dm = context.getResources().getDisplayMetrics();
117 | int titleHight;
118 |
119 | /**new sub title view*/
120 | TextView subTitleView = new TextView(context);
121 | this.mSubTitleTextView = subTitleView;
122 | subTitleView.setVisibility(View.GONE);
123 | subTitleView.setTextColor(Color.parseColor("#444444"));
124 | subTitleView.setTextSize(13);
125 | subTitleView.setSingleLine();
126 | subTitleView.setGravity(Gravity.CENTER);
127 | subTitleView.setEllipsize(TextUtils.TruncateAt.END);
128 | subTitleView.setClickable(false);
129 | subTitleView.setText("Test subTitleView");
130 |
131 | /**new title view*/
132 | TextView titleView = new TextView(context);
133 | this.mTitleTextView = titleView;
134 | titleView.setId(Title_View_Id);
135 | titleView.setGravity(Gravity.CENTER);
136 | titleView.setEllipsize(TextUtils.TruncateAt.END);
137 | titleView.setSingleLine();
138 | titleView.setClickable(true);
139 | if(mTitleStyle != -1)
140 | titleView.setTextAppearance(context, mTitleStyle);
141 | else
142 | titleView.setTextAppearance(context, TITLE_TEXT_DEFAULT_STYLE);
143 |
144 | if (!TextUtils.isEmpty(mTitleText)){
145 | titleView.setText(mTitleText);
146 | }
147 |
148 | RelativeLayout mRelativeLayout = new RelativeLayout(context);
149 | //mRelativeLayout.setGravity(Gravity.CENTER_HORIZONTAL);
150 |
151 | /**titleView layoutParams*/
152 | if(View.VISIBLE == subTitleView.getVisibility())
153 | titleHight = LayoutParams.WRAP_CONTENT;
154 | else
155 | titleHight = DEFAULT_TITLE_HEIGHT;
156 | LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, titleHight);
157 | lp.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);
158 | mRelativeLayout.addView(titleView, lp);
159 |
160 | /**subTitleView layoutParams*/
161 | lp = new LayoutParams(LayoutParams.WRAP_CONTENT, DEFAULT_TITLE_HEIGHT);
162 | lp.addRule(BELOW, Title_View_Id);
163 | lp.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);
164 | mRelativeLayout.addView(subTitleView, lp);
165 |
166 | //LayoutParams parms = new LayoutParams(LayoutParams.MATCH_PARENT, DEFAULT_TITLE_HEIGHT);
167 | //parms.addRule(RelativeLayout.RIGHT_OF, Left_Btn_View_Id);
168 | //parms.addRule(RelativeLayout.LEFT_OF, Right_Btn_View_Id);
169 | //parms.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);
170 | //mRelativeLayout.setLayoutParams(parms);
171 |
172 | addView(mRelativeLayout);
173 |
174 | /**Add left button view*/
175 | if(isShowLBtn){
176 | if (TextUtils.isEmpty(mLeftBtnText)){
177 | mLeftBtnImgView = new View(context);
178 | mLeftBtnImgView.setBackground(mLBtnDrawable);
179 | FrameLayout containerLayout = new FrameLayout(context);
180 | FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(DEFAULT_ICON_SIZE,DEFAULT_ICON_SIZE);
181 | params.gravity = Gravity.CENTER|Gravity.LEFT;
182 | containerLayout.addView(mLeftBtnImgView, params);
183 | this.mLeftBtnTextView = containerLayout;
184 |
185 | }else{
186 | TextView leftBtnView = new TextView(context);
187 | leftBtnView.setGravity(Gravity.CENTER|Gravity.LEFT);
188 | leftBtnView.setSingleLine(true);
189 | leftBtnView.setEllipsize(TextUtils.TruncateAt.END);
190 | leftBtnView.setText(mLeftBtnText);
191 | if (mLBtnStyle != -1){
192 | leftBtnView.setTextAppearance(context, mLBtnStyle);
193 | } else {
194 | leftBtnView.setTextAppearance(context, BTN_TEXT_DEFAULT_STYLE);
195 | }
196 | this.mLeftBtnTextView = leftBtnView;
197 | }
198 |
199 | this.mLeftBtnTextView.setId(Left_Btn_View_Id);
200 | this.mLeftBtnTextView.setClickable(true);
201 | this.mLeftBtnTextView.setOnClickListener(this);
202 | LayoutParams lps = new LayoutParams(LayoutParams.WRAP_CONTENT, DEFAULT_TITLE_HEIGHT);
203 | lps.setMargins(DeviceInforHelper.getPixelFromDip(10), 0, 0, 0);
204 | lps.addRule(RelativeLayout.ALIGN_PARENT_LEFT, RelativeLayout.TRUE);
205 | lps.addRule(RelativeLayout.CENTER_VERTICAL, RelativeLayout.TRUE);
206 | addView(mLeftBtnTextView, lps);
207 | }
208 |
209 | /**Add right button view*/
210 | if(isShowRBtn){
211 | if(TextUtils.isEmpty(mRightBtnText)){
212 | mRightBtnImgView = new View(context);
213 | mRightBtnImgView.setBackground(mRBtnBgDrawable);
214 | FrameLayout containerLayout = new FrameLayout(context);
215 | FrameLayout.LayoutParams subLp = new FrameLayout.LayoutParams(DEFAULT_ICON_SIZE+15, DEFAULT_ICON_SIZE);
216 | subLp.gravity = Gravity.CENTER|Gravity.RIGHT;
217 | containerLayout.addView(mRightBtnImgView, subLp);
218 | this.mRightBtnTextView = containerLayout;
219 | }else{
220 | TextView rightBtnView = new TextView(getContext());
221 | rightBtnView.setGravity(Gravity.CENTER|Gravity.RIGHT);
222 | rightBtnView.setSingleLine(true);
223 | rightBtnView.setEllipsize(TextUtils.TruncateAt.END);
224 | rightBtnView.setText(mRightBtnText);
225 | if (mRBtnStyle != -1){
226 | rightBtnView.setTextAppearance(context, mRBtnStyle);
227 | } else {
228 | rightBtnView.setTextAppearance(context, BTN_TEXT_DEFAULT_STYLE);
229 | }
230 |
231 | this.mRightBtnTextView = rightBtnView;
232 | }
233 |
234 | mRightBtnTextView.setId(Right_Btn_View_Id);
235 | mRightBtnTextView.setClickable(true);
236 | mRightBtnTextView.setOnClickListener(this);
237 | LayoutParams p = new LayoutParams(LayoutParams.WRAP_CONTENT, DEFAULT_TITLE_HEIGHT);
238 | p.setMargins(0, 0, DeviceInforHelper.getPixelFromDip(10), 0);
239 | p.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, RelativeLayout.TRUE);
240 | p.addRule(RelativeLayout.CENTER_VERTICAL, RelativeLayout.TRUE);
241 | addView(mRightBtnTextView, p);
242 | }
243 | }
244 |
245 | @Override
246 | public void onClick(View v) {
247 | switch (v.getId()){
248 | case Title_View_Id:
249 | if (mOnTitleClickListener != null)
250 | mOnTitleClickListener.onTitleClick(v);
251 | break;
252 | case Left_Btn_View_Id:
253 | if(mOnLeftBtnClickListener !=null)
254 | mOnLeftBtnClickListener.onRBtnClick(v);
255 | else
256 | sendKeyBackEvent();
257 | break;
258 | case Right_Btn_View_Id:
259 | if (mOnRightBtnClickListener != null)
260 | mOnRightBtnClickListener.onRBtnClick(v);
261 | break;
262 | default:
263 | break;
264 | }
265 | }
266 |
267 | // ===========================================================
268 | // Methods
269 | // ===========================================================
270 | public interface OnTitleClickListener {
271 | void onTitleClick(View v);
272 | }
273 |
274 | public interface OnRightBtnClickListener {
275 | void onRBtnClick(View v);
276 | }
277 |
278 | public interface OnLeftBtnClickListener {
279 | void onRBtnClick(View v);
280 | }
281 |
282 | public void setOnTitleClickListener(OnTitleClickListener listener) {
283 | mOnTitleClickListener = listener;
284 | }
285 |
286 | public void setOnRightBtnClickListener(OnRightBtnClickListener listener) {
287 | mOnRightBtnClickListener = listener;
288 | }
289 |
290 | public void setOnLeftBtnClickListener(OnLeftBtnClickListener listener){
291 | mOnLeftBtnClickListener = listener;
292 | }
293 |
294 | public void setTitleText(T obj) {
295 | if(obj == null)
296 | return;
297 | if(obj instanceof Integer)
298 | mTitleTextView.setText(getResources().getString((Integer) obj));
299 | else if(obj instanceof CharSequence)
300 | mTitleTextView.setText((CharSequence)obj);
301 | }
302 |
303 | public void setRightBtnText(T obj) {
304 | if(obj == null)
305 | return;
306 | if(obj instanceof Integer)
307 | ((TextView)mRightBtnTextView).setText(getResources().getString((Integer) obj));
308 | else if(obj instanceof CharSequence)
309 | ((TextView)mRightBtnTextView).setText((CharSequence)obj);
310 | }
311 |
312 | public View getRBtnView(){
313 | return mRightBtnTextView;
314 | }
315 |
316 | public View getRBtnImgView(){
317 | return mRightBtnImgView;
318 | }
319 |
320 | public void setRightBtnDrawable(T obj){
321 | if(obj == null || mRightBtnImgView == null)
322 | return;
323 | if(obj instanceof Integer)
324 | mRightBtnImgView.setBackgroundResource((Integer) obj);
325 | else
326 | mLeftBtnImgView.setBackground((Drawable)obj);
327 | }
328 |
329 | public void setLeftBtnText(T obj) {
330 | if(obj == null)
331 | return;
332 | if(obj instanceof Integer)
333 | ((TextView)mLeftBtnTextView).setText(getResources().getString((Integer) obj));
334 | else if(obj instanceof CharSequence)
335 | ((TextView)mLeftBtnTextView).setText((CharSequence)obj);
336 | }
337 |
338 | public void setLeftBtnDrawable(T obj){
339 | if(obj == null || mLeftBtnImgView == null)
340 | return;
341 | if(obj instanceof Integer)
342 | mLeftBtnImgView.setBackgroundResource((Integer) obj);
343 | else
344 | mLeftBtnImgView.setBackground((Drawable)obj);
345 | }
346 |
347 | public void setSubTitleText(T obj){
348 | if(obj == null)
349 | return;
350 | if(obj instanceof Integer)
351 | ((TextView)mSubTitleTextView).setText(getResources().getString((Integer) obj));
352 | else if(obj instanceof CharSequence)
353 | ((TextView)mSubTitleTextView).setText((CharSequence)obj);
354 | setSubTitleVisibility(View.VISIBLE);
355 | }
356 |
357 | public void setSubTitleVisibility(int visibility){
358 | mSubTitleTextView.setVisibility(visibility);
359 | ViewGroup.LayoutParams p = mTitleTextView.getLayoutParams();
360 | if(visibility == View.GONE){
361 | p.height = DEFAULT_TITLE_HEIGHT;
362 | }else if(visibility == View.VISIBLE){
363 | p.height = LayoutParams.WRAP_CONTENT;
364 | }
365 | }
366 |
367 | private void sendKeyBackEvent() {
368 | final Context context = getContext();
369 | if (context instanceof CoreActivity) {
370 | KeyEvent keyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK);
371 | ((CoreActivity) context).onKeyDown(KeyEvent.KEYCODE_BACK, keyEvent);
372 | } else if (context instanceof Activity) {
373 | KeyEvent keyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK);
374 | ((Activity) context).onKeyDown(KeyEvent.KEYCODE_BACK, keyEvent);
375 | }
376 | }
377 | // ===========================================================
378 | // Inner and Anonymous Classes
379 | // ===========================================================
380 | }
381 |
--------------------------------------------------------------------------------
/image-selector/src/main/java/com/iknow/imageselect/utils/MediaFileUtil.java:
--------------------------------------------------------------------------------
1 | package com.iknow.imageselect.utils;
2 |
3 | import android.content.ContentResolver;
4 | import android.content.Context;
5 | import android.database.Cursor;
6 | import android.graphics.Bitmap;
7 | import android.graphics.BitmapFactory;
8 | import android.net.Uri;
9 | import android.provider.BaseColumns;
10 | import android.provider.MediaStore;
11 | import android.support.v4.content.CursorLoader;
12 | import android.text.TextUtils;
13 | import android.util.Log;
14 | import com.iknow.imageselect.model.AlbumInfo;
15 | import com.iknow.imageselect.model.MediaInfo;
16 | import java.io.File;
17 | import java.util.ArrayList;
18 | import java.util.HashMap;
19 | import java.util.Iterator;
20 | import java.util.LinkedList;
21 | import java.util.Map;
22 |
23 | /**
24 | * Author: J.Chou
25 | * Email: who_know_me@163.com
26 | * Created: 2016年04月06日 4:24 PM
27 | * Description:
28 | */
29 |
30 | public class MediaFileUtil {
31 |
32 | static String[] projection = {
33 | MediaStore.Files.FileColumns._ID,
34 | MediaStore.Files.FileColumns.DATA,
35 | MediaStore.Files.FileColumns.DATE_ADDED,
36 | MediaStore.Files.FileColumns.MEDIA_TYPE,
37 | MediaStore.Files.FileColumns.MIME_TYPE,
38 | MediaStore.Files.FileColumns.TITLE
39 | };
40 |
41 | static String selection = MediaStore.Files.FileColumns.MEDIA_TYPE + "="
42 | + MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE
43 | + " OR "
44 | + MediaStore.Files.FileColumns.MEDIA_TYPE + "="
45 | + MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO;
46 |
47 |
48 | /**
49 | * param mContext
50 | * return
51 | */
52 | public static LinkedList getThumbnailsPhotosInfo(Context mContext) {
53 |
54 | LinkedList bitmaps = new LinkedList();
55 | Cursor cursor = null;
56 |
57 | try {
58 | cursor = mContext.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, null,
59 | null, MediaStore.Images.Media.DEFAULT_SORT_ORDER);
60 | if (cursor == null) {
61 | return bitmaps;
62 | }
63 | } catch (Exception err) {
64 | if (cursor != null)
65 | cursor.close();
66 | return bitmaps;
67 | }
68 |
69 | AlbumInfo albumInfo = null;
70 |
71 | HashMap> albums = getAlbumsInfo(mContext, cursor);
72 | cursor.close();
73 |
74 | String key = null;
75 | for (Iterator> it = albums.entrySet().iterator(); it.hasNext();) {
76 | Map.Entry e = (Map.Entry) it.next();
77 | LinkedList album = (LinkedList) e.getValue();
78 |
79 | if (album != null && album.size() > 0) {
80 | albumInfo = new AlbumInfo();
81 | key = (String) e.getKey();
82 | albumInfo.name = key.substring(key.lastIndexOf("/") + 1);
83 |
84 | albumInfo.fileId = album.get(0).fileId;
85 | albumInfo.filePath = album.get(0).filePath;
86 | ArrayList list = new ArrayList();
87 | for (int i = album.size() - 1; i >= 0; i--) {
88 | list.add(album.get(i));
89 | }
90 | albumInfo.medias = list;
91 |
92 | if (albumInfo.filePath.endsWith("DCIM/Camera")) {
93 | albumInfo.name = "相册";
94 | bitmaps.addFirst(albumInfo);
95 | } else {
96 | bitmaps.addLast(albumInfo);
97 | }
98 |
99 | }
100 | }
101 |
102 | return bitmaps;
103 | }
104 |
105 | public static HashMap> getAlbumsInfo(Context mContext,Cursor cursor) {
106 | HashMap> albumsInfos = new HashMap>();
107 | String _path = MediaStore.Images.Media.DATA;
108 | String _album = MediaStore.Images.Media.DEFAULT_SORT_ORDER;
109 | String _time = MediaStore.Images.Media.DATE_ADDED;
110 | String _rotate = MediaStore.Images.Media.ORIENTATION;
111 |
112 | HashMap thumbInfos = getThumbImgInfo(mContext);
113 |
114 | MediaInfo imageInfo = null;
115 | File file = null;
116 | try {
117 |
118 | if (cursor.moveToFirst()) {
119 | do {
120 | int _id = cursor.getInt(cursor.getColumnIndex(BaseColumns._ID));
121 | String path = cursor.getString(cursor.getColumnIndex(_path));
122 | String album = cursor.getString(cursor.getColumnIndex(_album));
123 | String time = cursor.getString(cursor.getColumnIndex(_time));
124 | int rotate = cursor.getInt(cursor.getColumnIndex(_rotate));
125 |
126 | file = new File(path);
127 | if (!file.exists() || file.length() == 0) {
128 | continue;
129 | }
130 |
131 | String subPath = path.substring(0, path.lastIndexOf("/"));
132 |
133 | if (albumsInfos.containsKey(getAlbumKey(subPath, album))) {
134 | LinkedList albums = albumsInfos
135 | .remove(getAlbumKey(subPath, album));
136 | imageInfo = new MediaInfo();
137 | imageInfo.fileId = _id;
138 | imageInfo.filePath = subPath;
139 | imageInfo.fileName = path;
140 | imageInfo.createTime = time;
141 | imageInfo.rotate = rotate;
142 | if(thumbInfos.containsKey(_id)){
143 | imageInfo.thumbPath = thumbInfos.get(_id);
144 | }
145 | albums.add(imageInfo);
146 | albumsInfos.put(getAlbumKey(subPath, album), albums);
147 | } else {
148 | LinkedList albums = new LinkedList();
149 | imageInfo = new MediaInfo();
150 | imageInfo.fileId = _id;
151 | imageInfo.filePath = subPath;
152 | imageInfo.fileName = path;
153 | imageInfo.createTime = time;
154 | imageInfo.rotate = rotate;
155 | if(thumbInfos.containsKey(_id)){
156 | imageInfo.thumbPath = thumbInfos.get(_id);
157 | }
158 | albums.add(imageInfo);
159 | albumsInfos.put(getAlbumKey(subPath, album), albums);
160 | }
161 | } while (cursor.moveToNext());
162 | }
163 | }catch(Exception e){
164 | e.printStackTrace();
165 | }
166 |
167 | return albumsInfos;
168 | }
169 |
170 | private static String getAlbumKey(String path, String name) {
171 | return path + "/" + name;
172 | }
173 |
174 | public static int getPicId(String pathAll) {
175 | String strId = pathAll.split("&")[0];
176 | int id = -1;
177 | try {
178 | id = Integer.valueOf(strId);
179 | } catch (NumberFormatException e) {
180 | e.printStackTrace();
181 | }
182 | return id;
183 | }
184 |
185 | public static Bitmap getThumbImage(Context mContext, int id) {
186 | return MediaStore.Images.Thumbnails.getThumbnail(mContext.getContentResolver(), id,
187 | MediaStore.Images.Thumbnails.MICRO_KIND, new BitmapFactory.Options());
188 |
189 | }
190 |
191 | public static String getFileName(String url) {
192 | if (TextUtils.isEmpty(url)) {
193 | return null;
194 | }
195 |
196 | return url.substring(url.lastIndexOf("/") + 1);
197 | }
198 |
199 | public static Bitmap getThumbImage(Context mContext, int id, BitmapFactory.Options options) {
200 | return MediaStore.Images.Thumbnails.getThumbnail(mContext.getContentResolver(), id,
201 | MediaStore.Images.Thumbnails.MICRO_KIND, options);
202 | }
203 |
204 | private static HashMap getThumbImgInfo(Context mContext){
205 | HashMap thumbMap = new HashMap();
206 |
207 | if(mContext == null){
208 | return thumbMap;
209 | }
210 |
211 | String[] projection = { MediaStore.Images.Thumbnails._ID, MediaStore.Images.Thumbnails.IMAGE_ID,
212 | MediaStore.Images.Thumbnails.DATA };
213 | Cursor cursor = null;
214 | try {
215 | cursor = mContext.getContentResolver().query(
216 | MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI, projection, null, null, null);
217 | if (cursor.moveToFirst()) {
218 | int image_id;
219 | String image_path;
220 | int image_idColumn = cursor.getColumnIndex(MediaStore.Images.Thumbnails.IMAGE_ID);
221 | int dataColumn = cursor.getColumnIndex(MediaStore.Images.Thumbnails.DATA);
222 | do {
223 | // Get the field values
224 | image_id = cursor.getInt(image_idColumn);
225 | image_path = cursor.getString(dataColumn);
226 |
227 | if(!new File(image_path).exists()){
228 | continue;
229 | }
230 |
231 | if(!TextUtils.isEmpty(image_path)){
232 | thumbMap.put(image_id, image_path);
233 | }
234 | } while (cursor.moveToNext());
235 | }
236 | } catch (Exception e) {
237 | e.printStackTrace();
238 | }finally{
239 | if(cursor != null){
240 | cursor.close();
241 | }
242 | }
243 |
244 | return thumbMap;
245 | }
246 |
247 | /**
248 | * 获取缩略图路径通过图片的id
249 | * param mContext
250 | * param id
251 | * return
252 | */
253 | public static String getThumbPathById(Context mContext, int id) {
254 |
255 | if(mContext == null){
256 | return null;
257 | }
258 |
259 | String[] projection = { MediaStore.Images.Thumbnails._ID, MediaStore.Images.Thumbnails.IMAGE_ID,
260 | MediaStore.Images.Thumbnails.DATA };
261 |
262 | String whereClause = MediaStore.Images.Thumbnails.IMAGE_ID + " = '"+ id + "'";
263 |
264 | Cursor cursor = mContext.getContentResolver().query(
265 | MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI, projection, whereClause, null, null);
266 | if (cursor == null || cursor.getCount() == 0) {
267 | if (cursor != null)
268 | cursor.close();
269 | return null;
270 | }
271 |
272 | String thumbPath = "";
273 | try {
274 | if (cursor.moveToFirst()) {
275 | int dataColumn = cursor.getColumnIndex(MediaStore.Images.Thumbnails.DATA);
276 | thumbPath = cursor.getString(dataColumn);
277 | }
278 | } catch (Exception e) {
279 | e.printStackTrace();
280 | }finally{
281 | if(cursor != null){
282 | cursor.close();
283 | }
284 | }
285 |
286 | return thumbPath;
287 | }
288 |
289 | public static Bitmap getThumbBitmap(Context mContext, String fileName) {
290 | Bitmap bitmap = null;
291 | BitmapFactory.Options options = new BitmapFactory.Options();
292 | options.inDither = false;
293 | options.inPreferredConfig = Bitmap.Config.ARGB_8888;
294 | // select condition.
295 | String whereClause = MediaStore.Images.Media.DISPLAY_NAME + " = '"
296 | + fileName + "'";
297 |
298 | // colection of results.
299 | Cursor cursor = mContext.getContentResolver().query(
300 | MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
301 | new String[] { MediaStore.Images.Media._ID }, whereClause,
302 | null, null);
303 | if (cursor == null || cursor.getCount() == 0) {
304 | if (cursor != null)
305 | cursor.close();
306 | return null;
307 | }
308 | cursor.moveToFirst();
309 | // image id in image table.
310 | String videoId = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media._ID));
311 | cursor.close();
312 | if (videoId == null) {
313 | return null;
314 | }
315 | long videoIdLong = Long.parseLong(videoId);
316 | // via imageid get the bimap type thumbnail in thumbnail table.
317 | bitmap = MediaStore.Images.Thumbnails.getThumbnail(
318 | mContext.getContentResolver(), videoIdLong,
319 | MediaStore.Images.Thumbnails.MINI_KIND, options);
320 | return bitmap;
321 | }
322 |
323 | /***
324 | * 获取本机相册所有的图片
325 | * param mContext
326 | */
327 | public static ArrayList getAllImageFiles(Context mContext){
328 | MediaInfo info;
329 | ArrayList _images = new ArrayList<>();
330 | try {
331 | String sortOrder = MediaStore.Images.Media.DATE_MODIFIED + " desc";
332 | Cursor cursor = mContext.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,null, null, null, sortOrder);
333 | while (cursor.moveToNext()) {
334 | info = new MediaInfo();
335 | info.fileName = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
336 | info.name = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DISPLAY_NAME));
337 | info.createTime = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATE_ADDED));
338 | info.fileId = cursor.getInt(cursor.getColumnIndex(MediaStore.Images.Media._ID));
339 | info.lat = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.LATITUDE));
340 | info.lon = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.LONGITUDE));
341 | if(!TextUtils.isEmpty(info.lat)){
342 | Log.e("jason","info.lat ="+info.lat);
343 | }
344 | if(!TextUtils.isEmpty(info.lon)){
345 | Log.e("jason","info.lon ="+info.lon);
346 | }
347 | _images.add(info);
348 | }
349 | cursor.close();
350 | }catch (Exception e){
351 | e.printStackTrace();
352 | }
353 |
354 | return _images;
355 |
356 | }
357 |
358 | public static ArrayList getAllVideoFiles(Context mContext){
359 | MediaInfo mediaInfo;
360 | ArrayList videos = new ArrayList<>();
361 | ContentResolver contentResolver = mContext.getContentResolver();
362 | try {
363 | Cursor cursor = contentResolver.query(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, null,
364 | null, null, MediaStore.Video.Media.DEFAULT_SORT_ORDER);
365 | while (cursor.moveToNext()) {
366 | mediaInfo = new MediaInfo();
367 | mediaInfo.fileName = cursor.getString(cursor.getColumnIndex(MediaStore.Video.Media.DATA));
368 | mediaInfo.createTime = cursor.getString(cursor.getColumnIndex(MediaStore.Video.Media.DATE_ADDED));
369 | mediaInfo.name = cursor.getString(cursor.getColumnIndex(MediaStore.Video.Media.DISPLAY_NAME));
370 | mediaInfo.mediaType = 3;
371 | videos.add(mediaInfo);
372 | }
373 |
374 | cursor.close();
375 | } catch (Exception e) {
376 | e.printStackTrace();
377 | }
378 | return videos;
379 | }
380 |
381 | public static ArrayList getAllMediaFiles(Context mContext){
382 | MediaInfo mediaInfo;
383 | ArrayList allMediasList = new ArrayList<>();
384 |
385 | Uri queryUri = MediaStore.Files.getContentUri("external");
386 |
387 | try {
388 | CursorLoader cursorLoader = new CursorLoader(
389 | mContext,
390 | queryUri,
391 | projection,
392 | selection,
393 | null, // Selection args (none).
394 | MediaStore.Files.FileColumns.DATE_ADDED + " DESC" // Sort order.
395 | );
396 |
397 | Cursor cursor = cursorLoader.loadInBackground();
398 |
399 | while (cursor.moveToNext()) {
400 | mediaInfo = new MediaInfo();
401 | mediaInfo.fileName = cursor.getString(cursor.getColumnIndex(MediaStore.Files.FileColumns.DATA));
402 | mediaInfo.createTime = cursor.getString(cursor.getColumnIndex(MediaStore.Files.FileColumns.DATE_ADDED));
403 | mediaInfo.name = cursor.getString(cursor.getColumnIndex(MediaStore.Files.FileColumns.TITLE));
404 | mediaInfo.mediaType = cursor.getInt(cursor.getColumnIndex(MediaStore.Files.FileColumns.MEDIA_TYPE));
405 | allMediasList.add(mediaInfo);
406 | }
407 | cursor.close();
408 | }catch (Exception e){
409 | e.printStackTrace();
410 | }
411 |
412 | return allMediasList;
413 | }
414 |
415 | }
416 |
--------------------------------------------------------------------------------
/image-selector/src/main/java/com/iknow/imageselect/photodraweeview/Attacher.java:
--------------------------------------------------------------------------------
1 | package com.iknow.imageselect.photodraweeview;
2 |
3 | import android.content.Context;
4 | import android.graphics.Matrix;
5 | import android.graphics.RectF;
6 | import android.os.Build;
7 | import android.support.annotation.Nullable;
8 | import android.support.v4.view.GestureDetectorCompat;
9 | import android.support.v4.view.MotionEventCompat;
10 | import android.support.v4.widget.ScrollerCompat;
11 | import android.view.GestureDetector;
12 | import android.view.MotionEvent;
13 | import android.view.View;
14 | import android.view.ViewParent;
15 | import android.view.animation.AccelerateDecelerateInterpolator;
16 | import android.view.animation.Interpolator;
17 |
18 | import com.facebook.drawee.drawable.ScalingUtils;
19 | import com.facebook.drawee.generic.GenericDraweeHierarchy;
20 | import com.facebook.drawee.view.DraweeView;
21 |
22 | import java.lang.ref.WeakReference;
23 |
24 | public class Attacher implements IAttacher, View.OnTouchListener, OnScaleDragGestureListener {
25 |
26 | private static final int EDGE_NONE = -1;
27 | private static final int EDGE_LEFT = 0;
28 | private static final int EDGE_RIGHT = 1;
29 | private static final int EDGE_BOTH = 2;
30 |
31 | private final float[] mMatrixValues = new float[9];
32 | private final RectF mDisplayRect = new RectF();
33 | private final Interpolator mZoomInterpolator = new AccelerateDecelerateInterpolator();
34 |
35 | private float mMinScale = IAttacher.DEFAULT_MIN_SCALE;
36 | private float mMidScale = IAttacher.DEFAULT_MID_SCALE;
37 | private float mMaxScale = IAttacher.DEFAULT_MAX_SCALE;
38 | private long mZoomDuration = IAttacher.ZOOM_DURATION;
39 |
40 | private ScaleDragDetector mScaleDragDetector;
41 | private GestureDetectorCompat mGestureDetector;
42 |
43 | private boolean mBlockParentIntercept = false;
44 | private boolean mAllowParentInterceptOnEdge = true;
45 | private int mScrollEdge = EDGE_BOTH;
46 |
47 | private final Matrix mMatrix = new Matrix();
48 | private int mImageInfoHeight = -1, mImageInfoWidth = -1;
49 | private FlingRunnable mCurrentFlingRunnable;
50 | private WeakReference> mDraweeView;
51 |
52 | private OnPhotoTapListener mPhotoTapListener;
53 | private OnViewTapListener mViewTapListener;
54 | private View.OnLongClickListener mLongClickListener;
55 | private OnScaleChangeListener mScaleChangeListener;
56 |
57 | public Attacher(DraweeView draweeView) {
58 | mDraweeView = new WeakReference<>(draweeView);
59 | draweeView.getHierarchy().setActualImageScaleType(ScalingUtils.ScaleType.FIT_CENTER);
60 | draweeView.setOnTouchListener(this);
61 | mScaleDragDetector = new ScaleDragDetector(draweeView.getContext(), this);
62 | mGestureDetector = new GestureDetectorCompat(draweeView.getContext(),
63 | new GestureDetector.SimpleOnGestureListener() {
64 | @Override public void onLongPress(MotionEvent e) {
65 | super.onLongPress(e);
66 | if (null != mLongClickListener) {
67 | mLongClickListener.onLongClick(getDraweeView());
68 | }
69 | }
70 | });
71 | mGestureDetector.setOnDoubleTapListener(new DefaultOnDoubleTapListener(this));
72 | }
73 |
74 | public void setOnDoubleTapListener(GestureDetector.OnDoubleTapListener newOnDoubleTapListener) {
75 | if (newOnDoubleTapListener != null) {
76 | this.mGestureDetector.setOnDoubleTapListener(newOnDoubleTapListener);
77 | } else {
78 | this.mGestureDetector.setOnDoubleTapListener(new DefaultOnDoubleTapListener(this));
79 | }
80 | }
81 |
82 | @Nullable public DraweeView getDraweeView() {
83 | return mDraweeView.get();
84 | }
85 |
86 | @Override public float getMinimumScale() {
87 | return mMinScale;
88 | }
89 |
90 | @Override
91 |
92 | public float getMediumScale() {
93 | return mMidScale;
94 | }
95 |
96 | @Override
97 |
98 | public float getMaximumScale() {
99 | return mMaxScale;
100 | }
101 |
102 | @Override public void setMaximumScale(float maximumScale) {
103 | checkZoomLevels(mMinScale, mMidScale, maximumScale);
104 | mMaxScale = maximumScale;
105 | }
106 |
107 | @Override public void setMediumScale(float mediumScale) {
108 | checkZoomLevels(mMinScale, mediumScale, mMaxScale);
109 | mMidScale = mediumScale;
110 | }
111 |
112 | @Override public void setMinimumScale(float minimumScale) {
113 | checkZoomLevels(minimumScale, mMidScale, mMaxScale);
114 | mMinScale = minimumScale;
115 | }
116 |
117 | @Override public float getScale() {
118 | return (float) Math.sqrt(
119 | (float) Math.pow(getMatrixValue(mMatrix, Matrix.MSCALE_X), 2) + (float) Math.pow(
120 | getMatrixValue(mMatrix, Matrix.MSKEW_Y), 2));
121 | }
122 |
123 | @Override public void setScale(float scale) {
124 | setScale(scale, false);
125 | }
126 |
127 | @Override public void setScale(float scale, boolean animate) {
128 | DraweeView draweeView = getDraweeView();
129 | if (draweeView != null) {
130 | setScale(scale, (draweeView.getRight()) / 2, (draweeView.getBottom()) / 2, false);
131 | }
132 | }
133 |
134 | @Override public void setScale(float scale, float focalX, float focalY, boolean animate) {
135 | DraweeView draweeView = getDraweeView();
136 |
137 | if (draweeView == null || scale < mMinScale || scale > mMaxScale) {
138 | return;
139 | }
140 |
141 | if (animate) {
142 | draweeView.post(new AnimatedZoomRunnable(getScale(), scale, focalX, focalY));
143 | } else {
144 | mMatrix.setScale(scale, scale, focalX, focalY);
145 | checkMatrixAndInvalidate();
146 | }
147 | }
148 |
149 | @Override public void setZoomTransitionDuration(long duration) {
150 | duration = duration < 0 ? IAttacher.ZOOM_DURATION : duration;
151 | mZoomDuration = duration;
152 | }
153 |
154 | @Override public void setAllowParentInterceptOnEdge(boolean allow) {
155 | mAllowParentInterceptOnEdge = allow;
156 | }
157 |
158 | @Override public void setOnScaleChangeListener(OnScaleChangeListener listener) {
159 | mScaleChangeListener = listener;
160 | }
161 |
162 | @Override public void setOnLongClickListener(View.OnLongClickListener listener) {
163 | mLongClickListener = listener;
164 | }
165 |
166 | @Override public void setOnPhotoTapListener(OnPhotoTapListener listener) {
167 | mPhotoTapListener = listener;
168 | }
169 |
170 | @Override public void setOnViewTapListener(OnViewTapListener listener) {
171 | mViewTapListener = listener;
172 | }
173 |
174 | @Override public OnPhotoTapListener getOnPhotoTapListener() {
175 | return mPhotoTapListener;
176 | }
177 |
178 | @Override public OnViewTapListener getOnViewTapListener() {
179 | return mViewTapListener;
180 | }
181 |
182 | @Override public void update(int imageInfoWidth, int imageInfoHeight) {
183 | mImageInfoWidth = imageInfoWidth;
184 | mImageInfoHeight = imageInfoHeight;
185 | updateBaseMatrix();
186 | }
187 |
188 | private static void checkZoomLevels(float minZoom, float midZoom, float maxZoom) {
189 | if (minZoom >= midZoom) {
190 | throw new IllegalArgumentException("MinZoom has to be less than MidZoom");
191 | } else if (midZoom >= maxZoom) {
192 | throw new IllegalArgumentException("MidZoom has to be less than MaxZoom");
193 | }
194 | }
195 |
196 | private int getViewWidth() {
197 |
198 | DraweeView draweeView = getDraweeView();
199 |
200 | if (draweeView != null) {
201 |
202 | return draweeView.getWidth()
203 | - draweeView.getPaddingLeft()
204 | - draweeView.getPaddingRight();
205 | }
206 |
207 | return 0;
208 | }
209 |
210 | private int getViewHeight() {
211 | DraweeView draweeView = getDraweeView();
212 | if (draweeView != null) {
213 | return draweeView.getHeight()
214 | - draweeView.getPaddingTop()
215 | - draweeView.getPaddingBottom();
216 | }
217 | return 0;
218 | }
219 |
220 | private float getMatrixValue(Matrix matrix, int whichValue) {
221 | matrix.getValues(mMatrixValues);
222 | return mMatrixValues[whichValue];
223 | }
224 |
225 | public Matrix getDrawMatrix() {
226 | return mMatrix;
227 | }
228 |
229 | public RectF getDisplayRect() {
230 | checkMatrixBounds();
231 | return getDisplayRect(getDrawMatrix());
232 | }
233 |
234 | public void checkMatrixAndInvalidate() {
235 |
236 | DraweeView draweeView = getDraweeView();
237 |
238 | if (draweeView == null) {
239 | return;
240 | }
241 |
242 | if (checkMatrixBounds()) {
243 | draweeView.invalidate();
244 | }
245 | }
246 |
247 | public boolean checkMatrixBounds() {
248 | RectF rect = getDisplayRect(getDrawMatrix());
249 | if (rect == null) {
250 | return false;
251 | }
252 |
253 | float height = rect.height();
254 | float width = rect.width();
255 | float deltaX = 0.0F;
256 | float deltaY = 0.0F;
257 | int viewHeight = getViewHeight();
258 |
259 | if (height <= (float) viewHeight) {
260 | deltaY = (viewHeight - height) / 2 - rect.top;
261 | } else if (rect.top > 0.0F) {
262 | deltaY = -rect.top;
263 | } else if (rect.bottom < (float) viewHeight) {
264 | deltaY = viewHeight - rect.bottom;
265 | }
266 | int viewWidth = getViewWidth();
267 | if (width <= viewWidth) {
268 | deltaX = (viewWidth - width) / 2 - rect.left;
269 | mScrollEdge = EDGE_BOTH;
270 | } else if (rect.left > 0) {
271 | deltaX = -rect.left;
272 | mScrollEdge = EDGE_LEFT;
273 | } else if (rect.right < viewWidth) {
274 | deltaX = viewWidth - rect.right;
275 | mScrollEdge = EDGE_RIGHT;
276 | } else {
277 | mScrollEdge = EDGE_NONE;
278 | }
279 |
280 | mMatrix.postTranslate(deltaX, deltaY);
281 | return true;
282 | }
283 |
284 | private RectF getDisplayRect(Matrix matrix) {
285 | DraweeView draweeView = getDraweeView();
286 | if (draweeView == null || (mImageInfoWidth == -1 && mImageInfoHeight == -1)) {
287 | return null;
288 | }
289 | mDisplayRect.set(0.0F, 0.0F, mImageInfoWidth, mImageInfoHeight);
290 | draweeView.getHierarchy().getActualImageBounds(mDisplayRect);
291 | matrix.mapRect(mDisplayRect);
292 | return mDisplayRect;
293 | }
294 |
295 | private void updateBaseMatrix() {
296 | if (mImageInfoWidth == -1 && mImageInfoHeight == -1) {
297 | return;
298 | }
299 | resetMatrix();
300 | }
301 |
302 | private void resetMatrix() {
303 | mMatrix.reset();
304 | checkMatrixBounds();
305 | DraweeView draweeView = getDraweeView();
306 | if (draweeView != null) {
307 | draweeView.invalidate();
308 | }
309 | }
310 |
311 | private void checkMinScale() {
312 | DraweeView draweeView = getDraweeView();
313 | if (draweeView == null) {
314 | return;
315 | }
316 |
317 | if (getScale() < mMinScale) {
318 | RectF rect = getDisplayRect();
319 | if (null != rect) {
320 | draweeView.post(new AnimatedZoomRunnable(getScale(), mMinScale, rect.centerX(),
321 | rect.centerY()));
322 | }
323 | }
324 | }
325 |
326 | @Override public void onScale(float scaleFactor, float focusX, float focusY) {
327 | if (getScale() < mMaxScale || scaleFactor < 1.0F) {
328 |
329 | if (mScaleChangeListener != null) {
330 | mScaleChangeListener.onScaleChange(scaleFactor, focusX, focusY);
331 | }
332 |
333 | mMatrix.postScale(scaleFactor, scaleFactor, focusX, focusY);
334 | checkMatrixAndInvalidate();
335 | }
336 | }
337 |
338 | @Override public void onScaleEnd() {
339 | checkMinScale();
340 | }
341 |
342 | @Override public void onDrag(float dx, float dy) {
343 |
344 | DraweeView draweeView = getDraweeView();
345 |
346 | if (draweeView != null && !mScaleDragDetector.isScaling()) {
347 | mMatrix.postTranslate(dx, dy);
348 | checkMatrixAndInvalidate();
349 |
350 | ViewParent parent = draweeView.getParent();
351 | if (parent == null) {
352 | return;
353 | }
354 |
355 | if (mAllowParentInterceptOnEdge
356 | && !mScaleDragDetector.isScaling()
357 | && !mBlockParentIntercept) {
358 | if (mScrollEdge == EDGE_BOTH || (mScrollEdge == EDGE_LEFT && dx >= 1f) || (
359 | mScrollEdge == EDGE_RIGHT
360 | && dx <= -1f)) {
361 | parent.requestDisallowInterceptTouchEvent(false);
362 | }
363 | } else {
364 | parent.requestDisallowInterceptTouchEvent(true);
365 | }
366 | }
367 | }
368 |
369 | @Override public void onFling(float startX, float startY, float velocityX, float velocityY) {
370 | DraweeView draweeView = getDraweeView();
371 | if (draweeView == null) {
372 | return;
373 | }
374 |
375 | mCurrentFlingRunnable = new FlingRunnable(draweeView.getContext());
376 | mCurrentFlingRunnable.fling(getViewWidth(), getViewHeight(), (int) velocityX,
377 | (int) velocityY);
378 | draweeView.post(mCurrentFlingRunnable);
379 | }
380 |
381 | @Override public boolean onTouch(View v, MotionEvent event) {
382 | int action = MotionEventCompat.getActionMasked(event);
383 | switch (action) {
384 | case MotionEvent.ACTION_DOWN: {
385 | ViewParent parent = v.getParent();
386 | if (parent != null) {
387 | parent.requestDisallowInterceptTouchEvent(true);
388 | }
389 | cancelFling();
390 | }
391 | break;
392 | case MotionEvent.ACTION_UP:
393 | case MotionEvent.ACTION_CANCEL: {
394 | ViewParent parent = v.getParent();
395 | if (parent != null) {
396 | parent.requestDisallowInterceptTouchEvent(false);
397 | }
398 | }
399 | break;
400 | }
401 |
402 | boolean wasScaling = mScaleDragDetector.isScaling();
403 | boolean wasDragging = mScaleDragDetector.isDragging();
404 |
405 | boolean handled = mScaleDragDetector.onTouchEvent(event);
406 |
407 | boolean noScale = !wasScaling && !mScaleDragDetector.isScaling();
408 | boolean noDrag = !wasDragging && !mScaleDragDetector.isDragging();
409 | mBlockParentIntercept = noScale && noDrag;
410 |
411 | if (mGestureDetector.onTouchEvent(event)) {
412 | handled = true;
413 | }
414 |
415 | return handled;
416 | }
417 |
418 | private class AnimatedZoomRunnable implements Runnable {
419 | private final float mFocalX, mFocalY;
420 | private final long mStartTime;
421 | private final float mZoomStart, mZoomEnd;
422 |
423 | public AnimatedZoomRunnable(final float currentZoom, final float targetZoom,
424 | final float focalX, final float focalY) {
425 | mFocalX = focalX;
426 | mFocalY = focalY;
427 | mStartTime = System.currentTimeMillis();
428 | mZoomStart = currentZoom;
429 | mZoomEnd = targetZoom;
430 | }
431 |
432 | @Override public void run() {
433 |
434 | DraweeView draweeView = getDraweeView();
435 | if (draweeView == null) {
436 | return;
437 | }
438 |
439 | float t = interpolate();
440 | float scale = mZoomStart + t * (mZoomEnd - mZoomStart);
441 | float deltaScale = scale / getScale();
442 |
443 | onScale(deltaScale, mFocalX, mFocalY);
444 |
445 | if (t < 1f) {
446 | postOnAnimation(draweeView, this);
447 | }
448 | }
449 |
450 | private float interpolate() {
451 | float t = 1f * (System.currentTimeMillis() - mStartTime) / mZoomDuration;
452 | t = Math.min(1f, t);
453 | t = mZoomInterpolator.getInterpolation(t);
454 | return t;
455 | }
456 | }
457 |
458 | private class FlingRunnable implements Runnable {
459 |
460 | private final ScrollerCompat mScroller;
461 | private int mCurrentX, mCurrentY;
462 |
463 | public FlingRunnable(Context context) {
464 | mScroller = ScrollerCompat.create(context);
465 | }
466 |
467 | public void cancelFling() {
468 | mScroller.abortAnimation();
469 | }
470 |
471 | public void fling(int viewWidth, int viewHeight, int velocityX, int velocityY) {
472 | final RectF rect = getDisplayRect();
473 | if (null == rect) {
474 | return;
475 | }
476 |
477 | final int startX = Math.round(-rect.left);
478 | final int minX, maxX, minY, maxY;
479 |
480 | if (viewWidth < rect.width()) {
481 | minX = 0;
482 | maxX = Math.round(rect.width() - viewWidth);
483 | } else {
484 | minX = maxX = startX;
485 | }
486 |
487 | final int startY = Math.round(-rect.top);
488 | if (viewHeight < rect.height()) {
489 | minY = 0;
490 | maxY = Math.round(rect.height() - viewHeight);
491 | } else {
492 | minY = maxY = startY;
493 | }
494 |
495 | mCurrentX = startX;
496 | mCurrentY = startY;
497 |
498 | if (startX != maxX || startY != maxY) {
499 | mScroller.fling(startX, startY, velocityX, velocityY, minX, maxX, minY, maxY, 0, 0);
500 | }
501 | }
502 |
503 | @Override public void run() {
504 | if (mScroller.isFinished()) {
505 | return;
506 | }
507 |
508 | DraweeView draweeView = getDraweeView();
509 |
510 | if (draweeView != null && mScroller.computeScrollOffset()) {
511 | final int newX = mScroller.getCurrX();
512 | final int newY = mScroller.getCurrY();
513 | mMatrix.postTranslate(mCurrentX - newX, mCurrentY - newY);
514 | draweeView.invalidate();
515 | mCurrentX = newX;
516 | mCurrentY = newY;
517 | postOnAnimation(draweeView, this);
518 | }
519 | }
520 | }
521 |
522 | private void cancelFling() {
523 | if (mCurrentFlingRunnable != null) {
524 | mCurrentFlingRunnable.cancelFling();
525 | mCurrentFlingRunnable = null;
526 | }
527 | }
528 |
529 | private void postOnAnimation(View view, Runnable runnable) {
530 | if (Build.VERSION.SDK_INT >= 16) {
531 | view.postOnAnimation(runnable);
532 | } else {
533 | view.postDelayed(runnable, 16L);
534 | }
535 | }
536 |
537 | protected void onDetachedFromWindow() {
538 | cancelFling();
539 | }
540 | }
541 |
--------------------------------------------------------------------------------