) data.getSerializableExtra(ImagePicker.EXTRA_IMAGE_ITEMS);
160 | if (images != null) {
161 | selImageList.clear();
162 | selImageList.addAll(images);
163 | adapter.setImages(selImageList);
164 | }
165 | }
166 | }
167 | }
168 | }
169 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/photo_dialog_in_anim.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/photo_dialog_out_anim.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/dialog_item_bg_only.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | -
5 |
6 |
7 |
8 |
9 | -
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/photo_choose_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/select_dialog_item_bg_buttom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | -
5 |
6 |
7 |
8 |
9 | -
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/select_dialog_item_bg_center.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | -
5 |
6 |
7 |
8 | -
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/select_dialog_item_bg_top.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | -
5 |
6 |
7 |
8 |
9 | -
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/selector_image_add.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_image_picker.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
10 |
11 |
16 |
17 |
25 |
26 |
30 |
31 |
36 |
37 |
42 |
43 |
48 |
49 |
54 |
55 |
62 |
63 |
68 |
69 |
74 |
75 |
76 |
77 |
78 |
83 |
84 |
92 |
93 |
98 |
99 |
105 |
106 |
112 |
113 |
114 |
115 |
116 |
122 |
123 |
129 |
130 |
139 |
140 |
145 |
146 |
147 |
152 |
153 |
158 |
159 |
164 |
165 |
166 |
172 |
173 |
178 |
179 |
185 |
186 |
194 |
195 |
203 |
204 |
210 |
211 |
219 |
220 |
221 |
226 |
227 |
232 |
233 |
241 |
242 |
247 |
248 |
256 |
257 |
258 |
264 |
265 |
269 |
270 |
278 |
279 |
284 |
285 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_wxdemo.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/list_item_image.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/view_dialog_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
15 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/view_dialog_select.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
21 |
22 |
31 |
32 |
33 |
43 |
44 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jeasonlzy/ImagePicker/f7cad47b259b89bb109905e2498c228bf9c35041/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/image_add_nor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jeasonlzy/ImagePicker/f7cad47b259b89bb109905e2498c228bf9c35041/app/src/main/res/mipmap-hdpi/image_add_nor.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/image_add_sel.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jeasonlzy/ImagePicker/f7cad47b259b89bb109905e2498c228bf9c35041/app/src/main/res/mipmap-hdpi/image_add_sel.png
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 | #33b5e5
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | ImagePicker
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
16 |
17 |
20 |
21 |
--------------------------------------------------------------------------------
/bintray.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.github.dcendents.android-maven'
2 | apply plugin: 'com.jfrog.bintray'
3 |
4 | version = "0.6.1" // 数据仓库依赖第三部分
5 |
6 | def siteUrl = 'https://github.com/jeasonlzy/ImagePicker'
7 | def gitUrl = 'https://github.com/jeasonlzy/ImagePicker.git'
8 | group = "com.lzy.widget" // 数据仓库依赖第一部分
9 |
10 | install {
11 | repositories.mavenInstaller {
12 | pom {
13 | project {
14 | packaging 'aar'
15 | name 'ImagePicker For Android' // 项目描述
16 | url siteUrl
17 | licenses {
18 | license {
19 | name 'The Apache Software License, Version 2.0'
20 | url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
21 | }
22 | }
23 | developers {
24 | developer {
25 | id 'jeasonlzy' // 开发者信息
26 | name 'LiaoZiYao' // 开发者信息
27 | email 'liaojeason@126.com' // 开发者信息
28 | }
29 | }
30 | scm {
31 | connection gitUrl
32 | developerConnection gitUrl
33 | url siteUrl
34 | }
35 | }
36 | }
37 | }
38 | }
39 |
40 | task sourcesJar(type: Jar) {
41 | from android.sourceSets.main.java.srcDirs
42 | classifier = 'sources'
43 | }
44 |
45 | task javadoc(type: Javadoc) {
46 | source = android.sourceSets.main.java.srcDirs
47 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
48 | }
49 |
50 | task javadocJar(type: Jar, dependsOn: javadoc) {
51 | classifier = 'javadoc'
52 | from javadoc.destinationDir
53 | }
54 |
55 | javadoc {
56 | options {
57 | encoding "UTF-8"
58 | charSet 'UTF-8'
59 | author true
60 | version true
61 | links "http://docs.oracle.com/javase/7/docs/api"
62 | title 'ImagePicker For Android' // 文档标题
63 | }
64 | }
65 |
66 | artifacts {
67 | archives javadocJar
68 | archives sourcesJar
69 | }
70 |
71 | Properties properties = new Properties()
72 | properties.load(project.rootProject.file('local.properties').newDataInputStream())
73 | bintray {
74 | user = properties.getProperty("bintray.user")
75 | key = properties.getProperty("bintray.apikey")
76 | configurations = ['archives']
77 | pkg {
78 | repo = "maven"
79 | name = "imagepicker" // 数据仓库依赖第二部分
80 | websiteUrl = siteUrl
81 | vcsUrl = gitUrl
82 | licenses = ["Apache-2.0"]
83 | publish = true
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/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:2.3.3'
9 |
10 | classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7'
11 | classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5'
12 | // NOTE: Do not place your application dependencies here; they belong
13 | // in the individual module build.gradle files
14 | }
15 | }
16 |
17 | allprojects {
18 | repositories {
19 | jcenter()
20 | }
21 | }
22 |
23 | task clean(type: Delete) {
24 | delete rootProject.buildDir
25 | }
26 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | ## Project-wide Gradle settings.
2 | #
3 | # For more details on how to configure your build environment visit
4 | # http://www.gradle.org/docs/current/userguide/build_environment.html
5 | #
6 | # Specifies the JVM arguments used for the daemon process.
7 | # The setting is particularly useful for tweaking memory settings.
8 | # Default value: -Xmx1024m -XX:MaxPermSize=256m
9 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
10 | #
11 | # When configured, Gradle will run in incubating parallel mode.
12 | # This option should only be used with decoupled projects. More details, visit
13 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
14 | # org.gradle.parallel=true
15 |
16 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jeasonlzy/ImagePicker/f7cad47b259b89bb109905e2498c228bf9c35041/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Apr 19 17:17:17 CST 2017
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-3.3-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 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/imagepicker/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Custom for Visual Studio
5 | *.cs diff=csharp
6 |
7 | # Standard to msysgit
8 | *.doc diff=astextplain
9 | *.DOC diff=astextplain
10 | *.docx diff=astextplain
11 | *.DOCX diff=astextplain
12 | *.dot diff=astextplain
13 | *.DOT diff=astextplain
14 | *.pdf diff=astextplain
15 | *.PDF diff=astextplain
16 | *.rtf diff=astextplain
17 | *.RTF diff=astextplain
18 |
--------------------------------------------------------------------------------
/imagepicker/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/imagepicker/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 25
5 | buildToolsVersion "25.0.3"
6 |
7 | defaultConfig {
8 | minSdkVersion 11
9 | targetSdkVersion 25
10 | versionCode 1
11 | versionName "1.0"
12 | vectorDrawables.useSupportLibrary = true
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 | compile 'com.android.support:appcompat-v7:25.3.1'
25 | compile 'com.android.support:recyclerview-v7:25.3.1'
26 | compile 'com.github.chrisbanes.photoview:library:1.2.4'
27 | }
28 |
29 | //apply from: '../bintray.gradle'
--------------------------------------------------------------------------------
/imagepicker/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 E:\Android\SDK/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/imagepicker/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
21 |
26 |
30 |
31 |
35 |
36 |
41 |
44 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/imagepicker/src/main/java/com/lzy/imagepicker/DataHolder.java:
--------------------------------------------------------------------------------
1 | package com.lzy.imagepicker;
2 |
3 | import com.lzy.imagepicker.bean.ImageItem;
4 |
5 | import java.util.HashMap;
6 | import java.util.List;
7 | import java.util.Map;
8 |
9 |
10 | /**
11 | * 新的DataHolder,使用单例和弱引用解决崩溃问题
12 | *
13 | * Author: nanchen
14 | * Email: liushilin520@foxmail.com
15 | * Date: 2017-03-20 07:01
16 | */
17 | public class DataHolder {
18 | public static final String DH_CURRENT_IMAGE_FOLDER_ITEMS = "dh_current_image_folder_items";
19 |
20 | private static DataHolder mInstance;
21 | private Map> data;
22 |
23 | public static DataHolder getInstance() {
24 | if (mInstance == null){
25 | synchronized (DataHolder.class){
26 | if (mInstance == null){
27 | mInstance = new DataHolder();
28 | }
29 | }
30 | }
31 | return mInstance;
32 | }
33 |
34 | private DataHolder() {
35 | data = new HashMap<>();
36 | }
37 |
38 | public void save(String id, List object) {
39 | if (data != null){
40 | data.put(id, object);
41 | }
42 | }
43 |
44 | public Object retrieve(String id) {
45 | if (data == null || mInstance == null){
46 | throw new RuntimeException("你必须先初始化");
47 | }
48 | return data.get(id);
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/imagepicker/src/main/java/com/lzy/imagepicker/ImageDataSource.java:
--------------------------------------------------------------------------------
1 | package com.lzy.imagepicker;
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.lzy.imagepicker.bean.ImageFolder;
12 | import com.lzy.imagepicker.bean.ImageItem;
13 |
14 | import java.io.File;
15 | import java.util.ArrayList;
16 | import java.util.List;
17 |
18 | /**
19 | * ================================================
20 | * 作 者:jeasonlzy(廖子尧 Github地址:https://github.com/jeasonlzy0216
21 | * 版 本:1.0
22 | * 创建日期:2016/5/19
23 | * 描 述:加载手机图片实现类
24 | * 修订历史:
25 | * ================================================
26 | */
27 | public class ImageDataSource implements LoaderManager.LoaderCallbacks {
28 |
29 | public static final int LOADER_ALL = 0; //加载所有图片
30 | public static final int LOADER_CATEGORY = 1; //分类加载图片
31 | private final String[] IMAGE_PROJECTION = { //查询图片需要的数据列
32 | MediaStore.Images.Media.DISPLAY_NAME, //图片的显示名称 aaa.jpg
33 | MediaStore.Images.Media.DATA, //图片的真实路径 /storage/emulated/0/pp/downloader/wallpaper/aaa.jpg
34 | MediaStore.Images.Media.SIZE, //图片的大小,long型 132492
35 | MediaStore.Images.Media.WIDTH, //图片的宽度,int型 1920
36 | MediaStore.Images.Media.HEIGHT, //图片的高度,int型 1080
37 | MediaStore.Images.Media.MIME_TYPE, //图片的类型 image/jpeg
38 | MediaStore.Images.Media.DATE_ADDED}; //图片被添加的时间,long型 1450518608
39 |
40 | private FragmentActivity activity;
41 | private OnImagesLoadedListener loadedListener; //图片加载完成的回调接口
42 | private ArrayList imageFolders = new ArrayList<>(); //所有的图片文件夹
43 |
44 | /**
45 | * @param activity 用于初始化LoaderManager,需要兼容到2.3
46 | * @param path 指定扫描的文件夹目录,可以为 null,表示扫描所有图片
47 | * @param loadedListener 图片加载完成的监听
48 | */
49 | public ImageDataSource(FragmentActivity activity, String path, OnImagesLoadedListener loadedListener) {
50 | this.activity = activity;
51 | this.loadedListener = loadedListener;
52 |
53 | LoaderManager loaderManager = activity.getSupportLoaderManager();
54 | if (path == null) {
55 | loaderManager.initLoader(LOADER_ALL, null, this);//加载所有的图片
56 | } else {
57 | //加载指定目录的图片
58 | Bundle bundle = new Bundle();
59 | bundle.putString("path", path);
60 | loaderManager.initLoader(LOADER_CATEGORY, bundle, this);
61 | }
62 | }
63 |
64 | @Override
65 | public Loader onCreateLoader(int id, Bundle args) {
66 | CursorLoader cursorLoader = null;
67 | //扫描所有图片
68 | if (id == LOADER_ALL)
69 | cursorLoader = new CursorLoader(activity, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, IMAGE_PROJECTION, null, null, IMAGE_PROJECTION[6] + " DESC");
70 | //扫描某个图片文件夹
71 | if (id == LOADER_CATEGORY)
72 | cursorLoader = new CursorLoader(activity, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, IMAGE_PROJECTION, IMAGE_PROJECTION[1] + " like '%" + args.getString("path") + "%'", null, IMAGE_PROJECTION[6] + " DESC");
73 |
74 | return cursorLoader;
75 | }
76 |
77 | @Override
78 | public void onLoadFinished(Loader loader, Cursor data) {
79 | imageFolders.clear();
80 | if (data != null) {
81 | ArrayList allImages = new ArrayList<>(); //所有图片的集合,不分文件夹
82 | while (data.moveToNext()) {
83 | //查询数据
84 | String imageName = data.getString(data.getColumnIndexOrThrow(IMAGE_PROJECTION[0]));
85 | String imagePath = data.getString(data.getColumnIndexOrThrow(IMAGE_PROJECTION[1]));
86 |
87 | File file = new File(imagePath);
88 | if (!file.exists() || file.length() <= 0) {
89 | continue;
90 | }
91 |
92 | long imageSize = data.getLong(data.getColumnIndexOrThrow(IMAGE_PROJECTION[2]));
93 | int imageWidth = data.getInt(data.getColumnIndexOrThrow(IMAGE_PROJECTION[3]));
94 | int imageHeight = data.getInt(data.getColumnIndexOrThrow(IMAGE_PROJECTION[4]));
95 | String imageMimeType = data.getString(data.getColumnIndexOrThrow(IMAGE_PROJECTION[5]));
96 | long imageAddTime = data.getLong(data.getColumnIndexOrThrow(IMAGE_PROJECTION[6]));
97 | //封装实体
98 | ImageItem imageItem = new ImageItem();
99 | imageItem.name = imageName;
100 | imageItem.path = imagePath;
101 | imageItem.size = imageSize;
102 | imageItem.width = imageWidth;
103 | imageItem.height = imageHeight;
104 | imageItem.mimeType = imageMimeType;
105 | imageItem.addTime = imageAddTime;
106 | allImages.add(imageItem);
107 | //根据父路径分类存放图片
108 | File imageFile = new File(imagePath);
109 | File imageParentFile = imageFile.getParentFile();
110 | ImageFolder imageFolder = new ImageFolder();
111 | imageFolder.name = imageParentFile.getName();
112 | imageFolder.path = imageParentFile.getAbsolutePath();
113 |
114 | if (!imageFolders.contains(imageFolder)) {
115 | ArrayList images = new ArrayList<>();
116 | images.add(imageItem);
117 | imageFolder.cover = imageItem;
118 | imageFolder.images = images;
119 | imageFolders.add(imageFolder);
120 | } else {
121 | imageFolders.get(imageFolders.indexOf(imageFolder)).images.add(imageItem);
122 | }
123 | }
124 | //防止没有图片报异常
125 | if (data.getCount() > 0 && allImages.size()>0) {
126 | //构造所有图片的集合
127 | ImageFolder allImagesFolder = new ImageFolder();
128 | allImagesFolder.name = activity.getResources().getString(R.string.ip_all_images);
129 | allImagesFolder.path = "/";
130 | allImagesFolder.cover = allImages.get(0);
131 | allImagesFolder.images = allImages;
132 | imageFolders.add(0, allImagesFolder); //确保第一条是所有图片
133 | }
134 | }
135 |
136 | //回调接口,通知图片数据准备完成
137 | ImagePicker.getInstance().setImageFolders(imageFolders);
138 | loadedListener.onImagesLoaded(imageFolders);
139 | }
140 |
141 | @Override
142 | public void onLoaderReset(Loader loader) {
143 | System.out.println("--------");
144 | }
145 |
146 | /** 所有图片加载完成的回调接口 */
147 | public interface OnImagesLoadedListener {
148 | void onImagesLoaded(List imageFolders);
149 | }
150 | }
151 |
--------------------------------------------------------------------------------
/imagepicker/src/main/java/com/lzy/imagepicker/ImagePickerProvider.java:
--------------------------------------------------------------------------------
1 | package com.lzy.imagepicker;
2 |
3 | import android.support.v4.content.FileProvider;
4 |
5 | /**
6 | * 自定义一个Provider,以免和引入的项目的provider冲突
7 | *
8 | * Author: nanchen
9 | * Email: liushilin520@foxmail.com
10 | * Date: 2017-03-17 16:10
11 | */
12 |
13 | public class ImagePickerProvider extends FileProvider {
14 | }
15 |
--------------------------------------------------------------------------------
/imagepicker/src/main/java/com/lzy/imagepicker/adapter/ImageFolderAdapter.java:
--------------------------------------------------------------------------------
1 | package com.lzy.imagepicker.adapter;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 | import android.widget.BaseAdapter;
9 | import android.widget.ImageView;
10 | import android.widget.TextView;
11 |
12 | import com.lzy.imagepicker.ImagePicker;
13 | import com.lzy.imagepicker.R;
14 | import com.lzy.imagepicker.util.Utils;
15 | import com.lzy.imagepicker.bean.ImageFolder;
16 |
17 | import java.util.ArrayList;
18 | import java.util.List;
19 |
20 |
21 | /**
22 | * ================================================
23 | * 作 者:jeasonlzy(廖子尧 Github地址:https://github.com/jeasonlzy0216
24 | * 版 本:1.0
25 | * 创建日期:2016/5/19
26 | * 描 述:
27 | * 修订历史:
28 | * ================================================
29 | */
30 | public class ImageFolderAdapter extends BaseAdapter {
31 |
32 | private ImagePicker imagePicker;
33 | private Activity mActivity;
34 | private LayoutInflater mInflater;
35 | private int mImageSize;
36 | private List imageFolders;
37 | private int lastSelected = 0;
38 |
39 | public ImageFolderAdapter(Activity activity, List folders) {
40 | mActivity = activity;
41 | if (folders != null && folders.size() > 0) imageFolders = folders;
42 | else imageFolders = new ArrayList<>();
43 |
44 | imagePicker = ImagePicker.getInstance();
45 | mImageSize = Utils.getImageItemWidth(mActivity);
46 | mInflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
47 | }
48 |
49 | public void refreshData(List folders) {
50 | if (folders != null && folders.size() > 0) imageFolders = folders;
51 | else imageFolders.clear();
52 | notifyDataSetChanged();
53 | }
54 |
55 | @Override
56 | public int getCount() {
57 | return imageFolders.size();
58 | }
59 |
60 | @Override
61 | public ImageFolder getItem(int position) {
62 | return imageFolders.get(position);
63 | }
64 |
65 | @Override
66 | public long getItemId(int position) {
67 | return position;
68 | }
69 |
70 | @Override
71 | public View getView(int position, View convertView, ViewGroup parent) {
72 | ViewHolder holder;
73 | if (convertView == null) {
74 | convertView = mInflater.inflate(R.layout.adapter_folder_list_item, parent, false);
75 | holder = new ViewHolder(convertView);
76 | } else {
77 | holder = (ViewHolder) convertView.getTag();
78 | }
79 |
80 | ImageFolder folder = getItem(position);
81 | holder.folderName.setText(folder.name);
82 | holder.imageCount.setText(mActivity.getString(R.string.ip_folder_image_count, folder.images.size()));
83 | imagePicker.getImageLoader().displayImage(mActivity, folder.cover.path, holder.cover, mImageSize, mImageSize);
84 |
85 | if (lastSelected == position) {
86 | holder.folderCheck.setVisibility(View.VISIBLE);
87 | } else {
88 | holder.folderCheck.setVisibility(View.INVISIBLE);
89 | }
90 |
91 | return convertView;
92 | }
93 |
94 | public void setSelectIndex(int i) {
95 | if (lastSelected == i) {
96 | return;
97 | }
98 | lastSelected = i;
99 | notifyDataSetChanged();
100 | }
101 |
102 | public int getSelectIndex() {
103 | return lastSelected;
104 | }
105 |
106 | private class ViewHolder {
107 | ImageView cover;
108 | TextView folderName;
109 | TextView imageCount;
110 | ImageView folderCheck;
111 |
112 | public ViewHolder(View view) {
113 | cover = (ImageView) view.findViewById(R.id.iv_cover);
114 | folderName = (TextView) view.findViewById(R.id.tv_folder_name);
115 | imageCount = (TextView) view.findViewById(R.id.tv_image_count);
116 | folderCheck = (ImageView) view.findViewById(R.id.iv_folder_check);
117 | view.setTag(this);
118 | }
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/imagepicker/src/main/java/com/lzy/imagepicker/adapter/ImagePageAdapter.java:
--------------------------------------------------------------------------------
1 | package com.lzy.imagepicker.adapter;
2 |
3 | import android.app.Activity;
4 | import android.support.v4.view.PagerAdapter;
5 | import android.util.DisplayMetrics;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 |
9 | import com.lzy.imagepicker.ImagePicker;
10 | import com.lzy.imagepicker.util.Utils;
11 | import com.lzy.imagepicker.bean.ImageItem;
12 |
13 | import java.util.ArrayList;
14 |
15 | import uk.co.senab.photoview.PhotoView;
16 | import uk.co.senab.photoview.PhotoViewAttacher;
17 |
18 | /**
19 | * ================================================
20 | * 作 者:jeasonlzy(廖子尧 Github地址:https://github.com/jeasonlzy0216
21 | * 版 本:1.0
22 | * 创建日期:2016/5/19
23 | * 描 述:
24 | * 修订历史:
25 | * ================================================
26 | */
27 | public class ImagePageAdapter extends PagerAdapter {
28 |
29 | private int screenWidth;
30 | private int screenHeight;
31 | private ImagePicker imagePicker;
32 | private ArrayList images = new ArrayList<>();
33 | private Activity mActivity;
34 | public PhotoViewClickListener listener;
35 |
36 | public ImagePageAdapter(Activity activity, ArrayList images) {
37 | this.mActivity = activity;
38 | this.images = images;
39 |
40 | DisplayMetrics dm = Utils.getScreenPix(activity);
41 | screenWidth = dm.widthPixels;
42 | screenHeight = dm.heightPixels;
43 | imagePicker = ImagePicker.getInstance();
44 | }
45 |
46 | public void setData(ArrayList images) {
47 | this.images = images;
48 | }
49 |
50 | public void setPhotoViewClickListener(PhotoViewClickListener listener) {
51 | this.listener = listener;
52 | }
53 |
54 | @Override
55 | public Object instantiateItem(ViewGroup container, int position) {
56 | PhotoView photoView = new PhotoView(mActivity);
57 | ImageItem imageItem = images.get(position);
58 | imagePicker.getImageLoader().displayImagePreview(mActivity, imageItem.path, photoView, screenWidth, screenHeight);
59 | photoView.setOnPhotoTapListener(new PhotoViewAttacher.OnPhotoTapListener() {
60 | @Override
61 | public void onPhotoTap(View view, float x, float y) {
62 | if (listener != null) listener.OnPhotoTapListener(view, x, y);
63 | }
64 | });
65 | container.addView(photoView);
66 | return photoView;
67 | }
68 |
69 | @Override
70 | public int getCount() {
71 | return images.size();
72 | }
73 |
74 | @Override
75 | public boolean isViewFromObject(View view, Object object) {
76 | return view == object;
77 | }
78 |
79 | @Override
80 | public void destroyItem(ViewGroup container, int position, Object object) {
81 | container.removeView((View) object);
82 | }
83 |
84 | @Override
85 | public int getItemPosition(Object object) {
86 | return POSITION_NONE;
87 | }
88 |
89 | public interface PhotoViewClickListener {
90 | void OnPhotoTapListener(View view, float v, float v1);
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/imagepicker/src/main/java/com/lzy/imagepicker/adapter/ImageRecyclerAdapter.java:
--------------------------------------------------------------------------------
1 | package com.lzy.imagepicker.adapter;
2 |
3 | import android.Manifest;
4 | import android.app.Activity;
5 | import android.support.v4.app.ActivityCompat;
6 | import android.support.v7.widget.RecyclerView;
7 | import android.support.v7.widget.RecyclerView.ViewHolder;
8 | import android.view.LayoutInflater;
9 | import android.view.View;
10 | import android.view.ViewGroup;
11 | import android.widget.AbsListView;
12 | import android.widget.ImageView;
13 | import android.widget.Toast;
14 |
15 | import com.lzy.imagepicker.ImagePicker;
16 | import com.lzy.imagepicker.R;
17 | import com.lzy.imagepicker.bean.ImageItem;
18 | import com.lzy.imagepicker.ui.ImageBaseActivity;
19 | import com.lzy.imagepicker.ui.ImageGridActivity;
20 | import com.lzy.imagepicker.util.Utils;
21 | import com.lzy.imagepicker.view.SuperCheckBox;
22 |
23 | import java.util.ArrayList;
24 |
25 | /**
26 | * 加载相册图片的RecyclerView适配器
27 | *
28 | * 用于替换原项目的GridView,使用局部刷新解决选中照片出现闪动问题
29 | *
30 | * 替换为RecyclerView后只是不再会导致全局刷新,
31 | *
32 | * 但还是会出现明显的重新加载图片,可能是picasso图片加载框架的问题
33 | *
34 | * Author: nanchen
35 | * Email: liushilin520@foxmail.com
36 | * Date: 2017-04-05 10:04
37 | */
38 |
39 | public class ImageRecyclerAdapter extends RecyclerView.Adapter {
40 |
41 |
42 | private static final int ITEM_TYPE_CAMERA = 0; //第一个条目是相机
43 | private static final int ITEM_TYPE_NORMAL = 1; //第一个条目不是相机
44 | private ImagePicker imagePicker;
45 | private Activity mActivity;
46 | private ArrayList images; //当前需要显示的所有的图片数据
47 | private ArrayList mSelectedImages; //全局保存的已经选中的图片数据
48 | private boolean isShowCamera; //是否显示拍照按钮
49 | private int mImageSize; //每个条目的大小
50 | private LayoutInflater mInflater;
51 | private OnImageItemClickListener listener; //图片被点击的监听
52 |
53 | public void setOnImageItemClickListener(OnImageItemClickListener listener) {
54 | this.listener = listener;
55 | }
56 |
57 | public interface OnImageItemClickListener {
58 | void onImageItemClick(View view, ImageItem imageItem, int position);
59 | }
60 |
61 | public void refreshData(ArrayList images) {
62 | if (images == null || images.size() == 0) this.images = new ArrayList<>();
63 | else this.images = images;
64 | notifyDataSetChanged();
65 | }
66 |
67 | /**
68 | * 构造方法
69 | */
70 | public ImageRecyclerAdapter(Activity activity, ArrayList images) {
71 | this.mActivity = activity;
72 | if (images == null || images.size() == 0) this.images = new ArrayList<>();
73 | else this.images = images;
74 |
75 | mImageSize = Utils.getImageItemWidth(mActivity);
76 | imagePicker = ImagePicker.getInstance();
77 | isShowCamera = imagePicker.isShowCamera();
78 | mSelectedImages = imagePicker.getSelectedImages();
79 | mInflater = LayoutInflater.from(activity);
80 | }
81 |
82 | @Override
83 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
84 | if (viewType == ITEM_TYPE_CAMERA){
85 | return new CameraViewHolder(mInflater.inflate(R.layout.adapter_camera_item,parent,false));
86 | }
87 | return new ImageViewHolder(mInflater.inflate(R.layout.adapter_image_list_item,parent,false));
88 | }
89 |
90 | @Override
91 | public void onBindViewHolder(ViewHolder holder, int position) {
92 | if (holder instanceof CameraViewHolder){
93 | ((CameraViewHolder)holder).bindCamera();
94 | }else if (holder instanceof ImageViewHolder){
95 | ((ImageViewHolder)holder).bind(position);
96 | }
97 | }
98 |
99 | @Override
100 | public int getItemViewType(int position) {
101 | if (isShowCamera) return position == 0 ? ITEM_TYPE_CAMERA : ITEM_TYPE_NORMAL;
102 | return ITEM_TYPE_NORMAL;
103 | }
104 |
105 | @Override
106 | public long getItemId(int position) {
107 | return position;
108 | }
109 |
110 | @Override
111 | public int getItemCount() {
112 | return isShowCamera ? images.size() + 1 : images.size();
113 | }
114 |
115 | public ImageItem getItem(int position) {
116 | if (isShowCamera) {
117 | if (position == 0) return null;
118 | return images.get(position - 1);
119 | } else {
120 | return images.get(position);
121 | }
122 | }
123 |
124 | private class ImageViewHolder extends ViewHolder{
125 |
126 | View rootView;
127 | ImageView ivThumb;
128 | View mask;
129 | View checkView;
130 | SuperCheckBox cbCheck;
131 |
132 |
133 | ImageViewHolder(View itemView) {
134 | super(itemView);
135 | rootView = itemView;
136 | ivThumb = (ImageView) itemView.findViewById(R.id.iv_thumb);
137 | mask = itemView.findViewById(R.id.mask);
138 | checkView=itemView.findViewById(R.id.checkView);
139 | cbCheck = (SuperCheckBox) itemView.findViewById(R.id.cb_check);
140 | itemView.setLayoutParams(new AbsListView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, mImageSize)); //让图片是个正方形
141 | }
142 |
143 | void bind(final int position){
144 | final ImageItem imageItem = getItem(position);
145 | ivThumb.setOnClickListener(new View.OnClickListener() {
146 | @Override
147 | public void onClick(View v) {
148 | if (listener != null) listener.onImageItemClick(rootView, imageItem, position);
149 | }
150 | });
151 | checkView.setOnClickListener(new View.OnClickListener() {
152 | @Override
153 | public void onClick(View v) {
154 | cbCheck.setChecked(!cbCheck.isChecked());
155 | int selectLimit = imagePicker.getSelectLimit();
156 | if (cbCheck.isChecked() && mSelectedImages.size() >= selectLimit) {
157 | Toast.makeText(mActivity.getApplicationContext(), mActivity.getString(R.string.ip_select_limit, selectLimit), Toast.LENGTH_SHORT).show();
158 | cbCheck.setChecked(false);
159 | mask.setVisibility(View.GONE);
160 | } else {
161 | imagePicker.addSelectedImageItem(position, imageItem, cbCheck.isChecked());
162 | mask.setVisibility(View.VISIBLE);
163 | }
164 | }
165 | });
166 | //根据是否多选,显示或隐藏checkbox
167 | if (imagePicker.isMultiMode()) {
168 | cbCheck.setVisibility(View.VISIBLE);
169 | boolean checked = mSelectedImages.contains(imageItem);
170 | if (checked) {
171 | mask.setVisibility(View.VISIBLE);
172 | cbCheck.setChecked(true);
173 | } else {
174 | mask.setVisibility(View.GONE);
175 | cbCheck.setChecked(false);
176 | }
177 | } else {
178 | cbCheck.setVisibility(View.GONE);
179 | }
180 | imagePicker.getImageLoader().displayImage(mActivity, imageItem.path, ivThumb, mImageSize, mImageSize); //显示图片
181 | }
182 |
183 | }
184 |
185 | private class CameraViewHolder extends ViewHolder{
186 |
187 | View mItemView;
188 |
189 | CameraViewHolder(View itemView) {
190 | super(itemView);
191 | mItemView = itemView;
192 | }
193 |
194 | void bindCamera(){
195 | mItemView.setLayoutParams(new AbsListView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, mImageSize)); //让图片是个正方形
196 | mItemView.setTag(null);
197 | mItemView.setOnClickListener(new View.OnClickListener() {
198 | @Override
199 | public void onClick(View v) {
200 | if (!((ImageBaseActivity) mActivity).checkPermission(Manifest.permission.CAMERA)) {
201 | ActivityCompat.requestPermissions(mActivity, new String[]{Manifest.permission.CAMERA}, ImageGridActivity.REQUEST_PERMISSION_CAMERA);
202 | } else {
203 | imagePicker.takePicture(mActivity, ImagePicker.REQUEST_CODE_TAKE);
204 | }
205 | }
206 | });
207 | }
208 | }
209 | }
210 |
--------------------------------------------------------------------------------
/imagepicker/src/main/java/com/lzy/imagepicker/bean/ImageFolder.java:
--------------------------------------------------------------------------------
1 | package com.lzy.imagepicker.bean;
2 |
3 | import java.io.Serializable;
4 | import java.util.ArrayList;
5 | import java.util.List;
6 |
7 | /**
8 | * ================================================
9 | * 作 者:jeasonlzy(廖子尧 Github地址:https://github.com/jeasonlzy0216
10 | * 版 本:1.0
11 | * 创建日期:2016/5/19
12 | * 描 述:图片文件夹
13 | * 修订历史:
14 | * ================================================
15 | */
16 | public class ImageFolder implements Serializable {
17 |
18 | public String name; //当前文件夹的名字
19 | public String path; //当前文件夹的路径
20 | public ImageItem cover; //当前文件夹需要要显示的缩略图,默认为最近的一次图片
21 | public ArrayList images; //当前文件夹下所有图片的集合
22 |
23 | /** 只要文件夹的路径和名字相同,就认为是相同的文件夹 */
24 | @Override
25 | public boolean equals(Object o) {
26 | try {
27 | ImageFolder other = (ImageFolder) o;
28 | return this.path.equalsIgnoreCase(other.path) && this.name.equalsIgnoreCase(other.name);
29 | } catch (ClassCastException e) {
30 | e.printStackTrace();
31 | }
32 | return super.equals(o);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/imagepicker/src/main/java/com/lzy/imagepicker/bean/ImageItem.java:
--------------------------------------------------------------------------------
1 | package com.lzy.imagepicker.bean;
2 |
3 | import android.os.Parcel;
4 | import android.os.Parcelable;
5 |
6 | import java.io.Serializable;
7 |
8 | /**
9 | * ================================================
10 | * 作 者:jeasonlzy(廖子尧 Github地址:https://github.com/jeasonlzy0216
11 | * 版 本:1.0
12 | * 创建日期:2016/5/19
13 | * 描 述:图片信息
14 | * 修订历史:
15 | * ================================================
16 | */
17 | public class ImageItem implements Serializable, Parcelable {
18 |
19 | public String name; //图片的名字
20 | public String path; //图片的路径
21 | public long size; //图片的大小
22 | public int width; //图片的宽度
23 | public int height; //图片的高度
24 | public String mimeType; //图片的类型
25 | public long addTime; //图片的创建时间
26 |
27 | /** 图片的路径和创建时间相同就认为是同一张图片 */
28 | @Override
29 | public boolean equals(Object o) {
30 | if (o instanceof ImageItem) {
31 | ImageItem item = (ImageItem) o;
32 | return this.path.equalsIgnoreCase(item.path) && this.addTime == item.addTime;
33 | }
34 |
35 | return super.equals(o);
36 | }
37 |
38 |
39 | @Override
40 | public int describeContents() {
41 | return 0;
42 | }
43 |
44 | @Override
45 | public void writeToParcel(Parcel dest, int flags) {
46 | dest.writeString(this.name);
47 | dest.writeString(this.path);
48 | dest.writeLong(this.size);
49 | dest.writeInt(this.width);
50 | dest.writeInt(this.height);
51 | dest.writeString(this.mimeType);
52 | dest.writeLong(this.addTime);
53 | }
54 |
55 | public ImageItem() {
56 | }
57 |
58 | protected ImageItem(Parcel in) {
59 | this.name = in.readString();
60 | this.path = in.readString();
61 | this.size = in.readLong();
62 | this.width = in.readInt();
63 | this.height = in.readInt();
64 | this.mimeType = in.readString();
65 | this.addTime = in.readLong();
66 | }
67 |
68 | public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
69 | @Override
70 | public ImageItem createFromParcel(Parcel source) {
71 | return new ImageItem(source);
72 | }
73 |
74 | @Override
75 | public ImageItem[] newArray(int size) {
76 | return new ImageItem[size];
77 | }
78 | };
79 | }
80 |
--------------------------------------------------------------------------------
/imagepicker/src/main/java/com/lzy/imagepicker/loader/ImageLoader.java:
--------------------------------------------------------------------------------
1 | package com.lzy.imagepicker.loader;
2 |
3 | import android.app.Activity;
4 | import android.widget.ImageView;
5 |
6 | import java.io.Serializable;
7 |
8 | /**
9 | * ================================================
10 | * 作 者:jeasonlzy(廖子尧 Github地址:https://github.com/jeasonlzy0216
11 | * 版 本:1.0
12 | * 创建日期:2016/5/19
13 | * 描 述:ImageLoader抽象类,外部需要实现这个类去加载图片, 尽力减少对第三方库的依赖,所以这么干了
14 | * 修订历史:
15 | * ================================================
16 | */
17 | public interface ImageLoader extends Serializable {
18 |
19 | void displayImage(Activity activity, String path, ImageView imageView, int width, int height);
20 |
21 | void displayImagePreview(Activity activity, String path, ImageView imageView, int width, int height);
22 |
23 | void clearMemoryCache();
24 | }
25 |
--------------------------------------------------------------------------------
/imagepicker/src/main/java/com/lzy/imagepicker/ui/ImageBaseActivity.java:
--------------------------------------------------------------------------------
1 | package com.lzy.imagepicker.ui;
2 |
3 | import android.annotation.TargetApi;
4 | import android.content.pm.PackageManager;
5 | import android.os.Build;
6 | import android.os.Bundle;
7 | import android.support.annotation.NonNull;
8 | import android.support.v4.app.ActivityCompat;
9 | import android.support.v7.app.AppCompatActivity;
10 | import android.view.Window;
11 | import android.view.WindowManager;
12 | import android.widget.Toast;
13 |
14 | import com.lzy.imagepicker.ImagePicker;
15 | import com.lzy.imagepicker.R;
16 | import com.lzy.imagepicker.view.SystemBarTintManager;
17 |
18 | /**
19 | * ================================================
20 | * 作 者:jeasonlzy(廖子尧 Github地址:https://github.com/jeasonlzy0216
21 | * 版 本:1.0
22 | * 创建日期:2016/5/19
23 | * 描 述:
24 | * 修订历史:
25 | * ================================================
26 | */
27 | public class ImageBaseActivity extends AppCompatActivity {
28 |
29 | protected SystemBarTintManager tintManager;
30 |
31 | @Override
32 | protected void onCreate(Bundle savedInstanceState) {
33 | super.onCreate(savedInstanceState);
34 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
35 | setTranslucentStatus(true);
36 | }
37 | tintManager = new SystemBarTintManager(this);
38 | tintManager.setStatusBarTintEnabled(true);
39 | tintManager.setStatusBarTintResource(R.color.ip_color_primary_dark); //设置上方状态栏的颜色
40 | }
41 |
42 | @TargetApi(19)
43 | private void setTranslucentStatus(boolean on) {
44 | Window win = getWindow();
45 | WindowManager.LayoutParams winParams = win.getAttributes();
46 | final int bits = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
47 | if (on) {
48 | winParams.flags |= bits;
49 | } else {
50 | winParams.flags &= ~bits;
51 | }
52 | win.setAttributes(winParams);
53 | }
54 |
55 | public boolean checkPermission(@NonNull String permission) {
56 | return ActivityCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED;
57 | }
58 |
59 | public void showToast(String toastText) {
60 | Toast.makeText(getApplicationContext(), toastText, Toast.LENGTH_SHORT).show();
61 | }
62 |
63 | @Override
64 | protected void onRestoreInstanceState(Bundle savedInstanceState) {
65 | super.onRestoreInstanceState(savedInstanceState);
66 | ImagePicker.getInstance().restoreInstanceState(savedInstanceState);
67 | }
68 |
69 | @Override
70 | protected void onSaveInstanceState(Bundle outState) {
71 | super.onSaveInstanceState(outState);
72 | ImagePicker.getInstance().saveInstanceState(outState);
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/imagepicker/src/main/java/com/lzy/imagepicker/ui/ImageCropActivity.java:
--------------------------------------------------------------------------------
1 | package com.lzy.imagepicker.ui;
2 |
3 | import android.content.Intent;
4 | import android.graphics.Bitmap;
5 | import android.graphics.BitmapFactory;
6 | import android.os.Bundle;
7 | import android.util.DisplayMetrics;
8 | import android.view.View;
9 | import android.widget.Button;
10 | import android.widget.TextView;
11 |
12 | import com.lzy.imagepicker.util.BitmapUtil;
13 | import com.lzy.imagepicker.ImagePicker;
14 | import com.lzy.imagepicker.R;
15 | import com.lzy.imagepicker.bean.ImageItem;
16 | import com.lzy.imagepicker.view.CropImageView;
17 |
18 | import java.io.File;
19 | import java.util.ArrayList;
20 |
21 | /**
22 | * ================================================
23 | * 作 者:jeasonlzy(廖子尧 Github地址:https://github.com/jeasonlzy0216
24 | * 版 本:1.0
25 | * 创建日期:2016/5/19
26 | * 描 述:
27 | * 修订历史:
28 | * ================================================
29 | */
30 | public class ImageCropActivity extends ImageBaseActivity implements View.OnClickListener, CropImageView.OnBitmapSaveCompleteListener {
31 |
32 | private CropImageView mCropImageView;
33 | private Bitmap mBitmap;
34 | private boolean mIsSaveRectangle;
35 | private int mOutputX;
36 | private int mOutputY;
37 | private ArrayList mImageItems;
38 | private ImagePicker imagePicker;
39 |
40 | @Override
41 | protected void onCreate(Bundle savedInstanceState) {
42 | super.onCreate(savedInstanceState);
43 | setContentView(R.layout.activity_image_crop);
44 |
45 | imagePicker = ImagePicker.getInstance();
46 |
47 | //初始化View
48 | findViewById(R.id.btn_back).setOnClickListener(this);
49 | Button btn_ok = (Button) findViewById(R.id.btn_ok);
50 | btn_ok.setText(getString(R.string.ip_complete));
51 | btn_ok.setOnClickListener(this);
52 | TextView tv_des = (TextView) findViewById(R.id.tv_des);
53 | tv_des.setText(getString(R.string.ip_photo_crop));
54 | mCropImageView = (CropImageView) findViewById(R.id.cv_crop_image);
55 | mCropImageView.setOnBitmapSaveCompleteListener(this);
56 |
57 | //获取需要的参数
58 | mOutputX = imagePicker.getOutPutX();
59 | mOutputY = imagePicker.getOutPutY();
60 | mIsSaveRectangle = imagePicker.isSaveRectangle();
61 | mImageItems = imagePicker.getSelectedImages();
62 | String imagePath = mImageItems.get(0).path;
63 |
64 | mCropImageView.setFocusStyle(imagePicker.getStyle());
65 | mCropImageView.setFocusWidth(imagePicker.getFocusWidth());
66 | mCropImageView.setFocusHeight(imagePicker.getFocusHeight());
67 |
68 | //缩放图片
69 | BitmapFactory.Options options = new BitmapFactory.Options();
70 | options.inJustDecodeBounds = true;
71 | BitmapFactory.decodeFile(imagePath, options);
72 | DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
73 | options.inSampleSize = calculateInSampleSize(options, displayMetrics.widthPixels, displayMetrics.heightPixels);
74 | options.inJustDecodeBounds = false;
75 | mBitmap = BitmapFactory.decodeFile(imagePath, options);
76 | // mCropImageView.setImageBitmap(mBitmap);
77 | //设置默认旋转角度
78 | mCropImageView.setImageBitmap(mCropImageView.rotate(mBitmap, BitmapUtil.getBitmapDegree(imagePath)));
79 |
80 | // mCropImageView.setImageURI(Uri.fromFile(new File(imagePath)));
81 | }
82 |
83 | public int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
84 | int width = options.outWidth;
85 | int height = options.outHeight;
86 | int inSampleSize = 1;
87 | if (height > reqHeight || width > reqWidth) {
88 | if (width > height) {
89 | inSampleSize = width / reqWidth;
90 | } else {
91 | inSampleSize = height / reqHeight;
92 | }
93 | }
94 | return inSampleSize;
95 | }
96 |
97 | @Override
98 | public void onClick(View v) {
99 | int id = v.getId();
100 | if (id == R.id.btn_back) {
101 | setResult(RESULT_CANCELED);
102 | finish();
103 | } else if (id == R.id.btn_ok) {
104 | mCropImageView.saveBitmapToFile(imagePicker.getCropCacheFolder(this), mOutputX, mOutputY, mIsSaveRectangle);
105 | }
106 | }
107 |
108 | @Override
109 | public void onBitmapSaveSuccess(File file) {
110 | // Toast.makeText(ImageCropActivity.this, "裁剪成功:" + file.getAbsolutePath(), Toast.LENGTH_SHORT).show();
111 |
112 | //裁剪后替换掉返回数据的内容,但是不要改变全局中的选中数据
113 | mImageItems.remove(0);
114 | ImageItem imageItem = new ImageItem();
115 | imageItem.path = file.getAbsolutePath();
116 | mImageItems.add(imageItem);
117 |
118 | Intent intent = new Intent();
119 | intent.putExtra(ImagePicker.EXTRA_RESULT_ITEMS, mImageItems);
120 | setResult(ImagePicker.RESULT_CODE_ITEMS, intent); //单选不需要裁剪,返回数据
121 | finish();
122 | }
123 |
124 | @Override
125 | public void onBitmapSaveError(File file) {
126 |
127 | }
128 |
129 | @Override
130 | protected void onDestroy() {
131 | super.onDestroy();
132 | mCropImageView.setOnBitmapSaveCompleteListener(null);
133 | if (null != mBitmap && !mBitmap.isRecycled()) {
134 | mBitmap.recycle();
135 | mBitmap = null;
136 | }
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/imagepicker/src/main/java/com/lzy/imagepicker/ui/ImagePreviewActivity.java:
--------------------------------------------------------------------------------
1 | package com.lzy.imagepicker.ui;
2 |
3 | import android.content.Intent;
4 | import android.graphics.Color;
5 | import android.os.Bundle;
6 | import android.support.v4.view.ViewPager;
7 | import android.text.format.Formatter;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 | import android.view.animation.AnimationUtils;
11 | import android.widget.Button;
12 | import android.widget.CompoundButton;
13 | import android.widget.Toast;
14 |
15 | import com.lzy.imagepicker.ImagePicker;
16 | import com.lzy.imagepicker.R;
17 | import com.lzy.imagepicker.bean.ImageItem;
18 | import com.lzy.imagepicker.util.NavigationBarChangeListener;
19 | import com.lzy.imagepicker.util.Utils;
20 | import com.lzy.imagepicker.view.SuperCheckBox;
21 |
22 | /**
23 | * ================================================
24 | * 作 者:jeasonlzy(廖子尧 Github地址:https://github.com/jeasonlzy0216
25 | * 版 本:1.0
26 | * 创建日期:2016/5/19
27 | * 描 述:
28 | * 修订历史:
29 | * ================================================
30 | */
31 | public class ImagePreviewActivity extends ImagePreviewBaseActivity implements ImagePicker.OnImageSelectedListener, View.OnClickListener, CompoundButton.OnCheckedChangeListener {
32 |
33 | public static final String ISORIGIN = "isOrigin";
34 |
35 | private boolean isOrigin; //是否选中原图
36 | private SuperCheckBox mCbCheck; //是否选中当前图片的CheckBox
37 | private SuperCheckBox mCbOrigin; //原图
38 | private Button mBtnOk; //确认图片的选择
39 | private View bottomBar;
40 | private View marginView;
41 |
42 | @Override
43 | protected void onCreate(Bundle savedInstanceState) {
44 | super.onCreate(savedInstanceState);
45 |
46 | isOrigin = getIntent().getBooleanExtra(ImagePreviewActivity.ISORIGIN, false);
47 | imagePicker.addOnImageSelectedListener(this);
48 | mBtnOk = (Button) findViewById(R.id.btn_ok);
49 | mBtnOk.setVisibility(View.VISIBLE);
50 | mBtnOk.setOnClickListener(this);
51 |
52 | bottomBar = findViewById(R.id.bottom_bar);
53 | bottomBar.setVisibility(View.VISIBLE);
54 |
55 | mCbCheck = (SuperCheckBox) findViewById(R.id.cb_check);
56 | mCbOrigin = (SuperCheckBox) findViewById(R.id.cb_origin);
57 | marginView = findViewById(R.id.margin_bottom);
58 | mCbOrigin.setText(getString(R.string.ip_origin));
59 | mCbOrigin.setOnCheckedChangeListener(this);
60 | mCbOrigin.setChecked(isOrigin);
61 |
62 | //初始化当前页面的状态
63 | onImageSelected(0, null, false);
64 | ImageItem item = mImageItems.get(mCurrentPosition);
65 | boolean isSelected = imagePicker.isSelect(item);
66 | mTitleCount.setText(getString(R.string.ip_preview_image_count, mCurrentPosition + 1, mImageItems.size()));
67 | mCbCheck.setChecked(isSelected);
68 | //滑动ViewPager的时候,根据外界的数据改变当前的选中状态和当前的图片的位置描述文本
69 | mViewPager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
70 | @Override
71 | public void onPageSelected(int position) {
72 | mCurrentPosition = position;
73 | ImageItem item = mImageItems.get(mCurrentPosition);
74 | boolean isSelected = imagePicker.isSelect(item);
75 | mCbCheck.setChecked(isSelected);
76 | mTitleCount.setText(getString(R.string.ip_preview_image_count, mCurrentPosition + 1, mImageItems.size()));
77 | }
78 | });
79 | //当点击当前选中按钮的时候,需要根据当前的选中状态添加和移除图片
80 | mCbCheck.setOnClickListener(new View.OnClickListener() {
81 | @Override
82 | public void onClick(View v) {
83 | ImageItem imageItem = mImageItems.get(mCurrentPosition);
84 | int selectLimit = imagePicker.getSelectLimit();
85 | if (mCbCheck.isChecked() && selectedImages.size() >= selectLimit) {
86 | Toast.makeText(ImagePreviewActivity.this, getString(R.string.ip_select_limit, selectLimit), Toast.LENGTH_SHORT).show();
87 | mCbCheck.setChecked(false);
88 | } else {
89 | imagePicker.addSelectedImageItem(mCurrentPosition, imageItem, mCbCheck.isChecked());
90 | }
91 | }
92 | });
93 | NavigationBarChangeListener.with(this).setListener(new NavigationBarChangeListener.OnSoftInputStateChangeListener() {
94 | @Override
95 | public void onNavigationBarShow(int orientation, int height) {
96 | marginView.setVisibility(View.VISIBLE);
97 | ViewGroup.LayoutParams layoutParams = marginView.getLayoutParams();
98 | if (layoutParams.height == 0) {
99 | layoutParams.height = Utils.getNavigationBarHeight(ImagePreviewActivity.this);
100 | marginView.requestLayout();
101 | }
102 | }
103 |
104 | @Override
105 | public void onNavigationBarHide(int orientation) {
106 | marginView.setVisibility(View.GONE);
107 | }
108 | });
109 | NavigationBarChangeListener.with(this, NavigationBarChangeListener.ORIENTATION_HORIZONTAL)
110 | .setListener(new NavigationBarChangeListener.OnSoftInputStateChangeListener() {
111 | @Override
112 | public void onNavigationBarShow(int orientation, int height) {
113 | topBar.setPadding(0, 0, height, 0);
114 | bottomBar.setPadding(0, 0, height, 0);
115 | }
116 |
117 | @Override
118 | public void onNavigationBarHide(int orientation) {
119 | topBar.setPadding(0, 0, 0, 0);
120 | bottomBar.setPadding(0, 0, 0, 0);
121 | }
122 | });
123 | }
124 |
125 |
126 |
127 | /**
128 | * 图片添加成功后,修改当前图片的选中数量
129 | * 当调用 addSelectedImageItem 或 deleteSelectedImageItem 都会触发当前回调
130 | */
131 | @Override
132 | public void onImageSelected(int position, ImageItem item, boolean isAdd) {
133 | if (imagePicker.getSelectImageCount() > 0) {
134 | mBtnOk.setText(getString(R.string.ip_select_complete, imagePicker.getSelectImageCount(), imagePicker.getSelectLimit()));
135 | } else {
136 | mBtnOk.setText(getString(R.string.ip_complete));
137 | }
138 |
139 | if (mCbOrigin.isChecked()) {
140 | long size = 0;
141 | for (ImageItem imageItem : selectedImages)
142 | size += imageItem.size;
143 | String fileSize = Formatter.formatFileSize(this, size);
144 | mCbOrigin.setText(getString(R.string.ip_origin_size, fileSize));
145 | }
146 | }
147 |
148 | @Override
149 | public void onClick(View v) {
150 | int id = v.getId();
151 | if (id == R.id.btn_ok) {
152 | if (imagePicker.getSelectedImages().size() == 0) {
153 | mCbCheck.setChecked(true);
154 | ImageItem imageItem = mImageItems.get(mCurrentPosition);
155 | imagePicker.addSelectedImageItem(mCurrentPosition, imageItem, mCbCheck.isChecked());
156 | }
157 | Intent intent = new Intent();
158 | intent.putExtra(ImagePicker.EXTRA_RESULT_ITEMS, imagePicker.getSelectedImages());
159 | setResult(ImagePicker.RESULT_CODE_ITEMS, intent);
160 | finish();
161 |
162 | } else if (id == R.id.btn_back) {
163 | Intent intent = new Intent();
164 | intent.putExtra(ImagePreviewActivity.ISORIGIN, isOrigin);
165 | setResult(ImagePicker.RESULT_CODE_BACK, intent);
166 | finish();
167 | }
168 | }
169 |
170 | @Override
171 | public void onBackPressed() {
172 | Intent intent = new Intent();
173 | intent.putExtra(ImagePreviewActivity.ISORIGIN, isOrigin);
174 | setResult(ImagePicker.RESULT_CODE_BACK, intent);
175 | finish();
176 | super.onBackPressed();
177 | }
178 |
179 | @Override
180 | public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
181 | int id = buttonView.getId();
182 | if (id == R.id.cb_origin) {
183 | if (isChecked) {
184 | long size = 0;
185 | for (ImageItem item : selectedImages)
186 | size += item.size;
187 | String fileSize = Formatter.formatFileSize(this, size);
188 | isOrigin = true;
189 | mCbOrigin.setText(getString(R.string.ip_origin_size, fileSize));
190 | } else {
191 | isOrigin = false;
192 | mCbOrigin.setText(getString(R.string.ip_origin));
193 | }
194 | }
195 | }
196 |
197 | @Override
198 | protected void onDestroy() {
199 | imagePicker.removeOnImageSelectedListener(this);
200 | super.onDestroy();
201 | }
202 |
203 | /**
204 | * 单击时,隐藏头和尾
205 | */
206 | @Override
207 | public void onImageSingleTap() {
208 | if (topBar.getVisibility() == View.VISIBLE) {
209 | topBar.setAnimation(AnimationUtils.loadAnimation(this, R.anim.top_out));
210 | bottomBar.setAnimation(AnimationUtils.loadAnimation(this, R.anim.fade_out));
211 | topBar.setVisibility(View.GONE);
212 | bottomBar.setVisibility(View.GONE);
213 | tintManager.setStatusBarTintResource(Color.TRANSPARENT);//通知栏所需颜色
214 | //给最外层布局加上这个属性表示,Activity全屏显示,且状态栏被隐藏覆盖掉。
215 | // if (Build.VERSION.SDK_INT >= 16) content.setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN);
216 | } else {
217 | topBar.setAnimation(AnimationUtils.loadAnimation(this, R.anim.top_in));
218 | bottomBar.setAnimation(AnimationUtils.loadAnimation(this, R.anim.fade_in));
219 | topBar.setVisibility(View.VISIBLE);
220 | bottomBar.setVisibility(View.VISIBLE);
221 | tintManager.setStatusBarTintResource(R.color.ip_color_primary_dark);//通知栏所需颜色
222 | //Activity全屏显示,但状态栏不会被隐藏覆盖,状态栏依然可见,Activity顶端布局部分会被状态遮住
223 | // if (Build.VERSION.SDK_INT >= 16) content.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
224 | }
225 | }
226 | }
227 |
--------------------------------------------------------------------------------
/imagepicker/src/main/java/com/lzy/imagepicker/ui/ImagePreviewBaseActivity.java:
--------------------------------------------------------------------------------
1 | package com.lzy.imagepicker.ui;
2 |
3 | import android.os.Build;
4 | import android.os.Bundle;
5 | import android.view.View;
6 | import android.widget.RelativeLayout;
7 | import android.widget.TextView;
8 |
9 | import com.lzy.imagepicker.DataHolder;
10 | import com.lzy.imagepicker.ImagePicker;
11 | import com.lzy.imagepicker.R;
12 | import com.lzy.imagepicker.adapter.ImagePageAdapter;
13 | import com.lzy.imagepicker.bean.ImageItem;
14 | import com.lzy.imagepicker.util.Utils;
15 | import com.lzy.imagepicker.view.ViewPagerFixed;
16 |
17 | import java.util.ArrayList;
18 |
19 | /**
20 | * ================================================
21 | * 作 者:jeasonlzy(廖子尧 Github地址:https://github.com/jeasonlzy0216
22 | * 版 本:1.0
23 | * 创建日期:2016/5/19
24 | * 描 述:
25 | * 修订历史:图片预览的基类
26 | * ================================================
27 | */
28 | public abstract class ImagePreviewBaseActivity extends ImageBaseActivity {
29 |
30 | protected ImagePicker imagePicker;
31 | protected ArrayList mImageItems; //跳转进ImagePreviewFragment的图片文件夹
32 | protected int mCurrentPosition = 0; //跳转进ImagePreviewFragment时的序号,第几个图片
33 | protected TextView mTitleCount; //显示当前图片的位置 例如 5/31
34 | protected ArrayList selectedImages; //所有已经选中的图片
35 | protected View content;
36 | protected View topBar;
37 | protected ViewPagerFixed mViewPager;
38 | protected ImagePageAdapter mAdapter;
39 | protected boolean isFromItems = false;
40 |
41 | @Override
42 | protected void onCreate(Bundle savedInstanceState) {
43 | super.onCreate(savedInstanceState);
44 | setContentView(R.layout.activity_image_preview);
45 |
46 | mCurrentPosition = getIntent().getIntExtra(ImagePicker.EXTRA_SELECTED_IMAGE_POSITION, 0);
47 | isFromItems = getIntent().getBooleanExtra(ImagePicker.EXTRA_FROM_ITEMS, false);
48 |
49 | if (isFromItems) {
50 | // 据说这样会导致大量图片崩溃
51 | mImageItems = (ArrayList) getIntent().getSerializableExtra(ImagePicker.EXTRA_IMAGE_ITEMS);
52 | } else {
53 | // 下面采用弱引用会导致预览崩溃
54 | mImageItems = (ArrayList) DataHolder.getInstance().retrieve(DataHolder.DH_CURRENT_IMAGE_FOLDER_ITEMS);
55 | }
56 |
57 | imagePicker = ImagePicker.getInstance();
58 | selectedImages = imagePicker.getSelectedImages();
59 |
60 | //初始化控件
61 | content = findViewById(R.id.content);
62 |
63 | //因为状态栏透明后,布局整体会上移,所以给头部加上状态栏的margin值,保证头部不会被覆盖
64 | topBar = findViewById(R.id.top_bar);
65 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
66 | RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) topBar.getLayoutParams();
67 | params.topMargin = Utils.getStatusHeight(this);
68 | topBar.setLayoutParams(params);
69 | }
70 | topBar.findViewById(R.id.btn_ok).setVisibility(View.GONE);
71 | topBar.findViewById(R.id.btn_back).setOnClickListener(new View.OnClickListener() {
72 | @Override
73 | public void onClick(View v) {
74 | finish();
75 | }
76 | });
77 |
78 | mTitleCount = (TextView) findViewById(R.id.tv_des);
79 |
80 | mViewPager = (ViewPagerFixed) findViewById(R.id.viewpager);
81 | mAdapter = new ImagePageAdapter(this, mImageItems);
82 | mAdapter.setPhotoViewClickListener(new ImagePageAdapter.PhotoViewClickListener() {
83 | @Override
84 | public void OnPhotoTapListener(View view, float v, float v1) {
85 | onImageSingleTap();
86 | }
87 | });
88 | mViewPager.setAdapter(mAdapter);
89 | mViewPager.setCurrentItem(mCurrentPosition, false);
90 |
91 | //初始化当前页面的状态
92 | mTitleCount.setText(getString(R.string.ip_preview_image_count, mCurrentPosition + 1, mImageItems.size()));
93 | }
94 |
95 | /** 单击时,隐藏头和尾 */
96 | public abstract void onImageSingleTap();
97 |
98 | @Override
99 | protected void onRestoreInstanceState(Bundle savedInstanceState) {
100 | super.onRestoreInstanceState(savedInstanceState);
101 | ImagePicker.getInstance().restoreInstanceState(savedInstanceState);
102 | }
103 |
104 | @Override
105 | protected void onSaveInstanceState(Bundle outState) {
106 | super.onSaveInstanceState(outState);
107 | ImagePicker.getInstance().saveInstanceState(outState);
108 | }
109 | }
--------------------------------------------------------------------------------
/imagepicker/src/main/java/com/lzy/imagepicker/ui/ImagePreviewDelActivity.java:
--------------------------------------------------------------------------------
1 | package com.lzy.imagepicker.ui;
2 |
3 | import android.content.DialogInterface;
4 | import android.content.Intent;
5 | import android.graphics.Color;
6 | import android.os.Bundle;
7 | import android.support.v4.view.ViewPager;
8 | import android.support.v7.app.AlertDialog;
9 | import android.view.View;
10 | import android.view.animation.AnimationUtils;
11 | import android.widget.ImageView;
12 |
13 | import com.lzy.imagepicker.ImagePicker;
14 | import com.lzy.imagepicker.R;
15 | import com.lzy.imagepicker.util.NavigationBarChangeListener;
16 |
17 | /**
18 | * ================================================
19 | * 作 者:jeasonlzy(廖子尧),ikkong (ikkong@163.com)
20 | * 版 本:1.0
21 | * 创建日期:2016/5/19
22 | * 描 述:
23 | * 修订历史:预览已经选择的图片,并可以删除, 感谢 ikkong 的提交
24 | * ================================================
25 | */
26 | public class ImagePreviewDelActivity extends ImagePreviewBaseActivity implements View.OnClickListener {
27 |
28 | @Override
29 | protected void onCreate(Bundle savedInstanceState) {
30 | super.onCreate(savedInstanceState);
31 |
32 | ImageView mBtnDel = (ImageView) findViewById(R.id.btn_del);
33 | mBtnDel.setOnClickListener(this);
34 | mBtnDel.setVisibility(View.VISIBLE);
35 | topBar.findViewById(R.id.btn_back).setOnClickListener(this);
36 |
37 | mTitleCount.setText(getString(R.string.ip_preview_image_count, mCurrentPosition + 1, mImageItems.size()));
38 | //滑动ViewPager的时候,根据外界的数据改变当前的选中状态和当前的图片的位置描述文本
39 | mViewPager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
40 | @Override
41 | public void onPageSelected(int position) {
42 | mCurrentPosition = position;
43 | mTitleCount.setText(getString(R.string.ip_preview_image_count, mCurrentPosition + 1, mImageItems.size()));
44 | }
45 | });
46 | NavigationBarChangeListener.with(this, NavigationBarChangeListener.ORIENTATION_HORIZONTAL)
47 | .setListener(new NavigationBarChangeListener.OnSoftInputStateChangeListener() {
48 | @Override
49 | public void onNavigationBarShow(int orientation, int height) {
50 | topBar.setPadding(0, 0, height, 0);
51 | }
52 |
53 | @Override
54 | public void onNavigationBarHide(int orientation) {
55 | topBar.setPadding(0, 0, 0, 0);
56 | }
57 | });
58 | }
59 |
60 | @Override
61 | public void onClick(View v) {
62 | int id = v.getId();
63 | if (id == R.id.btn_del) {
64 | showDeleteDialog();
65 | } else if (id == R.id.btn_back) {
66 | onBackPressed();
67 | }
68 | }
69 |
70 | /** 是否删除此张图片 */
71 | private void showDeleteDialog() {
72 | AlertDialog.Builder builder = new AlertDialog.Builder(this);
73 | builder.setTitle("提示");
74 | builder.setMessage("要删除这张照片吗?");
75 | builder.setNegativeButton("取消", null);
76 | builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
77 | @Override
78 | public void onClick(DialogInterface dialog, int which) {
79 | //移除当前图片刷新界面
80 | mImageItems.remove(mCurrentPosition);
81 | if (mImageItems.size() > 0) {
82 | mAdapter.setData(mImageItems);
83 | mAdapter.notifyDataSetChanged();
84 | mTitleCount.setText(getString(R.string.ip_preview_image_count, mCurrentPosition + 1, mImageItems.size()));
85 | } else {
86 | onBackPressed();
87 | }
88 | }
89 | });
90 | builder.show();
91 | }
92 |
93 | @Override
94 | public void onBackPressed() {
95 | Intent intent = new Intent();
96 | //带回最新数据
97 | intent.putExtra(ImagePicker.EXTRA_IMAGE_ITEMS, mImageItems);
98 | setResult(ImagePicker.RESULT_CODE_BACK, intent);
99 | finish();
100 | super.onBackPressed();
101 | }
102 |
103 | /** 单击时,隐藏头和尾 */
104 | @Override
105 | public void onImageSingleTap() {
106 | if (topBar.getVisibility() == View.VISIBLE) {
107 | topBar.setAnimation(AnimationUtils.loadAnimation(this, com.lzy.imagepicker.R.anim.top_out));
108 | topBar.setVisibility(View.GONE);
109 | tintManager.setStatusBarTintResource(Color.TRANSPARENT);//通知栏所需颜色
110 | //给最外层布局加上这个属性表示,Activity全屏显示,且状态栏被隐藏覆盖掉。
111 | // if (Build.VERSION.SDK_INT >= 16) content.setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN);
112 | } else {
113 | topBar.setAnimation(AnimationUtils.loadAnimation(this, com.lzy.imagepicker.R.anim.top_in));
114 | topBar.setVisibility(View.VISIBLE);
115 | tintManager.setStatusBarTintResource(R.color.ip_color_primary_dark);//通知栏所需颜色
116 | //Activity全屏显示,但状态栏不会被隐藏覆盖,状态栏依然可见,Activity顶端布局部分会被状态遮住
117 | // if (Build.VERSION.SDK_INT >= 16) content.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
118 | }
119 | }
120 | }
--------------------------------------------------------------------------------
/imagepicker/src/main/java/com/lzy/imagepicker/util/BitmapUtil.java:
--------------------------------------------------------------------------------
1 | package com.lzy.imagepicker.util;
2 |
3 | import android.app.Activity;
4 | import android.graphics.Bitmap;
5 | import android.graphics.BitmapFactory;
6 | import android.graphics.Matrix;
7 | import android.media.ExifInterface;
8 | import android.net.Uri;
9 | import android.provider.MediaStore;
10 |
11 | import java.io.File;
12 | import java.io.IOException;
13 |
14 | /**
15 | *
16 | * Bitmap工具类,主要是解决拍照旋转的适配
17 | *
18 | * Author: nanchen
19 | * Email: liushilin520@foxmail.com
20 | * Date: 2017-03-20 13:27
21 | */
22 |
23 | public class BitmapUtil {
24 |
25 | private BitmapUtil() {
26 | throw new UnsupportedOperationException("u can't instantiate me...");
27 | }
28 |
29 | /**
30 | * 获取图片的旋转角度
31 | *
32 | * @param path 图片绝对路径
33 | * @return 图片的旋转角度
34 | */
35 | public static int getBitmapDegree(String path) {
36 | int degree = 0;
37 | try {
38 | // 从指定路径下读取图片,并获取其EXIF信息
39 | ExifInterface exifInterface = new ExifInterface(path);
40 | // 获取图片的旋转信息
41 | int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
42 | switch (orientation) {
43 | case ExifInterface.ORIENTATION_ROTATE_90:
44 | degree = 90;
45 | break;
46 | case ExifInterface.ORIENTATION_ROTATE_180:
47 | degree = 180;
48 | break;
49 | case ExifInterface.ORIENTATION_ROTATE_270:
50 | degree = 270;
51 | break;
52 | }
53 | } catch (IOException e) {
54 | e.printStackTrace();
55 | }
56 | return degree;
57 | }
58 |
59 | /**
60 | * 将图片按照指定的角度进行旋转
61 | *
62 | * @param bitmap 需要旋转的图片
63 | * @param degree 指定的旋转角度
64 | * @return 旋转后的图片
65 | */
66 | public static Bitmap rotateBitmapByDegree(Bitmap bitmap, int degree) {
67 | // 根据旋转角度,生成旋转矩阵
68 | Matrix matrix = new Matrix();
69 | matrix.postRotate(degree);
70 | // 将原始图片按照旋转矩阵进行旋转,并得到新的图片
71 | Bitmap newBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
72 | if (!bitmap.isRecycled()) {
73 | bitmap.recycle();
74 | }
75 | return newBitmap;
76 | }
77 |
78 | /**
79 | * 获取我们需要的整理过旋转角度的Uri
80 | * @param activity 上下文环境
81 | * @param path 路径
82 | * @return 正常的Uri
83 | */
84 | public static Uri getRotatedUri(Activity activity, String path){
85 | int degree = BitmapUtil.getBitmapDegree(path);
86 | if (degree != 0){
87 | Bitmap bitmap = BitmapFactory.decodeFile(path);
88 | Bitmap newBitmap = BitmapUtil.rotateBitmapByDegree(bitmap,degree);
89 | return Uri.parse(MediaStore.Images.Media.insertImage(activity.getContentResolver(),newBitmap,null,null));
90 | }else{
91 | return Uri.fromFile(new File(path));
92 | }
93 | }
94 |
95 | /**
96 | * 将图片按照指定的角度进行旋转
97 | *
98 | * @param path 需要旋转的图片的路径
99 | * @param degree 指定的旋转角度
100 | * @return 旋转后的图片
101 | */
102 | public static Bitmap rotateBitmapByDegree(String path, int degree) {
103 | Bitmap bitmap = BitmapFactory.decodeFile(path);
104 | return rotateBitmapByDegree(bitmap,degree);
105 | }
106 |
107 | }
108 |
--------------------------------------------------------------------------------
/imagepicker/src/main/java/com/lzy/imagepicker/util/NavigationBarChangeListener.java:
--------------------------------------------------------------------------------
1 | package com.lzy.imagepicker.util;
2 |
3 | import android.app.Activity;
4 | import android.graphics.Rect;
5 | import android.view.View;
6 | import android.view.ViewTreeObserver;
7 |
8 | /**
9 | * Created by z-chu on 2017/9/4
10 | * 用于监听导航栏的显示和隐藏,主要用于适配华为EMUI系统上虚拟导航栏可随时收起和展开的情况
11 | */
12 | public class NavigationBarChangeListener implements ViewTreeObserver.OnGlobalLayoutListener {
13 |
14 | public static final int ORIENTATION_VERTICAL = 1; //监听竖屏模式导航栏的显示和隐藏
15 | public static final int ORIENTATION_HORIZONTAL = 2; //监听横屏模式导航栏的显示和隐藏
16 |
17 | private Rect rect;
18 | private View rootView;
19 | private boolean isShowNavigationBar = false;
20 | private int orientation;
21 | private OnSoftInputStateChangeListener listener;
22 |
23 | public NavigationBarChangeListener(View rootView, int orientation) {
24 | this.rootView = rootView;
25 | this.orientation = orientation;
26 | rect = new Rect();
27 | }
28 |
29 | @Override
30 | public void onGlobalLayout() {
31 | rect.setEmpty();
32 | rootView.getWindowVisibleDisplayFrame(rect);
33 | int heightDiff = 0;
34 | if (orientation == ORIENTATION_VERTICAL) {
35 | heightDiff = rootView.getHeight() - (rect.bottom - rect.top);
36 | } else if (orientation == ORIENTATION_HORIZONTAL) {
37 | heightDiff = rootView.getWidth() - (rect.right - rect.left);
38 | }
39 | int navigationBarHeight = Utils.hasVirtualNavigationBar(rootView.getContext()) ? Utils.getNavigationBarHeight(rootView.getContext()) : 0;
40 | if (heightDiff >= navigationBarHeight && heightDiff < navigationBarHeight * 2) {
41 | if (!isShowNavigationBar && listener != null) {
42 | listener.onNavigationBarShow(orientation, heightDiff);
43 | }
44 | isShowNavigationBar = true;
45 | } else {
46 | if (isShowNavigationBar && listener != null) {
47 | listener.onNavigationBarHide(orientation);
48 | }
49 | isShowNavigationBar = false;
50 | }
51 | }
52 |
53 | public void setListener(OnSoftInputStateChangeListener listener) {
54 | this.listener = listener;
55 | }
56 |
57 | public interface OnSoftInputStateChangeListener {
58 | void onNavigationBarShow(int orientation, int height);
59 |
60 | void onNavigationBarHide(int orientation);
61 | }
62 |
63 | public static NavigationBarChangeListener with(View rootView) {
64 | return with(rootView, ORIENTATION_VERTICAL);
65 | }
66 |
67 | public static NavigationBarChangeListener with(Activity activity) {
68 | return with(activity.findViewById(android.R.id.content), ORIENTATION_VERTICAL);
69 | }
70 |
71 | public static NavigationBarChangeListener with(View rootView, int orientation) {
72 | NavigationBarChangeListener changeListener = new NavigationBarChangeListener(rootView, orientation);
73 | rootView.getViewTreeObserver().addOnGlobalLayoutListener(changeListener);
74 | return changeListener;
75 | }
76 |
77 | public static NavigationBarChangeListener with(Activity activity, int orientation) {
78 | return with(activity.findViewById(android.R.id.content), orientation);
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/imagepicker/src/main/java/com/lzy/imagepicker/util/ProviderUtil.java:
--------------------------------------------------------------------------------
1 | package com.lzy.imagepicker.util;
2 |
3 | import android.content.Context;
4 |
5 | /**
6 | * 用于解决provider冲突的util
7 | *
8 | * Author: nanchen
9 | * Email: liushilin520@foxmail.com
10 | * Date: 2017-03-22 18:55
11 | */
12 |
13 | public class ProviderUtil {
14 |
15 | public static String getFileProviderName(Context context){
16 | return context.getPackageName()+".provider";
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/imagepicker/src/main/java/com/lzy/imagepicker/util/Utils.java:
--------------------------------------------------------------------------------
1 | package com.lzy.imagepicker.util;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.os.Build;
6 | import android.os.Environment;
7 | import android.util.DisplayMetrics;
8 | import android.util.TypedValue;
9 | import android.view.Display;
10 | import android.view.KeyCharacterMap;
11 | import android.view.KeyEvent;
12 | import android.view.ViewConfiguration;
13 | import android.view.WindowManager;
14 |
15 | /**
16 | * ================================================
17 | * 作 者:jeasonlzy(廖子尧 Github地址:https://github.com/jeasonlzy0216
18 | * 版 本:1.0
19 | * 创建日期:2016/5/19
20 | * 描 述:
21 | * 修订历史:
22 | * ================================================
23 | */
24 | public class Utils {
25 |
26 | /** 获得状态栏的高度 */
27 | public static int getStatusHeight(Context context) {
28 | int statusHeight = -1;
29 | try {
30 | Class> clazz = Class.forName("com.android.internal.R$dimen");
31 | Object object = clazz.newInstance();
32 | int height = Integer.parseInt(clazz.getField("status_bar_height").get(object).toString());
33 | statusHeight = context.getResources().getDimensionPixelSize(height);
34 | } catch (Exception e) {
35 | e.printStackTrace();
36 | }
37 | return statusHeight;
38 | }
39 |
40 | /** 根据屏幕宽度与密度计算GridView显示的列数, 最少为三列,并获取Item宽度 */
41 | public static int getImageItemWidth(Activity activity) {
42 | int screenWidth = activity.getResources().getDisplayMetrics().widthPixels;
43 | int densityDpi = activity.getResources().getDisplayMetrics().densityDpi;
44 | int cols = screenWidth / densityDpi;
45 | cols = cols < 3 ? 3 : cols;
46 | int columnSpace = (int) (2 * activity.getResources().getDisplayMetrics().density);
47 | return (screenWidth - columnSpace * (cols - 1)) / cols;
48 | }
49 |
50 | /**
51 | * 判断SDCard是否可用
52 | */
53 | public static boolean existSDCard() {
54 | return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
55 | }
56 |
57 | /**
58 | * 获取手机大小(分辨率)
59 | */
60 | public static DisplayMetrics getScreenPix(Activity activity) {
61 | DisplayMetrics displaysMetrics = new DisplayMetrics();
62 | activity.getWindowManager().getDefaultDisplay().getMetrics(displaysMetrics);
63 | return displaysMetrics;
64 | }
65 |
66 | /** dp转px */
67 | public static int dp2px(Context context, float dpVal) {
68 | return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpVal, context.getResources().getDisplayMetrics());
69 | }
70 |
71 | /**
72 | * 判断手机是否含有虚拟按键 99%
73 | */
74 | public static boolean hasVirtualNavigationBar(Context context) {
75 | boolean hasSoftwareKeys = true;
76 |
77 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
78 | Display d = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
79 |
80 | DisplayMetrics realDisplayMetrics = new DisplayMetrics();
81 | d.getRealMetrics(realDisplayMetrics);
82 |
83 | int realHeight = realDisplayMetrics.heightPixels;
84 | int realWidth = realDisplayMetrics.widthPixels;
85 |
86 | DisplayMetrics displayMetrics = new DisplayMetrics();
87 | d.getMetrics(displayMetrics);
88 |
89 | int displayHeight = displayMetrics.heightPixels;
90 | int displayWidth = displayMetrics.widthPixels;
91 |
92 | hasSoftwareKeys = (realWidth - displayWidth) > 0 || (realHeight - displayHeight) > 0;
93 | } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
94 | boolean hasMenuKey = ViewConfiguration.get(context).hasPermanentMenuKey();
95 | boolean hasBackKey = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK);
96 | hasSoftwareKeys = !hasMenuKey && !hasBackKey;
97 | }
98 |
99 | return hasSoftwareKeys;
100 | }
101 |
102 | /**
103 | * 获取导航栏高度,有些没有虚拟导航栏的手机也能获取到,建议先判断是否有虚拟按键
104 | */
105 | public static int getNavigationBarHeight(Context context) {
106 | int resourceId = context.getResources().getIdentifier("navigation_bar_height", "dimen", "android");
107 | return resourceId > 0 ? context.getResources().getDimensionPixelSize(resourceId) : 0;
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/imagepicker/src/main/java/com/lzy/imagepicker/view/FolderPopUpWindow.java:
--------------------------------------------------------------------------------
1 | package com.lzy.imagepicker.view;
2 |
3 | import android.animation.Animator;
4 | import android.animation.AnimatorSet;
5 | import android.animation.ObjectAnimator;
6 | import android.content.Context;
7 | import android.graphics.drawable.ColorDrawable;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 | import android.view.ViewTreeObserver;
11 | import android.view.animation.AccelerateDecelerateInterpolator;
12 | import android.widget.AdapterView;
13 | import android.widget.BaseAdapter;
14 | import android.widget.LinearLayout;
15 | import android.widget.ListView;
16 | import android.widget.PopupWindow;
17 |
18 | import com.lzy.imagepicker.R;
19 |
20 | /**
21 | * ================================================
22 | * 作 者:jeasonlzy(廖子尧)Github地址:https://github.com/jeasonlzy0216
23 | * 版 本:1.0
24 | * 创建日期:16/8/1
25 | * 描 述:
26 | * 修订历史:
27 | * ================================================
28 | */
29 | public class FolderPopUpWindow extends PopupWindow implements View.OnClickListener {
30 |
31 | private ListView listView;
32 | private OnItemClickListener onItemClickListener;
33 | private final View masker;
34 | private final View marginView;
35 | private int marginPx;
36 |
37 | public FolderPopUpWindow(Context context, BaseAdapter adapter) {
38 | super(context);
39 |
40 | final View view = View.inflate(context, R.layout.pop_folder, null);
41 | masker = view.findViewById(R.id.masker);
42 | masker.setOnClickListener(this);
43 | marginView = view.findViewById(R.id.margin);
44 | marginView.setOnClickListener(this);
45 | listView = (ListView) view.findViewById(R.id.listView);
46 | listView.setAdapter(adapter);
47 |
48 | setContentView(view);
49 | setWidth(ViewGroup.LayoutParams.MATCH_PARENT); //如果不设置,就是 AnchorView 的宽度
50 | setHeight(ViewGroup.LayoutParams.MATCH_PARENT);
51 | setFocusable(true);
52 | setOutsideTouchable(true);
53 | setBackgroundDrawable(new ColorDrawable(0));
54 | setAnimationStyle(0);
55 | view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
56 | @Override
57 | public void onGlobalLayout() {
58 | view.getViewTreeObserver().removeGlobalOnLayoutListener(this);
59 | int maxHeight = view.getHeight() * 5 / 8;
60 | int realHeight = listView.getHeight();
61 | ViewGroup.LayoutParams listParams = listView.getLayoutParams();
62 | listParams.height = realHeight > maxHeight ? maxHeight : realHeight;
63 | listView.setLayoutParams(listParams);
64 | LinearLayout.LayoutParams marginParams = (LinearLayout.LayoutParams) marginView.getLayoutParams();
65 | marginParams.height = marginPx;
66 | marginView.setLayoutParams(marginParams);
67 | enterAnimator();
68 | }
69 | });
70 | listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
71 | @Override
72 | public void onItemClick(AdapterView> adapterView, View view, int position, long l) {
73 | if (onItemClickListener != null) onItemClickListener.onItemClick(adapterView, view, position, l);
74 | }
75 | });
76 | }
77 |
78 | private void enterAnimator() {
79 | ObjectAnimator alpha = ObjectAnimator.ofFloat(masker, "alpha", 0, 1);
80 | ObjectAnimator translationY = ObjectAnimator.ofFloat(listView, "translationY", listView.getHeight(), 0);
81 | AnimatorSet set = new AnimatorSet();
82 | set.setDuration(400);
83 | set.playTogether(alpha, translationY);
84 | set.setInterpolator(new AccelerateDecelerateInterpolator());
85 | set.start();
86 | }
87 |
88 | @Override
89 | public void dismiss() {
90 | exitAnimator();
91 | }
92 |
93 | private void exitAnimator() {
94 | ObjectAnimator alpha = ObjectAnimator.ofFloat(masker, "alpha", 1, 0);
95 | ObjectAnimator translationY = ObjectAnimator.ofFloat(listView, "translationY", 0, listView.getHeight());
96 | AnimatorSet set = new AnimatorSet();
97 | set.setDuration(300);
98 | set.playTogether(alpha, translationY);
99 | set.setInterpolator(new AccelerateDecelerateInterpolator());
100 | set.addListener(new Animator.AnimatorListener() {
101 | @Override
102 | public void onAnimationStart(Animator animation) {
103 | listView.setVisibility(View.VISIBLE);
104 | }
105 |
106 | @Override
107 | public void onAnimationEnd(Animator animation) {
108 | FolderPopUpWindow.super.dismiss();
109 | }
110 |
111 | @Override
112 | public void onAnimationCancel(Animator animation) {
113 | }
114 |
115 | @Override
116 | public void onAnimationRepeat(Animator animation) {
117 | }
118 | });
119 | set.start();
120 | }
121 |
122 | public void setOnItemClickListener(OnItemClickListener listener) {
123 | this.onItemClickListener = listener;
124 | }
125 |
126 | public void setSelection(int selection) {
127 | listView.setSelection(selection);
128 | }
129 |
130 | public void setMargin(int marginPx) {
131 | this.marginPx = marginPx;
132 | }
133 |
134 | @Override
135 | public void onClick(View v) {
136 | dismiss();
137 | }
138 |
139 | public interface OnItemClickListener {
140 | void onItemClick(AdapterView> adapterView, View view, int position, long l);
141 | }
142 | }
143 |
--------------------------------------------------------------------------------
/imagepicker/src/main/java/com/lzy/imagepicker/view/GridSpacingItemDecoration.java:
--------------------------------------------------------------------------------
1 | package com.lzy.imagepicker.view;
2 |
3 | import android.graphics.Rect;
4 | import android.support.v7.widget.RecyclerView;
5 | import android.view.View;
6 |
7 | /**
8 | * author : zchu
9 | * date : 2017/8/30
10 | * desc : 为Recyclerview 的GridLayoutManager添加列间距
11 | */
12 |
13 | public class GridSpacingItemDecoration extends RecyclerView.ItemDecoration {
14 |
15 | private int spanCount;
16 | private int spacing;
17 | private boolean includeEdge;
18 |
19 | public GridSpacingItemDecoration(int spanCount, int spacing, boolean includeEdge) {
20 | this.spanCount = spanCount;
21 | this.spacing = spacing;
22 | this.includeEdge = includeEdge;
23 | }
24 |
25 | @Override
26 | public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
27 | int position = parent.getChildAdapterPosition(view); // item position
28 | int column = position % spanCount; // item column
29 |
30 | if (includeEdge) {
31 | outRect.left = spacing - column * spacing / spanCount; // spacing - column * ((1f / spanCount) * spacing)
32 | outRect.right = (column + 1) * spacing / spanCount; // (column + 1) * ((1f / spanCount) * spacing)
33 |
34 | if (position < spanCount) { // top edge
35 | outRect.top = spacing;
36 | }
37 | outRect.bottom = spacing; // item bottom
38 | } else {
39 | outRect.left = column * spacing / spanCount; // column * ((1f / spanCount) * spacing)
40 | outRect.right = spacing - (column + 1) * spacing / spanCount; // spacing - (column + 1) * ((1f / spanCount) * spacing)
41 | if (position >= spanCount) {
42 | outRect.top = spacing; // item top
43 | }
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/imagepicker/src/main/java/com/lzy/imagepicker/view/SuperCheckBox.java:
--------------------------------------------------------------------------------
1 | package com.lzy.imagepicker.view;
2 |
3 | import android.content.Context;
4 | import android.support.v7.widget.AppCompatCheckBox;
5 | import android.util.AttributeSet;
6 | import android.view.SoundEffectConstants;
7 |
8 | /**
9 | * ================================================
10 | * 作 者:jeasonlzy(廖子尧 Github地址:https://github.com/jeasonlzy0216
11 | * 版 本:1.0
12 | * 创建日期:2016/5/19
13 | * 描 述:带声音的CheckBox
14 | * 修订历史:
15 | * ================================================
16 | */
17 | public class SuperCheckBox extends AppCompatCheckBox {
18 |
19 | public SuperCheckBox(Context context) {
20 | super(context);
21 | }
22 |
23 | public SuperCheckBox(Context context, AttributeSet attrs) {
24 | super(context, attrs);
25 | }
26 |
27 | public SuperCheckBox(Context context, AttributeSet attrs, int defStyle) {
28 | super(context, attrs, defStyle);
29 | }
30 |
31 | @Override
32 | public boolean performClick() {
33 | final boolean handled = super.performClick();
34 | if (!handled) {
35 | // View only makes a sound effect if the onClickListener was
36 | // called, so we'll need to make one here instead.
37 | playSoundEffect(SoundEffectConstants.CLICK);
38 | }
39 | return handled;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/imagepicker/src/main/java/com/lzy/imagepicker/view/ViewPagerFixed.java:
--------------------------------------------------------------------------------
1 | package com.lzy.imagepicker.view;
2 |
3 | import android.content.Context;
4 | import android.support.v4.view.ViewPager;
5 | import android.util.AttributeSet;
6 | import android.view.MotionEvent;
7 |
8 | /**
9 | * ================================================
10 | * 作 者:jeasonlzy(廖子尧 Github地址:https://github.com/jeasonlzy0216
11 | * 版 本:1.0
12 | * 创建日期:2016/5/19
13 | * 描 述:修复图片在ViewPager控件中缩放报错的BUG
14 | * 修订历史:
15 | * ================================================
16 | */
17 | public class ViewPagerFixed extends ViewPager {
18 |
19 | public ViewPagerFixed(Context context) {
20 | super(context);
21 | }
22 |
23 | public ViewPagerFixed(Context context, AttributeSet attrs) {
24 | super(context, attrs);
25 | }
26 |
27 | @Override
28 | public boolean onTouchEvent(MotionEvent ev) {
29 | try {
30 | return super.onTouchEvent(ev);
31 | } catch (IllegalArgumentException ex) {
32 | ex.printStackTrace();
33 | }
34 | return false;
35 | }
36 |
37 | @Override
38 | public boolean onInterceptTouchEvent(MotionEvent ev) {
39 | try {
40 | return super.onInterceptTouchEvent(ev);
41 | } catch (IllegalArgumentException ex) {
42 | ex.printStackTrace();
43 | }
44 | return false;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/imagepicker/src/main/res/anim/fade_in.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
--------------------------------------------------------------------------------
/imagepicker/src/main/res/anim/fade_out.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
--------------------------------------------------------------------------------
/imagepicker/src/main/res/anim/hide_to_bottom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
9 |
13 |
14 |
--------------------------------------------------------------------------------
/imagepicker/src/main/res/anim/show_from_bottom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
12 |
13 |
--------------------------------------------------------------------------------
/imagepicker/src/main/res/anim/top_in.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/imagepicker/src/main/res/anim/top_out.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
--------------------------------------------------------------------------------
/imagepicker/src/main/res/drawable-v21/bg_folder_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | -
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/imagepicker/src/main/res/drawable/bg_btn_dis.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/imagepicker/src/main/res/drawable/bg_btn_nor.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/imagepicker/src/main/res/drawable/bg_btn_pre.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/imagepicker/src/main/res/drawable/bg_folder_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/imagepicker/src/main/res/drawable/bg_image_folder.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 |
--------------------------------------------------------------------------------
/imagepicker/src/main/res/drawable/ic_arrow_back.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/imagepicker/src/main/res/drawable/ic_cover_shade.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
--------------------------------------------------------------------------------
/imagepicker/src/main/res/drawable/ic_default_image.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
--------------------------------------------------------------------------------
/imagepicker/src/main/res/drawable/ic_vector_check.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/imagepicker/src/main/res/drawable/ic_vector_delete.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/imagepicker/src/main/res/drawable/selector_back_press.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/imagepicker/src/main/res/drawable/selector_grid_camera_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/imagepicker/src/main/res/drawable/selector_item_checked.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/imagepicker/src/main/res/drawable/selector_top_ok.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/imagepicker/src/main/res/layout/activity_image_crop.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
11 |
15 |
16 |
20 |
21 |
39 |
40 |
--------------------------------------------------------------------------------
/imagepicker/src/main/res/layout/activity_image_grid.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
11 |
12 |
16 |
17 |
26 |
27 |
33 |
34 |
41 |
42 |
53 |
54 |
62 |
63 |
64 |
65 |
66 |
79 |
80 |
81 |
82 |
83 |
--------------------------------------------------------------------------------
/imagepicker/src/main/res/layout/activity_image_preview.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
13 |
14 |
17 |
18 |
27 |
28 |
31 |
32 |
42 |
43 |
56 |
57 |
58 |
63 |
64 |
--------------------------------------------------------------------------------
/imagepicker/src/main/res/layout/adapter_camera_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
20 |
21 |
--------------------------------------------------------------------------------
/imagepicker/src/main/res/layout/adapter_folder_list_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
15 |
16 |
24 |
25 |
26 |
27 |
33 |
34 |
41 |
42 |
50 |
51 |
52 |
59 |
60 |
--------------------------------------------------------------------------------
/imagepicker/src/main/res/layout/adapter_image_list_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
13 |
14 |
18 |
19 |
25 |
26 |
37 |
38 |
47 |
48 |
--------------------------------------------------------------------------------
/imagepicker/src/main/res/layout/include_top_bar.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
17 |
18 |
25 |
26 |
37 |
38 |
54 |
55 |
65 |
--------------------------------------------------------------------------------
/imagepicker/src/main/res/layout/pop_folder.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
15 |
16 |
22 |
30 |
31 |
32 |
37 |
--------------------------------------------------------------------------------
/imagepicker/src/main/res/mipmap-xxhdpi/checkbox_checked.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jeasonlzy/ImagePicker/f7cad47b259b89bb109905e2498c228bf9c35041/imagepicker/src/main/res/mipmap-xxhdpi/checkbox_checked.png
--------------------------------------------------------------------------------
/imagepicker/src/main/res/mipmap-xxhdpi/checkbox_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jeasonlzy/ImagePicker/f7cad47b259b89bb109905e2498c228bf9c35041/imagepicker/src/main/res/mipmap-xxhdpi/checkbox_normal.png
--------------------------------------------------------------------------------
/imagepicker/src/main/res/mipmap-xxhdpi/grid_camera.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jeasonlzy/ImagePicker/f7cad47b259b89bb109905e2498c228bf9c35041/imagepicker/src/main/res/mipmap-xxhdpi/grid_camera.png
--------------------------------------------------------------------------------
/imagepicker/src/main/res/mipmap-xxhdpi/text_indicator.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jeasonlzy/ImagePicker/f7cad47b259b89bb109905e2498c228bf9c35041/imagepicker/src/main/res/mipmap-xxhdpi/text_indicator.png
--------------------------------------------------------------------------------
/imagepicker/src/main/res/values-v19/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
--------------------------------------------------------------------------------
/imagepicker/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/imagepicker/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #323336
4 | #393A3F
5 | #303135
6 | #ec2f3335
7 | #ffe0e0e0
8 | #353535
9 | #1AAD19
10 | #66ffffff
11 | #ffffff
12 |
--------------------------------------------------------------------------------
/imagepicker/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | 所有图片
3 | 共%1$d张
4 | %1$d/%2$d
5 | 最多选择%1$d张图片
6 | 完成
7 | 完成(%1$d/%2$d)
8 | 预览
9 | 预览(%1$d)
10 | 图片裁剪
11 | 原图
12 | 原图(%1$s)
13 |
14 |
--------------------------------------------------------------------------------
/imagepicker/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
11 |
12 |
13 |
16 |
17 |
23 |
--------------------------------------------------------------------------------
/imagepicker/src/main/res/xml/provider_paths.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':imagepicker'
2 |
--------------------------------------------------------------------------------