├── .gitignore
├── .idea
├── .name
├── compiler.xml
├── copyright
│ └── profiles_settings.xml
├── gradle.xml
├── misc.xml
├── modules.xml
├── runConfigurations.xml
└── vcs.xml
├── MultiImageSelector.iml
├── README.md
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── library
├── .gitignore
├── build.gradle
├── gradle.properties
├── library.iml
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── yongchun
│ │ └── library
│ │ └── ApplicationTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── yongchun
│ │ │ └── library
│ │ │ ├── adapter
│ │ │ ├── ImageFolderAdapter.java
│ │ │ └── ImageListAdapter.java
│ │ │ ├── model
│ │ │ ├── LocalMedia.java
│ │ │ └── LocalMediaFolder.java
│ │ │ ├── utils
│ │ │ ├── CropUtil.java
│ │ │ ├── FileUtils.java
│ │ │ ├── GridSpacingItemDecoration.java
│ │ │ ├── LocalMediaLoader.java
│ │ │ └── ScreenUtils.java
│ │ │ ├── view
│ │ │ ├── FolderWindow.java
│ │ │ ├── ImageCropActivity.java
│ │ │ ├── ImagePreviewActivity.java
│ │ │ ├── ImagePreviewFragment.java
│ │ │ └── ImageSelectorActivity.java
│ │ │ └── widget
│ │ │ ├── PreviewViewPager.java
│ │ │ └── SquareRelativeLayout.java
│ └── res
│ │ ├── anim
│ │ ├── down_out.xml
│ │ ├── fade_in.xml
│ │ ├── fade_out.xml
│ │ └── up_in.xml
│ │ ├── color
│ │ └── white_text_selector.xml
│ │ ├── drawable
│ │ ├── btn_round_green_disable.xml
│ │ ├── btn_round_green_enable.xml
│ │ ├── btn_round_green_selector.xml
│ │ ├── check_green.xml
│ │ ├── checkbox_checktor.xml
│ │ ├── checkbox_selector.xml
│ │ ├── image_placeholder.xml
│ │ ├── item_divider.xml
│ │ └── radio_button.xml
│ │ ├── layout
│ │ ├── activity_image_crop.xml
│ │ ├── activity_image_preview.xml
│ │ ├── activity_imageselector.xml
│ │ ├── fragment_image_preview.xml
│ │ ├── item_camera.xml
│ │ ├── item_folder.xml
│ │ ├── item_picture.xml
│ │ └── window_folder.xml
│ │ ├── mipmap-xhdpi
│ │ ├── ic_back.png
│ │ └── ic_camera.png
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_arrow.png
│ │ ├── ic_check.png
│ │ ├── ic_checked.png
│ │ ├── ic_placeholder.png
│ │ └── ic_radio_button.png
│ │ ├── values-zh-rCN
│ │ └── strings.xml
│ │ └── values
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── yongchun
│ └── library
│ └── ExampleUnitTest.java
├── sample
├── .gitignore
├── Example-release.apk
├── build.gradle
├── proguard-rules.pro
├── sample.iml
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── yongchun
│ │ └── multiimageselector
│ │ └── ApplicationTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── yongchun
│ │ │ └── multiimageselector
│ │ │ ├── MainActivity.java
│ │ │ └── SelectResultActivity.java
│ └── res
│ │ ├── layout
│ │ ├── activity_main.xml
│ │ ├── activity_result.xml
│ │ ├── item_result.xml
│ │ └── layout_number.xml
│ │ ├── mipmap-hdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-mdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_minus.png
│ │ └── ic_plus.png
│ │ ├── mipmap-xxhdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xxxhdpi
│ │ └── ic_launcher.png
│ │ ├── values-w820dp
│ │ └── dimens.xml
│ │ ├── values-zh-rCN
│ │ └── strings.xml
│ │ └── values
│ │ ├── attrs.xml
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── yongchun
│ └── multiimageselector
│ └── ExampleUnitTest.java
├── screenshot
├── Screenshot1.jpg
├── Screenshot2.jpg
├── Screenshot3.jpg
├── Screenshot4.jpg
└── Screenshot5.jpg
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle
2 | /local.properties
3 | /.idea/workspace.xml
4 | /.idea/libraries
5 | .DS_Store
6 | /build
7 | /captures
8 |
--------------------------------------------------------------------------------
/.idea/.name:
--------------------------------------------------------------------------------
1 | MultiImageSelector
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
18 |
19 |
--------------------------------------------------------------------------------
/.idea/misc.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 | Encapsulation issues
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 | 1.8
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 | 1.8
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/MultiImageSelector.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ImageSelector
2 | Image selector library for Android. Support single choice、multi-choice、cropping image and preview image.
3 |
4 | 
5 | 
6 | 
7 |
8 | 
9 | 
10 |
11 | ## Quick start
12 |
13 | 1) Add Library module as a dependency in your build.gradle file.
14 |
15 | or
16 |
17 | ```xml
18 | dependencies {
19 | compile 'com.android.support:recyclerview-v7:22.2.1'
20 | compile 'com.github.bumptech.glide:glide:3.6.1'
21 | compile 'com.commit451:PhotoView:1.2.4'
22 | compile 'com.isseiaoki:simplecropview:1.0.13'
23 | compile 'com.yongchun:com.yongchun.imageselector:1.1.0'
24 | }
25 | ```
26 |
27 | 2) Declare permission in your AndroidManifest.xml
28 |
29 | ```xml
30 |
31 |
32 | ```
33 | ```java
34 |
35 |
36 |
37 | ```
38 |
39 | 3) Call ImageSelectorActivity in your code
40 |
41 | ```java
42 | ImageSelectorActivity.start(MainActivity.this, maxSelectNum, mode, isShow,isPreview,isCrop);
43 | ```
44 | same this
45 |
46 | ```java
47 | public static void start(Activity activity, int maxSelectNum, int mode, boolean isShow, boolean enablePreview, boolean enableCrop) {
48 | Intent intent = new Intent(activity, ImageSelectorActivity.class);
49 | intent.putExtra(EXTRA_MAX_SELECT_NUM, maxSelectNum);
50 | intent.putExtra(EXTRA_SELECT_MODE, mode);
51 | intent.putExtra(EXTRA_SHOW_CAMERA, isShow);
52 | intent.putExtra(EXTRA_ENABLE_PREVIEW, enablePreview);
53 | intent.putExtra(EXTRA_ENABLE_CROP, enableCrop);
54 | activity.startActivityForResult(intent, REQUEST_IMAGE);
55 | }
56 | ```
57 | 4) Receive result in your onActivityResult Method
58 |
59 | ``` java
60 | @Override
61 | protected void onActivityResult(int requestCode, int resultCode, Intent data) {
62 | if(resultCode == RESULT_OK && requestCode == ImageSelectorActivity.REQUEST_IMAGE){
63 | ArrayList images = (ArrayList) data.getSerializableExtra(ImageSelectorActivity.REQUEST_OUTPUT);
64 | // do something
65 | }
66 | }
67 | ```
68 |
69 | ## Thanks
70 |
71 | * [Glide](https://github.com/bumptech/glide)
72 |
73 | * [PhotoView](https://github.com/chrisbanes/PhotoView)
74 |
75 | * [simplecropview](https://github.com/IsseiAoki/SimpleCropView)
76 |
77 | ###License
78 | >The MIT License (MIT)
79 |
80 | >Copyright (c) 2015 Dee
81 |
82 | >Permission is hereby granted, free of charge, to any person obtaining a copy
83 | of this software and associated documentation files (the "Software"), to deal
84 | in the Software without restriction, including without limitation the rights
85 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
86 | copies of the Software, and to permit persons to whom the Software is
87 | furnished to do so, subject to the following conditions:
88 |
89 | >The above copyright notice and this permission notice shall be included in all
90 | copies or substantial portions of the Software.
91 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:1.5.0'
9 |
10 | // NOTE: Do not place your application dependencies here; they belong
11 | // in the individual module build.gradle files
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | jcenter()
18 | }
19 | }
20 |
21 | task clean(type: Delete) {
22 | delete rootProject.buildDir
23 | }
24 |
--------------------------------------------------------------------------------
/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
19 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ioneday/ImageSelector/c922b7ba9b50a5983d4e26ba88441225a58e967e/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Thu Nov 19 10:13:17 CST 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.4-all.zip
7 |
--------------------------------------------------------------------------------
/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 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/library/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/library/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | buildscript {
3 | repositories {
4 | jcenter()
5 | }
6 | dependencies {
7 | classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.2'
8 | classpath "org.jfrog.buildinfo:build-info-extractor-gradle:3.1.1"
9 | }
10 | }
11 |
12 |
13 | android {
14 | compileSdkVersion 22
15 | buildToolsVersion "22.0.1"
16 |
17 | defaultConfig {
18 | minSdkVersion 15
19 | targetSdkVersion 22
20 | versionCode 1
21 | versionName "1.0"
22 | }
23 | buildTypes {
24 | release {
25 | minifyEnabled false
26 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
27 | }
28 | }
29 | sourceSets {
30 | main {
31 | manifest.srcFile 'src/main/AndroidManifest.xml'
32 | }
33 | }
34 | }
35 |
36 | dependencies {
37 | compile fileTree(include: ['*.jar'], dir: 'libs')
38 | testCompile 'junit:junit:4.12'
39 | compile 'com.android.support:appcompat-v7:22.2.1'
40 | compile 'com.android.support:recyclerview-v7:22.2.1'
41 | compile 'com.github.bumptech.glide:glide:3.6.1'
42 | compile 'com.commit451:PhotoView:1.2.4'
43 | compile 'com.isseiaoki:simplecropview:1.0.13'
44 | }
45 |
--------------------------------------------------------------------------------
/library/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
19 |
20 | PROJ_GROUP=com.yongchun
21 | PROJ_VERSION=1.1.0
22 | PROJ_NAME=ImageSelector
23 | PROJ_WEBSITEURL=https://github.com/ioneday/ImageSelector
24 | PROJ_ISSUETRACKERURL=
25 | PROJ_VCSURL=https://github.com/ioneday/ImageSelector.git
26 | PROJ_DESCRIPTION=Mulitple ImageSelector
27 | PROJ_ARTIFACTID=com.yongchun.imageselector
28 |
29 | DEVELOPER_ID=dee
30 | DEVELOPER_NAME=LiYongChun
31 | DEVELOPER_EMAIL=heiyongchun@gmail.com
32 |
--------------------------------------------------------------------------------
/library/library.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | generateDebugAndroidTestSources
19 | generateDebugSources
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 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
--------------------------------------------------------------------------------
/library/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/dzq/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 |
--------------------------------------------------------------------------------
/library/src/androidTest/java/com/yongchun/library/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package com.yongchun.library;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/library/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
11 |
14 |
17 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/library/src/main/java/com/yongchun/library/adapter/ImageFolderAdapter.java:
--------------------------------------------------------------------------------
1 | package com.yongchun.library.adapter;
2 |
3 | import android.content.Context;
4 | import android.support.v7.widget.RecyclerView;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 | import android.widget.ImageView;
9 | import android.widget.TextView;
10 |
11 | import com.bumptech.glide.Glide;
12 | import com.yongchun.library.R;
13 | import com.yongchun.library.model.LocalMedia;
14 | import com.yongchun.library.model.LocalMediaFolder;
15 |
16 | import java.io.File;
17 | import java.util.ArrayList;
18 | import java.util.List;
19 |
20 | /**
21 | * Created by dee on 15/11/20.
22 | */
23 | public class ImageFolderAdapter extends RecyclerView.Adapter{
24 | private Context context;
25 | private List folders = new ArrayList<>();
26 | private int checkedIndex = 0;
27 |
28 | private OnItemClickListener onItemClickListener;
29 | public ImageFolderAdapter(Context context) {
30 | this.context = context;
31 | }
32 |
33 | public void bindFolder(List folders){
34 | this.folders = folders;
35 | notifyDataSetChanged();
36 | }
37 |
38 | @Override
39 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
40 | View itemView = LayoutInflater.from(context).inflate(R.layout.item_folder,parent,false);
41 | return new ViewHolder(itemView);
42 | }
43 |
44 | @Override
45 | public void onBindViewHolder(ViewHolder holder, final int position) {
46 | final LocalMediaFolder folder = folders.get(position);
47 | Glide.with(context)
48 | .load(new File(folder.getFirstImagePath()))
49 | .placeholder(R.mipmap.ic_placeholder)
50 | .error(R.mipmap.ic_placeholder)
51 | .centerCrop()
52 | .into(holder.firstImage);
53 | holder.folderName.setText(folder.getName());
54 | holder.imageNum.setText(context.getString(R.string.num_postfix,folder.getImageNum()));
55 |
56 | holder.isSelected.setVisibility(checkedIndex == position ? View.VISIBLE : View.GONE);
57 |
58 | holder.contentView.setOnClickListener(new View.OnClickListener() {
59 | @Override
60 | public void onClick(View v) {
61 | if (onItemClickListener != null) {
62 | checkedIndex = position;
63 | notifyDataSetChanged();
64 | onItemClickListener.onItemClick(folder.getName(),folder.getImages());
65 | }
66 | }
67 | });
68 | }
69 |
70 | @Override
71 | public int getItemCount() {
72 | return folders.size();
73 | }
74 |
75 | class ViewHolder extends RecyclerView.ViewHolder{
76 | ImageView firstImage;
77 | TextView folderName;
78 | TextView imageNum;
79 | ImageView isSelected;
80 |
81 | View contentView;
82 | public ViewHolder(View itemView) {
83 | super(itemView);
84 | contentView = itemView;
85 | firstImage = (ImageView) itemView.findViewById(R.id.first_image);
86 | folderName = (TextView) itemView.findViewById(R.id.folder_name);
87 | imageNum = (TextView) itemView.findViewById(R.id.image_num);
88 | isSelected = (ImageView) itemView.findViewById(R.id.is_selected);
89 | }
90 | }
91 | public void setOnItemClickListener(OnItemClickListener onItemClickListener){
92 | this.onItemClickListener = onItemClickListener;
93 | }
94 | public interface OnItemClickListener{
95 | void onItemClick(String folderName,List images);
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/library/src/main/java/com/yongchun/library/adapter/ImageListAdapter.java:
--------------------------------------------------------------------------------
1 | package com.yongchun.library.adapter;
2 |
3 | import android.content.Context;
4 | import android.graphics.PorterDuff;
5 | import android.support.v7.widget.RecyclerView;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 | import android.widget.ImageView;
10 | import android.widget.Toast;
11 |
12 | import com.bumptech.glide.Glide;
13 | import com.yongchun.library.R;
14 | import com.yongchun.library.model.LocalMedia;
15 | import com.yongchun.library.view.ImageSelectorActivity;
16 |
17 | import java.io.File;
18 | import java.util.ArrayList;
19 | import java.util.List;
20 |
21 | /**
22 | * Created by dee on 15/11/19.
23 | */
24 | public class ImageListAdapter extends RecyclerView.Adapter {
25 | public static final int TYPE_CAMERA = 1;
26 | public static final int TYPE_PICTURE = 2;
27 |
28 | private Context context;
29 | private boolean showCamera = true;
30 | private boolean enablePreview = true;
31 | private int maxSelectNum;
32 | private int selectMode = ImageSelectorActivity.MODE_MULTIPLE;
33 |
34 | private List images = new ArrayList();
35 | private List selectImages = new ArrayList();
36 |
37 | private OnImageSelectChangedListener imageSelectChangedListener;
38 |
39 | public ImageListAdapter(Context context, int maxSelectNum, int mode, boolean showCamera, boolean enablePreview) {
40 | this.context = context;
41 | this.selectMode = mode;
42 | this.maxSelectNum = maxSelectNum;
43 | this.showCamera = showCamera;
44 | this.enablePreview = enablePreview;
45 | }
46 |
47 | public void bindImages(List images) {
48 | this.images = images;
49 | notifyDataSetChanged();
50 | }
51 |
52 | public void bindSelectImages(List images) {
53 | this.selectImages = images;
54 | notifyDataSetChanged();
55 | if (imageSelectChangedListener != null) {
56 | imageSelectChangedListener.onChange(selectImages);
57 | }
58 | }
59 |
60 | @Override
61 | public int getItemViewType(int position) {
62 | if (showCamera && position == 0) {
63 | return TYPE_CAMERA;
64 | } else {
65 | return TYPE_PICTURE;
66 | }
67 | }
68 |
69 | @Override
70 | public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
71 | if (viewType == TYPE_CAMERA) {
72 | View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_camera, parent, false);
73 | return new HeaderViewHolder(view);
74 | } else {
75 | View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_picture, parent, false);
76 | return new ViewHolder(view);
77 | }
78 | }
79 |
80 | @Override
81 | public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {
82 | if (getItemViewType(position) == TYPE_CAMERA) {
83 | HeaderViewHolder headerHolder = (HeaderViewHolder) holder;
84 | headerHolder.headerView.setOnClickListener(new View.OnClickListener() {
85 | @Override
86 | public void onClick(View v) {
87 | if (imageSelectChangedListener != null) {
88 | imageSelectChangedListener.onTakePhoto();
89 | }
90 | }
91 | });
92 | } else {
93 | final ViewHolder contentHolder = (ViewHolder) holder;
94 | final LocalMedia image = images.get(showCamera ? position - 1 : position);
95 |
96 | Glide.with(context)
97 | .load(new File(image.getPath()))
98 | .centerCrop()
99 | .thumbnail(0.5f)
100 | .placeholder(R.drawable.image_placeholder)
101 | .error(R.drawable.image_placeholder)
102 | .dontAnimate()
103 | .into(contentHolder.picture);
104 |
105 | if (selectMode == ImageSelectorActivity.MODE_SINGLE) {
106 | contentHolder.check.setVisibility(View.GONE);
107 | }
108 |
109 | selectImage(contentHolder, isSelected(image));
110 |
111 | if (enablePreview) {
112 | contentHolder.check.setOnClickListener(new View.OnClickListener() {
113 | @Override
114 | public void onClick(View v) {
115 | changeCheckboxState(contentHolder, image);
116 | }
117 | });
118 | }
119 |
120 | contentHolder.contentView.setOnClickListener(new View.OnClickListener() {
121 | @Override
122 | public void onClick(View v) {
123 | if ((selectMode == ImageSelectorActivity.MODE_SINGLE || enablePreview) && imageSelectChangedListener != null) {
124 | imageSelectChangedListener.onPictureClick(image, showCamera ? position - 1 : position);
125 | } else {
126 | changeCheckboxState(contentHolder, image);
127 | }
128 | }
129 | });
130 | }
131 | }
132 |
133 | @Override
134 | public int getItemCount() {
135 | return showCamera ? images.size() + 1 : images.size();
136 | }
137 |
138 | private void changeCheckboxState(ViewHolder contentHolder, LocalMedia image) {
139 | boolean isChecked = contentHolder.check.isSelected();
140 | if (selectImages.size() >= maxSelectNum && !isChecked) {
141 | Toast.makeText(context, context.getString(R.string.message_max_num, maxSelectNum), Toast.LENGTH_LONG).show();
142 | return;
143 | }
144 | if (isChecked) {
145 | for (LocalMedia media : selectImages) {
146 | if (media.getPath().equals(image.getPath())) {
147 | selectImages.remove(media);
148 | break;
149 | }
150 | }
151 | } else {
152 | selectImages.add(image);
153 | }
154 | selectImage(contentHolder, !isChecked);
155 | if (imageSelectChangedListener != null) {
156 | imageSelectChangedListener.onChange(selectImages);
157 | }
158 | }
159 |
160 | public List getSelectedImages() {
161 | return selectImages;
162 | }
163 |
164 | public List getImages() {
165 | return images;
166 | }
167 |
168 | public boolean isSelected(LocalMedia image) {
169 | for (LocalMedia media : selectImages) {
170 | if (media.getPath().equals(image.getPath())) {
171 | return true;
172 | }
173 | }
174 | return false;
175 | }
176 |
177 | public void selectImage(ViewHolder holder, boolean isChecked) {
178 | holder.check.setSelected(isChecked);
179 | if (isChecked) {
180 | holder.picture.setColorFilter(context.getResources().getColor(R.color.image_overlay2), PorterDuff.Mode.SRC_ATOP);
181 | } else {
182 | holder.picture.setColorFilter(context.getResources().getColor(R.color.image_overlay), PorterDuff.Mode.SRC_ATOP);
183 | }
184 | }
185 |
186 | static class HeaderViewHolder extends RecyclerView.ViewHolder {
187 | View headerView;
188 |
189 | public HeaderViewHolder(View itemView) {
190 | super(itemView);
191 | headerView = itemView;
192 | }
193 | }
194 |
195 | static class ViewHolder extends RecyclerView.ViewHolder {
196 | ImageView picture;
197 | ImageView check;
198 |
199 | View contentView;
200 |
201 | public ViewHolder(View itemView) {
202 | super(itemView);
203 | contentView = itemView;
204 | picture = (ImageView) itemView.findViewById(R.id.picture);
205 | check = (ImageView) itemView.findViewById(R.id.check);
206 | }
207 |
208 | }
209 |
210 | public interface OnImageSelectChangedListener {
211 | void onChange(List selectImages);
212 |
213 | void onTakePhoto();
214 |
215 | void onPictureClick(LocalMedia media, int position);
216 | }
217 |
218 | public void setOnImageSelectChangedListener(OnImageSelectChangedListener imageSelectChangedListener) {
219 | this.imageSelectChangedListener = imageSelectChangedListener;
220 | }
221 | }
222 |
--------------------------------------------------------------------------------
/library/src/main/java/com/yongchun/library/model/LocalMedia.java:
--------------------------------------------------------------------------------
1 | package com.yongchun.library.model;
2 |
3 | import java.io.Serializable;
4 |
5 | /**
6 | * Created by dee on 2015/8/5.
7 | */
8 | public class LocalMedia implements Serializable {
9 | private String path;
10 | private long duration;
11 | private long lastUpdateAt;
12 |
13 |
14 | public LocalMedia(String path, long lastUpdateAt, long duration) {
15 | this.path = path;
16 | this.duration = duration;
17 | this.lastUpdateAt = lastUpdateAt;
18 | }
19 |
20 | public LocalMedia(String path) {
21 | this.path = path;
22 | }
23 |
24 | public String getPath() {
25 | return path;
26 | }
27 |
28 | public void setPath(String path) {
29 | this.path = path;
30 | }
31 |
32 | public long getLastUpdateAt() {
33 | return lastUpdateAt;
34 | }
35 |
36 | public void setLastUpdateAt(long lastUpdateAt) {
37 | this.lastUpdateAt = lastUpdateAt;
38 | }
39 |
40 | public long getDuration() {
41 | return duration;
42 | }
43 | public void setDuration(long duration) {
44 | this.duration = duration;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/library/src/main/java/com/yongchun/library/model/LocalMediaFolder.java:
--------------------------------------------------------------------------------
1 | package com.yongchun.library.model;
2 |
3 | import java.io.Serializable;
4 | import java.util.ArrayList;
5 | import java.util.List;
6 |
7 | /**
8 | * Created by dee on 2015/8/5.
9 | */
10 | public class LocalMediaFolder implements Serializable {
11 | private String name;
12 | private String path;
13 | private String firstImagePath;
14 | private int imageNum;
15 | private List images = new ArrayList();
16 |
17 |
18 | public String getName() {
19 | return name;
20 | }
21 |
22 | public void setName(String name) {
23 | this.name = name;
24 | }
25 |
26 | public String getPath() {
27 | return path;
28 | }
29 |
30 | public void setPath(String path) {
31 | this.path = path;
32 | }
33 |
34 | public String getFirstImagePath() {
35 | return firstImagePath;
36 | }
37 |
38 | public void setFirstImagePath(String firstImagePath) {
39 | this.firstImagePath = firstImagePath;
40 | }
41 |
42 | public int getImageNum() {
43 | return imageNum;
44 | }
45 |
46 | public void setImageNum(int imageNum) {
47 | this.imageNum = imageNum;
48 | }
49 |
50 | public List getImages() {
51 | return images;
52 | }
53 |
54 | public void setImages(List images) {
55 | this.images = images;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/library/src/main/java/com/yongchun/library/utils/CropUtil.java:
--------------------------------------------------------------------------------
1 | package com.yongchun.library.utils;
2 |
3 | import android.content.ContentResolver;
4 | import android.content.Context;
5 | import android.database.Cursor;
6 | import android.media.ExifInterface;
7 | import android.net.Uri;
8 | import android.os.ParcelFileDescriptor;
9 | import android.provider.MediaStore;
10 | import android.support.annotation.Nullable;
11 | import android.text.TextUtils;
12 |
13 | import java.io.Closeable;
14 | import java.io.File;
15 | import java.io.FileDescriptor;
16 | import java.io.FileInputStream;
17 | import java.io.FileOutputStream;
18 | import java.io.IOException;
19 |
20 | /*
21 | * Modified from original in AOSP.
22 | */
23 | public class CropUtil {
24 |
25 | private static final String SCHEME_FILE = "file";
26 | private static final String SCHEME_CONTENT = "content";
27 |
28 | public static void closeSilently(@Nullable Closeable c) {
29 | if (c == null) return;
30 | try {
31 | c.close();
32 | } catch (Throwable t) {
33 | // Do nothing
34 | }
35 | }
36 |
37 | public static int getExifRotation(File imageFile) {
38 | if (imageFile == null) return 0;
39 | try {
40 | ExifInterface exif = new ExifInterface(imageFile.getAbsolutePath());
41 | // We only recognize a subset of orientation tag values
42 | switch (exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED)) {
43 | case ExifInterface.ORIENTATION_ROTATE_90:
44 | return 90;
45 | case ExifInterface.ORIENTATION_ROTATE_180:
46 | return 180;
47 | case ExifInterface.ORIENTATION_ROTATE_270:
48 | return 270;
49 | default:
50 | return ExifInterface.ORIENTATION_UNDEFINED;
51 | }
52 | } catch (IOException e) {
53 | return 0;
54 | }
55 | }
56 |
57 | public static boolean copyExifRotation(File sourceFile, File destFile) {
58 | if (sourceFile == null || destFile == null) return false;
59 | try {
60 | ExifInterface exifSource = new ExifInterface(sourceFile.getAbsolutePath());
61 | ExifInterface exifDest = new ExifInterface(destFile.getAbsolutePath());
62 | exifDest.setAttribute(ExifInterface.TAG_ORIENTATION, exifSource.getAttribute(ExifInterface.TAG_ORIENTATION));
63 | exifDest.saveAttributes();
64 | return true;
65 | } catch (IOException e) {
66 | return false;
67 | }
68 | }
69 |
70 | @Nullable
71 | public static File getFromMediaUri(Context context, ContentResolver resolver, Uri uri) {
72 | if (uri == null) return null;
73 |
74 | if (SCHEME_FILE.equals(uri.getScheme())) {
75 | return new File(uri.getPath());
76 | } else if (SCHEME_CONTENT.equals(uri.getScheme())) {
77 | final String[] filePathColumn = {MediaStore.MediaColumns.DATA, MediaStore.MediaColumns.DISPLAY_NAME};
78 | Cursor cursor = null;
79 | try {
80 | cursor = resolver.query(uri, filePathColumn, null, null, null);
81 | if (cursor != null && cursor.moveToFirst()) {
82 | final int columnIndex = (uri.toString().startsWith("content://com.google.android.gallery3d")) ?
83 | cursor.getColumnIndex(MediaStore.MediaColumns.DISPLAY_NAME) :
84 | cursor.getColumnIndex(MediaStore.MediaColumns.DATA);
85 | // Picasa images on API 13+
86 | if (columnIndex != -1) {
87 | String filePath = cursor.getString(columnIndex);
88 | if (!TextUtils.isEmpty(filePath)) {
89 | return new File(filePath);
90 | }
91 | }
92 | }
93 | } catch (IllegalArgumentException e) {
94 | // Google Drive images
95 | return getFromMediaUriPfd(context, resolver, uri);
96 | } catch (SecurityException ignored) {
97 | // Nothing we can do
98 | } finally {
99 | if (cursor != null) cursor.close();
100 | }
101 | }
102 | return null;
103 | }
104 |
105 | private static String getTempFilename(Context context) throws IOException {
106 | File outputDir = context.getCacheDir();
107 | File outputFile = File.createTempFile("image", "tmp", outputDir);
108 | return outputFile.getAbsolutePath();
109 | }
110 |
111 | @Nullable
112 | private static File getFromMediaUriPfd(Context context, ContentResolver resolver, Uri uri) {
113 | if (uri == null) return null;
114 |
115 | FileInputStream input = null;
116 | FileOutputStream output = null;
117 | try {
118 | ParcelFileDescriptor pfd = resolver.openFileDescriptor(uri, "r");
119 | FileDescriptor fd = pfd.getFileDescriptor();
120 | input = new FileInputStream(fd);
121 |
122 | String tempFilename = getTempFilename(context);
123 | output = new FileOutputStream(tempFilename);
124 |
125 | int read;
126 | byte[] bytes = new byte[4096];
127 | while ((read = input.read(bytes)) != -1) {
128 | output.write(bytes, 0, read);
129 | }
130 | return new File(tempFilename);
131 | } catch (IOException ignored) {
132 | // Nothing we can do
133 | } finally {
134 | closeSilently(input);
135 | closeSilently(output);
136 | }
137 | return null;
138 | }
139 |
140 | // public static void startBackgroundJob(MonitoredActivity activity,
141 | // String title, String message, Runnable job, Handler handler) {
142 | // // Make the progress dialog uncancelable, so that we can guarantee
143 | // // the thread will be done before the activity getting destroyed
144 | // ProgressDialog dialog = ProgressDialog.show(
145 | // activity, title, message, true, false);
146 | // new Thread(new BackgroundJob(activity, job, dialog, handler)).start();
147 | // }
148 |
149 | // private static class BackgroundJob extends MonitoredActivity.LifeCycleAdapter implements Runnable {
150 | //
151 | // private final MonitoredActivity activity;
152 | // private final ProgressDialog dialog;
153 | // private final Runnable job;
154 | // private final Handler handler;
155 | // private final Runnable cleanupRunner = new Runnable() {
156 | // public void run() {
157 | // activity.removeLifeCycleListener(BackgroundJob.this);
158 | // if (dialog.getWindow() != null) dialog.dismiss();
159 | // }
160 | // };
161 | //
162 | // public BackgroundJob(MonitoredActivity activity, Runnable job,
163 | // ProgressDialog dialog, Handler handler) {
164 | // this.activity = activity;
165 | // this.dialog = dialog;
166 | // this.job = job;
167 | // this.activity.addLifeCycleListener(this);
168 | // this.handler = handler;
169 | // }
170 | //
171 | // public void run() {
172 | // try {
173 | // job.run();
174 | // } finally {
175 | // handler.post(cleanupRunner);
176 | // }
177 | // }
178 | //
179 | // @Override
180 | // public void onActivityDestroyed(MonitoredActivity activity) {
181 | // // We get here only when the onDestroyed being called before
182 | // // the cleanupRunner. So, run it now and remove it from the queue
183 | // cleanupRunner.run();
184 | // handler.removeCallbacks(cleanupRunner);
185 | // }
186 | //
187 | // @Override
188 | // public void onActivityStopped(MonitoredActivity activity) {
189 | // dialog.hide();
190 | // }
191 | //
192 | // @Override
193 | // public void onActivityStarted(MonitoredActivity activity) {
194 | // dialog.show();
195 | // }
196 | // }
197 | }
198 |
--------------------------------------------------------------------------------
/library/src/main/java/com/yongchun/library/utils/FileUtils.java:
--------------------------------------------------------------------------------
1 | package com.yongchun.library.utils;
2 |
3 | import android.content.Context;
4 | import android.os.Environment;
5 |
6 | import java.io.File;
7 | import java.text.SimpleDateFormat;
8 | import java.util.Date;
9 | import java.util.Locale;
10 |
11 | /**
12 | * Created by dee on 15/11/20.
13 | */
14 | public class FileUtils {
15 | public static final String POSTFIX = ".JPEG";
16 | public static final String APP_NAME = "ImageSelector";
17 | public static final String CAMERA_PATH = "/" + APP_NAME + "/CameraImage/";
18 | public static final String CROP_PATH = "/" + APP_NAME + "/CropImage/";
19 |
20 | public static File createCameraFile(Context context) {
21 | return createMediaFile(context,CAMERA_PATH);
22 | }
23 | public static File createCropFile(Context context) {
24 | return createMediaFile(context,CROP_PATH);
25 | }
26 |
27 | private static File createMediaFile(Context context,String parentPath){
28 | String state = Environment.getExternalStorageState();
29 | File rootDir = state.equals(Environment.MEDIA_MOUNTED)?Environment.getExternalStorageDirectory():context.getCacheDir();
30 |
31 | File folderDir = new File(rootDir.getAbsolutePath() + parentPath);
32 | if (!folderDir.exists() && folderDir.mkdirs()){
33 |
34 | }
35 |
36 | String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.CHINA).format(new Date());
37 | String fileName = APP_NAME + "_" + timeStamp + "";
38 | File tmpFile = new File(folderDir, fileName + POSTFIX);
39 | return tmpFile;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/library/src/main/java/com/yongchun/library/utils/GridSpacingItemDecoration.java:
--------------------------------------------------------------------------------
1 | package com.yongchun.library.utils;
2 |
3 | import android.graphics.Rect;
4 | import android.support.v7.widget.RecyclerView;
5 | import android.view.View;
6 |
7 | /**
8 | * Created by dee on 2015/8/18.
9 | */
10 | public class GridSpacingItemDecoration extends RecyclerView.ItemDecoration {
11 |
12 | private int spanCount;
13 | private int spacing;
14 | private boolean includeEdge;
15 |
16 | public GridSpacingItemDecoration(int spanCount, int spacing, boolean includeEdge) {
17 | this.spanCount = spanCount;
18 | this.spacing = spacing;
19 | this.includeEdge = includeEdge;
20 | }
21 |
22 | @Override
23 | public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
24 | int position = parent.getChildAdapterPosition(view);
25 | int column = position % spanCount;
26 | if (includeEdge) {
27 | outRect.left = spacing - column * spacing / spanCount;
28 | outRect.right = (column + 1) * spacing / spanCount;
29 | if (position < spanCount) {
30 | outRect.top = spacing;
31 | }
32 | outRect.bottom = spacing;
33 | } else {
34 | outRect.left = column * spacing / spanCount;
35 | outRect.right = spacing - (column + 1) * spacing / spanCount;
36 | // if (position >= spanCount) {
37 | // outRect.top = spacing;
38 | // }
39 | if (position < spanCount) {
40 | outRect.top = spacing;
41 | }
42 | outRect.bottom = spacing;
43 | }
44 | }
45 | }
--------------------------------------------------------------------------------
/library/src/main/java/com/yongchun/library/utils/LocalMediaLoader.java:
--------------------------------------------------------------------------------
1 | package com.yongchun.library.utils;
2 |
3 | import android.database.Cursor;
4 | import android.os.Bundle;
5 | import android.provider.MediaStore;
6 | import android.support.v4.app.FragmentActivity;
7 | import android.support.v4.app.LoaderManager;
8 | import android.support.v4.content.CursorLoader;
9 | import android.support.v4.content.Loader;
10 |
11 | import com.yongchun.library.model.LocalMedia;
12 | import com.yongchun.library.model.LocalMediaFolder;
13 |
14 | import java.io.File;
15 | import java.io.FilenameFilter;
16 | import java.util.ArrayList;
17 | import java.util.Collections;
18 | import java.util.Comparator;
19 | import java.util.HashSet;
20 | import java.util.List;
21 |
22 | /**
23 | * Created by dee on 15/11/19.
24 | */
25 | public class LocalMediaLoader {
26 | // load type
27 | public static final int TYPE_IMAGE = 1;
28 | public static final int TYPE_VIDEO = 2;
29 |
30 | private final static String[] IMAGE_PROJECTION = {
31 | MediaStore.Images.Media.DATA,
32 | MediaStore.Images.Media.DISPLAY_NAME,
33 | MediaStore.Images.Media.DATE_ADDED,
34 | MediaStore.Images.Media._ID};
35 |
36 | private final static String[] VIDEO_PROJECTION = {
37 | MediaStore.Video.Media.DATA,
38 | MediaStore.Video.Media.DISPLAY_NAME,
39 | MediaStore.Video.Media.DATE_ADDED,
40 | MediaStore.Video.Media._ID,
41 | MediaStore.Video.Media.DURATION};
42 |
43 | private int type = TYPE_IMAGE;
44 | private FragmentActivity activity;
45 |
46 | public LocalMediaLoader(FragmentActivity activity, int type) {
47 | this.activity = activity;
48 | this.type = type;
49 | }
50 |
51 | HashSet mDirPaths = new HashSet();
52 |
53 | public void loadAllImage(final LocalMediaLoadListener imageLoadListener) {
54 | activity.getSupportLoaderManager().initLoader(type, null, new LoaderManager.LoaderCallbacks() {
55 | @Override
56 | public Loader onCreateLoader(int id, Bundle args) {
57 | CursorLoader cursorLoader = null;
58 | if (id == TYPE_IMAGE) {
59 | cursorLoader = new CursorLoader(
60 | activity, MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
61 | IMAGE_PROJECTION, MediaStore.Images.Media.MIME_TYPE + "=? or "
62 | + MediaStore.Images.Media.MIME_TYPE + "=?",
63 | new String[]{"image/jpeg", "image/png"}, IMAGE_PROJECTION[2] + " DESC");
64 | } else if (id == TYPE_VIDEO) {
65 | cursorLoader = new CursorLoader(
66 | activity, MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
67 | VIDEO_PROJECTION, null, null, VIDEO_PROJECTION[2] + " DESC");
68 | }
69 | return cursorLoader;
70 | }
71 |
72 | @Override
73 | public void onLoadFinished(Loader loader, Cursor data) {
74 | ArrayList imageFolders = new ArrayList();
75 | LocalMediaFolder allImageFolder = new LocalMediaFolder();
76 | List allImages = new ArrayList();
77 |
78 | while (data != null && data.moveToNext()) {
79 | // 获取图片的路径
80 | String path = data.getString(data
81 | .getColumnIndex(MediaStore.Images.Media.DATA));
82 | File file = new File(path);
83 | if (!file.exists())
84 | continue;
85 | // 获取该图片的目录路径名
86 | File parentFile = file.getParentFile();
87 | if (parentFile == null || !parentFile.exists())
88 | continue;
89 |
90 | String dirPath = parentFile.getAbsolutePath();
91 | // 利用一个HashSet防止多次扫描同一个文件夹
92 | if (mDirPaths.contains(dirPath)) {
93 | continue;
94 | } else {
95 | mDirPaths.add(dirPath);
96 | }
97 |
98 | if (parentFile.list() == null)
99 | continue;
100 | LocalMediaFolder localMediaFolder = getImageFolder(path, imageFolders);
101 |
102 | File[] files = parentFile.listFiles(new FilenameFilter() {
103 | @Override
104 | public boolean accept(File dir, String filename) {
105 | if (filename.endsWith(".jpg")
106 | || filename.endsWith(".png")
107 | || filename.endsWith(".jpeg"))
108 | return true;
109 | return false;
110 | }
111 | });
112 | ArrayList images = new ArrayList<>();
113 | for (int i = 0; i < files.length; i++) {
114 | File f = files[i];
115 | LocalMedia localMedia = new LocalMedia(f.getAbsolutePath());
116 | allImages.add(localMedia);
117 | images.add(localMedia);
118 | }
119 | if (images.size() > 0) {
120 | localMediaFolder.setImages(images);
121 | localMediaFolder.setImageNum(localMediaFolder.getImages().size());
122 | imageFolders.add(localMediaFolder);
123 | }
124 | }
125 |
126 | allImageFolder.setImages(allImages);
127 | allImageFolder.setImageNum(allImageFolder.getImages().size());
128 | allImageFolder.setFirstImagePath(allImages.get(0).getPath());
129 | allImageFolder.setName(activity.getString(com.yongchun.library.R.string.all_image));
130 | imageFolders.add(allImageFolder);
131 | sortFolder(imageFolders);
132 | imageLoadListener.loadComplete(imageFolders);
133 | if (data != null) data.close();
134 | }
135 |
136 | @Override
137 | public void onLoaderReset(Loader loader) {
138 | }
139 | });
140 | }
141 |
142 | private void sortFolder(List imageFolders) {
143 | // 文件夹按图片数量排序
144 | Collections.sort(imageFolders, new Comparator() {
145 | @Override
146 | public int compare(LocalMediaFolder lhs, LocalMediaFolder rhs) {
147 | if (lhs.getImages() == null || rhs.getImages() == null) {
148 | return 0;
149 | }
150 | int lsize = lhs.getImageNum();
151 | int rsize = rhs.getImageNum();
152 | return lsize == rsize ? 0 : (lsize < rsize ? 1 : -1);
153 | }
154 | });
155 | }
156 |
157 | private LocalMediaFolder getImageFolder(String path, List imageFolders) {
158 | File imageFile = new File(path);
159 | File folderFile = imageFile.getParentFile();
160 |
161 | for (LocalMediaFolder folder : imageFolders) {
162 | if (folder.getName().equals(folderFile.getName())) {
163 | return folder;
164 | }
165 | }
166 | LocalMediaFolder newFolder = new LocalMediaFolder();
167 | newFolder.setName(folderFile.getName());
168 | newFolder.setPath(folderFile.getAbsolutePath());
169 | newFolder.setFirstImagePath(path);
170 | return newFolder;
171 | }
172 |
173 | public interface LocalMediaLoadListener {
174 | void loadComplete(List folders);
175 | }
176 |
177 | }
178 |
--------------------------------------------------------------------------------
/library/src/main/java/com/yongchun/library/utils/ScreenUtils.java:
--------------------------------------------------------------------------------
1 | package com.yongchun.library.utils;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.util.DisplayMetrics;
6 |
7 | import java.lang.reflect.Field;
8 |
9 | /**
10 | * Created by dee on 15/11/19.
11 | */
12 | public class ScreenUtils {
13 | /**
14 | * dp2px
15 | */
16 | public static int dip2px(Context context, float dpValue) {
17 | final float scale = context.getResources().getDisplayMetrics().density;
18 | return (int) (dpValue * scale + 0.5f);
19 | }
20 | public static int getScreenWidth(Context context) {
21 | DisplayMetrics localDisplayMetrics = new DisplayMetrics();
22 | ((Activity) context).getWindowManager().getDefaultDisplay().getMetrics(localDisplayMetrics);
23 | return localDisplayMetrics.widthPixels;
24 | }
25 | public static int getScreenHeight(Context context) {
26 | DisplayMetrics localDisplayMetrics = new DisplayMetrics();
27 | ((Activity) context).getWindowManager().getDefaultDisplay().getMetrics(localDisplayMetrics);
28 | return localDisplayMetrics.heightPixels - getStatusBarHeight(context);
29 | }
30 | public static int getStatusBarHeight(Context context){
31 | Class> c = null;
32 | Object obj = null;
33 | Field field = null;
34 | int x = 0, statusBarHeight = 0;
35 | try {
36 | c = Class.forName("com.android.internal.R$dimen");
37 | obj = c.newInstance();
38 | field = c.getField("status_bar_height");
39 | x = Integer.parseInt(field.get(obj).toString());
40 | statusBarHeight = context.getResources().getDimensionPixelSize(x);
41 | } catch (Exception e1) {
42 | e1.printStackTrace();
43 | }
44 | return statusBarHeight;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/library/src/main/java/com/yongchun/library/view/FolderWindow.java:
--------------------------------------------------------------------------------
1 | package com.yongchun.library.view;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.graphics.Color;
6 | import android.graphics.Rect;
7 | import android.graphics.drawable.ColorDrawable;
8 | import android.graphics.drawable.Drawable;
9 | import android.support.v7.widget.LinearLayoutManager;
10 | import android.support.v7.widget.RecyclerView;
11 | import android.view.LayoutInflater;
12 | import android.view.View;
13 | import android.view.animation.Animation;
14 | import android.view.animation.AnimationUtils;
15 | import android.widget.PopupWindow;
16 |
17 | import com.yongchun.library.R;
18 | import com.yongchun.library.adapter.ImageFolderAdapter;
19 | import com.yongchun.library.model.LocalMediaFolder;
20 | import com.yongchun.library.utils.ScreenUtils;
21 |
22 | import java.lang.reflect.Method;
23 | import java.util.List;
24 |
25 | /**
26 | * Created by dee on 15/11/20.
27 | */
28 | public class FolderWindow extends PopupWindow {
29 | private Context context;
30 | private View window;
31 | private RecyclerView recyclerView;
32 | private ImageFolderAdapter adapter;
33 |
34 | private boolean isDismiss = false;
35 | public FolderWindow(Context context) {
36 | this.context = context;
37 | window = LayoutInflater.from(context).inflate(R.layout.window_folder, null);
38 | this.setContentView(window);
39 | this.setWidth(ScreenUtils.getScreenWidth(context));
40 | this.setHeight(ScreenUtils.getScreenHeight(context) - ScreenUtils.dip2px(context, 96));
41 | this.setAnimationStyle(R.style.WindowStyle);
42 | this.setFocusable(true);
43 | this.setOutsideTouchable(true);
44 | this.update();
45 | this.setBackgroundDrawable(new ColorDrawable(Color.argb(153, 0, 0, 0)));
46 |
47 | initView();
48 | registerListener();
49 | setPopupWindowTouchModal(this, false);
50 | }
51 |
52 | public void initView() {
53 | adapter = new ImageFolderAdapter(context);
54 |
55 | recyclerView = (RecyclerView) window.findViewById(R.id.folder_list);
56 | recyclerView.addItemDecoration(new ItemDivider());
57 | recyclerView.setLayoutManager(new LinearLayoutManager(context));
58 | recyclerView.setAdapter(adapter);
59 | }
60 |
61 | public void registerListener() {
62 |
63 | }
64 | public void bindFolder(List folders){
65 | adapter.bindFolder(folders);
66 | }
67 | @Override
68 | public void showAsDropDown(View anchor) {
69 | super.showAsDropDown(anchor);
70 | Animation animation = AnimationUtils.loadAnimation(context, R.anim.up_in);
71 | recyclerView.startAnimation(animation);
72 | }
73 | public void setOnItemClickListener(ImageFolderAdapter.OnItemClickListener onItemClickListener){
74 | adapter.setOnItemClickListener(onItemClickListener);
75 | }
76 | @Override
77 | public void dismiss() {
78 | if(isDismiss){
79 | return;
80 | }
81 | isDismiss = true;
82 | Animation animation = AnimationUtils.loadAnimation(context, R.anim.down_out);
83 | recyclerView.startAnimation(animation);
84 | dismiss();
85 | animation.setAnimationListener(new Animation.AnimationListener() {
86 | @Override
87 | public void onAnimationStart(Animation animation) {
88 |
89 | }
90 |
91 | @Override
92 | public void onAnimationEnd(Animation animation) {
93 | isDismiss = false;
94 | FolderWindow.super.dismiss();
95 | }
96 | @Override
97 | public void onAnimationRepeat(Animation animation) {
98 |
99 | }
100 | });
101 | }
102 |
103 | public static void setPopupWindowTouchModal(PopupWindow popupWindow,boolean touchModal) {
104 | if (null == popupWindow) {
105 | return;
106 | }
107 | Method method;
108 | try {
109 | method = PopupWindow.class.getDeclaredMethod("setTouchModal",boolean.class);
110 | method.setAccessible(true);
111 | method.invoke(popupWindow, touchModal);
112 | } catch (Exception e) {
113 | e.printStackTrace();
114 | }
115 | }
116 | public class ItemDivider extends RecyclerView.ItemDecoration {
117 | private Drawable mDrawable;
118 | public ItemDivider() {
119 | mDrawable = context.getResources().getDrawable(R.drawable.item_divider);
120 | }
121 | @Override
122 | public void onDrawOver(Canvas c, RecyclerView parent) {
123 | final int left = ScreenUtils.dip2px(parent.getContext(),16);
124 | final int right = parent.getWidth() - left;
125 |
126 | final int childCount = parent.getChildCount();
127 | for (int i = 0; i < childCount - 1; i++) {
128 | final View child = parent.getChildAt(i);
129 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
130 | final int top = child.getBottom() + params.bottomMargin;
131 | final int bottom = top + mDrawable.getIntrinsicHeight();
132 | mDrawable.setBounds(left, top, right, bottom);
133 | mDrawable.draw(c);
134 | }
135 | }
136 |
137 | @Override
138 | public void getItemOffsets(Rect outRect, int position, RecyclerView parent) {
139 | outRect.set(0, 0, 0, mDrawable.getIntrinsicWidth());
140 | }
141 |
142 | }
143 |
144 | }
145 |
--------------------------------------------------------------------------------
/library/src/main/java/com/yongchun/library/view/ImageCropActivity.java:
--------------------------------------------------------------------------------
1 | package com.yongchun.library.view;
2 |
3 | import android.app.Activity;
4 | import android.app.ProgressDialog;
5 | import android.content.Intent;
6 | import android.graphics.Bitmap;
7 | import android.graphics.BitmapFactory;
8 | import android.graphics.Matrix;
9 | import android.net.Uri;
10 | import android.opengl.GLES10;
11 | import android.os.Bundle;
12 | import android.os.Handler;
13 | import android.support.v7.app.AppCompatActivity;
14 | import android.support.v7.widget.Toolbar;
15 | import android.view.View;
16 | import android.widget.TextView;
17 |
18 | import com.isseiaoki.simplecropview.CropImageView;
19 | import com.yongchun.library.R;
20 | import com.yongchun.library.utils.CropUtil;
21 | import com.yongchun.library.utils.FileUtils;
22 |
23 | import java.io.File;
24 | import java.io.IOException;
25 | import java.io.InputStream;
26 | import java.io.OutputStream;
27 |
28 | /**
29 | * Created by dee on 15/11/26.
30 | */
31 | public class ImageCropActivity extends AppCompatActivity {
32 | public static final String EXTRA_PATH = "extraPath";
33 | public static final String OUTPUT_PATH = "outputPath";
34 | public static final int REQUEST_CROP = 69;
35 | private static final int SIZE_DEFAULT = 2048;
36 | private static final int SIZE_LIMIT = 4096;
37 |
38 | private Toolbar toolbar;
39 | private TextView doneText;
40 | private CropImageView cropImageView;
41 |
42 |
43 | private Uri sourceUri;
44 | private Uri saveUri;
45 |
46 | private final Handler handler = new Handler();
47 |
48 | public static void startCrop(Activity activity, String path) {
49 | Intent intent = new Intent(activity, ImageCropActivity.class);
50 | intent.putExtra(EXTRA_PATH, path);
51 | activity.startActivityForResult(intent, REQUEST_CROP);
52 | }
53 |
54 | @Override
55 | protected void onCreate(Bundle savedInstanceState) {
56 | super.onCreate(savedInstanceState);
57 | setContentView(R.layout.activity_image_crop);
58 | String path = getIntent().getStringExtra(EXTRA_PATH);
59 | sourceUri = Uri.fromFile(new File(path));
60 |
61 | initView();
62 | registerListener();
63 | }
64 |
65 | public void initView() {
66 | toolbar = (Toolbar) findViewById(R.id.toolbar);
67 | toolbar.setTitle("");
68 | setSupportActionBar(toolbar);
69 | toolbar.setNavigationIcon(R.mipmap.ic_back);
70 |
71 | doneText = (TextView) findViewById(R.id.done_text);
72 | cropImageView = (CropImageView) findViewById(R.id.cropImageView);
73 | cropImageView.setHandleSizeInDp(10);
74 |
75 |
76 | int exifRotation = CropUtil.getExifRotation(CropUtil.getFromMediaUri(this, getContentResolver(), sourceUri));
77 |
78 | InputStream is = null;
79 | try {
80 | int sampleSize = calculateBitmapSampleSize(sourceUri);
81 | is = getContentResolver().openInputStream(sourceUri);
82 | BitmapFactory.Options option = new BitmapFactory.Options();
83 | option.inSampleSize = sampleSize;
84 | Bitmap sizeBitmap = BitmapFactory.decodeStream(is, null, option);
85 | if(sizeBitmap==null)return;
86 | Matrix matrix = getRotateMatrix(sizeBitmap, exifRotation % 360);
87 | Bitmap rotated = Bitmap.createBitmap(sizeBitmap, 0, 0, sizeBitmap.getWidth(), sizeBitmap.getHeight(), matrix, true);
88 | cropImageView.setImageBitmap(rotated);
89 | } catch (IOException e) {
90 | e.printStackTrace();
91 | } catch (OutOfMemoryError e) {
92 | e.printStackTrace();
93 | } finally {
94 | CropUtil.closeSilently(is);
95 | }
96 | }
97 |
98 |
99 | public void registerListener() {
100 | toolbar.setNavigationOnClickListener(new View.OnClickListener() {
101 | @Override
102 | public void onClick(View v) {
103 | finish();
104 | }
105 | });
106 | doneText.setOnClickListener(new View.OnClickListener() {
107 | @Override
108 | public void onClick(View v) {
109 | ProgressDialog.show(
110 | ImageCropActivity.this, null, getString(R.string.save_ing), true, false);
111 | saveUri = Uri.fromFile(FileUtils.createCropFile(ImageCropActivity.this));
112 | saveOutput(cropImageView.getCroppedBitmap());
113 | }
114 | });
115 | }
116 |
117 | public Matrix getRotateMatrix(Bitmap bitmap, int rotation) {
118 | Matrix matrix = new Matrix();
119 | if (bitmap != null && rotation != 0) {
120 | int cx = bitmap.getWidth() / 2;
121 | int cy = bitmap.getHeight() / 2;
122 | matrix.preTranslate(-cx, -cy);
123 | matrix.postRotate(rotation);
124 | matrix.postTranslate(bitmap.getWidth() / 2, bitmap.getHeight() / 2);
125 | }
126 | return matrix;
127 | }
128 |
129 | private int calculateBitmapSampleSize(Uri bitmapUri) throws IOException {
130 | InputStream is = null;
131 | BitmapFactory.Options options = new BitmapFactory.Options();
132 | options.inJustDecodeBounds = true;
133 | try {
134 | is = getContentResolver().openInputStream(bitmapUri);
135 | BitmapFactory.decodeStream(is, null, options); // Just get image size
136 | } finally {
137 | CropUtil.closeSilently(is);
138 | }
139 |
140 | int maxSize = getMaxImageSize();
141 | int sampleSize = 1;
142 | while (options.outHeight / sampleSize > maxSize || options.outWidth / sampleSize > maxSize) {
143 | sampleSize = sampleSize << 1;
144 | }
145 | return sampleSize;
146 | }
147 |
148 | private int getMaxImageSize() {
149 | int textureLimit = getMaxTextureSize();
150 | if (textureLimit == 0) {
151 | return SIZE_DEFAULT;
152 | } else {
153 | return Math.min(textureLimit, SIZE_LIMIT);
154 | }
155 | }
156 |
157 | private int getMaxTextureSize() {
158 | int[] maxSize = new int[1];
159 | GLES10.glGetIntegerv(GLES10.GL_MAX_TEXTURE_SIZE, maxSize, 0);
160 | return maxSize[0];
161 | }
162 |
163 | private void saveOutput(Bitmap croppedImage) {
164 | if (saveUri != null) {
165 | OutputStream outputStream = null;
166 | try {
167 | outputStream = getContentResolver().openOutputStream(saveUri);
168 | if (outputStream != null) {
169 | croppedImage.compress(Bitmap.CompressFormat.JPEG, 90, outputStream);
170 | }
171 | } catch (IOException e) {
172 | e.printStackTrace();
173 | } finally {
174 | CropUtil.closeSilently(outputStream);
175 | }
176 | setResult(RESULT_OK, new Intent().putExtra(OUTPUT_PATH, saveUri.getPath()));
177 | }
178 | final Bitmap b = croppedImage;
179 | handler.post(new Runnable() {
180 | public void run() {
181 | b.recycle();
182 | }
183 | });
184 | finish();
185 | }
186 | }
187 |
--------------------------------------------------------------------------------
/library/src/main/java/com/yongchun/library/view/ImagePreviewActivity.java:
--------------------------------------------------------------------------------
1 | package com.yongchun.library.view;
2 |
3 | import android.app.Activity;
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 | import android.support.v4.app.Fragment;
7 | import android.support.v4.app.FragmentManager;
8 | import android.support.v4.app.FragmentPagerAdapter;
9 | import android.support.v4.view.ViewPager;
10 | import android.support.v7.app.AppCompatActivity;
11 | import android.support.v7.widget.Toolbar;
12 | import android.view.View;
13 | import android.view.WindowManager;
14 | import android.widget.CheckBox;
15 | import android.widget.LinearLayout;
16 | import android.widget.RelativeLayout;
17 | import android.widget.TextView;
18 | import android.widget.Toast;
19 |
20 | import com.yongchun.library.R;
21 | import com.yongchun.library.model.LocalMedia;
22 | import com.yongchun.library.widget.PreviewViewPager;
23 |
24 | import java.util.ArrayList;
25 | import java.util.List;
26 |
27 | /**
28 | * Created by dee on 15/11/24.
29 | */
30 | public class ImagePreviewActivity extends AppCompatActivity {
31 | public static final int REQUEST_PREVIEW = 68;
32 | public static final String EXTRA_PREVIEW_LIST = "previewList";
33 | public static final String EXTRA_PREVIEW_SELECT_LIST = "previewSelectList";
34 | public static final String EXTRA_MAX_SELECT_NUM = "maxSelectNum";
35 | public static final String EXTRA_POSITION = "position";
36 |
37 | public static final String OUTPUT_LIST = "outputList";
38 | public static final String OUTPUT_ISDONE = "isDone";
39 |
40 | private LinearLayout barLayout;
41 | private RelativeLayout selectBarLayout;
42 | private Toolbar toolbar;
43 | private TextView doneText;
44 | private CheckBox checkboxSelect;
45 | private PreviewViewPager viewPager;
46 |
47 |
48 | private int position;
49 | private int maxSelectNum;
50 | private List images = new ArrayList<>();
51 | private List selectImages = new ArrayList<>();
52 |
53 |
54 | private boolean isShowBar = true;
55 |
56 |
57 | public static void startPreview(Activity context, List images, List selectImages, int maxSelectNum, int position) {
58 | Intent intent = new Intent(context, ImagePreviewActivity.class);
59 | intent.putExtra(EXTRA_PREVIEW_LIST, (ArrayList) images);
60 | intent.putExtra(EXTRA_PREVIEW_SELECT_LIST, (ArrayList) selectImages);
61 | intent.putExtra(EXTRA_POSITION, position);
62 | intent.putExtra(EXTRA_MAX_SELECT_NUM, maxSelectNum);
63 | context.startActivityForResult(intent, REQUEST_PREVIEW);
64 | }
65 |
66 | @Override
67 | protected void onCreate(Bundle savedInstanceState) {
68 | super.onCreate(savedInstanceState);
69 | getWindow().addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
70 | setContentView(R.layout.activity_image_preview);
71 | initView();
72 | registerListener();
73 | }
74 |
75 | public void initView() {
76 | images = (List) getIntent().getSerializableExtra(EXTRA_PREVIEW_LIST);
77 | selectImages = (List) getIntent().getSerializableExtra(EXTRA_PREVIEW_SELECT_LIST);
78 | maxSelectNum = getIntent().getIntExtra(EXTRA_MAX_SELECT_NUM, 9);
79 | position = getIntent().getIntExtra(EXTRA_POSITION, 1);
80 |
81 | barLayout = (LinearLayout) findViewById(R.id.bar_layout);
82 | selectBarLayout = (RelativeLayout) findViewById(R.id.select_bar_layout);
83 |
84 | toolbar = (Toolbar) findViewById(R.id.toolbar);
85 | toolbar.setTitle((position + 1) + "/" + images.size());
86 | setSupportActionBar(toolbar);
87 | toolbar.setNavigationIcon(R.mipmap.ic_back);
88 |
89 |
90 | doneText = (TextView) findViewById(R.id.done_text);
91 | onSelectNumChange();
92 |
93 | checkboxSelect = (CheckBox) findViewById(R.id.checkbox_select);
94 | onImageSwitch(position);
95 |
96 |
97 | viewPager = (PreviewViewPager) findViewById(R.id.preview_pager);
98 | viewPager.setAdapter(new SimpleFragmentAdapter(getSupportFragmentManager()));
99 | viewPager.setCurrentItem(position);
100 | }
101 |
102 | public void registerListener() {
103 | viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
104 | @Override
105 | public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
106 | }
107 |
108 | @Override
109 | public void onPageSelected(int position) {
110 | toolbar.setTitle(position + 1 + "/" + images.size());
111 | onImageSwitch(position);
112 | }
113 |
114 | @Override
115 | public void onPageScrollStateChanged(int state) {
116 | }
117 | });
118 | toolbar.setNavigationOnClickListener(new View.OnClickListener() {
119 | @Override
120 | public void onClick(View v) {
121 | onDoneClick(false);
122 | }
123 | });
124 | checkboxSelect.setOnClickListener(new View.OnClickListener() {
125 | @Override
126 | public void onClick(View v) {
127 | boolean isChecked = checkboxSelect.isChecked();
128 | if (selectImages.size() >= maxSelectNum && isChecked) {
129 | Toast.makeText(ImagePreviewActivity.this, getString(R.string.message_max_num, maxSelectNum), Toast.LENGTH_LONG).show();
130 | checkboxSelect.setChecked(false);
131 | return;
132 | }
133 | LocalMedia image = images.get(viewPager.getCurrentItem());
134 | if (isChecked) {
135 | selectImages.add(image);
136 | } else {
137 | for (LocalMedia media : selectImages) {
138 | if (media.getPath().equals(image.getPath())) {
139 | selectImages.remove(media);
140 | break;
141 | }
142 | }
143 | }
144 | onSelectNumChange();
145 | }
146 | });
147 | doneText.setOnClickListener(new View.OnClickListener() {
148 | @Override
149 | public void onClick(View v) {
150 | onDoneClick(true);
151 | }
152 | });
153 | }
154 |
155 | public class SimpleFragmentAdapter extends FragmentPagerAdapter {
156 | public SimpleFragmentAdapter(FragmentManager fm) {
157 | super(fm);
158 | }
159 |
160 | @Override
161 | public Fragment getItem(int position) {
162 | return ImagePreviewFragment.getInstance(images.get(position).getPath());
163 | }
164 |
165 | @Override
166 | public int getCount() {
167 | return images.size();
168 | }
169 | }
170 |
171 | public void onSelectNumChange() {
172 | boolean enable = selectImages.size() != 0;
173 | doneText.setEnabled(enable);
174 | if (enable) {
175 | doneText.setText(getString(R.string.done_num, selectImages.size(), maxSelectNum));
176 | } else {
177 | doneText.setText(R.string.done);
178 | }
179 | }
180 |
181 | public void onImageSwitch(int position) {
182 | checkboxSelect.setChecked(isSelected(images.get(position)));
183 | }
184 |
185 | public boolean isSelected(LocalMedia image) {
186 | for (LocalMedia media : selectImages) {
187 | if (media.getPath().equals(image.getPath())) {
188 | return true;
189 | }
190 | }
191 | return false;
192 | }
193 |
194 | private void hideStatusBar() {
195 | WindowManager.LayoutParams attrs = getWindow().getAttributes();
196 | attrs.flags |= WindowManager.LayoutParams.FLAG_FULLSCREEN;
197 | getWindow().setAttributes(attrs);
198 | }
199 |
200 | private void showStatusBar() {
201 | WindowManager.LayoutParams attrs = getWindow().getAttributes();
202 | attrs.flags &= ~WindowManager.LayoutParams.FLAG_FULLSCREEN;
203 | getWindow().setAttributes(attrs);
204 | }
205 |
206 | public void switchBarVisibility() {
207 | barLayout.setVisibility(isShowBar ? View.GONE : View.VISIBLE);
208 | toolbar.setVisibility(isShowBar ? View.GONE : View.VISIBLE);
209 | selectBarLayout.setVisibility(isShowBar ? View.GONE : View.VISIBLE);
210 | if (isShowBar) {
211 | hideStatusBar();
212 | } else {
213 | showStatusBar();
214 | }
215 | isShowBar = !isShowBar;
216 | }
217 | public void onDoneClick(boolean isDone){
218 | Intent intent = new Intent();
219 | intent.putExtra(OUTPUT_LIST,(ArrayList)selectImages);
220 | intent.putExtra(OUTPUT_ISDONE,isDone);
221 | setResult(RESULT_OK,intent);
222 | finish();
223 | }
224 | }
225 |
--------------------------------------------------------------------------------
/library/src/main/java/com/yongchun/library/view/ImagePreviewFragment.java:
--------------------------------------------------------------------------------
1 | package com.yongchun.library.view;
2 |
3 | import android.graphics.Bitmap;
4 | import android.os.Bundle;
5 | import android.support.annotation.Nullable;
6 | import android.support.v4.app.Fragment;
7 | import android.view.LayoutInflater;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 | import android.widget.ImageView;
11 |
12 | import com.bumptech.glide.Glide;
13 | import com.bumptech.glide.request.animation.GlideAnimation;
14 | import com.bumptech.glide.request.target.SimpleTarget;
15 | import com.yongchun.library.R;
16 |
17 | import java.io.File;
18 |
19 | import uk.co.senab.photoview.PhotoViewAttacher;
20 |
21 | /**
22 | * Created by dee on 15/11/25.
23 | */
24 | public class ImagePreviewFragment extends Fragment {
25 | public static final String PATH = "path";
26 |
27 | public static ImagePreviewFragment getInstance(String path) {
28 | ImagePreviewFragment fragment = new ImagePreviewFragment();
29 | Bundle bundle = new Bundle();
30 | bundle.putString(PATH, path);
31 | fragment.setArguments(bundle);
32 | return fragment;
33 | }
34 |
35 | @Nullable
36 | @Override
37 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
38 | View contentView = inflater.inflate(R.layout.fragment_image_preview, container, false);
39 | final ImageView imageView = (ImageView) contentView.findViewById(R.id.preview_image);
40 | final PhotoViewAttacher mAttacher = new PhotoViewAttacher(imageView);
41 | Glide.with(container.getContext())
42 | .load(new File(getArguments().getString(PATH)))
43 | .asBitmap()
44 | .into(new SimpleTarget(480, 800) {
45 | @Override
46 | public void onResourceReady(Bitmap resource, GlideAnimation super Bitmap> glideAnimation) {
47 | imageView.setImageBitmap(resource);
48 | mAttacher.update();
49 | }
50 | });
51 | mAttacher.setOnViewTapListener(new PhotoViewAttacher.OnViewTapListener() {
52 | @Override
53 | public void onViewTap(View view, float x, float y) {
54 | ImagePreviewActivity activity = (ImagePreviewActivity) getActivity();
55 | activity.switchBarVisibility();
56 | }
57 | });
58 | return contentView;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/library/src/main/java/com/yongchun/library/view/ImageSelectorActivity.java:
--------------------------------------------------------------------------------
1 | package com.yongchun.library.view;
2 |
3 | import android.app.Activity;
4 | import android.content.Intent;
5 | import android.net.Uri;
6 | import android.os.Bundle;
7 | import android.provider.MediaStore;
8 | import android.support.v7.app.AppCompatActivity;
9 | import android.support.v7.widget.GridLayoutManager;
10 | import android.support.v7.widget.RecyclerView;
11 | import android.support.v7.widget.Toolbar;
12 | import android.view.View;
13 | import android.widget.LinearLayout;
14 | import android.widget.TextView;
15 |
16 | import com.yongchun.library.R;
17 | import com.yongchun.library.adapter.ImageFolderAdapter;
18 | import com.yongchun.library.adapter.ImageListAdapter;
19 | import com.yongchun.library.model.LocalMedia;
20 | import com.yongchun.library.model.LocalMediaFolder;
21 | import com.yongchun.library.utils.FileUtils;
22 | import com.yongchun.library.utils.GridSpacingItemDecoration;
23 | import com.yongchun.library.utils.LocalMediaLoader;
24 | import com.yongchun.library.utils.ScreenUtils;
25 |
26 | import java.io.File;
27 | import java.util.ArrayList;
28 | import java.util.List;
29 |
30 | /**
31 | * Created by dee on 15/11/19.
32 | */
33 | public class ImageSelectorActivity extends AppCompatActivity {
34 | public final static int REQUEST_IMAGE = 66;
35 | public final static int REQUEST_CAMERA = 67;
36 |
37 | public final static String BUNDLE_CAMERA_PATH = "CameraPath";
38 |
39 | public final static String REQUEST_OUTPUT = "outputList";
40 |
41 | public final static String EXTRA_SELECT_MODE = "SelectMode";
42 | public final static String EXTRA_SHOW_CAMERA = "ShowCamera";
43 | public final static String EXTRA_ENABLE_PREVIEW = "EnablePreview";
44 | public final static String EXTRA_ENABLE_CROP = "EnableCrop";
45 | public final static String EXTRA_MAX_SELECT_NUM = "MaxSelectNum";
46 |
47 | public final static int MODE_MULTIPLE = 1;
48 | public final static int MODE_SINGLE = 2;
49 |
50 | private int maxSelectNum = 9;
51 | private int selectMode = MODE_MULTIPLE;
52 | private boolean showCamera = true;
53 | private boolean enablePreview = true;
54 | private boolean enableCrop = false;
55 |
56 | private int spanCount = 3;
57 |
58 | private Toolbar toolbar;
59 | private TextView doneText;
60 |
61 | private TextView previewText;
62 |
63 | private RecyclerView recyclerView;
64 | private ImageListAdapter imageAdapter;
65 |
66 | private LinearLayout folderLayout;
67 | private TextView folderName;
68 | private FolderWindow folderWindow;
69 |
70 | private String cameraPath;
71 |
72 | public static void start(Activity activity, int maxSelectNum, int mode, boolean isShow, boolean enablePreview, boolean enableCrop) {
73 | Intent intent = new Intent(activity, ImageSelectorActivity.class);
74 | intent.putExtra(EXTRA_MAX_SELECT_NUM, maxSelectNum);
75 | intent.putExtra(EXTRA_SELECT_MODE, mode);
76 | intent.putExtra(EXTRA_SHOW_CAMERA, isShow);
77 | intent.putExtra(EXTRA_ENABLE_PREVIEW, enablePreview);
78 | intent.putExtra(EXTRA_ENABLE_CROP, enableCrop);
79 | activity.startActivityForResult(intent, REQUEST_IMAGE);
80 | }
81 |
82 | @Override
83 | protected void onCreate(Bundle savedInstanceState) {
84 | super.onCreate(savedInstanceState);
85 | setContentView(R.layout.activity_imageselector);
86 |
87 | maxSelectNum = getIntent().getIntExtra(EXTRA_MAX_SELECT_NUM, 9);
88 | selectMode = getIntent().getIntExtra(EXTRA_SELECT_MODE, MODE_MULTIPLE);
89 | showCamera = getIntent().getBooleanExtra(EXTRA_SHOW_CAMERA, true);
90 | enablePreview = getIntent().getBooleanExtra(EXTRA_ENABLE_PREVIEW, true);
91 | enableCrop = getIntent().getBooleanExtra(EXTRA_ENABLE_CROP, false);
92 |
93 | if (selectMode == MODE_MULTIPLE) {
94 | enableCrop = false;
95 | } else {
96 | enablePreview = false;
97 | }
98 | if (savedInstanceState != null) {
99 | cameraPath = savedInstanceState.getString(BUNDLE_CAMERA_PATH);
100 | }
101 | initView();
102 | registerListener();
103 | new LocalMediaLoader(this, LocalMediaLoader.TYPE_IMAGE).loadAllImage(new LocalMediaLoader.LocalMediaLoadListener() {
104 |
105 | @Override
106 | public void loadComplete(List folders) {
107 | folderWindow.bindFolder(folders);
108 | imageAdapter.bindImages(folders.get(0).getImages());
109 | }
110 | });
111 | }
112 |
113 | public void initView() {
114 | folderWindow = new FolderWindow(this);
115 |
116 | toolbar = (Toolbar) findViewById(R.id.toolbar);
117 | toolbar.setTitle(R.string.picture);
118 | setSupportActionBar(toolbar);
119 | toolbar.setNavigationIcon(R.mipmap.ic_back);
120 |
121 | doneText = (TextView) findViewById(R.id.done_text);
122 | doneText.setVisibility(selectMode == MODE_MULTIPLE ? View.VISIBLE : View.GONE);
123 |
124 | previewText = (TextView) findViewById(R.id.preview_text);
125 | previewText.setVisibility(enablePreview ? View.VISIBLE : View.GONE);
126 |
127 | folderLayout = (LinearLayout) findViewById(R.id.folder_layout);
128 | folderName = (TextView) findViewById(R.id.folder_name);
129 |
130 | recyclerView = (RecyclerView) findViewById(R.id.folder_list);
131 | recyclerView.setHasFixedSize(true);
132 | recyclerView.addItemDecoration(new GridSpacingItemDecoration(spanCount, ScreenUtils.dip2px(this, 2), false));
133 | recyclerView.setLayoutManager(new GridLayoutManager(this, spanCount));
134 |
135 | imageAdapter = new ImageListAdapter(this, maxSelectNum, selectMode, showCamera,enablePreview);
136 | recyclerView.setAdapter(imageAdapter);
137 |
138 | }
139 |
140 | public void registerListener() {
141 | toolbar.setNavigationOnClickListener(new View.OnClickListener() {
142 | @Override
143 | public void onClick(View v) {
144 | finish();
145 | }
146 | });
147 | folderLayout.setOnClickListener(new View.OnClickListener() {
148 | @Override
149 | public void onClick(View v) {
150 | if (folderWindow.isShowing()) {
151 | folderWindow.dismiss();
152 | } else {
153 | folderWindow.showAsDropDown(toolbar);
154 | }
155 | }
156 | });
157 | imageAdapter.setOnImageSelectChangedListener(new ImageListAdapter.OnImageSelectChangedListener() {
158 | @Override
159 | public void onChange(List selectImages) {
160 | boolean enable = selectImages.size() != 0;
161 | doneText.setEnabled(enable ? true : false);
162 | previewText.setEnabled(enable ? true : false);
163 | if (enable) {
164 | doneText.setText(getString(R.string.done_num, selectImages.size(), maxSelectNum));
165 | previewText.setText(getString(R.string.preview_num, selectImages.size()));
166 | } else {
167 | doneText.setText(R.string.done);
168 | previewText.setText(R.string.preview);
169 | }
170 | }
171 |
172 | @Override
173 | public void onTakePhoto() {
174 | startCamera();
175 | }
176 |
177 | @Override
178 | public void onPictureClick(LocalMedia media, int position) {
179 | if (enablePreview) {
180 | startPreview(imageAdapter.getImages(), position);
181 | } else if (enableCrop) {
182 | startCrop(media.getPath());
183 | } else {
184 | onSelectDone(media.getPath());
185 | }
186 | }
187 | });
188 | doneText.setOnClickListener(new View.OnClickListener() {
189 | @Override
190 | public void onClick(View v) {
191 | onSelectDone(imageAdapter.getSelectedImages());
192 | }
193 | });
194 | folderWindow.setOnItemClickListener(new ImageFolderAdapter.OnItemClickListener() {
195 | @Override
196 | public void onItemClick(String name, List images) {
197 | folderWindow.dismiss();
198 | imageAdapter.bindImages(images);
199 | folderName.setText(name);
200 | }
201 | });
202 | previewText.setOnClickListener(new View.OnClickListener() {
203 | @Override
204 | public void onClick(View v) {
205 | startPreview(imageAdapter.getSelectedImages(), 0);
206 | }
207 | });
208 | }
209 |
210 |
211 | @Override
212 | protected void onActivityResult(int requestCode, int resultCode, Intent data) {
213 | if (resultCode == RESULT_OK) {
214 | // on take photo success
215 | if (requestCode == REQUEST_CAMERA) {
216 | sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(new File(cameraPath))));
217 | if (enableCrop) {
218 | startCrop(cameraPath);
219 | } else {
220 | onSelectDone(cameraPath);
221 | }
222 | }
223 | //on preview select change
224 | else if (requestCode == ImagePreviewActivity.REQUEST_PREVIEW) {
225 | boolean isDone = data.getBooleanExtra(ImagePreviewActivity.OUTPUT_ISDONE, false);
226 | List images = (List) data.getSerializableExtra(ImagePreviewActivity.OUTPUT_LIST);
227 | if (isDone) {
228 | onSelectDone(images);
229 | }else{
230 | imageAdapter.bindSelectImages(images);
231 | }
232 | }
233 | // on crop success
234 | else if (requestCode == ImageCropActivity.REQUEST_CROP) {
235 | String path = data.getStringExtra(ImageCropActivity.OUTPUT_PATH);
236 | onSelectDone(path);
237 | }
238 | }
239 | }
240 |
241 | @Override
242 | protected void onSaveInstanceState(Bundle outState) {
243 | outState.putString(BUNDLE_CAMERA_PATH, cameraPath);
244 | }
245 |
246 | /**
247 | * start to camera、preview、crop
248 | */
249 | public void startCamera() {
250 | Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
251 | if (cameraIntent.resolveActivity(getPackageManager()) != null) {
252 | File cameraFile = FileUtils.createCameraFile(this);
253 | cameraPath = cameraFile.getAbsolutePath();
254 | cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(cameraFile));
255 | startActivityForResult(cameraIntent, REQUEST_CAMERA);
256 | }
257 | }
258 |
259 | public void startPreview(List previewImages, int position) {
260 | ImagePreviewActivity.startPreview(this, previewImages, imageAdapter.getSelectedImages(), maxSelectNum, position);
261 | }
262 |
263 | public void startCrop(String path) {
264 | ImageCropActivity.startCrop(this, path);
265 | }
266 |
267 | /**
268 | * on select done
269 | *
270 | * @param medias
271 | */
272 | public void onSelectDone(List medias) {
273 | ArrayList images = new ArrayList<>();
274 | for (LocalMedia media : medias) {
275 | images.add(media.getPath());
276 | }
277 | onResult(images);
278 | }
279 |
280 | public void onSelectDone(String path) {
281 | ArrayList images = new ArrayList<>();
282 | images.add(path);
283 | onResult(images);
284 | }
285 |
286 | public void onResult(ArrayList images) {
287 | setResult(RESULT_OK, new Intent().putStringArrayListExtra(REQUEST_OUTPUT, images));
288 | finish();
289 | }
290 | }
291 |
--------------------------------------------------------------------------------
/library/src/main/java/com/yongchun/library/widget/PreviewViewPager.java:
--------------------------------------------------------------------------------
1 | package com.yongchun.library.widget;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.view.MotionEvent;
6 |
7 | /**
8 | * Created by dee on 15/11/24.
9 | */
10 | public class PreviewViewPager extends android.support.v4.view.ViewPager {
11 |
12 | public PreviewViewPager(Context context) {
13 | super(context);
14 | }
15 |
16 | public PreviewViewPager(Context context, AttributeSet attrs) {
17 | super(context, attrs);
18 | }
19 |
20 | @Override
21 | public boolean onTouchEvent(MotionEvent ev) {
22 | try {
23 | return super.onTouchEvent(ev);
24 | } catch (IllegalArgumentException ex) {
25 | ex.printStackTrace();
26 | }
27 | return false;
28 | }
29 |
30 | @Override
31 | public boolean onInterceptTouchEvent(MotionEvent ev) {
32 | try {
33 | return super.onInterceptTouchEvent(ev);
34 | } catch (IllegalArgumentException ex) {
35 | ex.printStackTrace();
36 | }
37 | return false;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/library/src/main/java/com/yongchun/library/widget/SquareRelativeLayout.java:
--------------------------------------------------------------------------------
1 | package com.yongchun.library.widget;
2 |
3 | import android.annotation.TargetApi;
4 | import android.content.Context;
5 | import android.os.Build;
6 | import android.util.AttributeSet;
7 | import android.widget.RelativeLayout;
8 |
9 | /**
10 | * Created by dee on 15/11/19.
11 | */
12 | public class SquareRelativeLayout extends RelativeLayout {
13 |
14 | public SquareRelativeLayout(Context context) {
15 | super(context);
16 | }
17 |
18 | public SquareRelativeLayout(Context context, AttributeSet attrs) {
19 | super(context, attrs);
20 | }
21 |
22 | public SquareRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
23 | super(context, attrs, defStyleAttr);
24 | }
25 |
26 | @TargetApi(Build.VERSION_CODES.LOLLIPOP)
27 | public SquareRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
28 | super(context, attrs, defStyleAttr, defStyleRes);
29 | }
30 |
31 | @Override
32 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
33 | // Set a square layout.
34 | super.onMeasure(widthMeasureSpec, widthMeasureSpec);
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/library/src/main/res/anim/down_out.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
--------------------------------------------------------------------------------
/library/src/main/res/anim/fade_in.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
--------------------------------------------------------------------------------
/library/src/main/res/anim/fade_out.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
--------------------------------------------------------------------------------
/library/src/main/res/anim/up_in.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
--------------------------------------------------------------------------------
/library/src/main/res/color/white_text_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/library/src/main/res/drawable/btn_round_green_disable.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/library/src/main/res/drawable/btn_round_green_enable.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/library/src/main/res/drawable/btn_round_green_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/library/src/main/res/drawable/check_green.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/library/src/main/res/drawable/checkbox_checktor.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/library/src/main/res/drawable/checkbox_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/library/src/main/res/drawable/image_placeholder.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
7 |
8 |
9 | -
10 |
11 |
12 |
--------------------------------------------------------------------------------
/library/src/main/res/drawable/item_divider.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/library/src/main/res/drawable/radio_button.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/library/src/main/res/layout/activity_image_crop.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
14 |
15 |
27 |
28 |
29 |
34 |
--------------------------------------------------------------------------------
/library/src/main/res/layout/activity_image_preview.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
12 |
17 |
18 |
22 |
23 |
29 |
30 |
42 |
43 |
44 |
45 |
52 |
53 |
54 |
66 |
67 |
--------------------------------------------------------------------------------
/library/src/main/res/layout/activity_imageselector.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
14 |
26 |
27 |
28 |
34 |
35 |
41 |
42 |
50 |
51 |
52 |
59 |
60 |
66 |
67 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/library/src/main/res/layout/fragment_image_preview.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
--------------------------------------------------------------------------------
/library/src/main/res/layout/item_camera.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
14 |
22 |
--------------------------------------------------------------------------------
/library/src/main/res/layout/item_folder.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
17 |
18 |
24 |
25 |
32 |
33 |
40 |
41 |
42 |
47 |
--------------------------------------------------------------------------------
/library/src/main/res/layout/item_picture.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
9 |
10 |
17 |
--------------------------------------------------------------------------------
/library/src/main/res/layout/window_folder.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
22 |
--------------------------------------------------------------------------------
/library/src/main/res/mipmap-xhdpi/ic_back.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ioneday/ImageSelector/c922b7ba9b50a5983d4e26ba88441225a58e967e/library/src/main/res/mipmap-xhdpi/ic_back.png
--------------------------------------------------------------------------------
/library/src/main/res/mipmap-xhdpi/ic_camera.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ioneday/ImageSelector/c922b7ba9b50a5983d4e26ba88441225a58e967e/library/src/main/res/mipmap-xhdpi/ic_camera.png
--------------------------------------------------------------------------------
/library/src/main/res/mipmap-xxhdpi/ic_arrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ioneday/ImageSelector/c922b7ba9b50a5983d4e26ba88441225a58e967e/library/src/main/res/mipmap-xxhdpi/ic_arrow.png
--------------------------------------------------------------------------------
/library/src/main/res/mipmap-xxhdpi/ic_check.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ioneday/ImageSelector/c922b7ba9b50a5983d4e26ba88441225a58e967e/library/src/main/res/mipmap-xxhdpi/ic_check.png
--------------------------------------------------------------------------------
/library/src/main/res/mipmap-xxhdpi/ic_checked.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ioneday/ImageSelector/c922b7ba9b50a5983d4e26ba88441225a58e967e/library/src/main/res/mipmap-xxhdpi/ic_checked.png
--------------------------------------------------------------------------------
/library/src/main/res/mipmap-xxhdpi/ic_placeholder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ioneday/ImageSelector/c922b7ba9b50a5983d4e26ba88441225a58e967e/library/src/main/res/mipmap-xxhdpi/ic_placeholder.png
--------------------------------------------------------------------------------
/library/src/main/res/mipmap-xxhdpi/ic_radio_button.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ioneday/ImageSelector/c922b7ba9b50a5983d4e26ba88441225a58e967e/library/src/main/res/mipmap-xxhdpi/ic_radio_button.png
--------------------------------------------------------------------------------
/library/src/main/res/values-zh-rCN/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 所有图片
4 | 图片
5 | 拍摄照片
6 | 预览
7 | 预览(%1$s)
8 | 选择
9 | 完成
10 | 使用
11 | 完成(%1$s/%2$s)
12 | %1$s张
13 | 你最多可以选择%1$s张图片
14 | 保存图片中…
15 |
--------------------------------------------------------------------------------
/library/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #ffffff
4 | #ADFFFFFF
5 | #000000
6 | #333333
7 | #43c117
8 | #AD43c117
9 | #393a3e
10 | #dd393a3e
11 | #999999
12 | #dcdcdc
13 | #353535
14 | #20000000
15 | #80000000
16 |
--------------------------------------------------------------------------------
/library/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 2dp
4 | 48dp
5 | 32dp
6 | 8dp
7 | 16dp
8 | 25dp
9 | 74dp
10 | 52dp
11 |
12 | 17sp
13 | 15sp
14 | 13sp
15 |
--------------------------------------------------------------------------------
/library/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Library
3 | Images
4 | All Images
5 | Take Photo
6 | Preview
7 | Preview(%1$s)
8 | Select
9 | Done
10 | OK
11 | %1$s
12 | Done(%1$s/%2$s)
13 | Up to %1$s photos can be selected
14 | Saving picture…
15 |
16 |
--------------------------------------------------------------------------------
/library/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
16 |
20 |
21 |
25 |
26 |
--------------------------------------------------------------------------------
/library/src/test/java/com/yongchun/library/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.yongchun.library;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * To work on unit tests, switch the Test Artifact in the Build Variants view.
9 | */
10 | public class ExampleUnitTest {
11 | @Test
12 | public void addition_isCorrect() throws Exception {
13 | assertEquals(4, 2 + 2);
14 | }
15 | }
--------------------------------------------------------------------------------
/sample/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/sample/Example-release.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ioneday/ImageSelector/c922b7ba9b50a5983d4e26ba88441225a58e967e/sample/Example-release.apk
--------------------------------------------------------------------------------
/sample/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 22
5 | buildToolsVersion "22.0.1"
6 |
7 | defaultConfig {
8 | applicationId "com.yongchun.multiimageselector"
9 | minSdkVersion 15
10 | targetSdkVersion 22
11 | versionCode 1
12 | versionName "1.0"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | }
21 |
22 | dependencies {
23 | compile fileTree(include: ['*.jar'], dir: 'libs')
24 | testCompile 'junit:junit:4.12'
25 | compile 'com.android.support:appcompat-v7:22.2.1'
26 | compile project(':library')
27 | }
28 |
--------------------------------------------------------------------------------
/sample/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/dzq/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 |
--------------------------------------------------------------------------------
/sample/sample.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | generateDebugAndroidTestSources
19 | generateDebugSources
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 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
--------------------------------------------------------------------------------
/sample/src/androidTest/java/com/yongchun/multiimageselector/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package com.yongchun.multiimageselector;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/sample/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/yongchun/multiimageselector/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.yongchun.multiimageselector;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 | import android.support.v7.app.AppCompatActivity;
6 | import android.view.View;
7 | import android.widget.Button;
8 | import android.widget.EditText;
9 | import android.widget.ImageButton;
10 | import android.widget.RadioGroup;
11 |
12 | import com.yongchun.library.view.ImageSelectorActivity;
13 |
14 | import java.util.ArrayList;
15 |
16 | public class MainActivity extends AppCompatActivity {
17 | private ImageButton minus;
18 | private ImageButton plus;
19 | private EditText selectNumText;
20 |
21 | private RadioGroup selectMode;
22 | private RadioGroup showCamera;
23 | private RadioGroup enablePreview;
24 | private RadioGroup enableCrop;
25 |
26 | private Button selectPicture;
27 |
28 | private int maxSelectNum = 9;
29 | @Override
30 | protected void onCreate(Bundle savedInstanceState) {
31 | super.onCreate(savedInstanceState);
32 | setContentView(R.layout.activity_main);
33 |
34 | initView();
35 | registerListener();
36 |
37 | }
38 | public void initView(){
39 | minus = (ImageButton) findViewById(R.id.minus);
40 | plus = (ImageButton) findViewById(R.id.plus);
41 | selectNumText = (EditText) findViewById(R.id.select_num);
42 |
43 | selectMode = (RadioGroup) findViewById(R.id.select_mode);
44 | showCamera = (RadioGroup) findViewById(R.id.show_camera);
45 | enablePreview = (RadioGroup) findViewById(R.id.enable_preview);
46 | enableCrop = (RadioGroup) findViewById(R.id.enable_crop);
47 |
48 | selectPicture = (Button) findViewById(R.id.select_picture);
49 | }
50 | public void registerListener(){
51 | selectMode.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
52 | @Override
53 | public void onCheckedChanged(RadioGroup group, int checkedId) {
54 | if(checkedId == R.id.mode_single){
55 | enableCrop.check(R.id.crop_enable);
56 | findViewById(R.id.crop_enable).setEnabled(true);
57 |
58 | enablePreview.check(R.id.preview_disable);
59 | findViewById(R.id.preview_enable).setEnabled(false);
60 | }else{
61 | enableCrop.check(R.id.crop_disable);
62 | findViewById(R.id.crop_enable).setEnabled(false);
63 |
64 | enablePreview.check(R.id.preview_enable);
65 | findViewById(R.id.preview_enable).setEnabled(true);
66 | }
67 | }
68 | });
69 | minus.setOnClickListener(new View.OnClickListener() {
70 | @Override
71 | public void onClick(View v) {
72 | maxSelectNum --;
73 | selectNumText.setText(maxSelectNum+"");
74 | }
75 | });
76 | plus.setOnClickListener(new View.OnClickListener() {
77 | @Override
78 | public void onClick(View v) {
79 | maxSelectNum ++;
80 | selectNumText.setText(maxSelectNum+"");
81 | }
82 | });
83 | selectPicture.setOnClickListener(new View.OnClickListener() {
84 | @Override
85 | public void onClick(View v) {
86 | int mode = selectMode.getCheckedRadioButtonId()==R.id.mode_multiple?ImageSelectorActivity.MODE_MULTIPLE:ImageSelectorActivity.MODE_SINGLE;
87 | boolean isShow = showCamera.getCheckedRadioButtonId()==R.id.camera_yes?true:false;
88 | boolean isPreview = enablePreview.getCheckedRadioButtonId()==R.id.preview_enable?true:false;
89 | boolean isCrop = enableCrop.getCheckedRadioButtonId()==R.id.crop_enable?true:false;
90 |
91 | ImageSelectorActivity.start(MainActivity.this, maxSelectNum, mode, isShow,isPreview,isCrop);
92 | }
93 | });
94 | }
95 |
96 | @Override
97 | protected void onActivityResult(int requestCode, int resultCode, Intent data) {
98 | if(resultCode == RESULT_OK && requestCode == ImageSelectorActivity.REQUEST_IMAGE){
99 | ArrayList images = (ArrayList) data.getSerializableExtra(ImageSelectorActivity.REQUEST_OUTPUT);
100 | startActivity(new Intent(this,SelectResultActivity.class).putExtra(SelectResultActivity.EXTRA_IMAGES,images));
101 | }
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/yongchun/multiimageselector/SelectResultActivity.java:
--------------------------------------------------------------------------------
1 | package com.yongchun.multiimageselector;
2 |
3 | import android.os.Bundle;
4 | import android.support.v7.app.AppCompatActivity;
5 | import android.support.v7.widget.GridLayoutManager;
6 | import android.support.v7.widget.RecyclerView;
7 | import android.view.LayoutInflater;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 | import android.widget.ImageView;
11 |
12 | import com.bumptech.glide.Glide;
13 |
14 | import java.io.File;
15 | import java.util.ArrayList;
16 |
17 | /**
18 | * Created by dee on 15/11/27.
19 | */
20 | public class SelectResultActivity extends AppCompatActivity {
21 | public static final String EXTRA_IMAGES = "extraImages";
22 | private RecyclerView resultRecyclerView;
23 | private ImageView singleImageView;
24 |
25 | private ArrayList images = new ArrayList<>();
26 |
27 | @Override
28 | protected void onCreate(Bundle savedInstanceState) {
29 | super.onCreate(savedInstanceState);
30 | setContentView(R.layout.activity_result);
31 |
32 | initView();
33 | }
34 |
35 | public void initView() {
36 | images = (ArrayList) getIntent().getSerializableExtra(EXTRA_IMAGES);
37 | singleImageView = (ImageView) findViewById(R.id.single_image);
38 |
39 | resultRecyclerView = (RecyclerView) findViewById(R.id.result_recycler);
40 | resultRecyclerView.setLayoutManager(new GridLayoutManager(this, 3));
41 |
42 | if (images.size() == 1) {
43 | resultRecyclerView.setVisibility(View.GONE);
44 | Glide.with(SelectResultActivity.this)
45 | .load(new File(images.get(0)))
46 | .into(singleImageView);
47 | } else {
48 | singleImageView.setVisibility(View.GONE);
49 | resultRecyclerView.setAdapter(new GridAdapter());
50 | }
51 |
52 | }
53 |
54 | private class GridAdapter extends RecyclerView.Adapter {
55 |
56 | @Override
57 | public GridAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
58 | View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_result, parent, false);
59 | return new ViewHolder(itemView);
60 | }
61 |
62 | @Override
63 | public void onBindViewHolder(GridAdapter.ViewHolder holder, int position) {
64 | Glide.with(SelectResultActivity.this)
65 | .load(new File(images.get(position)))
66 | .centerCrop()
67 | .into(holder.imageView);
68 | }
69 |
70 | @Override
71 | public int getItemCount() {
72 | return images.size();
73 | }
74 |
75 | class ViewHolder extends RecyclerView.ViewHolder {
76 | ImageView imageView;
77 |
78 | public ViewHolder(View itemView) {
79 | super(itemView);
80 | imageView = (ImageView) itemView.findViewById(R.id.image);
81 | }
82 | }
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/sample/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
19 |
20 |
21 |
22 |
28 |
29 |
37 |
38 |
44 |
45 |
52 |
53 |
54 |
60 |
61 |
69 |
70 |
76 |
77 |
84 |
85 |
86 |
92 |
93 |
101 |
102 |
108 |
109 |
116 |
117 |
118 |
124 |
125 |
133 |
134 |
141 |
142 |
149 |
150 |
151 |
159 |
160 |
--------------------------------------------------------------------------------
/sample/src/main/res/layout/activity_result.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
15 |
--------------------------------------------------------------------------------
/sample/src/main/res/layout/item_result.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
10 |
--------------------------------------------------------------------------------
/sample/src/main/res/layout/layout_number.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
14 |
15 |
25 |
26 |
31 |
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ioneday/ImageSelector/c922b7ba9b50a5983d4e26ba88441225a58e967e/sample/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ioneday/ImageSelector/c922b7ba9b50a5983d4e26ba88441225a58e967e/sample/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ioneday/ImageSelector/c922b7ba9b50a5983d4e26ba88441225a58e967e/sample/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xhdpi/ic_minus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ioneday/ImageSelector/c922b7ba9b50a5983d4e26ba88441225a58e967e/sample/src/main/res/mipmap-xhdpi/ic_minus.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xhdpi/ic_plus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ioneday/ImageSelector/c922b7ba9b50a5983d4e26ba88441225a58e967e/sample/src/main/res/mipmap-xhdpi/ic_plus.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ioneday/ImageSelector/c922b7ba9b50a5983d4e26ba88441225a58e967e/sample/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ioneday/ImageSelector/c922b7ba9b50a5983d4e26ba88441225a58e967e/sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/sample/src/main/res/values-zh-rCN/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 可选择图片数量
4 | 选择图片
5 | 选择模式
6 | 单选
7 | 多选
8 | 显示拍照选项
9 | 是
10 | 否
11 | 打开预览选项
12 | 打开剪切选项
13 | 打开
14 | 关闭
15 |
--------------------------------------------------------------------------------
/sample/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/sample/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/sample/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/sample/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | MultiImageSelector
3 | Select picture
4 | Maximum number of options
5 | Selection mode
6 | Single
7 | Multiple
8 | Show Camera
9 | Yes
10 | No
11 |
12 | Enable Preview
13 | Enable Crop Image
14 | Enable
15 | Disable
16 |
17 |
--------------------------------------------------------------------------------
/sample/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/sample/src/test/java/com/yongchun/multiimageselector/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.yongchun.multiimageselector;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * To work on unit tests, switch the Test Artifact in the Build Variants view.
9 | */
10 | public class ExampleUnitTest {
11 | @Test
12 | public void addition_isCorrect() throws Exception {
13 | assertEquals(4, 2 + 2);
14 | }
15 | }
--------------------------------------------------------------------------------
/screenshot/Screenshot1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ioneday/ImageSelector/c922b7ba9b50a5983d4e26ba88441225a58e967e/screenshot/Screenshot1.jpg
--------------------------------------------------------------------------------
/screenshot/Screenshot2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ioneday/ImageSelector/c922b7ba9b50a5983d4e26ba88441225a58e967e/screenshot/Screenshot2.jpg
--------------------------------------------------------------------------------
/screenshot/Screenshot3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ioneday/ImageSelector/c922b7ba9b50a5983d4e26ba88441225a58e967e/screenshot/Screenshot3.jpg
--------------------------------------------------------------------------------
/screenshot/Screenshot4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ioneday/ImageSelector/c922b7ba9b50a5983d4e26ba88441225a58e967e/screenshot/Screenshot4.jpg
--------------------------------------------------------------------------------
/screenshot/Screenshot5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ioneday/ImageSelector/c922b7ba9b50a5983d4e26ba88441225a58e967e/screenshot/Screenshot5.jpg
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':sample', ':library'
2 |
--------------------------------------------------------------------------------