├── .idea
├── .name
├── copyright
│ └── profiles_settings.xml
├── encodings.xml
├── vcs.xml
├── modules.xml
├── runConfigurations.xml
├── gradle.xml
├── compiler.xml
└── misc.xml
├── app
├── .gitignore
├── src
│ └── main
│ │ ├── res
│ │ ├── mipmap-hdpi
│ │ │ └── ic_launcher.png
│ │ ├── mipmap-mdpi
│ │ │ └── ic_launcher.png
│ │ ├── mipmap-xhdpi
│ │ │ └── ic_launcher.png
│ │ ├── drawable-xhdpi
│ │ │ ├── take_pic.9.png
│ │ │ ├── directory_bg.9.png
│ │ │ ├── ic_arrow_back.png
│ │ │ ├── ic_arrow_check.png
│ │ │ ├── ic_product_9.9.png
│ │ │ ├── image_choose.png
│ │ │ ├── image_not_chose.png
│ │ │ └── pull_up_arrow.9.png
│ │ ├── mipmap-xxhdpi
│ │ │ └── ic_launcher.png
│ │ ├── values
│ │ │ ├── styles.xml
│ │ │ ├── colors.xml
│ │ │ └── strings.xml
│ │ ├── drawable
│ │ │ └── choose_directory_bg.xml
│ │ └── layout
│ │ │ ├── widget_zoom_iamge.xml
│ │ │ ├── item_pick_up_image.xml
│ │ │ ├── item_titlebar.xml
│ │ │ ├── activity_pick_big_images.xml
│ │ │ ├── item_list_view_album_directory.xml
│ │ │ └── activity_pick_or_take_image_activity.xml
│ │ ├── java
│ │ └── com
│ │ │ └── zhao
│ │ │ └── album
│ │ │ ├── AppContext.java
│ │ │ ├── SingleImageModel.java
│ │ │ ├── CommonUtil.java
│ │ │ ├── ImageDirectoryModel.java
│ │ │ ├── PickBigImagesActivity.java
│ │ │ ├── AlbumBitmapCacheHelper.java
│ │ │ ├── ZoomImageView.java
│ │ │ └── PickOrTakeImageActivity.java
│ │ └── AndroidManifest.xml
├── build.gradle
├── proguard-rules.pro
└── app.iml
├── settings.gradle
├── .gitignore
├── README.md
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── README.md~
├── gradle.properties
├── AlbumImageSelect.iml
├── LICENSE
├── gradlew.bat
└── gradlew
/.idea/.name:
--------------------------------------------------------------------------------
1 | AlbumImageSelect
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle
2 | /local.properties
3 | /.idea/workspace.xml
4 | /.idea/libraries
5 | .DS_Store
6 | /build
7 | /captures
8 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # AlbumImageSelect
2 | 仿最新版微信相册选择
3 |
4 | [android仿最新版本微信相册](http://blog.csdn.net/self_study/article/details/46607815)
5 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhaozepeng/AlbumImageSelect/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/README.md~:
--------------------------------------------------------------------------------
1 | # AlbumImageSelect
2 | 仿最新版微信相册选择
3 |
4 | [android仿最新版本微信相册](http://blog.csdn.net/self_study/article/details/46607815)
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhaozepeng/AlbumImageSelect/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhaozepeng/AlbumImageSelect/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhaozepeng/AlbumImageSelect/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/take_pic.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhaozepeng/AlbumImageSelect/HEAD/app/src/main/res/drawable-xhdpi/take_pic.9.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhaozepeng/AlbumImageSelect/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/directory_bg.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhaozepeng/AlbumImageSelect/HEAD/app/src/main/res/drawable-xhdpi/directory_bg.9.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_arrow_back.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhaozepeng/AlbumImageSelect/HEAD/app/src/main/res/drawable-xhdpi/ic_arrow_back.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_arrow_check.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhaozepeng/AlbumImageSelect/HEAD/app/src/main/res/drawable-xhdpi/ic_arrow_check.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_product_9.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhaozepeng/AlbumImageSelect/HEAD/app/src/main/res/drawable-xhdpi/ic_product_9.9.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/image_choose.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhaozepeng/AlbumImageSelect/HEAD/app/src/main/res/drawable-xhdpi/image_choose.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/image_not_chose.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhaozepeng/AlbumImageSelect/HEAD/app/src/main/res/drawable-xhdpi/image_not_chose.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/pull_up_arrow.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhaozepeng/AlbumImageSelect/HEAD/app/src/main/res/drawable-xhdpi/pull_up_arrow.9.png
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Apr 10 15:27:10 PDT 2013
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/choose_directory_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #353535
4 | #aaaaaa
5 | #d9d9d9
6 | #FFFFFF
7 | #00000000
8 | #ADD8E6
9 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhao/album/AppContext.java:
--------------------------------------------------------------------------------
1 | package com.zhao.album;
2 |
3 | import android.app.Application;
4 |
5 | /**
6 | * @author: zzp(zhao_zepeng@hotmail.com)
7 | * @since: 2015-06-22
8 | * Description: #TODO
9 | */
10 | public class AppContext extends Application{
11 | private static AppContext instance;
12 |
13 | @Override
14 | public void onCreate() {
15 | super.onCreate();
16 | instance = this;
17 | }
18 |
19 | public static AppContext getInstance(){
20 | return instance;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/widget_zoom_iamge.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | AlbumImageSelect
3 | 全部图片
4 | 预览
5 | 预览(%1$d)
6 | 完成
7 | 完成(%1$d/%2$d)
8 | 你最多只能选择%1$d张照片
9 | 选择
10 | 你还没有选择任何图片
11 | 正在批量上传
12 |
13 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 23
5 | buildToolsVersion "22.0.1"
6 |
7 | defaultConfig {
8 | applicationId "com.android.zzp.albumimageselect"
9 | minSdkVersion 8
10 | targetSdkVersion 23
11 | versionCode 1
12 | versionName "1.0"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | }
21 |
22 | dependencies {
23 | compile fileTree(dir: 'libs', include: ['*.jar'])
24 | compile 'com.android.support:appcompat-v7:23.1.1'
25 | }
26 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhao/album/SingleImageModel.java:
--------------------------------------------------------------------------------
1 | package com.zhao.album;
2 |
3 | import java.io.Serializable;
4 |
5 | /**
6 | * @author: zzp
7 | * @since: 2015-06-16
8 | */
9 | public class SingleImageModel implements Serializable{
10 | public String path;
11 | public boolean isPicked;
12 | public long date;
13 | public long id;
14 | public SingleImageModel(String path, boolean isPicked, long date, long id){
15 | this.path = path;
16 | this.isPicked = isPicked;
17 | this.date = date;
18 | this.id = id;
19 | }
20 | public SingleImageModel(){
21 |
22 | }
23 | public boolean isThisImage(String path){
24 | return this.path.equalsIgnoreCase(path);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/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 /home/zzp/adt-bundle-linux-x86_64-20140702/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 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
--------------------------------------------------------------------------------
/AlbumImageSelect.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_pick_up_image.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
10 |
16 |
17 |
27 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_titlebar.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
16 |
17 |
26 |
27 |
36 |
37 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2015, zhaozepeng
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | * Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | * Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | * Neither the name of AlbumImageSelect nor the names of its
15 | contributors may be used to endorse or promote products derived from
16 | this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 |
29 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_pick_big_images.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
10 |
14 |
15 |
20 |
21 |
22 |
31 |
32 |
40 |
41 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_list_view_album_directory.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
15 |
20 |
21 |
22 |
30 |
38 |
45 |
46 |
47 |
54 |
55 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 | 1.7
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhao/album/CommonUtil.java:
--------------------------------------------------------------------------------
1 | package com.zhao.album;
2 |
3 | import android.content.Context;
4 | import android.os.Environment;
5 |
6 | import java.io.ByteArrayOutputStream;
7 | import java.io.IOException;
8 | import java.io.ObjectOutputStream;
9 | import java.io.Serializable;
10 | import java.io.UnsupportedEncodingException;
11 | import java.security.MessageDigest;
12 | import java.security.NoSuchAlgorithmException;
13 |
14 | /**
15 | * @author: zzp(zhao_zepeng@hotmail.com)
16 | * @since: 2015-06-22
17 | * Description:
18 | */
19 | public class CommonUtil {
20 | /**
21 | * 根据手机的分辨率从 dp 的单位 转成为 px(像素)
22 | */
23 | public static int dip2px(Context context, float dpValue) {
24 | final float scale = context.getResources().getDisplayMetrics().density;
25 | return (int) (dpValue * scale + 0.5f);
26 | }
27 |
28 |
29 |
30 | /**
31 | * md5加密
32 | */
33 | public static String md5(Object object) {
34 | byte[] hash;
35 | try {
36 | hash = MessageDigest.getInstance("MD5").digest(toByteArray(object));
37 | } catch (NoSuchAlgorithmException e) {
38 | throw new RuntimeException("Huh, MD5 should be supported?", e);
39 | }
40 |
41 | StringBuilder hex = new StringBuilder(hash.length * 2);
42 | for (byte b : hash) {
43 | if ((b & 0xFF) < 0x10) hex.append("0");
44 | hex.append(Integer.toHexString(b & 0xFF));
45 | }
46 | return hex.toString();
47 | }
48 |
49 | public static byte[] toByteArray (Object obj) {
50 | byte[] bytes = null;
51 | ByteArrayOutputStream bos = new ByteArrayOutputStream();
52 | try {
53 | ObjectOutputStream oos = new ObjectOutputStream(bos);
54 | oos.writeObject(obj);
55 | oos.flush();
56 | bytes = bos.toByteArray ();
57 | oos.close();
58 | bos.close();
59 | } catch (IOException ex) {
60 | ex.printStackTrace();
61 | }
62 | return bytes;
63 | }
64 |
65 |
66 |
67 | /**
68 | * 获取存储路径
69 | */
70 | public static String getDataPath() {
71 | String path;
72 | if (isExistSDcard())
73 | path = Environment.getExternalStorageDirectory().getPath() + "/albumSelect";
74 | else
75 | path = AppContext.getInstance().getFilesDir().getPath();
76 | if (!path.endsWith("/"))
77 | path = path + "/";
78 | return path;
79 | }
80 |
81 |
82 | /**
83 | * 检测SDcard是否存在
84 | *
85 | * @return
86 | */
87 | public static boolean isExistSDcard() {
88 | String state = Environment.getExternalStorageState();
89 | if (state.equals(Environment.MEDIA_MOUNTED))
90 | return true;
91 | else {
92 | return false;
93 | }
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhao/album/ImageDirectoryModel.java:
--------------------------------------------------------------------------------
1 | package com.zhao.album;
2 |
3 | import android.util.Log;
4 |
5 | import java.io.Serializable;
6 | import java.util.ArrayList;
7 |
8 | /**
9 | * @author: zzp
10 | * @since: 2015-06-11
11 | * Description: 一个图片文件夹对应实体
12 | */
13 | public class ImageDirectoryModel implements Serializable{
14 |
15 |
16 | /** 图片的路径,对应图片是否被选中的数组 */
17 | private ArrayList images;
18 |
19 | public ImageDirectoryModel(){
20 | images = new ArrayList();
21 | }
22 |
23 | public ArrayList getImages() {
24 | return images;
25 | }
26 |
27 | /**
28 | * 把一张图片path添加进这个文件夹中
29 | * @param path 图片地址
30 | */
31 | public void addImage(String path, long date, long id){
32 | SingleImageModel image = new SingleImageModel(path, false, date, id);
33 | images.add(image);
34 | }
35 |
36 | public void addSingleImageModel(SingleImageModel model){
37 | images.add(model);
38 | }
39 |
40 | /**
41 | * 将一张图片从该文件夹中删除
42 | * @param path 图片地址
43 | */
44 | public void removeImage(String path){
45 | for (SingleImageModel image : images){
46 | if (image.isThisImage(path)){
47 | images.remove(image);
48 | break;
49 | }
50 | }
51 | }
52 |
53 | /**
54 | * 选中该图片
55 | * @param path 图片地址
56 | */
57 | public void setImage(String path){
58 | for (SingleImageModel image : images){
59 | if (image.isThisImage(path)){
60 | if(image.isPicked){
61 | Log.e("zhao", "this image is picked!!!");
62 | }
63 | image.isPicked = true;
64 | break;
65 | }
66 | }
67 | }
68 |
69 | /**
70 | * 不选中该图片
71 | * @param path 图片地址
72 | */
73 | public void unsetImage(String path){
74 | for (SingleImageModel image : images){
75 | if (image.isThisImage(path)){
76 | if(!image.isPicked){
77 | Log.e("zhao", "this image isn't picked!!!");
78 | }
79 | image.isPicked = false;
80 | break;
81 | }
82 | }
83 | }
84 |
85 | /**
86 | * 转变图片的选中状态
87 | */
88 | public void toggleSetImage(int position){
89 | SingleImageModel model = images.get(position);
90 | model.isPicked = !model.isPicked;
91 | }
92 |
93 | /**
94 | * 转变图片的选中状态
95 | */
96 | public void toggleSetImage(String path){
97 | for (SingleImageModel model : images){
98 | if (model.path.equalsIgnoreCase(path)) {
99 | model.isPicked = !model.isPicked;
100 | break;
101 | }
102 | }
103 | }
104 |
105 | /**
106 | * 返回该文件夹的所有文件数量
107 | */
108 | public int getImageCounts(){
109 | return images.size();
110 | }
111 |
112 | /**
113 | * 根据图片的位置返回该图片的url
114 | * @param position 图片位置
115 | */
116 | public String getImagePath(int position){
117 | return images.get(position).path;
118 | }
119 |
120 | /**
121 | * 根据图片的位置返回该图片是否被选中
122 | * @param position 图片位置
123 | */
124 | public boolean getImagePickOrNot(int position){
125 | return images.get(position).isPicked;
126 | }
127 |
128 | /**
129 | * 该文件夹中是否有选中的图片
130 | */
131 | public boolean hasChoosePic(){
132 | for (SingleImageModel model : images){
133 | if (model.isPicked)
134 | return true;
135 | }
136 | return false;
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_pick_or_take_image_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
10 |
11 |
14 |
23 |
24 |
25 |
31 |
39 |
40 |
47 |
57 |
58 |
59 |
71 |
78 |
87 |
88 |
89 |
95 |
104 |
105 |
106 |
107 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/app/app.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | generateDebugAndroidTestSources
19 | generateDebugSources
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhao/album/PickBigImagesActivity.java:
--------------------------------------------------------------------------------
1 | package com.zhao.album;
2 |
3 | import android.app.Activity;
4 | import android.content.Intent;
5 | import android.graphics.Bitmap;
6 | import android.os.Bundle;
7 | import android.support.v4.view.PagerAdapter;
8 | import android.support.v4.view.ViewPager;
9 | import android.view.LayoutInflater;
10 | import android.view.View;
11 | import android.view.ViewGroup;
12 | import android.widget.Button;
13 | import android.widget.ImageView;
14 | import android.widget.TextView;
15 | import android.widget.Toast;
16 |
17 | import com.android.zzp.albumimageselect.R;
18 |
19 | import java.util.ArrayList;
20 |
21 | /**
22 | * @author: zzp
23 | * @since: 2015-06-15
24 | * Description: 仿微信大图选择界面
25 | */
26 | public class PickBigImagesActivity extends Activity implements ViewPager.OnPageChangeListener, View.OnClickListener{
27 | private ViewPager viewPager;
28 | private TextView tv_choose_pic;
29 | private ImageView iv_choose_state;
30 | private Button btn_choose_finish;
31 |
32 | private MyViewPagerAdapter adapter;
33 |
34 | private ArrayList allimages;
35 | ArrayList picklist;
36 | /** 当前选中的图片 */
37 | private int currentPic;
38 |
39 | private int last_pics;
40 | private int total_pics;
41 |
42 | private boolean isFinish = false;
43 |
44 | /** 选择的照片文件夹 */
45 | public final static String EXTRA_DATA = "extra_data";
46 | /** 所有被选中的图片 */
47 | public final static String EXTRA_ALL_PICK_DATA = "extra_pick_data";
48 | /** 当前被选中的照片 */
49 | public final static String EXTRA_CURRENT_PIC = "extra_current_pic";
50 | /** 剩余的可选择照片 */
51 | public final static String EXTRA_LAST_PIC = "extra_last_pic";
52 | /** 总的照片 */
53 | public final static String EXTRA_TOTAL_PIC = "extra_total_pic";
54 |
55 | @Override
56 | public void onCreate(Bundle savedInstanceState) {
57 | super.onCreate(savedInstanceState);
58 | setContentView(R.layout.activity_pick_big_images);
59 | initFindView();
60 | initData();
61 | }
62 |
63 | protected void initFindView() {
64 | viewPager = (ViewPager) findViewById(R.id.vp_content);
65 | tv_choose_pic = (TextView) findViewById(R.id.tv_choose_pic);
66 | iv_choose_state = (ImageView) findViewById(R.id.iv_choose_state);
67 | tv_choose_pic.setOnClickListener(this);
68 | iv_choose_state.setOnClickListener(this);
69 |
70 |
71 | findViewById(R.id.iv_back).setOnClickListener(new View.OnClickListener() {
72 | @Override
73 | public void onClick(View v) {
74 | finish();
75 | }
76 | });
77 |
78 | btn_choose_finish = (Button) findViewById(R.id.btn_choose_finish);
79 | btn_choose_finish.setText("完成");
80 | btn_choose_finish.setOnClickListener(new View.OnClickListener() {
81 |
82 | @Override
83 | public void onClick(View v) {
84 | isFinish = true;
85 | finish();
86 | }
87 | });
88 |
89 | if(last_pics < total_pics) {
90 | btn_choose_finish.setTextColor(getResources().getColor(R.color.white));
91 | btn_choose_finish.setText(String.format(getString(R.string.choose_pic_finish_with_num), total_pics - last_pics, total_pics));
92 | }
93 | }
94 |
95 | protected void initData() {
96 | allimages = (ArrayList) getIntent().getSerializableExtra(EXTRA_DATA);
97 | picklist = (ArrayList) getIntent().getSerializableExtra(EXTRA_ALL_PICK_DATA);
98 | if (picklist == null)
99 | picklist = new ArrayList();
100 | currentPic = getIntent().getIntExtra(EXTRA_CURRENT_PIC, 0);
101 |
102 | last_pics = getIntent().getIntExtra(EXTRA_LAST_PIC, 0);
103 | total_pics = getIntent().getIntExtra(EXTRA_TOTAL_PIC, 9);
104 |
105 | setTitle((currentPic + 1) + "/" + getImagesCount());
106 | //如果该图片被选中
107 | if (getChooseStateFromList(currentPic)){
108 | iv_choose_state.setBackgroundResource(R.drawable.image_choose);
109 | }else{
110 | iv_choose_state.setBackgroundResource(R.drawable.image_not_chose);
111 | }
112 |
113 | adapter = new MyViewPagerAdapter();
114 | viewPager.setAdapter(adapter);
115 | viewPager.setOnPageChangeListener(this);
116 | viewPager.setCurrentItem(currentPic);
117 | }
118 |
119 | @Override
120 | public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
121 |
122 | }
123 |
124 | @Override
125 | public void onPageSelected(int position) {
126 | //如果该图片被选中
127 | if (getChooseStateFromList(position)){
128 | iv_choose_state.setBackgroundResource(R.drawable.image_choose);
129 | }else{
130 | iv_choose_state.setBackgroundResource(R.drawable.image_not_chose);
131 | }
132 | currentPic = position;
133 | ((TextView)findViewById(R.id.tv_title)).setText((currentPic + 1) + "/" + getImagesCount());
134 | }
135 |
136 | @Override
137 | public void onPageScrollStateChanged(int state) {
138 | }
139 |
140 | @Override
141 | public void onClick(View view) {
142 | toggleChooseState(currentPic);
143 | //如果被选中
144 | if(getChooseStateFromList(currentPic)){
145 | if (last_pics <= 0){
146 | toggleChooseState(currentPic);
147 | Toast.makeText(this, String.format(getString(R.string.choose_pic_num_out_of_index), total_pics), Toast.LENGTH_SHORT).show();
148 | return ;
149 | }
150 | picklist.add(getPathFromList(currentPic));
151 | last_pics --;
152 | iv_choose_state.setBackgroundResource(R.drawable.image_choose);
153 | if(last_pics == total_pics-1){
154 | btn_choose_finish.setTextColor(getResources().getColor(R.color.white));
155 | }
156 | btn_choose_finish.setText(String.format(getString(R.string.choose_pic_finish_with_num), total_pics-last_pics, total_pics));
157 | }else{
158 | picklist.remove(getPathFromList(currentPic));
159 | last_pics ++;
160 | iv_choose_state.setBackgroundResource(R.drawable.image_not_chose);
161 | if(last_pics == total_pics){
162 | btn_choose_finish.setTextColor(getResources().getColor(R.color.found_description_color));
163 | btn_choose_finish.setText(getString(R.string.choose_pic_finish));
164 | }else{
165 | btn_choose_finish.setText(String.format(getString(R.string.choose_pic_finish_with_num), total_pics-last_pics, total_pics));
166 | }
167 | }
168 | }
169 |
170 | private class MyViewPagerAdapter extends PagerAdapter {
171 |
172 | @Override
173 | public int getCount() {
174 | return getImagesCount();
175 | }
176 |
177 | @Override
178 | public Object instantiateItem(ViewGroup container, int position) {
179 | View view = LayoutInflater.from(PickBigImagesActivity.this).inflate(R.layout.widget_zoom_iamge, null);
180 | final ZoomImageView zoomImageView = (ZoomImageView) view.findViewById(R.id.zoom_image_view);
181 |
182 | AlbumBitmapCacheHelper.getInstance().addPathToShowlist(getPathFromList(position));
183 | zoomImageView.setTag(getPathFromList(position));
184 | Bitmap bitmap = AlbumBitmapCacheHelper.getInstance().getBitmap(getPathFromList(position), 0, 0, new AlbumBitmapCacheHelper.ILoadImageCallback() {
185 | @Override
186 | public void onLoadImageCallBack(Bitmap bitmap, String path, Object... objects) {
187 | ZoomImageView view = ((ZoomImageView)viewPager.findViewWithTag(path));
188 | if (view != null && bitmap != null)
189 | ((ZoomImageView)viewPager.findViewWithTag(path)).setSourceImageBitmap(bitmap, PickBigImagesActivity.this);
190 | }
191 | }, position);
192 | if (bitmap != null){
193 | zoomImageView.setSourceImageBitmap(bitmap, PickBigImagesActivity.this);
194 | }
195 | container.addView(view);
196 | return view;
197 | }
198 |
199 | @Override
200 | public void destroyItem(ViewGroup container, int position, Object object) {
201 | View view = (View) object;
202 | container.removeView(view);
203 | AlbumBitmapCacheHelper.getInstance().removePathFromShowlist(getPathFromList(position));
204 | }
205 |
206 | @Override
207 | public boolean isViewFromObject(View view, Object object) {
208 | return view == object;
209 | }
210 | }
211 |
212 | /**
213 | * 通过位置获取该位置图片的path
214 | */
215 | private String getPathFromList(int position){
216 | return allimages.get(position).path;
217 | }
218 |
219 | /**
220 | * 通过位置获取该位置图片的选中状态
221 | */
222 | private boolean getChooseStateFromList(int position){
223 | return allimages.get(position).isPicked;
224 | }
225 |
226 | /**
227 | * 反转图片的选中状态
228 | */
229 | private void toggleChooseState(int position){
230 | allimages.get(position).isPicked = !allimages.get(position).isPicked;
231 | }
232 |
233 | /**
234 | * 获得所有的图片数量
235 | */
236 | private int getImagesCount(){
237 | return allimages.size();
238 | }
239 |
240 | @Override
241 | public void finish() {
242 | Intent data = new Intent();
243 | data.putExtra("pick_data", picklist);
244 | data.putExtra("isFinish", isFinish);
245 | setResult(RESULT_OK, data);
246 | super.finish();
247 | }
248 | }
249 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhao/album/AlbumBitmapCacheHelper.java:
--------------------------------------------------------------------------------
1 | package com.zhao.album;
2 |
3 |
4 | import android.content.Context;
5 | import android.graphics.Bitmap;
6 | import android.graphics.BitmapFactory;
7 | import android.os.Handler;
8 | import android.os.Message;
9 | import android.support.v4.util.LruCache;
10 | import android.util.Log;
11 | import android.view.WindowManager;
12 |
13 | import java.io.ByteArrayOutputStream;
14 | import java.io.File;
15 | import java.io.FileNotFoundException;
16 | import java.io.FileOutputStream;
17 | import java.io.IOException;
18 | import java.util.ArrayList;
19 | import java.util.concurrent.LinkedBlockingQueue;
20 | import java.util.concurrent.ThreadPoolExecutor;
21 | import java.util.concurrent.TimeUnit;
22 |
23 | /**
24 | * @author: zzp
25 | * @since: 2015-06-10
26 | * Description: 相册页加载图片,省内存,防止oom
27 | */
28 | public class AlbumBitmapCacheHelper {
29 | //线程安全的单例模式
30 | private volatile static AlbumBitmapCacheHelper instance = null;
31 | private LruCache cache;
32 | /**
33 | * 用来优化图片的展示效果,保存当前显示的图片path
34 | */
35 | private ArrayList currentShowString;
36 | // private ContentResolver cr;
37 |
38 | private AlbumBitmapCacheHelper() {
39 | //分配1/4的运行时内存给图片显示
40 | final int memory = (int) (Runtime.getRuntime().maxMemory() / 1024 / 4);
41 |
42 | cache = new LruCache(memory) {
43 | @Override
44 | protected int sizeOf(String key, Bitmap value) {
45 | //获取每张bitmap大小
46 | return value.getRowBytes() * value.getHeight() / 1024;
47 | }
48 | };
49 |
50 | currentShowString = new ArrayList();
51 | // cr = AppContext.getInstance().getContentResolver();
52 | }
53 |
54 | /**
55 | * 释放所有的内存
56 | */
57 | public void releaseAllSizeCache(){
58 | cache.evictAll();
59 | cache.resize(1);
60 | }
61 |
62 | public void releaseHalfSizeCache() {
63 | cache.resize((int) (Runtime.getRuntime().maxMemory() / 1024 / 8));
64 | }
65 |
66 | public void resizeCache() {
67 | cache.resize((int) (Runtime.getRuntime().maxMemory() / 1024 / 4));
68 | }
69 |
70 | /**
71 | * 选择完毕,直接释放缓存所占的内存
72 | */
73 | public void clearCache() {
74 | cache.evictAll();
75 | cache = null;
76 | instance = null;
77 | }
78 |
79 | public static AlbumBitmapCacheHelper getInstance() {
80 | if (instance == null) {
81 | synchronized (AlbumBitmapCacheHelper.class) {
82 | if (instance == null) {
83 | instance = new AlbumBitmapCacheHelper();
84 | }
85 | }
86 | }
87 | return instance;
88 | }
89 |
90 | /**
91 | * 通过图片的path回调该图片的bitmap
92 | *
93 | * @param path 图片地址
94 | * @param width 需要显示图片的宽度,0代表显示完整图片
95 | * @param height 需要显示图片的高度,0代表显示完整图片
96 | * @param callback 加载bitmap成功回调
97 | * @param objects 用来直接返回标识
98 | */
99 | public Bitmap getBitmap(final String path, int width, int height, final ILoadImageCallback callback, Object... objects){
100 | Bitmap bitmap = getBitmapFromCache(path, width, height);
101 | //如果能够从缓存中获取符合要求的图片,则直接回调
102 | if (bitmap != null) {
103 | Log.e("zhao", "get bitmap from cache");
104 | } else {
105 | decodeBitmapFromPath(path, width, height, callback, objects);
106 | }
107 | return bitmap;
108 | }
109 |
110 | //try another size to get better display
111 | ThreadPoolExecutor tpe = new ThreadPoolExecutor(2, 5, 10, TimeUnit.SECONDS, new LinkedBlockingQueue());
112 | // ExecutorService tpe = Executors.newFixedThreadPool(1);
113 |
114 | /**
115 | * 通过path获取图片bitmap
116 | */
117 | private void decodeBitmapFromPath(final String path, final int width, final int height, final ILoadImageCallback callback, final Object... objects) throws OutOfMemoryError {
118 | final Handler handler = new Handler() {
119 | @Override
120 | public void handleMessage(Message msg) {
121 | callback.onLoadImageCallBack((Bitmap) msg.obj, path, objects);
122 | }
123 | };
124 | //防止主线程卡顿
125 | tpe.execute(new Runnable() {
126 | @Override
127 | public void run() {
128 | if (!currentShowString.contains(path)||cache==null) {
129 | return;
130 | }
131 | Bitmap bitmap = null;
132 | //返回大图,屏幕宽度为准
133 | if (width == 0 || height == 0) {
134 | BitmapFactory.Options options = new BitmapFactory.Options();
135 | options.inJustDecodeBounds = true;
136 | BitmapFactory.decodeFile(path, options);
137 | options.inSampleSize = computeScale(options, ((WindowManager) (AppContext.getInstance().getSystemService(Context.WINDOW_SERVICE))).getDefaultDisplay().getWidth(), ((WindowManager) (AppContext.getInstance().getSystemService(Context.WINDOW_SERVICE))).getDefaultDisplay().getWidth());
138 | options.inJustDecodeBounds = false;
139 | try {
140 | bitmap = BitmapFactory.decodeFile(path, options);
141 | } catch (OutOfMemoryError e) {
142 | releaseAllSizeCache();
143 | bitmap = BitmapFactory.decodeFile(path, options);
144 | }
145 | } else {
146 | //返回小图,第一步,从temp目录下取该图片指定大小的缓存,如果取不到,
147 | // 第二步,计算samplesize,如果samplesize > 4,
148 | // 第三步则将压缩后的图片存入temp目录下,以便下次快速取出
149 | String hash = CommonUtil.md5(path+"_"+width+"_"+height);
150 | File file = new File(CommonUtil.getDataPath());
151 | if (!file.exists())
152 | file.mkdirs();
153 | //临时文件的文件名
154 | String tempPath = CommonUtil.getDataPath() + hash + ".temp";
155 | File picFile = new File(path);
156 | File tempFile = new File(tempPath);
157 | //如果该文件存在,并且temp文件的创建时间要原文件之后
158 | if (tempFile.exists() && (picFile.lastModified() <= tempFile.lastModified()))
159 | bitmap = BitmapFactory.decodeFile(tempPath);
160 | //无法在临时文件的缩略图目录找到该图片,于是执行第二步
161 | if (bitmap == null) {
162 | BitmapFactory.Options options = new BitmapFactory.Options();
163 | options.inJustDecodeBounds = true;
164 | BitmapFactory.decodeFile(path, options);
165 | options.inSampleSize = computeScale(options, width, height);
166 | options.inJustDecodeBounds = false;
167 | //获取手机自带缩略图,速度依旧很慢,所以该方案放弃
168 | // if(objects.length != 0){
169 | // long start = System.currentTimeMillis();
170 | // bitmap = MediaStore.Images.Thumbnails.getThumbnail(cr, Long.parseLong(objects[0].toString()),
171 | // MediaStore.Video.Thumbnails.MINI_KIND, options);
172 | // }else{
173 | try {
174 | bitmap = BitmapFactory.decodeFile(path, options);
175 | }catch (OutOfMemoryError error){
176 | bitmap = null;
177 | }
178 | if (bitmap != null && cache!=null) {
179 | bitmap = centerSquareScaleBitmap(bitmap, ((bitmap.getWidth() > bitmap.getHeight()) ? bitmap.getHeight() : bitmap.getWidth()));
180 | }
181 | //第三步,如果缩放比例大于4,该图的加载会非常慢,所以将该图保存到临时目录下以便下次的快速加载
182 | if (options.inSampleSize>=4 && bitmap!=null) {
183 | try {
184 | file = new File(tempPath);
185 | if (!file.exists())
186 | file.createNewFile();
187 | else {
188 | file.delete();
189 | file.createNewFile();
190 | }
191 | FileOutputStream fos = new FileOutputStream(file);
192 | ByteArrayOutputStream baos = new ByteArrayOutputStream();
193 | bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
194 | fos.write(baos.toByteArray());
195 | fos.flush();
196 | fos.close();
197 | } catch (FileNotFoundException e) {
198 | e.printStackTrace();
199 | } catch (IOException e) {
200 | e.printStackTrace();
201 | }
202 | }
203 | // }
204 | }else{
205 | //从temp目录加载出来的图片也要放入到cache中
206 | if (bitmap != null && cache!=null) {
207 | bitmap = centerSquareScaleBitmap(bitmap, ((bitmap.getWidth() > bitmap.getHeight()) ? bitmap.getHeight() : bitmap.getWidth()));
208 | }
209 | }
210 | }
211 | if (bitmap != null && cache!=null)
212 | cache.put(path +"_"+ width +"_"+height, bitmap);
213 | Message msg = Message.obtain();
214 | msg.obj = bitmap;
215 | handler.sendMessage(msg);
216 | }
217 | });
218 | }
219 |
220 | /**
221 | * @param bitmap 原图
222 | * @param edgeLength 希望得到的正方形部分的边长
223 | * @return 缩放截取正中部分后的位图。
224 | */
225 | public static Bitmap centerSquareScaleBitmap(Bitmap bitmap, int edgeLength) {
226 | if (null == bitmap || edgeLength <= 0) {
227 | return null;
228 | }
229 | Bitmap result = bitmap;
230 | int widthOrg = bitmap.getWidth();
231 | int heightOrg = bitmap.getHeight();
232 |
233 | //从图中截取正中间的正方形部分。
234 | int xTopLeft = (widthOrg - edgeLength) / 2;
235 | int yTopLeft = (heightOrg - edgeLength) / 2;
236 |
237 | if (xTopLeft == 0 && yTopLeft == 0) return result;
238 |
239 | try {
240 | result = Bitmap.createBitmap(bitmap, xTopLeft, yTopLeft, edgeLength, edgeLength);
241 | bitmap.recycle();
242 | } catch (OutOfMemoryError e) {
243 | return result;
244 | }
245 |
246 | return result;
247 | }
248 |
249 | /**
250 | * 计算缩放比例
251 | */
252 | private int computeScale(BitmapFactory.Options options, int width, int height) {
253 | if (options == null) return 1;
254 | int widthScale = (int)((float) options.outWidth / (float) width);
255 | int heightScale = (int)((float) options.outHeight / (float) height);
256 | //选择缩放比例较大的那个
257 | int scale = (widthScale > heightScale ? widthScale : heightScale);
258 | if (scale < 1) scale = 1;
259 | return scale;
260 | }
261 |
262 | /**
263 | * 获取lrucache中的图片,如果该图片的宽度和长度无法和需要的相符,则返回null
264 | *
265 | * @param path 图片地址,key
266 | * @param width 需要的图片宽度
267 | * @param height 需要的图片长度
268 | * @return 图片value
269 | */
270 | private Bitmap getBitmapFromCache(final String path, int width, int height) {
271 | return cache.get(path +"_"+ width +"_"+height);
272 | }
273 |
274 | /**
275 | * 将要展示的path加入到list
276 | */
277 | public void addPathToShowlist(String path) {
278 | currentShowString.add(path);
279 | }
280 |
281 | /**
282 | * 从展示list中删除该path
283 | */
284 | public void removePathFromShowlist(String path) {
285 | currentShowString.remove(path);
286 | }
287 |
288 | /**
289 | * 加载图片成功的接口回调
290 | */
291 | public interface ILoadImageCallback {
292 | void onLoadImageCallBack(Bitmap bitmap, String path, Object... objects);
293 | }
294 |
295 | /**
296 | * 移出该threads中的所有线程
297 | */
298 | public void removeAllThreads() {
299 | currentShowString.clear();
300 | for (Runnable runnable : tpe.getQueue()) {
301 | tpe.remove(runnable);
302 | }
303 | }
304 |
305 | }
306 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhao/album/ZoomImageView.java:
--------------------------------------------------------------------------------
1 | package com.zhao.album;
2 |
3 |
4 | import android.app.Activity;
5 | import android.content.Context;
6 | import android.graphics.Bitmap;
7 | import android.graphics.Canvas;
8 | import android.graphics.Matrix;
9 | import android.util.AttributeSet;
10 | import android.view.MotionEvent;
11 | import android.view.WindowManager;
12 | import android.widget.ImageView;
13 |
14 | /**
15 | * 自定义的ImageView控制,可对图片进行多点触控缩放和拖动
16 | */
17 | public class ZoomImageView extends ImageView {
18 |
19 | /**
20 | * 初始化状态常量
21 | */
22 | public static final int STATUS_INIT = 1;
23 |
24 | /**
25 | * 图片放大状态常量
26 | */
27 | public static final int STATUS_ZOOM_OUT = 2;
28 |
29 | /**
30 | * 图片缩小状态常量
31 | */
32 | public static final int STATUS_ZOOM_IN = 3;
33 |
34 | /**
35 | * 图片拖动状态常量
36 | */
37 | public static final int STATUS_MOVE = 4;
38 |
39 | /**
40 | * 用于对图片进行移动和缩放变换的矩阵
41 | */
42 | private Matrix matrix = new Matrix();
43 |
44 | /**
45 | * 待展示的Bitmap对象
46 | */
47 | private Bitmap sourceBitmap;
48 |
49 | /**
50 | * 记录当前操作的状态,可选值为STATUS_INIT、STATUS_ZOOM_OUT、STATUS_ZOOM_IN和STATUS_MOVE
51 | */
52 | private int currentStatus;
53 |
54 | /**
55 | * ZoomImageView控件的宽度
56 | */
57 | private int width;
58 |
59 | /**
60 | * ZoomImageView控件的高度
61 | */
62 | private int height;
63 |
64 | /**
65 | * 记录两指同时放在屏幕上时,中心点的横坐标值
66 | */
67 | private float centerPointX;
68 |
69 | /**
70 | * 记录两指同时放在屏幕上时,中心点的纵坐标值
71 | */
72 | private float centerPointY;
73 |
74 | /**
75 | * 记录当前图片的宽度,图片被缩放时,这个值会一起变动
76 | */
77 | private float currentBitmapWidth;
78 |
79 | /**
80 | * 记录当前图片的高度,图片被缩放时,这个值会一起变动
81 | */
82 | private float currentBitmapHeight;
83 |
84 | /**
85 | * 记录上次手指移动时的横坐标
86 | */
87 | private float lastXMove = -1;
88 |
89 | /**
90 | * 记录上次手指移动时的纵坐标
91 | */
92 | private float lastYMove = -1;
93 |
94 | /**
95 | * 记录手指在横坐标方向上的移动距离
96 | */
97 | private float movedDistanceX;
98 |
99 | /**
100 | * 记录手指在纵坐标方向上的移动距离
101 | */
102 | private float movedDistanceY;
103 |
104 | /**
105 | * 记录图片在矩阵上的横向偏移值
106 | */
107 | private float totalTranslateX;
108 |
109 | /**
110 | * 记录图片在矩阵上的纵向偏移值
111 | */
112 | private float totalTranslateY;
113 |
114 | /**
115 | * 记录图片在矩阵上的总缩放比例
116 | */
117 | private float totalRatio;
118 |
119 | /**
120 | * 记录手指移动的距离所造成的缩放比例
121 | */
122 | private float scaledRatio;
123 |
124 | /**
125 | * 记录图片初始化时的缩放比例
126 | */
127 | private float initRatio;
128 |
129 | /**
130 | * 记录上次两指之间的距离
131 | */
132 | private double lastFingerDis;
133 |
134 | private boolean isIntected;
135 | private float lx = -1, ly = -1;
136 |
137 | /** 是否初始化完成 */
138 | private boolean isInited = false;
139 |
140 | /**
141 | * ZoomImageView构造函数,将当前操作状态设为STATUS_INIT。
142 | *
143 | * @param context
144 | * @param attrs
145 | */
146 |
147 | private Context context;
148 |
149 | public ZoomImageView(Context context, AttributeSet attrs) {
150 | super(context, attrs);
151 | currentStatus = STATUS_INIT;
152 | this.context = context;
153 | // 初始化默认图
154 | // sourceBitmap = BitmapFactory.decodeResource(getResources(),
155 | // R.drawable.ic_product);
156 | }
157 |
158 | /**
159 | * 将待展示的图片设置进来。
160 | *
161 | * @param bitmap 待展示的Bitmap对象
162 | */
163 | public void setSourceImageBitmap(Bitmap bitmap, Activity activity) {
164 | sourceBitmap = bitmap;
165 | int screenWidth = ((WindowManager) (AppContext.getInstance().getSystemService(Context.WINDOW_SERVICE))).getDefaultDisplay().getWidth();
166 | int screenHeight = ((WindowManager) (AppContext.getInstance().getSystemService(Context.WINDOW_SERVICE))).getDefaultDisplay().getHeight();
167 | sourceBitmap = resizeImage(sourceBitmap, screenWidth, screenHeight);
168 | invalidate();
169 | }
170 |
171 | public Bitmap resizeImage(Bitmap bitmap, int w, int h) {
172 | int width = bitmap.getWidth();//144
173 | int height = bitmap.getHeight();//144
174 |
175 | if (width <= 0 || height <= 0) return null;
176 |
177 | int newWidth = w;//1080
178 | int newHeight = (w * height) / width;//1920
179 |
180 | float scaleWidth = ((float) newWidth) / width;
181 | float scaleHeight = ((float) newHeight) / height;
182 |
183 | Matrix matrix = new Matrix();
184 | matrix.postScale(scaleWidth, scaleHeight);
185 | // if you want to rotate the Bitmap
186 | // matrix.postRotate(45);
187 | Bitmap resizedBitmap = null;
188 | try {
189 | resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);
190 | }catch (OutOfMemoryError e){
191 | resizedBitmap = bitmap;
192 | }
193 |
194 | return resizedBitmap;
195 | }
196 |
197 | @Override
198 | protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
199 | super.onLayout(changed, left, top, right, bottom);
200 | if (changed) {
201 | // 分别获取到ZoomImageView的宽度和高度
202 | width = getWidth();
203 | height = getHeight();
204 | }
205 | }
206 |
207 | @Override
208 | public boolean onTouchEvent(MotionEvent event) {
209 | if(!isInited){
210 | return false;
211 | }
212 | if (initRatio == totalRatio) {
213 | getParent().requestDisallowInterceptTouchEvent(false);
214 | } else {
215 | getParent().requestDisallowInterceptTouchEvent(true);
216 | }
217 | switch (event.getActionMasked()) {
218 | case MotionEvent.ACTION_DOWN:
219 | if (event.getPointerCount() == 1 && initRatio == totalRatio) {
220 | //表示点击的时候是用单指,避免UP事件的时候,先放开一只手,而导致触发一个点的事件
221 | isIntected = true;
222 | //记录本次点击的位置,避免滑动的时候,交给下层,从而导致页面的关闭
223 | lx = event.getX();
224 | ly = event.getY();
225 | }
226 | break;
227 | case MotionEvent.ACTION_POINTER_DOWN:
228 | if (event.getPointerCount() == 2) {
229 | // 当有两个手指按在屏幕上时,计算两指之间的距离
230 | lastFingerDis = distanceBetweenFingers(event);
231 | isIntected = false;
232 | }
233 | break;
234 | case MotionEvent.ACTION_CANCEL:
235 | case MotionEvent.ACTION_MOVE:
236 | if (event.getPointerCount() == 1) {
237 | // 只有单指按在屏幕上移动时,为拖动状态
238 | float xMove = event.getX();
239 | float yMove = event.getY();
240 | if (lastXMove == -1 && lastYMove == -1) {
241 | lastXMove = xMove;
242 | lastYMove = yMove;
243 | }
244 | currentStatus = STATUS_MOVE;
245 | movedDistanceX = xMove - lastXMove;
246 | movedDistanceY = yMove - lastYMove;
247 | // 进行边界检查,不允许将图片拖出边界
248 | if (totalTranslateX + movedDistanceX > 0) {
249 | movedDistanceX = 0;
250 | } else if (width - (totalTranslateX + movedDistanceX) > currentBitmapWidth) {
251 | movedDistanceX = 0;
252 | }
253 | if (totalTranslateY + movedDistanceY > 0) {
254 | movedDistanceY = 0;
255 | } else if (height - (totalTranslateY + movedDistanceY) > currentBitmapHeight) {
256 | movedDistanceY = 0;
257 | }
258 | // 调用onDraw()方法绘制图片
259 | invalidate();
260 | lastXMove = xMove;
261 | lastYMove = yMove;
262 | } else if (event.getPointerCount() == 2) {
263 | // 有两个手指按在屏幕上移动时,为缩放状态
264 | centerPointBetweenFingers(event);
265 | double fingerDis = distanceBetweenFingers(event);
266 | if (fingerDis > lastFingerDis) {
267 | currentStatus = STATUS_ZOOM_OUT;
268 | } else {
269 | currentStatus = STATUS_ZOOM_IN;
270 | }
271 | // 进行缩放倍数检查,最大只允许将图片放大4倍,最小可以缩小到初始化比例
272 | if ((currentStatus == STATUS_ZOOM_OUT && totalRatio < 4 * initRatio) || (currentStatus == STATUS_ZOOM_IN && totalRatio > initRatio)) {
273 | scaledRatio = (float) (fingerDis / lastFingerDis);
274 | totalRatio = totalRatio * scaledRatio;
275 | if (totalRatio > 4 * initRatio) {
276 | totalRatio = 4 * initRatio;
277 | } else if (totalRatio < initRatio) {
278 | totalRatio = initRatio;
279 | }
280 | // 调用onDraw()方法绘制图片
281 | invalidate();
282 | lastFingerDis = fingerDis;
283 | }
284 | }
285 | break;
286 | case MotionEvent.ACTION_POINTER_UP:
287 | if (event.getPointerCount() == 2) {
288 | // 手指离开屏幕时将临时值还原
289 | lastXMove = -1;
290 | lastYMove = -1;
291 | }
292 | break;
293 | case MotionEvent.ACTION_UP:
294 | if (initRatio == totalRatio && event.getPointerCount() == 1 && isIntected) {
295 | if (Math.abs(event.getX() - lx) < 10 && Math.abs(event.getY() - ly) < 10) {
296 | return false;
297 | }
298 | }
299 | // 手指离开屏幕时将临时值还原
300 | lastXMove = -1;
301 | lastYMove = -1;
302 | break;
303 | default:
304 | break;
305 | }
306 | return true;
307 | }
308 |
309 | /**
310 | * 根据currentStatus的值来决定对图片进行什么样的绘制操作。
311 | */
312 | @Override
313 | protected void onDraw(Canvas canvas) {
314 | switch (currentStatus) {
315 | case STATUS_ZOOM_OUT:
316 | case STATUS_ZOOM_IN:
317 | zoom(canvas);
318 | break;
319 | case STATUS_MOVE:
320 | move(canvas);
321 | break;
322 | case STATUS_INIT:
323 | initBitmap(canvas);
324 | break;
325 | default:
326 | if (sourceBitmap != null) {
327 | canvas.drawBitmap(sourceBitmap, matrix, null);
328 | }
329 | break;
330 | }
331 | }
332 |
333 | /**
334 | * 对图片进行缩放处理。
335 | *
336 | * @param canvas
337 | */
338 | private void zoom(Canvas canvas) {
339 | if (sourceBitmap == null) return;
340 | matrix.reset();
341 | // 将图片按总缩放比例进行缩放
342 | matrix.postScale(totalRatio, totalRatio);
343 | float scaledWidth = sourceBitmap.getWidth() * totalRatio;
344 | float scaledHeight = sourceBitmap.getHeight() * totalRatio;
345 | float translateX = 0f;
346 | float translateY = 0f;
347 | // 如果当前图片宽度小于屏幕宽度,则按屏幕中心的横坐标进行水平缩放。否则按两指的中心点的横坐标进行水平缩放
348 | if (currentBitmapWidth < width) {
349 | translateX = (width - scaledWidth) / 2f;
350 | } else {
351 | translateX = totalTranslateX * scaledRatio + centerPointX * (1 - scaledRatio);
352 | // 进行边界检查,保证图片缩放后在水平方向上不会偏移出屏幕
353 | if (translateX > 0) {
354 | translateX = 0;
355 | } else if (width - translateX > scaledWidth) {
356 | translateX = width - scaledWidth;
357 | }
358 | }
359 | // 如果当前图片高度小于屏幕高度,则按屏幕中心的纵坐标进行垂直缩放。否则按两指的中心点的纵坐标进行垂直缩放
360 | if (currentBitmapHeight < height) {
361 | translateY = (height - scaledHeight) / 2f;
362 | } else {
363 | translateY = totalTranslateY * scaledRatio + centerPointY * (1 - scaledRatio);
364 | // 进行边界检查,保证图片缩放后在垂直方向上不会偏移出屏幕
365 | if (translateY > 0) {
366 | translateY = 0;
367 | } else if (height - translateY > scaledHeight) {
368 | translateY = height - scaledHeight;
369 | }
370 | }
371 | // 缩放后对图片进行偏移,以保证缩放后中心点位置不变
372 | matrix.postTranslate(translateX, translateY);
373 | totalTranslateX = translateX;
374 | totalTranslateY = translateY;
375 | currentBitmapWidth = scaledWidth;
376 | currentBitmapHeight = scaledHeight;
377 | canvas.drawBitmap(sourceBitmap, matrix, null);
378 | }
379 |
380 | /**
381 | * 对图片进行平移处理
382 | *
383 | * @param canvas
384 | */
385 | private void move(Canvas canvas) {
386 | matrix.reset();
387 | // 根据手指移动的距离计算出总偏移值
388 | float translateX = totalTranslateX + movedDistanceX;
389 | float translateY = totalTranslateY + movedDistanceY;
390 | // 先按照已有的缩放比例对图片进行缩放
391 | matrix.postScale(totalRatio, totalRatio);
392 | // 再根据移动距离进行偏移
393 | matrix.postTranslate(translateX, translateY);
394 | totalTranslateX = translateX;
395 | totalTranslateY = translateY;
396 | if (null != sourceBitmap) canvas.drawBitmap(sourceBitmap, matrix, null);
397 | // else
398 | // T.showShort(getContext(), "sourceBitmap ==null");
399 | }
400 |
401 | /**
402 | * 对图片进行初始化操作,包括让图片居中,以及当图片大于屏幕宽高时对图片进行压缩。
403 | *
404 | * @param canvas
405 | */
406 | private void initBitmap(Canvas canvas) {
407 | if (sourceBitmap != null) {
408 | isInited = true;
409 | matrix.reset();
410 | int bitmapWidth = sourceBitmap.getWidth();
411 | int bitmapHeight = sourceBitmap.getHeight();
412 | if (bitmapWidth > width || bitmapHeight > height) {
413 | if (bitmapWidth - width > bitmapHeight - height) {
414 | // 当图片宽度大于屏幕宽度时,将图片等比例压缩,使它可以完全显示出来
415 | float ratio = width / (bitmapWidth * 1.0f);
416 | matrix.postScale(ratio, ratio);
417 | float translateY = (height - (bitmapHeight * ratio)) / 2f;
418 | // 在纵坐标方向上进行偏移,以保证图片居中显示
419 | matrix.postTranslate(0, translateY);
420 | totalTranslateY = translateY;
421 | totalRatio = initRatio = ratio;
422 | } else {
423 | // 当图片高度大于屏幕高度时,将图片等比例压缩,使它可以完全显示出来
424 | float ratio = height / (bitmapHeight * 1.0f);
425 | matrix.postScale(ratio, ratio);
426 | float translateX = (width - (bitmapWidth * ratio)) / 2f;
427 | // 在横坐标方向上进行偏移,以保证图片居中显示
428 | matrix.postTranslate(translateX, 0);
429 | totalTranslateX = translateX;
430 | totalRatio = initRatio = ratio;
431 | }
432 | currentBitmapWidth = bitmapWidth * initRatio;
433 | currentBitmapHeight = bitmapHeight * initRatio;
434 | } else {
435 | // 当图片的宽高都小于屏幕宽高时,直接让图片居中显示
436 | float translateX = (width - sourceBitmap.getWidth()) / 2f;
437 | float translateY = (height - sourceBitmap.getHeight()) / 2f;
438 | matrix.postTranslate(translateX, translateY);
439 | totalTranslateX = translateX;
440 | totalTranslateY = translateY;
441 | totalRatio = initRatio = 1f;
442 | currentBitmapWidth = bitmapWidth;
443 | currentBitmapHeight = bitmapHeight;
444 | }
445 | canvas.drawBitmap(sourceBitmap, matrix, null);
446 | }
447 | }
448 |
449 | /**
450 | * 计算两个手指之间的距离。
451 | *
452 | * @param event
453 | * @return 两个手指之间的距离
454 | */
455 | private double distanceBetweenFingers(MotionEvent event) {
456 | float disX = Math.abs(event.getX(0) - event.getX(1));
457 | float disY = Math.abs(event.getY(0) - event.getY(1));
458 | return Math.sqrt(disX * disX + disY * disY);
459 | }
460 |
461 | /**
462 | * 计算两个手指之间中心点的坐标。
463 | *
464 | * @param event
465 | */
466 | private void centerPointBetweenFingers(MotionEvent event) {
467 | float xPoint0 = event.getX(0);
468 | float yPoint0 = event.getY(0);
469 | float xPoint1 = event.getX(1);
470 | float yPoint1 = event.getY(1);
471 | centerPointX = (xPoint0 + xPoint1) / 2;
472 | centerPointY = (yPoint0 + yPoint1) / 2;
473 | }
474 |
475 | }
476 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhao/album/PickOrTakeImageActivity.java:
--------------------------------------------------------------------------------
1 | package com.zhao.album;
2 |
3 | import android.Manifest;
4 | import android.animation.ObjectAnimator;
5 | import android.animation.ValueAnimator;
6 | import android.annotation.TargetApi;
7 | import android.app.Activity;
8 | import android.app.AlertDialog;
9 | import android.app.Dialog;
10 | import android.content.ContentResolver;
11 | import android.content.Context;
12 | import android.content.DialogInterface;
13 | import android.content.Intent;
14 | import android.content.pm.PackageManager;
15 | import android.database.Cursor;
16 | import android.graphics.Bitmap;
17 | import android.graphics.drawable.BitmapDrawable;
18 | import android.net.Uri;
19 | import android.os.Build;
20 | import android.os.Bundle;
21 | import android.os.Handler;
22 | import android.os.Message;
23 | import android.provider.MediaStore;
24 | import android.support.v4.app.ActivityCompat;
25 | import android.support.v4.content.ContextCompat;
26 | import android.view.LayoutInflater;
27 | import android.view.MotionEvent;
28 | import android.view.View;
29 | import android.view.ViewGroup;
30 | import android.view.WindowManager;
31 | import android.view.animation.AlphaAnimation;
32 | import android.view.animation.Animation;
33 | import android.widget.AbsListView;
34 | import android.widget.AdapterView;
35 | import android.widget.BaseAdapter;
36 | import android.widget.Button;
37 | import android.widget.GridView;
38 | import android.widget.ImageView;
39 | import android.widget.ListView;
40 | import android.widget.RelativeLayout;
41 | import android.widget.TextView;
42 | import android.widget.Toast;
43 |
44 | import com.android.zzp.albumimageselect.R;
45 |
46 | import java.io.File;
47 | import java.io.IOException;
48 | import java.lang.ref.WeakReference;
49 | import java.text.SimpleDateFormat;
50 | import java.util.ArrayList;
51 | import java.util.Calendar;
52 | import java.util.TimeZone;
53 |
54 | /**
55 | * @author: zzp
56 | * @since: 2015-06-10
57 | * Description: 仿微信选取手机所有图片,或者拍照界面
58 | */
59 | public class PickOrTakeImageActivity extends Activity implements View.OnClickListener, AdapterView.OnItemClickListener,
60 | AbsListView.OnScrollListener, View.OnTouchListener{
61 |
62 | /** 按时间排序的所有图片list */
63 | private ArrayList allImages;
64 | /** 按目录排序的所有图片list */
65 | private ArrayList imageDirectories;
66 | /** 选中图片的信息 */
67 | ArrayList picklist = new ArrayList();
68 |
69 | private MyHandler handler;
70 |
71 | /** 当前显示的文件夹路径,全部-- -1 */
72 | private int currentShowPosition;
73 |
74 | private GridView gridView = null;
75 | private int firstVisibleItem = 0;
76 | private int currentState = SCROLL_STATE_IDLE;
77 | private int currentTouchState = MotionEvent.ACTION_UP;
78 |
79 | private TextView tv_choose_image_directory;
80 | private View v_line;
81 | private TextView tv_preview;
82 | private RelativeLayout rl_bottom;
83 | private RelativeLayout rl_date;
84 | private TextView tv_date;
85 |
86 | private Button btn_choose_finish;
87 |
88 | private LayoutInflater inflater = null;
89 | private GridViewAdapter adapter;
90 |
91 | //拍照的文件的文件名
92 | String tempPath = null;
93 |
94 | /** 选择文件夹的弹出框 */
95 | // private PopupWindow window;
96 | private RelativeLayout rl_choose_directory;
97 | private ListView listView;
98 | private ListviewAdapter listviewAdapter;
99 |
100 | private ObjectAnimator animation;
101 | private ObjectAnimator reverseanimation;
102 |
103 | private Animation alphaAnimation = new AlphaAnimation(1.0f, 0.0f);
104 | // private TranslateAnimation animation;
105 | // private TranslateAnimation reverseanimation;
106 |
107 | /** 每张图片需要显示的高度和宽度 */
108 | private int perWidth;
109 |
110 | /** 选择图片的数量总数,默认为9 */
111 | private int picNums = 9;
112 | /** 当前选中的图片数量 */
113 | private int currentPicNums = 0;
114 |
115 | /** 最新一张图片的时间 */
116 | private long lastPicTime = 0;
117 |
118 | public static final String EXTRA_NUMS = "extra_nums";
119 | public static final int CODE_FOR_PIC_BIG = 1;
120 | public static final int CODE_FOR_PIC_BIG_PREVIEW = 2;
121 | public static final int CODE_FOR_TAKE_PIC = 3;
122 | public static final int CODE_FOR_WRITE_PERMISSION = 100;
123 |
124 | @Override
125 | public void onCreate(Bundle savedInstanceState) {
126 | super.onCreate(savedInstanceState);
127 | setContentView(R.layout.activity_pick_or_take_image_activity);
128 | initView();
129 | initData();
130 | }
131 |
132 | @TargetApi(Build.VERSION_CODES.HONEYCOMB)
133 | protected void initView() {
134 | gridView = (GridView) findViewById(R.id.gv_content);
135 | gridView.setOnTouchListener(this);
136 |
137 | tv_choose_image_directory = (TextView) findViewById(R.id.tv_choose_image_directory);
138 | tv_preview = (TextView) findViewById(R.id.tv_preview);
139 | v_line = findViewById(R.id.v_line);
140 | rl_bottom = (RelativeLayout) findViewById(R.id.rl_bottom);
141 | rl_bottom.setOnClickListener(this);
142 |
143 | rl_date = (RelativeLayout) findViewById(R.id.rl_date);
144 | tv_date = (TextView) findViewById(R.id.tv_date);
145 |
146 | // listView = new ListView(this);
147 |
148 | rl_choose_directory = (RelativeLayout) findViewById(R.id.rl_choose_directory);
149 | listView = (ListView) findViewById(R.id.lv_directories);
150 | listView.setOnItemClickListener(this);
151 | listviewAdapter = new ListviewAdapter();
152 |
153 | // animation = new TranslateAnimation(0, 0, 0, -CommonUtil.dip2px(this, 300));
154 | // reverseanimation = new TranslateAnimation(0, 0, -CommonUtil.dip2px(this, 300), 0);
155 | if (Build.VERSION.SDK_INT < 11){
156 | // no animation cause low SDK version
157 | }else{
158 | animation = ObjectAnimator.ofInt(listView, "bottomMargin", -CommonUtil.dip2px(this, 400), 0);
159 | animation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
160 | @Override
161 | public void onAnimationUpdate(ValueAnimator valueAnimator) {
162 | int value = (Integer) valueAnimator.getAnimatedValue();
163 | RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) listView.getLayoutParams();
164 | rl_choose_directory.setAlpha(1 - Math.abs(value / CommonUtil.dip2px(PickOrTakeImageActivity.this, 400)));
165 | params.bottomMargin = value;
166 | listView.setLayoutParams(params);
167 | listView.invalidate();
168 | rl_choose_directory.invalidate();
169 | }
170 | });
171 | animation.setDuration(500);
172 |
173 | reverseanimation = ObjectAnimator.ofInt(listView, "bottomMargin", 0, -CommonUtil.dip2px(this, 400));
174 | reverseanimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
175 | @Override
176 | public void onAnimationUpdate(ValueAnimator valueAnimator) {
177 | int value = (Integer) valueAnimator.getAnimatedValue();
178 | RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) listView.getLayoutParams();
179 | params.bottomMargin = value;
180 | listView.setLayoutParams(params);
181 | rl_choose_directory.setAlpha(1 - Math.abs(value / CommonUtil.dip2px(PickOrTakeImageActivity.this, 400)));
182 | if (value <= -CommonUtil.dip2px(PickOrTakeImageActivity.this, 300)) {
183 | rl_choose_directory.setVisibility(View.GONE);
184 | }
185 | listView.invalidate();
186 | rl_choose_directory.invalidate();
187 | }
188 | });
189 | reverseanimation.setDuration(500);
190 | }
191 |
192 | alphaAnimation.setDuration(1000);
193 | alphaAnimation.setAnimationListener(new Animation.AnimationListener() {
194 | @Override
195 | public void onAnimationStart(Animation animation) {
196 | }
197 |
198 | @Override
199 | public void onAnimationEnd(Animation animation) {
200 | rl_date.setVisibility(View.GONE);
201 | }
202 |
203 | @Override
204 | public void onAnimationRepeat(Animation animation) {
205 | }
206 | });
207 |
208 | // LinearLayout parent = new LinearLayout(this);
209 | // parent.addView(listView);
210 |
211 | //不使用popupwindow方案
212 | // window = new PopupWindow();
213 | // window.setWidth(AppContext.getInstance().getScreenWidth());
214 | // window.setHeight(CommonUtil.dip2px(this, 300));
215 | // window.setContentView(parent);
216 | // window.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);
217 | // window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
218 | // window.setBackgroundDrawable(getResources().getDrawable(R.color.white));
219 |
220 | findViewById(R.id.iv_back).setOnClickListener(new View.OnClickListener() {
221 | @Override
222 | public void onClick(View v) {
223 | finish();
224 | }
225 | });
226 |
227 | ((TextView)findViewById(R.id.tv_title)).setText("选择图片");
228 |
229 | btn_choose_finish = (Button) findViewById(R.id.btn_choose_finish);
230 | btn_choose_finish.setOnClickListener(new View.OnClickListener() {
231 |
232 | @Override
233 | public void onClick(View v) {
234 | returnDataAndClose();
235 | }
236 | });
237 | }
238 |
239 | protected void initData() {
240 | inflater = LayoutInflater.from(this);
241 |
242 | allImages = new ArrayList<>();
243 | imageDirectories = new ArrayList<>();
244 |
245 | handler = new MyHandler(this);
246 | //默认显示全部图片
247 | currentShowPosition = -1;
248 | adapter = new GridViewAdapter();
249 |
250 | getAllImages();
251 |
252 | tv_choose_image_directory.setText(getString(R.string.all_pic));
253 | tv_preview.setText(getString(R.string.preview_without_num));
254 |
255 | rl_choose_directory.setOnClickListener(this);
256 | tv_choose_image_directory.setOnClickListener(this);
257 | tv_preview.setOnClickListener(this);
258 | //计算每张图片应该显示的宽度
259 | perWidth = (((WindowManager) (AppContext.getInstance().getSystemService(Context.WINDOW_SERVICE))).getDefaultDisplay().getWidth() - CommonUtil.dip2px(this, 4))/3;
260 |
261 | picNums = getIntent().getIntExtra(EXTRA_NUMS, 9);
262 |
263 | if (picNums == 1){
264 | tv_preview.setVisibility(View.GONE);
265 | v_line.setVisibility(View.GONE);
266 | btn_choose_finish.setVisibility(View.GONE);
267 | }else{
268 | btn_choose_finish.setText("完成");
269 | }
270 | }
271 |
272 | /**
273 | * 6.0版本之后需要动态申请权限
274 | */
275 | private void getAllImages(){
276 | //使用兼容库就无需判断系统版本
277 | int hasWriteContactsPermission = ContextCompat.checkSelfPermission(getApplication(), Manifest.permission.WRITE_EXTERNAL_STORAGE);
278 | if (hasWriteContactsPermission == PackageManager.PERMISSION_GRANTED) {
279 | startGetImageThread();
280 | }
281 | //需要弹出dialog让用户手动赋予权限
282 | else{
283 | ActivityCompat.requestPermissions(PickOrTakeImageActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, CODE_FOR_WRITE_PERMISSION);
284 | }
285 | }
286 |
287 | /**
288 | * 从手机中获取所有的手机图片
289 | */
290 | private void startGetImageThread(){
291 | new Thread(new Runnable() {
292 | @Override
293 | public void run() {
294 | Uri uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
295 | ContentResolver contentResolver = getContentResolver();
296 | //获取jpeg和png格式的文件,并且按照时间进行倒序
297 | Cursor cursor = contentResolver.query(uri, null, MediaStore.Images.Media.MIME_TYPE + "=\"image/jpeg\" or " +
298 | MediaStore.Images.Media.MIME_TYPE + "=\"image/png\"", null, MediaStore.Images.Media.DATE_MODIFIED+" desc");
299 | if (cursor != null){
300 | allImages.clear();
301 | while (cursor.moveToNext()){
302 | SingleImageModel singleImageModel = new SingleImageModel();
303 | singleImageModel.path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
304 | try {
305 | singleImageModel.date = Long.parseLong(cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATE_MODIFIED)));
306 | }catch (NumberFormatException e){
307 | singleImageModel.date = System.currentTimeMillis();
308 | }
309 | try {
310 | singleImageModel.id = Long.parseLong(cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID)));
311 | }catch (NumberFormatException e){
312 | singleImageModel.id = 0;
313 | }
314 | allImages.add(singleImageModel);
315 |
316 | //存入按照目录分配的list
317 | String path = singleImageModel.path;
318 | String parentPath = new File(path).getParent();
319 | putImageToParentDirectories(parentPath, path, singleImageModel.date, singleImageModel.id);
320 | }
321 | handler.sendEmptyMessage(0);
322 | }
323 | }
324 | }).start();
325 | }
326 |
327 | @Override
328 | public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
329 | if (requestCode == CODE_FOR_WRITE_PERMISSION){
330 | if (permissions[0].equals(Manifest.permission.WRITE_EXTERNAL_STORAGE)
331 | &&grantResults[0] == PackageManager.PERMISSION_GRANTED){
332 | //用户同意使用write
333 | startGetImageThread();
334 | }else{
335 | //用户不同意,向用户展示该权限作用
336 | if (!ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
337 | AlertDialog dialog = new AlertDialog.Builder(this)
338 | .setMessage("该相册需要赋予访问存储的权限,不开启将无法正常工作!")
339 | .setPositiveButton("确定", new DialogInterface.OnClickListener() {
340 | @Override
341 | public void onClick(DialogInterface dialog, int which) {
342 | finish();
343 | }
344 | })
345 | .setNegativeButton("取消", new DialogInterface.OnClickListener() {
346 | @Override
347 | public void onClick(DialogInterface dialog, int which) {
348 | finish();
349 | }
350 | }).create();
351 | dialog.show();
352 | return;
353 | }
354 | finish();
355 | }
356 | }
357 | }
358 |
359 | @Override
360 | public void onClick(View view) {
361 | int i = view.getId();
362 | if (i == R.id.tv_choose_image_directory) {// window.showAsDropDown(tv_choose_image_directory);
363 | if (Build.VERSION.SDK_INT < 11) {
364 | if (rl_choose_directory.getVisibility() == View.VISIBLE) {
365 | rl_choose_directory.setVisibility(View.GONE);
366 | } else {
367 | rl_choose_directory.setVisibility(View.VISIBLE);
368 | RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) listView.getLayoutParams();
369 | params.bottomMargin = 0;
370 | listView.setLayoutParams(params);
371 | ((ViewGroup) (listView.getParent())).invalidate();
372 | }
373 | } else {
374 | if (rl_choose_directory.getVisibility() == View.VISIBLE) {
375 | reverseanimation.start();
376 | } else {
377 | rl_choose_directory.setVisibility(View.VISIBLE);
378 | animation.start();
379 | }
380 | }
381 |
382 | } else if (i == R.id.tv_preview) {
383 | if (currentPicNums > 0) {
384 | Intent intent = new Intent();
385 | intent.setClass(PickOrTakeImageActivity.this, PickBigImagesActivity.class);
386 | intent.putExtra(PickBigImagesActivity.EXTRA_DATA, getChoosePicFromList());
387 | intent.putExtra(PickBigImagesActivity.EXTRA_ALL_PICK_DATA, picklist);
388 | intent.putExtra(PickBigImagesActivity.EXTRA_CURRENT_PIC, 0);
389 | intent.putExtra(PickBigImagesActivity.EXTRA_LAST_PIC, picNums - currentPicNums);
390 | intent.putExtra(PickBigImagesActivity.EXTRA_TOTAL_PIC, picNums);
391 | startActivityForResult(intent, CODE_FOR_PIC_BIG_PREVIEW);
392 | AlbumBitmapCacheHelper.getInstance().releaseHalfSizeCache();
393 | }
394 |
395 | } else if (i == R.id.rl_choose_directory) {
396 | if (Build.VERSION.SDK_INT < 11) {
397 | if (rl_choose_directory.getVisibility() == View.VISIBLE) {
398 | rl_choose_directory.setVisibility(View.GONE);
399 | } else {
400 | rl_choose_directory.setVisibility(View.VISIBLE);
401 | RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) listView.getLayoutParams();
402 | params.bottomMargin = 0;
403 | listView.setLayoutParams(params);
404 | ((ViewGroup) (listView.getParent())).invalidate();
405 | }
406 | } else {
407 | if (rl_choose_directory.getVisibility() == View.VISIBLE) {
408 | reverseanimation.start();
409 | } else {
410 | rl_choose_directory.setVisibility(View.VISIBLE);
411 | animation.start();
412 | }
413 | }
414 |
415 | } else {
416 | }
417 | }
418 |
419 | @Override
420 | public void onItemClick(AdapterView> adapterView, View view, int i, long l) {
421 | AlbumBitmapCacheHelper.getInstance().removeAllThreads();
422 | //点击的全部图片
423 | if(!(currentShowPosition == i-1)){
424 | currentShowPosition = i-1;
425 | reloadDataByChooseDirectory();
426 | }
427 | }
428 |
429 | /**
430 | * 重新加载当前页面数据
431 | */
432 | private void reloadDataByChooseDirectory(){
433 | if(currentShowPosition == -1){
434 | tv_choose_image_directory.setText(getString(R.string.all_pic));
435 | }else {
436 | tv_choose_image_directory.setText(new File(imageDirectories.get(currentShowPosition).directoryPath).getName());
437 | }
438 | //去除当前正在加载的所有图片,重新开始
439 | AlbumBitmapCacheHelper.getInstance().removeAllThreads();
440 | gridView.setAdapter(adapter);
441 | gridView.smoothScrollToPosition(0);
442 | View v = listView.findViewWithTag("picked");
443 | if (v != null) {
444 | v.setVisibility(View.GONE);
445 | v.setTag(null);
446 | }
447 | v = (View) listView.findViewWithTag(currentShowPosition + 1).getParent().getParent();
448 | if (v != null) {
449 | v.findViewById(R.id.iv_directory_check).setVisibility(View.VISIBLE);
450 | v.findViewById(R.id.iv_directory_check).setTag("picked");
451 | }
452 | if (Build.VERSION.SDK_INT < 11){
453 | rl_choose_directory.setVisibility(View.GONE);
454 | }else {
455 | reverseanimation.start();
456 | }
457 | }
458 |
459 | @Override
460 | public void onBackPressed() {
461 | if(rl_choose_directory.getVisibility() == View.VISIBLE){
462 | if (Build.VERSION.SDK_INT < 11){
463 | rl_choose_directory.setVisibility(View.GONE);
464 | }else {
465 | reverseanimation.start();
466 | }
467 | }else {
468 | //离开此页面之后记住要清空cache内存
469 | AlbumBitmapCacheHelper.getInstance().clearCache();
470 | super.onBackPressed();
471 | }
472 | }
473 |
474 | @Override
475 | public void onScrollStateChanged(AbsListView absListView, int i) {
476 | currentState = i;
477 | if (currentState == SCROLL_STATE_IDLE){
478 | rl_date.setAnimation(alphaAnimation);
479 | alphaAnimation.startNow();
480 | }
481 | if (currentTouchState == MotionEvent.ACTION_UP && currentState != SCROLL_STATE_FLING){
482 | rl_date.setAnimation(alphaAnimation);
483 | alphaAnimation.startNow();
484 | }
485 | }
486 |
487 | @Override
488 | public void onScroll(AbsListView absListView, int i, int i1, int i2) {
489 | firstVisibleItem = i;
490 | //保证当选择全部文件夹的时候,显示的时间为第一个图片,排除第一个拍照图片
491 | if (currentShowPosition == -1 && firstVisibleItem > 0)
492 | firstVisibleItem --;
493 | if(lastPicTime != getImageDirectoryModelDateFromMapById(firstVisibleItem)) {
494 | lastPicTime = getImageDirectoryModelDateFromMapById(firstVisibleItem);
495 | }
496 | if (currentState == SCROLL_STATE_TOUCH_SCROLL){
497 | showTimeLine(lastPicTime);
498 | }
499 | if (currentTouchState == MotionEvent.ACTION_UP && currentState == SCROLL_STATE_FLING){
500 | showTimeLine(lastPicTime);
501 | }
502 | }
503 |
504 | @Override
505 | public boolean onTouch(View view, MotionEvent motionEvent) {
506 | switch (motionEvent.getAction()){
507 | case MotionEvent.ACTION_DOWN:
508 | currentTouchState = MotionEvent.ACTION_DOWN;
509 | break;
510 | case MotionEvent.ACTION_MOVE:
511 | currentTouchState = MotionEvent.ACTION_MOVE;
512 | break;
513 | case MotionEvent.ACTION_UP:
514 | currentTouchState = MotionEvent.ACTION_UP;
515 | break;
516 | }
517 | return false;
518 | }
519 |
520 | /**
521 | * leak memory
522 | */
523 | private static class MyHandler extends Handler{
524 |
525 | WeakReference activity = null;
526 |
527 | public MyHandler(PickOrTakeImageActivity context){
528 | activity = new WeakReference(context);
529 | }
530 |
531 | @Override
532 | public void handleMessage(Message msg) {
533 | if (activity.get() == null)
534 | return;
535 | if (activity.get().gridView.getAdapter() == null){
536 | activity.get().gridView.setAdapter(activity.get().adapter);
537 | }else
538 | activity.get().adapter.notifyDataSetChanged();
539 | activity.get().listView.setAdapter(activity.get().listviewAdapter);
540 | activity.get().gridView.setOnScrollListener(activity.get());
541 | super.handleMessage(msg);
542 | }
543 | }
544 |
545 | /**
546 | * gridview适配器
547 | */
548 | private class GridViewAdapter extends BaseAdapter{
549 |
550 | @Override
551 | public int getCount() {
552 | int size = 0;
553 | //如果显示全部图片,则第一项为
554 | if(currentShowPosition == -1){
555 | size = allImages.size() + 1;
556 | }else{
557 | size = imageDirectories.get(currentShowPosition).images.getImageCounts();
558 | }
559 | return size;
560 | }
561 |
562 | @Override
563 | public Object getItem(int i) {
564 | return null;
565 | }
566 |
567 | @Override
568 | public long getItemId(int i) {
569 | return i;
570 | }
571 |
572 | @Override
573 | public View getView(int i, View view, ViewGroup viewGroup) {
574 | //第一个要显示拍摄照片图片
575 | if (currentShowPosition == -1 && i==0){
576 | view = new ImageView(PickOrTakeImageActivity.this);
577 | ((ImageView)view).setBackgroundResource(R.drawable.take_pic);
578 | view.setOnClickListener(new View.OnClickListener() {
579 | @Override
580 | public void onClick(View v) {
581 | takePic();
582 | }
583 | });
584 | view.setLayoutParams(new GridView.LayoutParams(perWidth, perWidth));
585 | return view;
586 | }
587 | //在此处直接进行处理最好,能够省去其他部分的处理,其他部分直接可以使用原来的数据结构
588 | if (currentShowPosition == -1)
589 | i--;
590 | //其他部分的处理
591 | final String path = getImageDirectoryModelUrlFromMapById(i);
592 | lastPicTime = getImageDirectoryModelDateFromMapById(i);
593 | if(view==null || view.getTag()==null){
594 | view = inflater.inflate(R.layout.item_pick_up_image, null);
595 | GridViewHolder holder = new GridViewHolder();
596 | holder.iv_content = (ImageView) view.findViewById(R.id.iv_content);
597 | holder.v_gray_masking = view.findViewById(R.id.v_gray_masking);
598 | holder.iv_pick_or_not = (ImageView) view.findViewById(R.id.iv_pick_or_not);
599 | if(picNums == 1){
600 | holder.iv_pick_or_not.setVisibility(View.GONE);
601 | }
602 |
603 | OnclickListenerWithHolder listener = new OnclickListenerWithHolder(holder);
604 | holder.iv_content.setOnClickListener(listener);
605 | holder.iv_pick_or_not.setOnClickListener(listener);
606 | view.setTag(holder);
607 | //要在这进行设置,在外面设置会导致第一个项点击效果异常
608 | view.setLayoutParams(new GridView.LayoutParams(perWidth, perWidth));
609 | }
610 | final GridViewHolder holder = (GridViewHolder) view.getTag();
611 | //一定不要忘记更新position
612 | holder.position = i;
613 | //如果该图片被选中,则讲状态变为选中状态
614 | if (getImageDirectoryModelStateFromMapById(i)){
615 | holder.v_gray_masking.setVisibility(View.VISIBLE);
616 | holder.iv_pick_or_not.setImageResource(R.drawable.image_choose);
617 | }else{
618 | holder.v_gray_masking.setVisibility(View.GONE);
619 | holder.iv_pick_or_not.setImageResource(R.drawable.image_not_chose);
620 | }
621 | //优化显示效果
622 | if(holder.iv_content.getTag() != null) {
623 | String remove = (String) holder.iv_content.getTag();
624 | AlbumBitmapCacheHelper.getInstance().removePathFromShowlist(remove);
625 | }
626 | AlbumBitmapCacheHelper.getInstance().addPathToShowlist(path);
627 | holder.iv_content.setTag(path);
628 | Bitmap bitmap = AlbumBitmapCacheHelper.getInstance().getBitmap(path, perWidth, perWidth, new AlbumBitmapCacheHelper.ILoadImageCallback() {
629 | @Override
630 | public void onLoadImageCallBack(Bitmap bitmap, String path1, Object... objects) {
631 | if (bitmap == null) {
632 | return;
633 | }
634 | BitmapDrawable bd = new BitmapDrawable(getResources(), bitmap);
635 | View v = gridView.findViewWithTag(path1);
636 | if (v != null)
637 | v.setBackgroundDrawable(bd);
638 | }
639 | }, i);
640 | if (bitmap != null){
641 | BitmapDrawable bd = new BitmapDrawable(getResources(), bitmap);
642 | holder.iv_content.setBackgroundDrawable(bd);
643 | }else{
644 | holder.iv_content.setBackgroundResource(R.drawable.ic_product_9);
645 | }
646 | return view;
647 | }
648 | }
649 |
650 | private class GridViewHolder{
651 | public ImageView iv_content;
652 | public View v_gray_masking;
653 | public ImageView iv_pick_or_not;
654 | public int position;
655 | }
656 |
657 | /**
658 | * 调用系统相机进行拍照
659 | */
660 | private void takePic(){
661 | String name = "temp";
662 | if (!new File(CommonUtil.getDataPath()).exists())
663 | new File(CommonUtil.getDataPath()).mkdirs();
664 | tempPath = CommonUtil.getDataPath() + name + ".jpg";
665 | File file = new File(tempPath);
666 | try {
667 | if (file.exists())
668 | file.delete();
669 | file.createNewFile();
670 | }catch (IOException e){
671 | e.printStackTrace();
672 | }
673 | Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
674 | intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file));
675 | startActivityForResult(intent, CODE_FOR_TAKE_PIC);
676 | }
677 |
678 | /**
679 | * 展示顶部的时间
680 | */
681 | private void showTimeLine(long date){
682 | alphaAnimation.cancel();
683 | rl_date.setVisibility(View.VISIBLE);
684 | tv_date.setText(calculateShowTime(date*1000));
685 | }
686 |
687 | /**
688 | * 计算照片的具体时间
689 | * @param time
690 | * @return
691 | */
692 | private String calculateShowTime(long time){
693 |
694 | final Calendar c = Calendar.getInstance();
695 | c.setTimeZone(TimeZone.getTimeZone("GMT+8:00"));
696 | int mDayWeek = c.get(Calendar.DAY_OF_WEEK);
697 | mDayWeek -- ;
698 | //习惯性的还是定周一为第一天
699 | if (mDayWeek == 0)
700 | mDayWeek = 7;
701 | int mWeek = c.get(Calendar.WEEK_OF_MONTH);
702 | int mHour = c.get(Calendar.HOUR_OF_DAY);
703 | int mMinute = c.get(Calendar.MINUTE);
704 |
705 | if((System.currentTimeMillis()-time) < (mHour*60 + mMinute)*60*1000){
706 | return "今天";
707 | }else if((System.currentTimeMillis()-time) < (mDayWeek)*24*60*60*1000){
708 | return "本周";
709 | }else if((System.currentTimeMillis()-time) < ((long)((mWeek-1)*7+mDayWeek))*24*60*60*1000){
710 | return "这个月";
711 | }else{
712 | SimpleDateFormat format = new SimpleDateFormat("yyyy/MM", java.util.Locale.getDefault());
713 | return format.format(time);
714 | }
715 | }
716 |
717 | private class ListviewAdapter extends BaseAdapter{
718 |
719 | @Override
720 | public int getCount() {
721 | if (imageDirectories.size() == 0)
722 | return 0;
723 | else
724 | return imageDirectories.size() + 1;
725 | }
726 |
727 | @Override
728 | public Object getItem(int i) {
729 | return null;
730 | }
731 |
732 | @Override
733 | public long getItemId(int i) {
734 | return i;
735 | }
736 |
737 | @Override
738 | public int getItemViewType(int position) {
739 | if(position == 0) {
740 | return 0;
741 | }
742 | return 1;
743 | }
744 |
745 | @Override
746 | public int getViewTypeCount() {
747 | return 2;
748 | }
749 |
750 | @Override
751 | public View getView(int i, View view, ViewGroup viewGroup) {
752 | if(view==null || view.getTag()==null){
753 | view = inflater.inflate(R.layout.item_list_view_album_directory, null);
754 | ListViewHolder holder = new ListViewHolder();
755 | holder.iv_directory_pic = (ImageView) view.findViewById(R.id.iv_directory_pic);
756 | holder.tv_directory_name = (TextView) view.findViewById(R.id.tv_directory_name);
757 | holder.iv_directory_check = (ImageView) view.findViewById(R.id.iv_directory_check);
758 | holder.tv_directory_nums = (TextView) view.findViewById(R.id.tv_directory_nums);
759 | view.setTag(holder);
760 | }
761 | final ListViewHolder holder = (ListViewHolder) view.getTag();
762 | holder.position = i;
763 | holder.tv_directory_name.setTag(i);
764 | String path = null;
765 | //全部图片
766 | if(getItemViewType(i) == 0){
767 | holder.tv_directory_name.setText(getString(R.string.all_pic) + " ");
768 | int size = 0;
769 | for (SingleImageDirectories directories : imageDirectories)
770 | size += directories.images.getImageCounts();
771 | holder.tv_directory_nums.setText(size +"张");
772 | //获取第0个位置的图片,即第一张图片展示
773 | path = imageDirectories.get(0).images.getImagePath(0);
774 | if(currentShowPosition == -1){
775 | holder.iv_directory_check.setTag("picked");
776 | holder.iv_directory_check.setVisibility(View.VISIBLE);
777 | }else{
778 | holder.iv_directory_check.setTag(null);
779 | holder.iv_directory_check.setVisibility(View.INVISIBLE);
780 | }
781 | }else{
782 | holder.tv_directory_nums.setText(imageDirectories.get(i-1).images.getImageCounts() +"张");
783 | if(currentShowPosition == i-1){
784 | holder.iv_directory_check.setTag("picked");
785 | holder.iv_directory_check.setVisibility(View.VISIBLE);
786 | }else{
787 | holder.iv_directory_check.setTag(null);
788 | holder.iv_directory_check.setVisibility(View.INVISIBLE);
789 | }
790 | holder.tv_directory_name.setText(new File(imageDirectories.get(i-1).directoryPath).getName()+" ");
791 | //获取第0个位置的图片,即第一张图片展示
792 | path = imageDirectories.get(i-1).images.getImagePath(0);
793 | }
794 | if(path == null)
795 | return null;
796 | if (holder.iv_directory_pic.getTag() != null) {
797 | AlbumBitmapCacheHelper.getInstance().removePathFromShowlist((String) (holder.iv_directory_pic.getTag()));
798 | }
799 | AlbumBitmapCacheHelper.getInstance().addPathToShowlist(path);
800 | if(getItemViewType(i) == 0) {
801 | holder.iv_directory_pic.setTag(path + "all");
802 | }
803 | else
804 | holder.iv_directory_pic.setTag(path);
805 | Bitmap bitmap = AlbumBitmapCacheHelper.getInstance().getBitmap(path, 225, 225, new AlbumBitmapCacheHelper.ILoadImageCallback() {
806 | @Override
807 | public void onLoadImageCallBack(Bitmap bitmap, String path, Object... objects) {
808 | if (bitmap == null) return;
809 | BitmapDrawable bd = new BitmapDrawable(getResources(), bitmap);
810 | View v = null;
811 | if (objects[0].toString().equals("0")) {
812 | v = listView.findViewWithTag(path + "all");
813 | } else {
814 | v = listView.findViewWithTag(path);
815 | }
816 | if (v != null) v.setBackgroundDrawable(bd);
817 | }
818 | }, getItemViewType(i));
819 | if (bitmap != null){
820 | BitmapDrawable bd = new BitmapDrawable(getResources(), bitmap);
821 | holder.iv_directory_pic.setBackgroundDrawable(bd);
822 | }else{
823 | holder.iv_directory_pic.setBackgroundResource(R.drawable.ic_product_9);
824 | }
825 | return view;
826 | }
827 | }
828 |
829 | private class ListViewHolder{
830 | public ImageView iv_directory_pic;
831 | public TextView tv_directory_name;
832 | public ImageView iv_directory_check;
833 | public TextView tv_directory_nums;
834 | public int position;
835 | }
836 |
837 | /**
838 | * 根据id获取map中相对应的图片路径
839 | */
840 | private String getImageDirectoryModelUrlFromMapById(int position){
841 | //如果是选择的全部图片
842 | if(currentShowPosition == -1){
843 | return allImages.get(position).path;
844 | }else{
845 | return imageDirectories.get(currentShowPosition).images.getImagePath(position);
846 | }
847 | }
848 |
849 | /**
850 | * 根据id获取map中相对应的图片时间
851 | */
852 | private long getImageDirectoryModelDateFromMapById(int position){
853 | if (allImages.size() ==0){
854 | return System.currentTimeMillis();
855 | }
856 | //如果是选择的全部图片
857 | if(currentShowPosition == -1){
858 | return allImages.get(position).date;
859 | }else{
860 | return imageDirectories.get(currentShowPosition).images.getImages().get(position).date;
861 | }
862 | }
863 |
864 | /**
865 | * 根据id获取map中相对应的图片选中状态
866 | */
867 | private boolean getImageDirectoryModelStateFromMapById(int position){
868 | //如果是选择的全部图片
869 | if(currentShowPosition == -1){
870 | return allImages.get(position).isPicked;
871 | }else{
872 | return imageDirectories.get(currentShowPosition).images.getImagePickOrNot(position);
873 | }
874 | }
875 |
876 | /**
877 | * 转变该位置图片的选中状态
878 | * @param position
879 | */
880 | private void toggleImageDirectoryModelStateFromMapById(int position){
881 | //如果是选择的全部图片
882 | if(currentShowPosition == -1){
883 | allImages.get(position).isPicked = !allImages.get(position).isPicked;
884 | for (SingleImageDirectories directories : imageDirectories){
885 | directories.images.toggleSetImage(allImages.get(position).path);
886 | }
887 | }else{
888 | imageDirectories.get(currentShowPosition).images.toggleSetImage(position);
889 | for (SingleImageModel model : allImages){
890 | if (model.path.equalsIgnoreCase(imageDirectories.get(currentShowPosition).images.getImagePath(position)))
891 | model.isPicked = !model.isPicked;
892 | }
893 | }
894 | }
895 |
896 | /**
897 | * 带holder的监听器
898 | */
899 | private class OnclickListenerWithHolder implements View.OnClickListener{
900 | GridViewHolder holder;
901 |
902 | public OnclickListenerWithHolder(GridViewHolder holder){
903 | this.holder = holder;
904 | }
905 |
906 | @Override
907 | public void onClick(View view) {
908 | int position = holder.position;
909 | int i = view.getId();
910 | if (i == R.id.iv_content) {
911 | if (picNums > 1) {
912 | Intent intent = new Intent();
913 | intent.setClass(PickOrTakeImageActivity.this, PickBigImagesActivity.class);
914 | //TODO 这里由于涉及到intent传递的数据不能太大的问题,所以如果需要,这里需要进行另外的处理,写入到内存或者写入到文件中
915 | intent.putExtra(PickBigImagesActivity.EXTRA_DATA, getAllImagesFromCurrentDirectory());
916 | intent.putExtra(PickBigImagesActivity.EXTRA_ALL_PICK_DATA, picklist);
917 | intent.putExtra(PickBigImagesActivity.EXTRA_CURRENT_PIC, position);
918 | intent.putExtra(PickBigImagesActivity.EXTRA_LAST_PIC, picNums - currentPicNums);
919 | intent.putExtra(PickBigImagesActivity.EXTRA_TOTAL_PIC, picNums);
920 | startActivityForResult(intent, CODE_FOR_PIC_BIG);
921 | AlbumBitmapCacheHelper.getInstance().releaseHalfSizeCache();
922 | }else{
923 | picklist.add(getImageDirectoryModelUrlFromMapById(holder.position));
924 | currentPicNums++;
925 | returnDataAndClose();
926 | }
927 |
928 | } else if (i == R.id.iv_pick_or_not) {
929 | toggleImageDirectoryModelStateFromMapById(position);
930 | if (getImageDirectoryModelStateFromMapById(position)) {
931 | if (currentPicNums == picNums) {
932 | toggleImageDirectoryModelStateFromMapById(position);
933 | Toast.makeText(PickOrTakeImageActivity.this, String.format(getString(R.string.choose_pic_num_out_of_index), picNums), Toast.LENGTH_SHORT).show();
934 | return;
935 | }
936 | picklist.add(getImageDirectoryModelUrlFromMapById(holder.position));
937 | holder.iv_pick_or_not.setImageResource(R.drawable.image_choose);
938 | holder.v_gray_masking.setVisibility(View.VISIBLE);
939 | currentPicNums++;
940 | if (currentPicNums == 1) {
941 | btn_choose_finish.setTextColor(getResources().getColor(R.color.white));
942 | }
943 | tv_preview.setText(String.format(getString(R.string.preview_with_num), currentPicNums));
944 | btn_choose_finish.setText(String.format(getString(R.string.choose_pic_finish_with_num), currentPicNums, picNums));
945 | } else {
946 | picklist.remove(getImageDirectoryModelUrlFromMapById(holder.position));
947 | holder.iv_pick_or_not.setImageResource(R.drawable.image_not_chose);
948 | holder.v_gray_masking.setVisibility(View.GONE);
949 | currentPicNums--;
950 | if (currentPicNums == 0) {
951 | btn_choose_finish.setTextColor(getResources().getColor(R.color.found_description_color));
952 | btn_choose_finish.setText(getString(R.string.choose_pic_finish));
953 | tv_preview.setText(getString(R.string.preview_without_num));
954 | } else {
955 | tv_preview.setText(String.format(getString(R.string.preview_with_num), currentPicNums));
956 | btn_choose_finish.setText(String.format(getString(R.string.choose_pic_finish_with_num), currentPicNums, picNums));
957 | }
958 | }
959 | // adapter.notifyDataSetChanged();
960 |
961 | } else {
962 | }
963 | }
964 | }
965 |
966 | @Override
967 | protected void onActivityResult(int requestCode, int resultCode, Intent data) {
968 | super.onActivityResult(requestCode, resultCode, data);
969 | switch (requestCode){
970 | case CODE_FOR_PIC_BIG:
971 | case CODE_FOR_PIC_BIG_PREVIEW:
972 | AlbumBitmapCacheHelper.getInstance().resizeCache();
973 | if(resultCode == RESULT_OK && data != null) {
974 | ArrayList temp = (ArrayList) data.getSerializableExtra("pick_data");
975 | //如果返回的list中含该path,但是picklist不含有该path,选中
976 | for (String path : temp){
977 | if (!picklist.contains(path)){
978 | View v = gridView.findViewWithTag(path);
979 | if(v != null) {
980 | ((ViewGroup) (v.getParent())).findViewById(R.id.v_gray_masking).setVisibility(View.VISIBLE);
981 | ((ImageView) ((ViewGroup) (v.getParent())).findViewById(R.id.iv_pick_or_not)).setImageResource(R.drawable.image_choose);
982 | }
983 | setPickStateFromHashMap(path, true);
984 | currentPicNums ++;
985 | }
986 | }
987 | //如果返回的list中不含该path,但是picklist含有该path,不选中
988 | for (String path : picklist){
989 | if (!temp.contains(path)){
990 | View v = gridView.findViewWithTag(path);
991 | if(v != null) {
992 | ((ViewGroup) (v.getParent())).findViewById(R.id.v_gray_masking).setVisibility(View.GONE);
993 | ((ImageView) ((ViewGroup) (v.getParent())).findViewById(R.id.iv_pick_or_not)).setImageResource(R.drawable.image_not_chose);
994 | }
995 | currentPicNums --;
996 | setPickStateFromHashMap(path, false);
997 | }
998 | }
999 | picklist = temp;
1000 | if (currentPicNums == 0) {
1001 | tv_preview.setText(getString(R.string.preview_without_num));
1002 | btn_choose_finish.setTextColor(getResources().getColor(R.color.found_description_color));
1003 | btn_choose_finish.setText(getString(R.string.choose_pic_finish));
1004 | }
1005 | else {
1006 | btn_choose_finish.setText(String.format(getString(R.string.choose_pic_finish_with_num), currentPicNums, picNums));
1007 | btn_choose_finish.setTextColor(getResources().getColor(R.color.white));
1008 | tv_preview.setText(String.format(getString(R.string.preview_with_num), currentPicNums));
1009 | }
1010 | boolean isFinish = data.getBooleanExtra("isFinish", false);
1011 | if (isFinish){
1012 | returnDataAndClose();
1013 | }
1014 | }
1015 | break;
1016 | case CODE_FOR_TAKE_PIC:
1017 | if (resultCode == RESULT_OK){
1018 | //临时文件的文件名
1019 | Toast.makeText(this, "拍照的图片 "+tempPath, Toast.LENGTH_LONG).show();
1020 |
1021 | //扫描最新的图片进相册
1022 | Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
1023 | Uri uri = Uri.fromFile(new File(tempPath));
1024 | intent.setData(uri);
1025 | sendBroadcast(intent);
1026 |
1027 | //重新拉取最新数据库文件
1028 | getAllImages();
1029 | }
1030 | break;
1031 | default:
1032 | break;
1033 | }
1034 | }
1035 |
1036 | /**
1037 | * 点击完成按钮之后将图片的地址返回到上一个页面
1038 | */
1039 | private void returnDataAndClose(){
1040 | AlbumBitmapCacheHelper.getInstance().clearCache();
1041 | if (currentPicNums == 0){
1042 | Toast.makeText(this, getString(R.string.not_choose_any_pick), Toast.LENGTH_SHORT).show();
1043 | return;
1044 | }
1045 | StringBuilder sb = new StringBuilder();
1046 | for (String model : picklist){
1047 | sb.append(model+"\n");
1048 | }
1049 | TextView textview = new TextView(this);
1050 | textview.setText(sb);
1051 | Dialog dialog = new Dialog(this);
1052 | dialog.setTitle("结果");
1053 | dialog.setContentView(textview);
1054 | dialog.show();
1055 | if (picNums == 1)
1056 | picklist.clear();
1057 | // Intent data = new Intent();
1058 | // data.putExtra("data", list);
1059 | // setResult(RESULT_OK, data);
1060 | // finish();
1061 | }
1062 |
1063 | /**
1064 | * 设置该图片的选中状态
1065 | */
1066 | private void setPickStateFromHashMap(String path, boolean isPick){
1067 | for (SingleImageDirectories directories : imageDirectories){
1068 | if(isPick)
1069 | directories.images.setImage(path);
1070 | else
1071 | directories.images.unsetImage(path);
1072 | }
1073 | for (SingleImageModel model : allImages){
1074 | if (model.path.equalsIgnoreCase(path))
1075 | model.isPicked = isPick;
1076 | }
1077 | }
1078 |
1079 | /**
1080 | * 获取所有的选中图片
1081 | */
1082 | private ArrayList getChoosePicFromList(){
1083 | ArrayList list = new ArrayList();
1084 | for (String path : picklist){
1085 | SingleImageModel model = new SingleImageModel(path, true, 0, 0);
1086 | list.add(model);
1087 | }
1088 | return list;
1089 | }
1090 |
1091 | /**
1092 | * 获取当前选中文件夹中给的所有图片
1093 | */
1094 | private ArrayList getAllImagesFromCurrentDirectory(){
1095 | ArrayList list = new ArrayList();
1096 | if(currentShowPosition == -1) {
1097 | for (SingleImageModel model : allImages) {
1098 | list.add(model);
1099 | }
1100 | }else{
1101 | for (SingleImageModel model : imageDirectories.get(currentShowPosition).images.getImages()) {
1102 | list.add(model);
1103 | }
1104 | }
1105 | return list;
1106 | }
1107 |
1108 | /**
1109 | * 将图片插入到对应parentPath路径的文件夹中
1110 | */
1111 | private void putImageToParentDirectories(String parentPath, String path, long date, long id){
1112 | ImageDirectoryModel model = getModelFromKey(parentPath);
1113 | if (model == null){
1114 | model = new ImageDirectoryModel();
1115 | SingleImageDirectories directories = new SingleImageDirectories();
1116 | directories.images = model;
1117 | directories.directoryPath = parentPath;
1118 | imageDirectories.add(directories);
1119 | }
1120 | model.addImage(path, date, id);
1121 | }
1122 |
1123 | private ImageDirectoryModel getModelFromKey(String path){
1124 | for (SingleImageDirectories directories : imageDirectories){
1125 | if(directories.directoryPath.equalsIgnoreCase(path)){
1126 | return directories.images;
1127 | }
1128 | }
1129 | return null;
1130 | }
1131 |
1132 | /**
1133 | * 一个文件夹中的图片数据实体
1134 | */
1135 | private class SingleImageDirectories{
1136 | /** 父目录的路径 */
1137 | public String directoryPath;
1138 | /** 目录下的所有图片实体 */
1139 | public ImageDirectoryModel images;
1140 | }
1141 | }
1142 |
--------------------------------------------------------------------------------