├── .gitignore
├── .travis.yml
├── LICENSE
├── PhotoPicker
├── .gitignore
├── build.gradle
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── me
│ │ └── iwf
│ │ └── photopicker
│ │ ├── PhotoPagerActivity.java
│ │ ├── PhotoPicker.java
│ │ ├── PhotoPickerActivity.java
│ │ ├── PhotoPreview.java
│ │ ├── adapter
│ │ ├── PhotoDialogAdapter.java
│ │ ├── PhotoGridAdapter.java
│ │ ├── PhotoPagerAdapter.java
│ │ ├── PopupDirectoryListAdapter.java
│ │ └── SelectableAdapter.java
│ │ ├── entity
│ │ ├── Photo.java
│ │ └── PhotoDirectory.java
│ │ ├── event
│ │ ├── OnItemCheckListener.java
│ │ ├── OnPhotoClickListener.java
│ │ ├── PhotoOnLongClick.java
│ │ ├── PhotoOnLongClickManager.java
│ │ └── Selectable.java
│ │ ├── fragment
│ │ ├── ImagePagerFragment.java
│ │ └── PhotoPickerFragment.java
│ │ ├── utils
│ │ ├── AndroidLifecycleUtils.java
│ │ ├── FileUtils.java
│ │ ├── ImageCaptureManager.java
│ │ ├── MediaStoreHelper.java
│ │ ├── PermissionsConstant.java
│ │ ├── PermissionsUtils.java
│ │ └── PhotoDirectoryLoader.java
│ │ └── widget
│ │ ├── SquareItemLayout.java
│ │ └── TouchImageView.java
│ └── res
│ ├── drawable-hdpi
│ ├── __picker_checkbox_marked.png
│ ├── __picker_checkbox_n.png
│ ├── __picker_ic_broken_image_black_48dp.png
│ ├── __picker_ic_camera_n.png
│ ├── __picker_ic_camera_p.png
│ ├── __picker_ic_delete_black_24dp.png
│ ├── __picker_ic_delete_n.png
│ ├── __picker_ic_delete_p.png
│ └── __picker_ic_photo_black_48dp.png
│ ├── drawable-mdpi
│ ├── __picker_checkbox_marked.png
│ ├── __picker_checkbox_n.png
│ ├── __picker_ic_broken_image_black_48dp.png
│ ├── __picker_ic_camera_n.png
│ ├── __picker_ic_camera_p.png
│ ├── __picker_ic_delete_black_24dp.png
│ ├── __picker_ic_delete_n.png
│ ├── __picker_ic_delete_p.png
│ └── __picker_ic_photo_black_48dp.png
│ ├── drawable-v21
│ └── __picker_bg_material_item.xml
│ ├── drawable-xhdpi
│ ├── __picker_checkbox_marked.png
│ ├── __picker_checkbox_n.png
│ ├── __picker_ic_broken_image_black_48dp.png
│ ├── __picker_ic_camera_n.png
│ ├── __picker_ic_camera_p.png
│ ├── __picker_ic_delete_black_24dp.png
│ ├── __picker_ic_delete_n.png
│ ├── __picker_ic_delete_p.png
│ ├── __picker_ic_gf_triangle_arrow.png
│ └── __picker_ic_photo_black_48dp.png
│ ├── drawable-xxhdpi
│ ├── __picker_checkbox_marked.png
│ ├── __picker_checkbox_n.png
│ ├── __picker_ic_broken_image_black_48dp.png
│ ├── __picker_ic_camera_n.png
│ ├── __picker_ic_camera_p.png
│ ├── __picker_ic_delete_black_24dp.png
│ ├── __picker_ic_delete_n.png
│ ├── __picker_ic_delete_p.png
│ └── __picker_ic_photo_black_48dp.png
│ ├── drawable-xxxhdpi
│ ├── __picker_checkbox_marked.png
│ ├── __picker_checkbox_n.png
│ ├── __picker_ic_broken_image_black_48dp.png
│ ├── __picker_ic_camera_n.png
│ ├── __picker_ic_camera_p.png
│ ├── __picker_ic_delete_black_24dp.png
│ ├── __picker_ic_delete_n.png
│ ├── __picker_ic_delete_p.png
│ └── __picker_ic_photo_black_48dp.png
│ ├── drawable
│ ├── __picker_bg_dialog.xml
│ ├── __picker_bg_material_item.xml
│ ├── __picker_camera.xml
│ ├── __picker_checkbox_bg.xml
│ ├── __picker_delete.xml
│ ├── __picker_item_dialog_selector.xml
│ ├── __picker_item_dialog_selector_bottom.xml
│ ├── __picker_item_dialog_selector_top.xml
│ └── __picker_photo_bg.xml
│ ├── layout
│ ├── __picker_activity_photo_crop.xml
│ ├── __picker_activity_photo_pager.xml
│ ├── __picker_activity_photo_picker.xml
│ ├── __picker_dialog_photo_pager.xml
│ ├── __picker_fragment_photo_picker.xml
│ ├── __picker_item_dialog.xml
│ ├── __picker_item_directory.xml
│ ├── __picker_item_photo.xml
│ ├── __picker_picker_fragment_image_pager.xml
│ ├── __picker_picker_item_pager.xml
│ └── __picker_toolbar.xml
│ ├── menu
│ ├── __picker_menu_picker.xml
│ └── __picker_menu_preview.xml
│ ├── values-es
│ └── strings.xml
│ ├── values-pt
│ └── strings.xml
│ ├── values-v21
│ └── colors.xml
│ ├── values-zh
│ └── strings.xml
│ ├── values
│ ├── colors.xml
│ ├── dimen.xml
│ ├── strings.xml
│ └── styles.xml
│ └── xml
│ └── __picker_provider_paths.xml
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── me
│ │ └── iwf
│ │ └── PhotoPickerDemo
│ │ ├── LineGridView.java
│ │ ├── MainActivity.java
│ │ ├── PhotoAdapter.java
│ │ ├── PreViewGridAdapter.java
│ │ ├── PreViewImgActivity.java
│ │ └── RecyclerItemClickListener.java
│ └── res
│ ├── drawable-hdpi
│ └── actionbar_back.png
│ ├── drawable
│ └── bg_item_photo.xml
│ ├── layout
│ ├── activity_main.xml
│ ├── activity_preview_img.xml
│ ├── alert_onlongclick.xml
│ ├── item_add.xml
│ └── item_img.xml
│ ├── mipmap-hdpi
│ └── ic_launcher.png
│ ├── mipmap-mdpi
│ └── ic_launcher.png
│ ├── mipmap-xhdpi
│ └── ic_launcher.png
│ ├── mipmap-xxhdpi
│ └── ic_launcher.png
│ ├── mipmap-xxxhdpi
│ └── ic_launcher.png
│ ├── values-zh
│ └── strings.xml
│ └── values
│ ├── colors.xml
│ ├── dimens.xml
│ ├── strings.xml
│ └── styles.xml
├── build.gradle
├── circle.sh
├── circle.yml
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── image
├── danxuancaijian.gif
├── duoxuan.gif
├── paizhao.gif
└── wangtu.gif
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 | ### Android template
3 | # Built application files
4 | *.apk
5 | *.ap_
6 |
7 | # Files for the ART/Dalvik VM
8 | *.dex
9 |
10 | # Java class files
11 | *.class
12 |
13 | # Generated files
14 | bin/
15 | gen/
16 | out/
17 |
18 | # Gradle files
19 | .gradle/
20 | build/
21 |
22 | # Local configuration file (sdk path, etc)
23 | local.properties
24 |
25 | # Proguard folder generated by Eclipse
26 | proguard/
27 |
28 | # Log Files
29 | *.log
30 |
31 | # Android Studio Navigation editor temp files
32 | .navigation/
33 |
34 | # Android Studio captures folder
35 | captures/
36 |
37 | # Intellij
38 | *.iml
39 | .idea/
40 |
41 | # Keystore files
42 | *.jks
43 |
44 | /art
45 |
46 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: android
2 | jdk: oraclejdk8
3 |
4 | before_install:
5 | - chmod +x gradlew
6 |
7 | android:
8 | components:
9 | - tools
10 | - platform-tools
11 | - build-tools-25.0.1
12 | - android-25
13 | - extra-android-m2repository
14 |
15 | notifications:
16 | email: false
17 |
18 | sudo: false
19 |
20 | script: ./gradlew clean build --stacktrace
21 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/PhotoPicker/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 | PhotoPicker-PhotoPicker.iml
--------------------------------------------------------------------------------
/PhotoPicker/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'com.github.dcendents.android-maven'
3 |
4 | android {
5 | compileSdkVersion 27
6 | buildToolsVersion "26.0.2"
7 | resourcePrefix "__picker_"
8 | lintOptions {
9 | abortOnError false
10 | checkReleaseBuilds false
11 | }
12 | defaultConfig {
13 | minSdkVersion 15
14 | targetSdkVersion 27
15 | }
16 | dexOptions {
17 | javaMaxHeapSize "4g"
18 | }
19 |
20 | buildTypes {
21 | release {
22 | minifyEnabled false
23 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
24 | }
25 | }
26 | }
27 |
28 | dependencies {
29 | compile "com.android.support:appcompat-v7:27.0.2"
30 | compile "com.android.support:design:27.0.2"
31 | compile "com.android.support:recyclerview-v7:27.0.2"
32 | compile 'com.nineoldandroids:library:2.4.0'
33 | compile 'com.yalantis:ucrop:2.2.0'
34 | compile 'com.github.bumptech.glide:glide:4.3.1'
35 | }
36 |
37 | // 指定编码
38 | tasks.withType(JavaCompile) {
39 | options.encoding = "UTF-8"
40 | }
41 |
42 | // 打包源码
43 | task sourcesJar(type: Jar) {
44 | from android.sourceSets.main.java.srcDirs
45 | classifier = 'sources'
46 | }
47 |
48 | task javadoc(type: Javadoc) {
49 | failOnError false
50 | source = android.sourceSets.main.java.sourceFiles
51 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
52 | classpath += configurations.compile
53 | }
54 |
55 | // 制作文档(Javadoc)
56 | task javadocJar(type: Jar, dependsOn: javadoc) {
57 | classifier = 'javadoc'
58 | from javadoc.destinationDir
59 | }
60 |
61 | artifacts {
62 | archives sourcesJar
63 | archives javadocJar
64 | }
65 |
66 |
--------------------------------------------------------------------------------
/PhotoPicker/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
15 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/PhotoPicker/src/main/java/me/iwf/photopicker/PhotoPagerActivity.java:
--------------------------------------------------------------------------------
1 | package me.iwf.photopicker;
2 |
3 | import android.content.DialogInterface;
4 | import android.content.Intent;
5 | import android.os.Build;
6 | import android.os.Bundle;
7 | import android.support.design.widget.Snackbar;
8 | import android.support.v4.view.ViewPager;
9 | import android.support.v7.app.ActionBar;
10 | import android.support.v7.app.AlertDialog;
11 | import android.support.v7.app.AppCompatActivity;
12 | import android.support.v7.widget.Toolbar;
13 | import android.view.Menu;
14 | import android.view.MenuItem;
15 | import android.view.View;
16 | import android.view.WindowManager;
17 |
18 | import java.util.ArrayList;
19 | import java.util.List;
20 |
21 | import me.iwf.photopicker.fragment.ImagePagerFragment;
22 |
23 | import static me.iwf.photopicker.PhotoPicker.KEY_SELECTED_PHOTOS;
24 | import static me.iwf.photopicker.PhotoPreview.EXTRA_CURRENT_ITEM;
25 | import static me.iwf.photopicker.PhotoPreview.EXTRA_LONG_DATA;
26 | import static me.iwf.photopicker.PhotoPreview.EXTRA_PHOTOS;
27 | import static me.iwf.photopicker.PhotoPreview.EXTRA_SHOW_DELETE;
28 | import static me.iwf.photopicker.PhotoPreview.EXTRA_SHOW_TOOLBAR;
29 |
30 | /**
31 | * Created by donglua on 15/6/24.
32 | */
33 |
34 | // modify PhotoPagerActivity.java add showToolbar
35 |
36 | public class PhotoPagerActivity extends AppCompatActivity {
37 |
38 | private ImagePagerFragment pagerFragment;
39 |
40 | private ActionBar actionBar;
41 | private boolean showDelete, showToolbar;
42 |
43 | @Override
44 | protected void onCreate(Bundle savedInstanceState) {
45 | super.onCreate(savedInstanceState);
46 | showToolbar = getIntent().getBooleanExtra(EXTRA_SHOW_TOOLBAR, true);
47 | if (!showToolbar) {
48 | getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
49 | }
50 |
51 | setContentView(R.layout.__picker_activity_photo_pager);
52 |
53 | int currentItem = getIntent().getIntExtra(EXTRA_CURRENT_ITEM, 0);
54 | List paths = getIntent().getStringArrayListExtra(EXTRA_PHOTOS);
55 | ArrayList longData = getIntent().getStringArrayListExtra(EXTRA_LONG_DATA);
56 |
57 | showDelete = getIntent().getBooleanExtra(EXTRA_SHOW_DELETE, true);
58 | if (!showToolbar) {
59 | showDelete = false;
60 | }
61 |
62 | if (pagerFragment == null) {
63 | pagerFragment =
64 | (ImagePagerFragment) getSupportFragmentManager().findFragmentById(R.id.photoPagerFragment);
65 | }
66 | pagerFragment.setPhotos(paths, currentItem,longData);
67 |
68 | Toolbar mToolbar = (Toolbar) findViewById(R.id.toolbar);
69 | setSupportActionBar(mToolbar);
70 |
71 | actionBar = getSupportActionBar();
72 |
73 | if (actionBar != null) {
74 | actionBar.setDisplayHomeAsUpEnabled(true);
75 | updateActionBarTitle();
76 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
77 | actionBar.setElevation(25);
78 | }
79 | }
80 |
81 |
82 | pagerFragment.getViewPager().addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
83 | @Override
84 | public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
85 | updateActionBarTitle();
86 | }
87 | });
88 |
89 | if (!showToolbar) {
90 | mToolbar.setVisibility(View.GONE);
91 | }
92 | }
93 |
94 |
95 | @Override
96 | public boolean onCreateOptionsMenu(Menu menu) {
97 | if (showDelete) {
98 | getMenuInflater().inflate(R.menu.__picker_menu_preview, menu);
99 | }
100 | return true;
101 | }
102 |
103 |
104 | @Override
105 | public void onBackPressed() {
106 |
107 | Intent intent = new Intent();
108 | intent.putExtra(KEY_SELECTED_PHOTOS, pagerFragment.getPaths());
109 | setResult(RESULT_OK, intent);
110 | finish();
111 | super.onBackPressed();
112 | }
113 |
114 |
115 | @Override
116 | public boolean onOptionsItemSelected(MenuItem item) {
117 |
118 | if (item.getItemId() == android.R.id.home) {
119 | onBackPressed();
120 | return true;
121 | }
122 |
123 | if (item.getItemId() == R.id.delete) {
124 | final int index = pagerFragment.getCurrentItem();
125 |
126 | final String deletedPath = pagerFragment.getPaths().get(index);
127 |
128 | Snackbar snackbar = Snackbar.make(pagerFragment.getView(), R.string.__picker_deleted_a_photo,
129 | Snackbar.LENGTH_LONG);
130 |
131 | if (pagerFragment.getPaths().size() <= 1) {
132 |
133 | // show confirm dialog
134 | new AlertDialog.Builder(this)
135 | .setTitle(R.string.__picker_confirm_to_delete)
136 | .setPositiveButton(R.string.__picker_yes, new DialogInterface.OnClickListener() {
137 | @Override
138 | public void onClick(DialogInterface dialogInterface, int i) {
139 | dialogInterface.dismiss();
140 | pagerFragment.getPaths().remove(index);
141 | pagerFragment.getViewPager().getAdapter().notifyDataSetChanged();
142 | onBackPressed();
143 | }
144 | })
145 | .setNegativeButton(R.string.__picker_cancel, new DialogInterface.OnClickListener() {
146 | @Override
147 | public void onClick(DialogInterface dialogInterface, int i) {
148 | dialogInterface.dismiss();
149 | }
150 | })
151 | .show();
152 |
153 | } else {
154 |
155 | snackbar.show();
156 |
157 | pagerFragment.getPaths().remove(index);
158 | pagerFragment.getViewPager().getAdapter().notifyDataSetChanged();
159 | }
160 |
161 | snackbar.setAction(R.string.__picker_undo, new View.OnClickListener() {
162 | @Override
163 | public void onClick(View view) {
164 | if (pagerFragment.getPaths().size() > 0) {
165 | pagerFragment.getPaths().add(index, deletedPath);
166 | } else {
167 | pagerFragment.getPaths().add(deletedPath);
168 | }
169 | pagerFragment.getViewPager().getAdapter().notifyDataSetChanged();
170 | pagerFragment.getViewPager().setCurrentItem(index, true);
171 | }
172 | });
173 |
174 | return true;
175 | }
176 |
177 | return super.onOptionsItemSelected(item);
178 | }
179 |
180 | public void updateActionBarTitle() {
181 | if (actionBar != null) actionBar.setTitle(
182 | getString(R.string.__picker_image_index, pagerFragment.getViewPager().getCurrentItem() + 1,
183 | pagerFragment.getPaths().size()));
184 | }
185 | }
186 |
--------------------------------------------------------------------------------
/PhotoPicker/src/main/java/me/iwf/photopicker/PhotoPicker.java:
--------------------------------------------------------------------------------
1 | package me.iwf.photopicker;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.os.Bundle;
7 | import android.support.annotation.ColorRes;
8 | import android.support.annotation.NonNull;
9 |
10 | import java.util.ArrayList;
11 |
12 | import me.iwf.photopicker.utils.PermissionsUtils;
13 |
14 | /**
15 | * Created by Donglua on 16/6/25.
16 | * Builder class to ease Intent setup.
17 | */
18 |
19 | // modify PhotoPicker
20 |
21 | public class PhotoPicker {
22 |
23 | public static final int REQUEST_CODE = 233;
24 |
25 | public static final int CROP_CODE = 101;
26 |
27 |
28 | public final static int DEFAULT_MAX_COUNT = 9;
29 | public final static int DEFAULT_COLUMN_NUMBER = 3;
30 |
31 | public final static String KEY_SELECTED_PHOTOS = "SELECTED_PHOTOS";
32 | public final static String KEY_CAMEAR_PATH = "CAMEAR_PATH";
33 |
34 |
35 | public final static String EXTRA_MAX_COUNT = "MAX_COUNT";
36 | public final static String EXTRA_SHOW_CAMERA = "SHOW_CAMERA";
37 | public final static String EXTRA_OPEN_CAMERA = "OPEN_CAMERA";
38 | public final static String EXTRA_OPEN_CROP = "OPEN_CROP";
39 | public final static String EXTRA_CROP_X = "CROP_X";
40 | public final static String EXTRA_CROP_Y = "CROP_Y";
41 | public final static String EXTRA_CROP_TOOLBARCOLOR = "TOOLBAR_COLORS";
42 | public final static String EXTRA_CROP_STATUSBARCOLOR = "STATUSBAR_COLORS";
43 |
44 | public final static String EXTRA_SHOW_GIF = "SHOW_GIF";
45 | public final static String EXTRA_GRID_COLUMN = "column";
46 | public final static String EXTRA_ORIGINAL_PHOTOS = "ORIGINAL_PHOTOS";
47 | public final static String EXTRA_PREVIEW_ENABLED = "PREVIEW_ENABLED";
48 |
49 | public static PhotoPickerBuilder builder() {
50 | return new PhotoPickerBuilder();
51 | }
52 |
53 | public static class PhotoPickerBuilder {
54 | private Bundle mPickerOptionsBundle;
55 | private Intent mPickerIntent;
56 |
57 | public PhotoPickerBuilder() {
58 | mPickerOptionsBundle = new Bundle();
59 | mPickerIntent = new Intent();
60 | }
61 |
62 | /**
63 | * Send the Intent from an Activity with a custom request code
64 | *
65 | * @param activity Activity to receive result
66 | * @param requestCode requestCode for result
67 | */
68 | public void start(@NonNull Activity activity, int requestCode) {
69 | if (PermissionsUtils.checkReadStoragePermission(activity)) {
70 | activity.startActivityForResult(getIntent(activity), requestCode);
71 | }
72 | }
73 |
74 | /**
75 | * @param fragment Fragment to receive result
76 | * @param requestCode requestCode for result
77 | */
78 | public void start(@NonNull Context context,
79 | @NonNull android.support.v4.app.Fragment fragment, int requestCode) {
80 | if (PermissionsUtils.checkReadStoragePermission(fragment.getActivity())) {
81 | fragment.startActivityForResult(getIntent(context), requestCode);
82 | }
83 | }
84 |
85 | /**
86 | * Send the Intent with a custom request code
87 | *
88 | * @param fragment Fragment to receive result
89 | */
90 | public void start(@NonNull Context context,
91 | @NonNull android.support.v4.app.Fragment fragment) {
92 | if (PermissionsUtils.checkReadStoragePermission(fragment.getActivity())) {
93 | fragment.startActivityForResult(getIntent(context), REQUEST_CODE);
94 | }
95 | }
96 |
97 | /**
98 | * Get Intent to start {@link PhotoPickerActivity}
99 | *
100 | * @return Intent for {@link PhotoPickerActivity}
101 | */
102 | public Intent getIntent(@NonNull Context context) {
103 | mPickerIntent.setClass(context, PhotoPickerActivity.class);
104 | mPickerIntent.putExtras(mPickerOptionsBundle);
105 | return mPickerIntent;
106 | }
107 |
108 | /**
109 | * Send the crop Intent from an Activity
110 | *
111 | * @param activity Activity to receive result
112 | */
113 | public void start(@NonNull Activity activity) {
114 | if (mPickerOptionsBundle.getBoolean(EXTRA_OPEN_CROP, false) || mPickerOptionsBundle.getBoolean(EXTRA_OPEN_CAMERA, false)) {
115 | start(activity, CROP_CODE);
116 | } else {
117 | start(activity, REQUEST_CODE);
118 | }
119 | }
120 |
121 | public void startCamera(@NonNull Activity activity) {
122 | start(activity, CROP_CODE);
123 | }
124 |
125 | public PhotoPickerBuilder setPhotoCount(int photoCount) {
126 | mPickerOptionsBundle.putInt(EXTRA_MAX_COUNT, photoCount);
127 | return this;
128 | }
129 |
130 | public PhotoPickerBuilder setGridColumnCount(int columnCount) {
131 | mPickerOptionsBundle.putInt(EXTRA_GRID_COLUMN, columnCount);
132 | return this;
133 | }
134 |
135 | public PhotoPickerBuilder setShowGif(boolean showGif) {
136 | mPickerOptionsBundle.putBoolean(EXTRA_SHOW_GIF, showGif);
137 | return this;
138 | }
139 |
140 | public PhotoPickerBuilder setShowCamera(boolean showCamera) {
141 | mPickerOptionsBundle.putBoolean(EXTRA_SHOW_CAMERA, showCamera);
142 | return this;
143 | }
144 |
145 | public PhotoPickerBuilder setSelected(ArrayList imagesUri) {
146 | mPickerOptionsBundle.putStringArrayList(EXTRA_ORIGINAL_PHOTOS, imagesUri);
147 | return this;
148 | }
149 |
150 | public PhotoPickerBuilder setPreviewEnabled(boolean previewEnabled) {
151 | mPickerOptionsBundle.putBoolean(EXTRA_PREVIEW_ENABLED, previewEnabled);
152 | return this;
153 | }
154 |
155 | public PhotoPickerBuilder setOpenCamera(boolean openCamera) {
156 | mPickerOptionsBundle.putBoolean(EXTRA_OPEN_CAMERA, openCamera);
157 | return this;
158 | }
159 |
160 | public PhotoPickerBuilder setCrop(boolean isCrop) {
161 | mPickerOptionsBundle.putBoolean(EXTRA_OPEN_CROP, isCrop);
162 | return this;
163 | }
164 |
165 | public PhotoPickerBuilder setCropXY(int x, int y) {
166 | mPickerOptionsBundle.putInt(EXTRA_CROP_X, x);
167 | mPickerOptionsBundle.putInt(EXTRA_CROP_Y, y);
168 | return this;
169 | }
170 |
171 | public PhotoPickerBuilder setCropColors(@ColorRes int toolbarColor, @ColorRes int statusBarColor) {
172 | mPickerOptionsBundle.putInt(EXTRA_CROP_TOOLBARCOLOR, toolbarColor);
173 | mPickerOptionsBundle.putInt(EXTRA_CROP_STATUSBARCOLOR, statusBarColor);
174 | return this;
175 | }
176 | }
177 | }
178 |
--------------------------------------------------------------------------------
/PhotoPicker/src/main/java/me/iwf/photopicker/PhotoPickerActivity.java:
--------------------------------------------------------------------------------
1 | package me.iwf.photopicker;
2 |
3 | import android.content.Intent;
4 | import android.graphics.Bitmap;
5 | import android.net.Uri;
6 | import android.os.Build;
7 | import android.os.Bundle;
8 | import android.support.v4.content.ContextCompat;
9 | import android.support.v7.app.ActionBar;
10 | import android.support.v7.app.AppCompatActivity;
11 | import android.support.v7.widget.Toolbar;
12 | import android.view.Menu;
13 | import android.view.MenuItem;
14 | import android.view.View;
15 | import android.widget.LinearLayout;
16 | import android.widget.Toast;
17 |
18 | import com.yalantis.ucrop.UCrop;
19 |
20 | import java.io.File;
21 | import java.text.SimpleDateFormat;
22 | import java.util.ArrayList;
23 | import java.util.Date;
24 | import java.util.List;
25 | import java.util.Locale;
26 |
27 | import me.iwf.photopicker.entity.Photo;
28 | import me.iwf.photopicker.event.OnItemCheckListener;
29 | import me.iwf.photopicker.fragment.ImagePagerFragment;
30 | import me.iwf.photopicker.fragment.PhotoPickerFragment;
31 |
32 | import static android.widget.Toast.LENGTH_LONG;
33 | import static me.iwf.photopicker.PhotoPicker.DEFAULT_COLUMN_NUMBER;
34 | import static me.iwf.photopicker.PhotoPicker.DEFAULT_MAX_COUNT;
35 | import static me.iwf.photopicker.PhotoPicker.EXTRA_CROP_STATUSBARCOLOR;
36 | import static me.iwf.photopicker.PhotoPicker.EXTRA_CROP_TOOLBARCOLOR;
37 | import static me.iwf.photopicker.PhotoPicker.EXTRA_CROP_X;
38 | import static me.iwf.photopicker.PhotoPicker.EXTRA_CROP_Y;
39 | import static me.iwf.photopicker.PhotoPicker.EXTRA_GRID_COLUMN;
40 | import static me.iwf.photopicker.PhotoPicker.EXTRA_MAX_COUNT;
41 | import static me.iwf.photopicker.PhotoPicker.EXTRA_OPEN_CAMERA;
42 | import static me.iwf.photopicker.PhotoPicker.EXTRA_OPEN_CROP;
43 | import static me.iwf.photopicker.PhotoPicker.EXTRA_ORIGINAL_PHOTOS;
44 | import static me.iwf.photopicker.PhotoPicker.EXTRA_PREVIEW_ENABLED;
45 | import static me.iwf.photopicker.PhotoPicker.EXTRA_SHOW_CAMERA;
46 | import static me.iwf.photopicker.PhotoPicker.EXTRA_SHOW_GIF;
47 | import static me.iwf.photopicker.PhotoPicker.KEY_SELECTED_PHOTOS;
48 |
49 | public class PhotoPickerActivity extends AppCompatActivity {
50 |
51 | private PhotoPickerFragment pickerFragment;
52 | private ImagePagerFragment imagePagerFragment;
53 | private MenuItem menuDoneItem;
54 |
55 | private int maxCount = DEFAULT_MAX_COUNT;
56 |
57 | /**
58 | * to prevent multiple calls to inflate menu
59 | */
60 |
61 | private boolean menuIsInflated = false;
62 |
63 | private boolean showGif = false;
64 | private int columnNumber = DEFAULT_COLUMN_NUMBER;
65 | private ArrayList originalPhotos = null;
66 | private boolean isCrop = false;
67 | private LinearLayout linear_view;
68 | private int cropX;
69 | private int cropY;
70 | private int toolbarColor;
71 | private int statusbarColor;
72 |
73 |
74 | @Override
75 | protected void onCreate(Bundle savedInstanceState) {
76 | super.onCreate(savedInstanceState);
77 |
78 | boolean showCamera = getIntent().getBooleanExtra(EXTRA_SHOW_CAMERA, true);
79 | boolean openCamera = getIntent().getBooleanExtra(EXTRA_OPEN_CAMERA, false);
80 | isCrop = getIntent().getBooleanExtra(EXTRA_OPEN_CROP, false);
81 | cropX = getIntent().getIntExtra(EXTRA_CROP_X, 1);
82 | cropY = getIntent().getIntExtra(EXTRA_CROP_Y, 1);
83 |
84 | toolbarColor = getIntent().getIntExtra(EXTRA_CROP_TOOLBARCOLOR, R.color.__picker_crop_toolbar_bg);
85 | statusbarColor = getIntent().getIntExtra(EXTRA_CROP_STATUSBARCOLOR, R.color.__picker_crop_status_bg);
86 | boolean showGif = getIntent().getBooleanExtra(EXTRA_SHOW_GIF, false);
87 | boolean previewEnabled = getIntent().getBooleanExtra(EXTRA_PREVIEW_ENABLED, true);
88 |
89 | setShowGif(showGif);
90 |
91 | setContentView(R.layout.__picker_activity_photo_picker);
92 | linear_view = (LinearLayout) findViewById(R.id.linear_view);
93 | Toolbar mToolbar = (Toolbar) findViewById(R.id.toolbar);
94 | setSupportActionBar(mToolbar);
95 | setTitle(R.string.__picker_title);
96 |
97 | ActionBar actionBar = getSupportActionBar();
98 |
99 | assert actionBar != null;
100 | actionBar.setDisplayHomeAsUpEnabled(true);
101 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
102 | actionBar.setElevation(25);
103 | }
104 |
105 | maxCount = getIntent().getIntExtra(EXTRA_MAX_COUNT, DEFAULT_MAX_COUNT);
106 | columnNumber = getIntent().getIntExtra(EXTRA_GRID_COLUMN, DEFAULT_COLUMN_NUMBER);
107 | originalPhotos = getIntent().getStringArrayListExtra(EXTRA_ORIGINAL_PHOTOS);
108 |
109 |
110 | pickerFragment = (PhotoPickerFragment) getSupportFragmentManager().findFragmentByTag("tag");
111 | if (pickerFragment == null) {
112 | pickerFragment = PhotoPickerFragment
113 | .newInstance(showCamera, showGif, previewEnabled, columnNumber, maxCount, originalPhotos, isCrop,openCamera);
114 | getSupportFragmentManager()
115 | .beginTransaction()
116 | .replace(R.id.container, pickerFragment, "tag")
117 | .commit();
118 | getSupportFragmentManager().executePendingTransactions();
119 | }
120 |
121 | pickerFragment.getPhotoGridAdapter().setOnItemCheckListener(new OnItemCheckListener() {
122 | @Override
123 | public boolean onItemCheck(int position, Photo photo, final int selectedItemCount) {
124 |
125 | menuDoneItem.setEnabled(selectedItemCount > 0);
126 |
127 | if (maxCount <= 1) {
128 | if (isCrop) {
129 | openCropActivity(photo.getPath());
130 | return false;
131 | }
132 | List photos = pickerFragment.getPhotoGridAdapter().getSelectedPhotos();
133 | if (!photos.contains(photo.getPath())) {
134 | photos.clear();
135 | pickerFragment.getPhotoGridAdapter().notifyDataSetChanged();
136 | }
137 | return true;
138 | }
139 |
140 | if (selectedItemCount > maxCount) {
141 | Toast.makeText(getActivity(), getString(R.string.__picker_over_max_count_tips, maxCount),
142 | LENGTH_LONG).show();
143 | return false;
144 | }
145 | if (!isCrop) {
146 | menuDoneItem.setTitle(getString(R.string.__picker_done_with_count, selectedItemCount, maxCount));
147 | }
148 | return true;
149 | }
150 | });
151 |
152 | if (openCamera) {
153 | linear_view.setVisibility(View.GONE);
154 | pickerFragment.activityCamera();
155 | }
156 | }
157 |
158 | public void openCropActivity(String path) {
159 | String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.ENGLISH).format(new Date());
160 | String imageFileName = "JPEG_" + timeStamp + ".jpg";
161 |
162 | UCrop.Options options = new UCrop.Options();
163 | options.setCompressionFormat(Bitmap.CompressFormat.JPEG);
164 | options.setHideBottomControls(true);
165 | options.setFreeStyleCropEnabled(false);
166 | options.setCompressionQuality(100);
167 |
168 | options.setToolbarColor(ContextCompat.getColor(this,toolbarColor));
169 | options.setStatusBarColor(ContextCompat.getColor(this, statusbarColor));
170 |
171 | UCrop.of(Uri.fromFile(new File(path)), Uri.fromFile(new File(getActivity().getCacheDir(), imageFileName)))
172 | .withAspectRatio(cropX, cropY)
173 | .withOptions(options)
174 | .start(PhotoPickerActivity.this);
175 | }
176 |
177 |
178 | /**
179 | * Overriding this method allows us to run our exit animation first, then exiting
180 | * the activity when it complete.
181 | */
182 | @Override
183 | public void onBackPressed() {
184 | if (imagePagerFragment != null && imagePagerFragment.isVisible()) {
185 | imagePagerFragment.runExitAnimation(new Runnable() {
186 | public void run() {
187 | if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
188 | getSupportFragmentManager().popBackStack();
189 | }
190 | }
191 | });
192 | } else {
193 | super.onBackPressed();
194 | }
195 | }
196 |
197 |
198 | public void addImagePagerFragment(ImagePagerFragment imagePagerFragment) {
199 | this.imagePagerFragment = imagePagerFragment;
200 | getSupportFragmentManager()
201 | .beginTransaction()
202 | .replace(R.id.container, this.imagePagerFragment)
203 | .addToBackStack(null)
204 | .commit();
205 | }
206 |
207 | @Override
208 | public boolean onCreateOptionsMenu(Menu menu) {
209 | if (!menuIsInflated) {
210 | getMenuInflater().inflate(R.menu.__picker_menu_picker, menu);
211 | menuDoneItem = menu.findItem(R.id.done);
212 | if (originalPhotos != null && originalPhotos.size() > 0 && !isCrop) {
213 | menuDoneItem.setEnabled(true);
214 | menuDoneItem.setTitle(
215 | getString(R.string.__picker_done_with_count, originalPhotos.size(), maxCount));
216 | } else {
217 | menuDoneItem.setEnabled(false);
218 | }
219 | menuIsInflated = true;
220 | return true;
221 | }
222 | return false;
223 | }
224 |
225 |
226 | @Override
227 | public boolean onOptionsItemSelected(MenuItem item) {
228 | if (item.getItemId() == android.R.id.home) {
229 | super.onBackPressed();
230 | return true;
231 | }
232 |
233 | if (item.getItemId() == R.id.done && !isCrop) {
234 | Intent intent = new Intent();
235 | ArrayList selectedPhotos = pickerFragment.getPhotoGridAdapter().getSelectedPhotoPaths();
236 | intent.putStringArrayListExtra(KEY_SELECTED_PHOTOS, selectedPhotos);
237 | setResult(RESULT_OK, intent);
238 | finish();
239 | return true;
240 | }
241 |
242 | return super.onOptionsItemSelected(item);
243 | }
244 |
245 | public void PhotoCamear(String path) {
246 | Intent intent = new Intent();
247 | intent.putExtra(PhotoPicker.KEY_CAMEAR_PATH, path);
248 | setResult(RESULT_OK, intent);
249 | finish();
250 | }
251 |
252 |
253 | @Override
254 | public void onActivityResult(int requestCode, int resultCode, Intent data) {
255 | super.onActivityResult(requestCode, resultCode, data);
256 | pickerFragment.onActivityResult(requestCode, resultCode, data);
257 | }
258 |
259 |
260 | public PhotoPickerActivity getActivity() {
261 | return this;
262 | }
263 |
264 | public boolean isShowGif() {
265 | return showGif;
266 | }
267 |
268 | public void setShowGif(boolean showGif) {
269 | this.showGif = showGif;
270 | }
271 | }
272 |
--------------------------------------------------------------------------------
/PhotoPicker/src/main/java/me/iwf/photopicker/PhotoPreview.java:
--------------------------------------------------------------------------------
1 | package me.iwf.photopicker;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.os.Bundle;
7 | import android.support.annotation.NonNull;
8 | import java.util.ArrayList;
9 |
10 | /**
11 | * Created by Donglua on 16/6/25.
12 | * Builder class to ease Intent setup.
13 | */
14 | // modify PhotoPreview.java
15 | public class PhotoPreview {
16 |
17 | public final static int REQUEST_CODE = 666;
18 |
19 | public final static String EXTRA_CURRENT_ITEM = "current_item";
20 | public final static String EXTRA_PHOTOS = "photos";
21 | public final static String EXTRA_LONG_DATA = "onLongClickListData";
22 |
23 | public final static String EXTRA_SHOW_DELETE = "show_delete";
24 | public final static String EXTRA_SHOW_TOOLBAR = "show_toolbar";
25 |
26 | public static PhotoPreviewBuilder builder() {
27 | return new PhotoPreviewBuilder();
28 | }
29 |
30 |
31 | public static class PhotoPreviewBuilder {
32 | private Bundle mPreviewOptionsBundle;
33 | private Intent mPreviewIntent;
34 |
35 | public PhotoPreviewBuilder() {
36 | mPreviewOptionsBundle = new Bundle();
37 | mPreviewIntent = new Intent();
38 | }
39 |
40 | /**
41 | * Send the Intent from an Activity with a custom request code
42 | *
43 | * @param activity Activity to receive result
44 | * @param requestCode requestCode for result
45 | */
46 | public void start(@NonNull Activity activity, int requestCode) {
47 | activity.startActivityForResult(getIntent(activity), requestCode);
48 | }
49 |
50 | /**
51 | * Send the Intent with a custom request code
52 | *
53 | * @param fragment Fragment to receive result
54 | * @param requestCode requestCode for result
55 | */
56 | public void start(@NonNull Context context, @NonNull android.support.v4.app.Fragment fragment, int requestCode) {
57 | fragment.startActivityForResult(getIntent(context), requestCode);
58 | }
59 |
60 | /**
61 | * Send the Intent with a custom request code
62 | *
63 | * @param fragment Fragment to receive result
64 | */
65 | public void start(@NonNull Context context, @NonNull android.support.v4.app.Fragment fragment) {
66 | fragment.startActivityForResult(getIntent(context), REQUEST_CODE);
67 | }
68 |
69 | /**
70 | * Send the crop Intent from an Activity
71 | *
72 | * @param activity Activity to receive result
73 | */
74 | public void start(@NonNull Activity activity) {
75 | start(activity, REQUEST_CODE);
76 | }
77 |
78 | /**
79 | * Get Intent to start {@link PhotoPickerActivity}
80 | *
81 | * @return Intent for {@link PhotoPickerActivity}
82 | */
83 | public Intent getIntent(@NonNull Context context) {
84 | mPreviewIntent.setClass(context, PhotoPagerActivity.class);
85 | mPreviewIntent.putExtras(mPreviewOptionsBundle);
86 | return mPreviewIntent;
87 | }
88 |
89 | public PhotoPreviewBuilder setPhotos(ArrayList photoPaths) {
90 | mPreviewOptionsBundle.putStringArrayList(EXTRA_PHOTOS, photoPaths);
91 | return this;
92 | }
93 |
94 | public PhotoPreviewBuilder setOnLongClickListData(ArrayList onLongClickListData) {
95 | mPreviewOptionsBundle.putStringArrayList(EXTRA_LONG_DATA, onLongClickListData);
96 | return this;
97 | }
98 |
99 | public PhotoPreviewBuilder setCurrentItem(int currentItem) {
100 | mPreviewOptionsBundle.putInt(EXTRA_CURRENT_ITEM, currentItem);
101 | return this;
102 | }
103 |
104 | public PhotoPreviewBuilder setShowDeleteButton(boolean showDeleteButton) {
105 | mPreviewOptionsBundle.putBoolean(EXTRA_SHOW_DELETE, showDeleteButton);
106 | return this;
107 | }
108 |
109 | public PhotoPreviewBuilder setShowToolbar(boolean showToolbar) {
110 | mPreviewOptionsBundle.putBoolean(EXTRA_SHOW_TOOLBAR, showToolbar);
111 | return this;
112 | }
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/PhotoPicker/src/main/java/me/iwf/photopicker/adapter/PhotoDialogAdapter.java:
--------------------------------------------------------------------------------
1 | package me.iwf.photopicker.adapter;
2 |
3 | import android.content.Context;
4 | import android.view.LayoutInflater;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 | import android.widget.BaseAdapter;
8 | import android.widget.TextView;
9 |
10 | import java.util.ArrayList;
11 |
12 | import me.iwf.photopicker.R;
13 |
14 | /**
15 | * Created by Administrator on 2016/4/7.
16 | */
17 | public class PhotoDialogAdapter extends BaseAdapter {
18 | private ArrayList lstImageItem;
19 | private Context mContext;
20 |
21 | public PhotoDialogAdapter(Context mContext, ArrayList arg0) {
22 | this.lstImageItem = arg0;
23 | this.mContext = mContext;
24 | }
25 |
26 | public int getCount() {
27 | return lstImageItem.size();
28 | }
29 |
30 | public Object getItem(int position) {
31 | return lstImageItem.get(position);
32 | }
33 |
34 | public long getItemId(int position) {
35 | return position;
36 | }
37 |
38 | public View getView(int position, View view, ViewGroup parent) {
39 |
40 | ViewHolder viewHolder = null;
41 | if (view == null) {
42 | viewHolder = new ViewHolder();
43 | view = LayoutInflater.from(mContext).inflate(R.layout.__picker_item_dialog, null);
44 | viewHolder.tv_dialog = (TextView) view.findViewById(R.id.tv_dialog);
45 |
46 | view.setTag(viewHolder);
47 | } else {
48 | viewHolder = (ViewHolder) view.getTag();
49 | }
50 | if (position == 0) {
51 | viewHolder.tv_dialog.setBackgroundResource(R.drawable.__picker_item_dialog_selector_top);
52 | } else if (position == getCount() - 1) {
53 | viewHolder.tv_dialog.setBackgroundResource(R.drawable.__picker_item_dialog_selector_bottom);
54 | } else {
55 | viewHolder.tv_dialog.setBackgroundResource(R.drawable.__picker_item_dialog_selector);
56 | }
57 |
58 | viewHolder.tv_dialog.setText(lstImageItem.get(position));
59 | return view;
60 | }
61 |
62 | class ViewHolder {
63 | TextView tv_dialog;
64 | }
65 | }
--------------------------------------------------------------------------------
/PhotoPicker/src/main/java/me/iwf/photopicker/adapter/PhotoGridAdapter.java:
--------------------------------------------------------------------------------
1 | package me.iwf.photopicker.adapter;
2 |
3 | import android.content.Context;
4 | import android.support.v7.widget.RecyclerView;
5 | import android.util.DisplayMetrics;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 | import android.view.WindowManager;
10 | import android.widget.ImageView;
11 |
12 | import com.bumptech.glide.Glide;
13 | import com.bumptech.glide.RequestManager;
14 | import com.bumptech.glide.request.RequestOptions;
15 |
16 | import java.io.File;
17 | import java.util.ArrayList;
18 | import java.util.List;
19 |
20 | import me.iwf.photopicker.R;
21 | import me.iwf.photopicker.entity.Photo;
22 | import me.iwf.photopicker.entity.PhotoDirectory;
23 | import me.iwf.photopicker.event.OnItemCheckListener;
24 | import me.iwf.photopicker.event.OnPhotoClickListener;
25 | import me.iwf.photopicker.utils.AndroidLifecycleUtils;
26 | import me.iwf.photopicker.utils.MediaStoreHelper;
27 |
28 | /**
29 | * Created by donglua on 15/5/31.
30 | */
31 | public class PhotoGridAdapter extends SelectableAdapter {
32 |
33 | private LayoutInflater inflater;
34 | private RequestManager glide;
35 |
36 | private OnItemCheckListener onItemCheckListener = null;
37 | private OnPhotoClickListener onPhotoClickListener = null;
38 | private View.OnClickListener onCameraClickListener = null;
39 |
40 |
41 | public final static int ITEM_TYPE_CAMERA = 100;
42 | public final static int ITEM_TYPE_PHOTO = 101;
43 | private final static int COL_NUMBER_DEFAULT = 3;
44 |
45 | private boolean hasCamera = true;
46 | private boolean previewEnable = true;
47 |
48 | private int imageSize;
49 | private int columnNumber = COL_NUMBER_DEFAULT;
50 |
51 |
52 | public PhotoGridAdapter(Context context, RequestManager requestManager, List photoDirectories) {
53 | this.photoDirectories = photoDirectories;
54 | this.glide = requestManager;
55 | inflater = LayoutInflater.from(context);
56 | setColumnNumber(context, columnNumber);
57 | }
58 |
59 | public PhotoGridAdapter(Context context, RequestManager requestManager, List photoDirectories, ArrayList orginalPhotos, int colNum) {
60 | this(context, requestManager, photoDirectories);
61 | setColumnNumber(context, colNum);
62 | selectedPhotos = new ArrayList<>();
63 | if (orginalPhotos != null) selectedPhotos.addAll(orginalPhotos);
64 | }
65 |
66 | private void setColumnNumber(Context context, int columnNumber) {
67 | this.columnNumber = columnNumber;
68 | WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
69 | DisplayMetrics metrics = new DisplayMetrics();
70 | wm.getDefaultDisplay().getMetrics(metrics);
71 | int widthPixels = metrics.widthPixels;
72 | imageSize = widthPixels / columnNumber;
73 | }
74 |
75 | @Override
76 | public int getItemViewType(int position) {
77 | return (showCamera() && position == 0) ? ITEM_TYPE_CAMERA : ITEM_TYPE_PHOTO;
78 | }
79 |
80 |
81 | @Override
82 | public PhotoViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
83 | final View itemView = inflater.inflate(R.layout.__picker_item_photo, parent, false);
84 | final PhotoViewHolder holder = new PhotoViewHolder(itemView);
85 | if (viewType == ITEM_TYPE_CAMERA) {
86 | holder.vSelected.setVisibility(View.GONE);
87 | holder.ivPhoto.setScaleType(ImageView.ScaleType.CENTER);
88 |
89 | holder.ivPhoto.setOnClickListener(new View.OnClickListener() {
90 | @Override
91 | public void onClick(View view) {
92 | if (onCameraClickListener != null) {
93 | onCameraClickListener.onClick(view);
94 | }
95 | }
96 | });
97 | }
98 | return holder;
99 | }
100 |
101 |
102 | @Override
103 | public void onBindViewHolder(final PhotoViewHolder holder, int position) {
104 |
105 | if (getItemViewType(position) == ITEM_TYPE_PHOTO) {
106 |
107 | List photos = getCurrentPhotos();
108 | final Photo photo;
109 |
110 | if (showCamera()) {
111 | photo = photos.get(position - 1);
112 | } else {
113 | photo = photos.get(position);
114 | }
115 |
116 | boolean canLoadImage = AndroidLifecycleUtils.canLoadImage(holder.ivPhoto.getContext());
117 |
118 | if (canLoadImage) {
119 | final RequestOptions options = new RequestOptions();
120 | options.centerCrop()
121 | .dontAnimate()
122 | .override(imageSize, imageSize)
123 | .placeholder(R.drawable.__picker_ic_photo_black_48dp)
124 | .error(R.drawable.__picker_ic_broken_image_black_48dp);
125 |
126 | glide.setDefaultRequestOptions(options)
127 | .load(new File(photo.getPath()))
128 | .thumbnail(0.5f)
129 | .into(holder.ivPhoto);
130 | }
131 |
132 | final boolean isChecked = isSelected(photo);
133 |
134 | holder.vSelected.setSelected(isChecked);
135 | holder.ivPhoto.setSelected(isChecked);
136 |
137 | holder.ivPhoto.setOnClickListener(new View.OnClickListener() {
138 | @Override
139 | public void onClick(View view) {
140 | if (onPhotoClickListener != null) {
141 | int pos = holder.getAdapterPosition();
142 | if (previewEnable) {
143 | onPhotoClickListener.onClick(view, pos, showCamera());
144 | } else {
145 | holder.vSelected.performClick();
146 | }
147 | }
148 | }
149 | });
150 | holder.vSelected.setOnClickListener(new View.OnClickListener() {
151 | @Override
152 | public void onClick(View view) {
153 | int pos = holder.getAdapterPosition();
154 | boolean isEnable = true;
155 |
156 | if (onItemCheckListener != null) {
157 | isEnable = onItemCheckListener.onItemCheck(pos, photo,
158 | getSelectedPhotos().size() + (isSelected(photo) ? -1 : 1));
159 | }
160 | if (isEnable) {
161 | toggleSelection(photo);
162 | notifyItemChanged(pos);
163 | }
164 | }
165 | });
166 |
167 | } else {
168 | holder.ivPhoto.setImageResource(R.drawable.__picker_camera);
169 | }
170 | }
171 |
172 |
173 | @Override
174 | public int getItemCount() {
175 | int photosCount =
176 | photoDirectories.size() == 0 ? 0 : getCurrentPhotos().size();
177 | if (showCamera()) {
178 | return photosCount + 1;
179 | }
180 | return photosCount;
181 | }
182 |
183 |
184 | public static class PhotoViewHolder extends RecyclerView.ViewHolder {
185 | private ImageView ivPhoto;
186 | private View vSelected;
187 |
188 | public PhotoViewHolder(View itemView) {
189 | super(itemView);
190 | ivPhoto = (ImageView) itemView.findViewById(R.id.iv_photo);
191 | vSelected = itemView.findViewById(R.id.v_selected);
192 | }
193 | }
194 |
195 |
196 | public void setOnItemCheckListener(OnItemCheckListener onItemCheckListener) {
197 | this.onItemCheckListener = onItemCheckListener;
198 | }
199 |
200 |
201 | public void setOnPhotoClickListener(OnPhotoClickListener onPhotoClickListener) {
202 | this.onPhotoClickListener = onPhotoClickListener;
203 | }
204 |
205 |
206 | public void setOnCameraClickListener(View.OnClickListener onCameraClickListener) {
207 | this.onCameraClickListener = onCameraClickListener;
208 | }
209 |
210 |
211 | public ArrayList getSelectedPhotoPaths() {
212 | ArrayList selectedPhotoPaths = new ArrayList<>(getSelectedItemCount());
213 |
214 | for (String photo : selectedPhotos) {
215 | selectedPhotoPaths.add(photo);
216 | }
217 |
218 | return selectedPhotoPaths;
219 | }
220 |
221 |
222 | public void setShowCamera(boolean hasCamera) {
223 | this.hasCamera = hasCamera;
224 | }
225 |
226 | public void setPreviewEnable(boolean previewEnable) {
227 | this.previewEnable = previewEnable;
228 | }
229 |
230 | public boolean showCamera() {
231 | return (hasCamera && currentDirectoryIndex == MediaStoreHelper.INDEX_ALL_PHOTOS);
232 | }
233 |
234 | @Override
235 | public void onViewRecycled(PhotoViewHolder holder) {
236 | glide.clear(holder.ivPhoto);
237 | super.onViewRecycled(holder);
238 | }
239 | }
240 |
--------------------------------------------------------------------------------
/PhotoPicker/src/main/java/me/iwf/photopicker/adapter/PhotoPagerAdapter.java:
--------------------------------------------------------------------------------
1 | package me.iwf.photopicker.adapter;
2 |
3 | import android.app.Activity;
4 | import android.app.AlertDialog;
5 | import android.content.Context;
6 | import android.net.Uri;
7 | import android.support.v4.view.PagerAdapter;
8 | import android.view.Gravity;
9 | import android.view.LayoutInflater;
10 | import android.view.View;
11 | import android.view.ViewGroup;
12 | import android.widget.AdapterView;
13 | import android.widget.ImageView;
14 | import android.widget.LinearLayout;
15 | import android.widget.ListView;
16 | import android.widget.Toast;
17 |
18 | import com.bumptech.glide.Glide;
19 | import com.bumptech.glide.RequestManager;
20 | import com.bumptech.glide.request.RequestOptions;
21 |
22 | import java.io.File;
23 | import java.util.ArrayList;
24 | import java.util.List;
25 |
26 | import me.iwf.photopicker.R;
27 | import me.iwf.photopicker.event.PhotoOnLongClick;
28 | import me.iwf.photopicker.event.PhotoOnLongClickManager;
29 | import me.iwf.photopicker.utils.AndroidLifecycleUtils;
30 |
31 | /**
32 | * Created by donglua on 15/6/21.
33 | */
34 |
35 | // modify PhotoPickerFragment.java add setOnLongClickListener
36 |
37 | public class PhotoPagerAdapter extends PagerAdapter {
38 |
39 | private List paths = new ArrayList<>();
40 | private ArrayList longData;
41 |
42 | private RequestManager mGlide;
43 |
44 | public PhotoPagerAdapter(RequestManager glide, List paths, ArrayList longData) {
45 | this.paths = paths;
46 | this.mGlide = glide;
47 | this.longData = longData;
48 | }
49 |
50 | @Override
51 | public Object instantiateItem(ViewGroup container, final int position) {
52 | final Context context = container.getContext();
53 | View itemView = LayoutInflater.from(context)
54 | .inflate(R.layout.__picker_picker_item_pager, container, false);
55 |
56 | final ImageView imageView = (ImageView) itemView.findViewById(R.id.iv_pager);
57 |
58 | final String path = paths.get(position);
59 | final Uri uri;
60 | if (path.startsWith("http")) {
61 | uri = Uri.parse(path);
62 | } else {
63 | uri = Uri.fromFile(new File(path));
64 | }
65 |
66 | boolean canLoadImage = AndroidLifecycleUtils.canLoadImage(context);
67 |
68 | if (canLoadImage) {
69 | final RequestOptions options = new RequestOptions();
70 | options.dontAnimate()
71 | .dontTransform()
72 | .override(800, 800)
73 | .placeholder(R.drawable.__picker_ic_photo_black_48dp)
74 | .error(R.drawable.__picker_ic_broken_image_black_48dp);
75 | mGlide.setDefaultRequestOptions(options).load(uri)
76 | .thumbnail(0.1f)
77 | .into(imageView);
78 | }
79 |
80 | imageView.setOnClickListener(new View.OnClickListener() {
81 | @Override
82 | public void onClick(View view) {
83 | if (context instanceof Activity) {
84 | if (!((Activity) context).isFinishing()) {
85 | ((Activity) context).onBackPressed();
86 | }
87 | }
88 | }
89 | });
90 |
91 | imageView.setOnLongClickListener(new View.OnLongClickListener() {
92 | @Override
93 | public boolean onLongClick(View view) {
94 | if (longData != null && longData.size() > 0) {
95 | OnLongDialog(context, path);
96 | }
97 | return true;
98 | }
99 | });
100 |
101 | container.addView(itemView);
102 |
103 | return itemView;
104 | }
105 |
106 | private void OnLongDialog(Context context, final String path) {
107 | final AlertDialog albumDialog = new AlertDialog.Builder(context).create();
108 | albumDialog.setCanceledOnTouchOutside(true);
109 | albumDialog.setCancelable(true);
110 | View v = LayoutInflater.from(context).inflate(
111 | R.layout.__picker_dialog_photo_pager, null);
112 | albumDialog.show();
113 | // ViewGroup.LayoutParams layoutParams = new LinearLayout.LayoutParams(280, ViewGroup.LayoutParams.MATCH_PARENT);
114 | albumDialog.setContentView(v);
115 | albumDialog.getWindow().setGravity(Gravity.CENTER);
116 | albumDialog.getWindow().setBackgroundDrawableResource(R.drawable.__picker_bg_dialog);
117 | ListView dialog_lv = (ListView) v.findViewById(R.id.dialog_lv);
118 |
119 | PhotoDialogAdapter photoDialogAdapter = new PhotoDialogAdapter(context, longData);
120 | dialog_lv.setAdapter(photoDialogAdapter);
121 | dialog_lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
122 | @Override
123 | public void onItemClick(AdapterView> adapterView, View view, int i, long l) {
124 | albumDialog.dismiss();
125 | PhotoOnLongClickManager photoOnLongClickManager = PhotoOnLongClickManager.getInstance();
126 | photoOnLongClickManager.setOnLongClick(i, path);
127 | }
128 | });
129 | }
130 |
131 | public void setLongData(ArrayList longData){
132 | this.longData = longData;
133 | }
134 |
135 | @Override
136 | public int getCount() {
137 | return paths.size();
138 | }
139 |
140 |
141 | @Override
142 | public boolean isViewFromObject(View view, Object object) {
143 | return view == object;
144 | }
145 |
146 |
147 | @Override
148 | public void destroyItem(ViewGroup container, int position, Object object) {
149 | container.removeView((View) object);
150 | mGlide.clear((View) object);
151 | }
152 |
153 | @Override
154 | public int getItemPosition(Object object) {
155 | return POSITION_NONE;
156 | }
157 |
158 |
159 |
160 | }
161 |
--------------------------------------------------------------------------------
/PhotoPicker/src/main/java/me/iwf/photopicker/adapter/PopupDirectoryListAdapter.java:
--------------------------------------------------------------------------------
1 | package me.iwf.photopicker.adapter;
2 |
3 | import android.view.LayoutInflater;
4 | import android.view.View;
5 | import android.view.ViewGroup;
6 | import android.widget.BaseAdapter;
7 | import android.widget.ImageView;
8 | import android.widget.TextView;
9 | import com.bumptech.glide.RequestManager;
10 | import com.bumptech.glide.request.RequestOptions;
11 |
12 | import java.util.ArrayList;
13 | import java.util.List;
14 | import me.iwf.photopicker.R;
15 | import me.iwf.photopicker.entity.PhotoDirectory;
16 |
17 | /**
18 | * Created by donglua on 15/6/28.
19 | */
20 | public class PopupDirectoryListAdapter extends BaseAdapter {
21 |
22 |
23 | private List directories = new ArrayList<>();
24 | private RequestManager glide;
25 |
26 | public PopupDirectoryListAdapter(RequestManager glide, List directories) {
27 | this.directories = directories;
28 | this.glide = glide;
29 | }
30 |
31 |
32 | @Override public int getCount() {
33 | return directories.size();
34 | }
35 |
36 |
37 | @Override public PhotoDirectory getItem(int position) {
38 | return directories.get(position);
39 | }
40 |
41 |
42 | @Override public long getItemId(int position) {
43 | return directories.get(position).hashCode();
44 | }
45 |
46 |
47 | @Override public View getView(int position, View convertView, ViewGroup parent) {
48 | ViewHolder holder;
49 | if (convertView == null) {
50 | LayoutInflater mLayoutInflater = LayoutInflater.from(parent.getContext());
51 | convertView = mLayoutInflater.inflate(R.layout.__picker_item_directory, parent, false);
52 | holder = new ViewHolder(convertView);
53 | convertView.setTag(holder);
54 | } else {
55 | holder = (ViewHolder) convertView.getTag();
56 | }
57 |
58 | holder.bindData(directories.get(position));
59 |
60 | return convertView;
61 | }
62 |
63 | private class ViewHolder {
64 |
65 | public ImageView ivCover;
66 | public TextView tvName;
67 | public TextView tvCount;
68 |
69 | public ViewHolder(View rootView) {
70 | ivCover = (ImageView) rootView.findViewById(R.id.iv_dir_cover);
71 | tvName = (TextView) rootView.findViewById(R.id.tv_dir_name);
72 | tvCount = (TextView) rootView.findViewById(R.id.tv_dir_count);
73 | }
74 |
75 | public void bindData(PhotoDirectory directory) {
76 | final RequestOptions options = new RequestOptions();
77 | options.dontAnimate()
78 | .dontTransform()
79 | .override(800, 800)
80 | .placeholder(R.drawable.__picker_ic_photo_black_48dp)
81 | .error(R.drawable.__picker_ic_broken_image_black_48dp);
82 | glide.setDefaultRequestOptions(options)
83 | .load(directory.getCoverPath())
84 | .thumbnail(0.1f)
85 | .into(ivCover);
86 | tvName.setText(directory.getName());
87 | tvCount.setText(tvCount.getContext().getString(R.string.__picker_image_count, directory.getPhotos().size()));
88 | }
89 | }
90 |
91 | }
92 |
--------------------------------------------------------------------------------
/PhotoPicker/src/main/java/me/iwf/photopicker/adapter/SelectableAdapter.java:
--------------------------------------------------------------------------------
1 | package me.iwf.photopicker.adapter;
2 |
3 | import android.support.v7.widget.RecyclerView;
4 |
5 | import java.util.ArrayList;
6 | import java.util.List;
7 |
8 | import me.iwf.photopicker.entity.Photo;
9 | import me.iwf.photopicker.entity.PhotoDirectory;
10 | import me.iwf.photopicker.event.Selectable;
11 |
12 | public abstract class SelectableAdapter
13 | extends RecyclerView.Adapter implements Selectable {
14 |
15 | private static final String TAG = SelectableAdapter.class.getSimpleName();
16 |
17 | protected List photoDirectories;
18 | protected List selectedPhotos;
19 |
20 | public int currentDirectoryIndex = 0;
21 |
22 |
23 | public SelectableAdapter() {
24 | photoDirectories = new ArrayList<>();
25 | selectedPhotos = new ArrayList<>();
26 | }
27 |
28 |
29 | /**
30 | * Indicates if the item at position where is selected
31 | *
32 | * @param photo Photo of the item to check
33 | * @return true if the item is selected, false otherwise
34 | */
35 | @Override public boolean isSelected(Photo photo) {
36 | return getSelectedPhotos().contains(photo.getPath());
37 | }
38 |
39 | /**
40 | * Toggle the selection status of the item at a given position
41 | *
42 | * @param photo Photo of the item to toggle the selection status for
43 | */
44 | @Override public void toggleSelection(Photo photo) {
45 | if (selectedPhotos.contains(photo.getPath())) {
46 | selectedPhotos.remove(photo.getPath());
47 | } else {
48 | selectedPhotos.add(photo.getPath());
49 | }
50 | }
51 |
52 |
53 | /**
54 | * Clear the selection status for all items
55 | */
56 | @Override public void clearSelection() {
57 | selectedPhotos.clear();
58 | }
59 |
60 |
61 | /**
62 | * Count the selected items
63 | *
64 | * @return Selected items count
65 | */
66 | @Override public int getSelectedItemCount() {
67 | return selectedPhotos.size();
68 | }
69 |
70 |
71 | public void setCurrentDirectoryIndex(int currentDirectoryIndex) {
72 | this.currentDirectoryIndex = currentDirectoryIndex;
73 | }
74 |
75 |
76 | public List getCurrentPhotos() {
77 | return photoDirectories.get(currentDirectoryIndex).getPhotos();
78 | }
79 |
80 |
81 | public List getCurrentPhotoPaths() {
82 | List currentPhotoPaths = new ArrayList<>(getCurrentPhotos().size());
83 | for (Photo photo : getCurrentPhotos()) {
84 | currentPhotoPaths.add(photo.getPath());
85 | }
86 | return currentPhotoPaths;
87 | }
88 |
89 |
90 | public List getSelectedPhotos() {
91 | return selectedPhotos;
92 | }
93 |
94 | }
--------------------------------------------------------------------------------
/PhotoPicker/src/main/java/me/iwf/photopicker/entity/Photo.java:
--------------------------------------------------------------------------------
1 | package me.iwf.photopicker.entity;
2 |
3 | /**
4 | * Created by donglua on 15/6/30.
5 | */
6 | public class Photo {
7 |
8 | private int id;
9 | private String path;
10 |
11 | public Photo(int id, String path) {
12 | this.id = id;
13 | this.path = path;
14 | }
15 |
16 | public Photo() {
17 | }
18 |
19 | @Override public boolean equals(Object o) {
20 | if (this == o) return true;
21 | if (!(o instanceof Photo)) return false;
22 |
23 | Photo photo = (Photo) o;
24 |
25 | return id == photo.id;
26 | }
27 |
28 | @Override public int hashCode() {
29 | return id;
30 | }
31 |
32 | public String getPath() {
33 | return path;
34 | }
35 |
36 | public void setPath(String path) {
37 | this.path = path;
38 | }
39 |
40 | public int getId() {
41 | return id;
42 | }
43 |
44 | public void setId(int id) {
45 | this.id = id;
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/PhotoPicker/src/main/java/me/iwf/photopicker/entity/PhotoDirectory.java:
--------------------------------------------------------------------------------
1 | package me.iwf.photopicker.entity;
2 |
3 | import android.text.TextUtils;
4 |
5 | import java.util.ArrayList;
6 | import java.util.List;
7 |
8 | import me.iwf.photopicker.utils.FileUtils;
9 |
10 | /**
11 | * Created by donglua on 15/6/28.
12 | */
13 | public class PhotoDirectory {
14 |
15 | private String id;
16 | private String coverPath;
17 | private String name;
18 | private long dateAdded;
19 | private List photos = new ArrayList<>();
20 |
21 | @Override public boolean equals(Object o) {
22 | if (this == o) return true;
23 | if (!(o instanceof PhotoDirectory)) return false;
24 |
25 | PhotoDirectory directory = (PhotoDirectory) o;
26 |
27 | boolean hasId = !TextUtils.isEmpty(id);
28 | boolean otherHasId = !TextUtils.isEmpty(directory.id);
29 |
30 | if (hasId && otherHasId) {
31 | if (!TextUtils.equals(id, directory.id)) {
32 | return false;
33 | }
34 |
35 | return TextUtils.equals(name, directory.name);
36 | }
37 |
38 | return false;
39 | }
40 |
41 | @Override public int hashCode() {
42 | if (TextUtils.isEmpty(id)) {
43 | if (TextUtils.isEmpty(name)) {
44 | return 0;
45 | }
46 |
47 | return name.hashCode();
48 | }
49 |
50 | int result = id.hashCode();
51 |
52 | if (TextUtils.isEmpty(name)) {
53 | return result;
54 | }
55 |
56 | result = 31 * result + name.hashCode();
57 | return result;
58 | }
59 |
60 | public String getId() {
61 | return id;
62 | }
63 |
64 | public void setId(String id) {
65 | this.id = id;
66 | }
67 |
68 | public String getCoverPath() {
69 | return coverPath;
70 | }
71 |
72 | public void setCoverPath(String coverPath) {
73 | this.coverPath = coverPath;
74 | }
75 |
76 | public String getName() {
77 | return name;
78 | }
79 |
80 | public void setName(String name) {
81 | this.name = name;
82 | }
83 |
84 | public long getDateAdded() {
85 | return dateAdded;
86 | }
87 |
88 | public void setDateAdded(long dateAdded) {
89 | this.dateAdded = dateAdded;
90 | }
91 |
92 | public List getPhotos() {
93 | return photos;
94 | }
95 |
96 | public void setPhotos(List photos) {
97 | if (photos == null) return;
98 | for (int i = 0, j = 0, num = photos.size(); i < num; i++) {
99 | Photo p = photos.get(j);
100 | if (p == null || !FileUtils.fileIsExists(p.getPath())) {
101 | photos.remove(j);
102 | } else {
103 | j++;
104 | }
105 | }
106 | this.photos = photos;
107 | }
108 |
109 | public List getPhotoPaths() {
110 | List paths = new ArrayList<>(photos.size());
111 | for (Photo photo : photos) {
112 | paths.add(photo.getPath());
113 | }
114 | return paths;
115 | }
116 |
117 | public void addPhoto(int id, String path) {
118 | if (FileUtils.fileIsExists(path)) {
119 | photos.add(new Photo(id, path));
120 | }
121 | }
122 |
123 | }
124 |
--------------------------------------------------------------------------------
/PhotoPicker/src/main/java/me/iwf/photopicker/event/OnItemCheckListener.java:
--------------------------------------------------------------------------------
1 | package me.iwf.photopicker.event;
2 |
3 | import me.iwf.photopicker.entity.Photo;
4 |
5 | /**
6 | * Created by donglua on 15/6/20.
7 | */
8 | public interface OnItemCheckListener {
9 |
10 | /***
11 | *
12 | * @param position 所选图片的位置
13 | * @param path 所选的图片
14 | * @param selectedItemCount 已选数量
15 | * @return enable check
16 | */
17 | boolean onItemCheck(int position, Photo path, int selectedItemCount);
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/PhotoPicker/src/main/java/me/iwf/photopicker/event/OnPhotoClickListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
3 | * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan.
4 | * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna.
5 | * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus.
6 | * Vestibulum commodo. Ut rhoncus gravida arcu.
7 | */
8 |
9 | package me.iwf.photopicker.event;
10 |
11 | import android.view.View;
12 |
13 | /**
14 | * Created by donglua on 15/6/20.
15 | */
16 | public interface OnPhotoClickListener {
17 |
18 | void onClick(View v, int position, boolean showCamera);
19 | }
20 |
--------------------------------------------------------------------------------
/PhotoPicker/src/main/java/me/iwf/photopicker/event/PhotoOnLongClick.java:
--------------------------------------------------------------------------------
1 | package me.iwf.photopicker.event;
2 |
3 | /**
4 | * Created by q805699513 on 2017/1/22.
5 | */
6 |
7 | public interface PhotoOnLongClick {
8 | public void sendOnLongClick(int position,String path);
9 | }
10 |
--------------------------------------------------------------------------------
/PhotoPicker/src/main/java/me/iwf/photopicker/event/PhotoOnLongClickManager.java:
--------------------------------------------------------------------------------
1 | package me.iwf.photopicker.event;
2 |
3 | /**
4 | * Created by q805699513 on 2017/1/22.
5 | */
6 |
7 | public class PhotoOnLongClickManager {
8 | private static PhotoOnLongClick listener;
9 | private static PhotoOnLongClickManager photoOnLongClickManager;
10 | public static PhotoOnLongClickManager getInstance() {
11 |
12 | if (photoOnLongClickManager == null) {
13 | photoOnLongClickManager = new PhotoOnLongClickManager();
14 | }
15 | return photoOnLongClickManager;
16 | }
17 |
18 | public void setOnLongClickListener(PhotoOnLongClick nm) {
19 | // if (listener==null){
20 | listener = nm;
21 | // }
22 | }
23 |
24 | public void setOnLongClick(int position, String path) {
25 | if (listener!=null){
26 | listener.sendOnLongClick(position, path);
27 | }
28 | }
29 | }
--------------------------------------------------------------------------------
/PhotoPicker/src/main/java/me/iwf/photopicker/event/Selectable.java:
--------------------------------------------------------------------------------
1 | package me.iwf.photopicker.event;
2 |
3 | import me.iwf.photopicker.entity.Photo;
4 |
5 | /**
6 | * Created by donglua on 15/6/30.
7 | */
8 | public interface Selectable {
9 |
10 |
11 | /**
12 | * Indicates if the item at position position is selected
13 | *
14 | * @param photo Photo of the item to check
15 | * @return true if the item is selected, false otherwise
16 | */
17 | boolean isSelected(Photo photo);
18 |
19 | /**
20 | * Toggle the selection status of the item at a given position
21 | *
22 | * @param photo Photo of the item to toggle the selection status for
23 | */
24 | void toggleSelection(Photo photo);
25 |
26 | /**
27 | * Clear the selection status for all items
28 | */
29 | void clearSelection();
30 |
31 | /**
32 | * Count the selected items
33 | *
34 | * @return Selected items count
35 | */
36 | int getSelectedItemCount();
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/PhotoPicker/src/main/java/me/iwf/photopicker/fragment/ImagePagerFragment.java:
--------------------------------------------------------------------------------
1 | package me.iwf.photopicker.fragment;
2 |
3 | import android.graphics.ColorMatrix;
4 | import android.graphics.ColorMatrixColorFilter;
5 | import android.os.Bundle;
6 | import android.support.annotation.Nullable;
7 | import android.support.v4.app.Fragment;
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.view.ViewTreeObserver;
13 | import android.view.animation.AccelerateInterpolator;
14 | import android.view.animation.DecelerateInterpolator;
15 | import com.bumptech.glide.Glide;
16 | import com.nineoldandroids.animation.Animator;
17 | import com.nineoldandroids.animation.ObjectAnimator;
18 | import com.nineoldandroids.view.ViewHelper;
19 | import com.nineoldandroids.view.ViewPropertyAnimator;
20 | import java.util.ArrayList;
21 | import java.util.Arrays;
22 | import java.util.List;
23 | import me.iwf.photopicker.R;
24 | import me.iwf.photopicker.adapter.PhotoPagerAdapter;
25 |
26 | /**
27 | * Created by donglua on 15/6/21.
28 | */
29 |
30 | // modify ImagePagerFragment.java
31 |
32 | public class ImagePagerFragment extends Fragment {
33 |
34 | public final static String ARG_PATH = "PATHS";
35 | public final static String ARG_CURRENT_ITEM = "ARG_CURRENT_ITEM";
36 |
37 | private ArrayList paths;
38 | private ArrayList longData;
39 |
40 | private ViewPager mViewPager;
41 | private PhotoPagerAdapter mPagerAdapter;
42 |
43 | public final static long ANIM_DURATION = 200L;
44 |
45 | public final static String ARG_THUMBNAIL_TOP = "THUMBNAIL_TOP";
46 | public final static String ARG_THUMBNAIL_LEFT = "THUMBNAIL_LEFT";
47 | public final static String ARG_THUMBNAIL_WIDTH = "THUMBNAIL_WIDTH";
48 | public final static String ARG_THUMBNAIL_HEIGHT = "THUMBNAIL_HEIGHT";
49 | public final static String ARG_HAS_ANIM = "HAS_ANIM";
50 |
51 | private int thumbnailTop = 0;
52 | private int thumbnailLeft = 0;
53 | private int thumbnailWidth = 0;
54 | private int thumbnailHeight = 0;
55 |
56 | private boolean hasAnim = false;
57 |
58 | private final ColorMatrix colorizerMatrix = new ColorMatrix();
59 |
60 | private int currentItem = 0;
61 |
62 |
63 | public static ImagePagerFragment newInstance(List paths, int currentItem) {
64 |
65 | ImagePagerFragment f = new ImagePagerFragment();
66 |
67 | Bundle args = new Bundle();
68 | args.putStringArray(ARG_PATH, paths.toArray(new String[paths.size()]));
69 | args.putInt(ARG_CURRENT_ITEM, currentItem);
70 | args.putBoolean(ARG_HAS_ANIM, false);
71 |
72 | f.setArguments(args);
73 | return f;
74 | }
75 |
76 |
77 | public static ImagePagerFragment newInstance(List paths, int currentItem, int[] screenLocation, int thumbnailWidth, int thumbnailHeight) {
78 |
79 | ImagePagerFragment f = newInstance(paths, currentItem);
80 |
81 | f.getArguments().putInt(ARG_THUMBNAIL_LEFT, screenLocation[0]);
82 | f.getArguments().putInt(ARG_THUMBNAIL_TOP, screenLocation[1]);
83 | f.getArguments().putInt(ARG_THUMBNAIL_WIDTH, thumbnailWidth);
84 | f.getArguments().putInt(ARG_THUMBNAIL_HEIGHT, thumbnailHeight);
85 | f.getArguments().putBoolean(ARG_HAS_ANIM, true);
86 |
87 | return f;
88 | }
89 |
90 |
91 | public void setPhotos(List paths, int currentItem, ArrayList longData) {
92 | if (this.paths == null) {
93 | this.paths = new ArrayList<>();
94 | } else {
95 | this.paths.clear();
96 | this.paths.addAll(paths);
97 | }
98 |
99 | this.currentItem = currentItem;
100 | mPagerAdapter.setLongData(longData);
101 | mViewPager.setCurrentItem(currentItem);
102 | mViewPager.getAdapter().notifyDataSetChanged();
103 | }
104 |
105 |
106 | @Override public void onCreate(Bundle savedInstanceState) {
107 | super.onCreate(savedInstanceState);
108 |
109 | paths = new ArrayList<>();
110 | longData = new ArrayList<>();
111 | Bundle bundle = getArguments();
112 |
113 | if (bundle != null) {
114 | String[] pathArr = bundle.getStringArray(ARG_PATH);
115 | paths.clear();
116 | if (pathArr != null) {
117 |
118 | paths = new ArrayList<>(Arrays.asList(pathArr));
119 | }
120 |
121 | hasAnim = bundle.getBoolean(ARG_HAS_ANIM);
122 | currentItem = bundle.getInt(ARG_CURRENT_ITEM);
123 | thumbnailTop = bundle.getInt(ARG_THUMBNAIL_TOP);
124 | thumbnailLeft = bundle.getInt(ARG_THUMBNAIL_LEFT);
125 | thumbnailWidth = bundle.getInt(ARG_THUMBNAIL_WIDTH);
126 | thumbnailHeight = bundle.getInt(ARG_THUMBNAIL_HEIGHT);
127 | }
128 |
129 | mPagerAdapter = new PhotoPagerAdapter(Glide.with(this), paths,longData);
130 | }
131 |
132 |
133 | @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container,
134 | Bundle savedInstanceState) {
135 |
136 | View rootView = inflater.inflate(R.layout.__picker_picker_fragment_image_pager, container, false);
137 |
138 | mViewPager = (ViewPager) rootView.findViewById(R.id.vp_photos);
139 | mViewPager.setAdapter(mPagerAdapter);
140 | mViewPager.setCurrentItem(currentItem);
141 | mViewPager.setOffscreenPageLimit(5);
142 |
143 | // Only run the animation if we're coming from the parent activity, not if
144 | // we're recreated automatically by the window manager (e.g., device rotation)
145 | if (savedInstanceState == null && hasAnim) {
146 | ViewTreeObserver observer = mViewPager.getViewTreeObserver();
147 | observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
148 | @Override
149 | public boolean onPreDraw() {
150 |
151 | mViewPager.getViewTreeObserver().removeOnPreDrawListener(this);
152 |
153 | // Figure out where the thumbnail and full size versions are, relative
154 | // to the screen and each other
155 | int[] screenLocation = new int[2];
156 | mViewPager.getLocationOnScreen(screenLocation);
157 | thumbnailLeft = thumbnailLeft - screenLocation[0];
158 | thumbnailTop = thumbnailTop - screenLocation[1];
159 |
160 | runEnterAnimation();
161 |
162 | return true;
163 | }
164 | });
165 | }
166 |
167 |
168 | mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
169 | @Override
170 | public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
171 |
172 | }
173 |
174 | @Override public void onPageSelected(int position) {
175 | hasAnim = currentItem == position;
176 | }
177 |
178 | @Override public void onPageScrollStateChanged(int state) {
179 |
180 | }
181 | });
182 |
183 | return rootView;
184 | }
185 |
186 |
187 | /**
188 | * The enter animation scales the picture in from its previous thumbnail
189 | * size/location, colorizing it in parallel. In parallel, the background of the
190 | * activity is fading in. When the pictue is in place, the text description
191 | * drops down.
192 | */
193 | private void runEnterAnimation() {
194 | final long duration = ANIM_DURATION;
195 |
196 | // Set starting values for properties we're going to animate. These
197 | // values scale and position the full size version down to the thumbnail
198 | // size/location, from which we'll animate it back up
199 | ViewHelper.setPivotX(mViewPager, 0);
200 | ViewHelper.setPivotY(mViewPager, 0);
201 | ViewHelper.setScaleX(mViewPager, (float) thumbnailWidth / mViewPager.getWidth());
202 | ViewHelper.setScaleY(mViewPager, (float) thumbnailHeight / mViewPager.getHeight());
203 | ViewHelper.setTranslationX(mViewPager, thumbnailLeft);
204 | ViewHelper.setTranslationY(mViewPager, thumbnailTop);
205 |
206 | // Animate scale and translation to go from thumbnail to full size
207 | ViewPropertyAnimator.animate(mViewPager)
208 | .setDuration(duration)
209 | .scaleX(1)
210 | .scaleY(1)
211 | .translationX(0)
212 | .translationY(0)
213 | .setInterpolator(new DecelerateInterpolator());
214 |
215 | // Fade in the black background
216 | ObjectAnimator bgAnim = ObjectAnimator.ofInt(mViewPager.getBackground(), "alpha", 0, 255);
217 | bgAnim.setDuration(duration);
218 | bgAnim.start();
219 |
220 | // Animate a color filter to take the image from grayscale to full color.
221 | // This happens in parallel with the image scaling and moving into place.
222 | ObjectAnimator colorizer = ObjectAnimator.ofFloat(ImagePagerFragment.this,
223 | "saturation", 0, 1);
224 | colorizer.setDuration(duration);
225 | colorizer.start();
226 |
227 | }
228 |
229 |
230 | /**
231 | * The exit animation is basically a reverse of the enter animation, except that if
232 | * the orientation has changed we simply scale the picture back into the center of
233 | * the screen.
234 | *
235 | * @param endAction This action gets run after the animation completes (this is
236 | * when we actually switch activities)
237 | */
238 | public void runExitAnimation(final Runnable endAction) {
239 |
240 | if (!getArguments().getBoolean(ARG_HAS_ANIM, false) || !hasAnim) {
241 | endAction.run();
242 | return;
243 | }
244 |
245 | final long duration = ANIM_DURATION;
246 |
247 | // Animate image back to thumbnail size/location
248 | ViewPropertyAnimator.animate(mViewPager)
249 | .setDuration(duration)
250 | .setInterpolator(new AccelerateInterpolator())
251 | .scaleX((float) thumbnailWidth / mViewPager.getWidth())
252 | .scaleY((float) thumbnailHeight / mViewPager.getHeight())
253 | .translationX(thumbnailLeft)
254 | .translationY(thumbnailTop)
255 | .setListener(new Animator.AnimatorListener() {
256 | @Override public void onAnimationStart(Animator animation) {
257 | }
258 | @Override public void onAnimationEnd(Animator animation) {
259 | endAction.run();
260 | }
261 | @Override public void onAnimationCancel(Animator animation) {
262 | }
263 | @Override public void onAnimationRepeat(Animator animation) {
264 | }
265 | });
266 |
267 | // Fade out background
268 | ObjectAnimator bgAnim = ObjectAnimator.ofInt(mViewPager.getBackground(), "alpha", 0);
269 | bgAnim.setDuration(duration);
270 | bgAnim.start();
271 |
272 | // Animate a color filter to take the image back to grayscale,
273 | // in parallel with the image scaling and moving into place.
274 | ObjectAnimator colorizer =
275 | ObjectAnimator.ofFloat(ImagePagerFragment.this, "saturation", 1, 0);
276 | colorizer.setDuration(duration);
277 | colorizer.start();
278 | }
279 |
280 |
281 | /**
282 | * This is called by the colorizing animator. It sets a saturation factor that is then
283 | * passed onto a filter on the picture's drawable.
284 | * @param value saturation
285 | */
286 | public void setSaturation(float value) {
287 | colorizerMatrix.setSaturation(value);
288 | ColorMatrixColorFilter colorizerFilter = new ColorMatrixColorFilter(colorizerMatrix);
289 | mViewPager.getBackground().setColorFilter(colorizerFilter);
290 | }
291 |
292 |
293 | public ViewPager getViewPager() {
294 | return mViewPager;
295 | }
296 |
297 |
298 | public ArrayList getPaths() {
299 | return paths;
300 | }
301 |
302 |
303 | public int getCurrentItem() {
304 | return mViewPager.getCurrentItem();
305 | }
306 |
307 | @Override public void onDestroy() {
308 | super.onDestroy();
309 |
310 | paths.clear();
311 | paths = null;
312 |
313 | if (mViewPager != null) {
314 | mViewPager.setAdapter(null);
315 | }
316 | }
317 | }
318 |
--------------------------------------------------------------------------------
/PhotoPicker/src/main/java/me/iwf/photopicker/fragment/PhotoPickerFragment.java:
--------------------------------------------------------------------------------
1 | package me.iwf.photopicker.fragment;
2 |
3 | import android.content.ActivityNotFoundException;
4 | import android.content.Intent;
5 | import android.content.pm.PackageManager;
6 | import android.net.Uri;
7 | import android.os.Bundle;
8 | import android.support.annotation.NonNull;
9 | import android.support.v4.app.Fragment;
10 | import android.support.v4.app.FragmentActivity;
11 | import android.support.v7.widget.DefaultItemAnimator;
12 | import android.support.v7.widget.ListPopupWindow;
13 | import android.support.v7.widget.OrientationHelper;
14 | import android.support.v7.widget.RecyclerView;
15 | import android.support.v7.widget.StaggeredGridLayoutManager;
16 | import android.view.Gravity;
17 | import android.view.LayoutInflater;
18 | import android.view.View;
19 | import android.view.View.OnClickListener;
20 | import android.view.ViewGroup;
21 | import android.widget.AdapterView;
22 | import android.widget.Button;
23 | import android.widget.Toast;
24 |
25 | import com.bumptech.glide.Glide;
26 | import com.bumptech.glide.RequestManager;
27 | import com.yalantis.ucrop.UCrop;
28 |
29 | import java.io.IOException;
30 | import java.util.ArrayList;
31 | import java.util.List;
32 |
33 | import me.iwf.photopicker.PhotoPickerActivity;
34 | import me.iwf.photopicker.R;
35 | import me.iwf.photopicker.adapter.PhotoGridAdapter;
36 | import me.iwf.photopicker.adapter.PopupDirectoryListAdapter;
37 | import me.iwf.photopicker.entity.Photo;
38 | import me.iwf.photopicker.entity.PhotoDirectory;
39 | import me.iwf.photopicker.event.OnPhotoClickListener;
40 | import me.iwf.photopicker.utils.AndroidLifecycleUtils;
41 | import me.iwf.photopicker.utils.ImageCaptureManager;
42 | import me.iwf.photopicker.utils.MediaStoreHelper;
43 | import me.iwf.photopicker.utils.PermissionsConstant;
44 | import me.iwf.photopicker.utils.PermissionsUtils;
45 |
46 | import static android.app.Activity.RESULT_CANCELED;
47 | import static android.app.Activity.RESULT_OK;
48 | import static me.iwf.photopicker.PhotoPicker.DEFAULT_COLUMN_NUMBER;
49 | import static me.iwf.photopicker.PhotoPicker.EXTRA_PREVIEW_ENABLED;
50 | import static me.iwf.photopicker.PhotoPicker.EXTRA_SHOW_GIF;
51 | import static me.iwf.photopicker.utils.MediaStoreHelper.INDEX_ALL_PHOTOS;
52 |
53 | public class PhotoPickerFragment extends Fragment {
54 |
55 | private ImageCaptureManager captureManager;
56 | private PhotoGridAdapter photoGridAdapter;
57 |
58 | private PopupDirectoryListAdapter listAdapter;
59 | //所有photos的路径
60 | private List directories;
61 | //传入的已选照片
62 | private ArrayList originalPhotos;
63 |
64 | private int SCROLL_THRESHOLD = 30;
65 | int column;
66 | //目录弹出框的一次最多显示的目录数目
67 | public static int COUNT_MAX = 4;
68 | private final static String EXTRA_CAMERA = "camera";
69 | private final static String EXTRA_COLUMN = "column";
70 | private final static String EXTRA_COUNT = "count";
71 | private final static String EXTRA_GIF = "gif";
72 | private final static String EXTRA_ORIGIN = "origin";
73 | private final static String EXTRA_CROP = "Crop";
74 | private final static String EXTRA_OPEN_CAMERA = "openCamera";
75 |
76 |
77 | private ListPopupWindow listPopupWindow;
78 | private RequestManager mGlideRequestManager;
79 | private boolean isCrop;
80 | private boolean isOpenCamera;
81 |
82 | public static PhotoPickerFragment newInstance(boolean showCamera, boolean showGif,
83 | boolean previewEnable, int column, int maxCount, ArrayList originalPhotos, boolean isCrop, boolean openCamera) {
84 | Bundle args = new Bundle();
85 | args.putBoolean(EXTRA_CAMERA, showCamera);
86 | args.putBoolean(EXTRA_GIF, showGif);
87 | args.putBoolean(EXTRA_PREVIEW_ENABLED, previewEnable);
88 | args.putInt(EXTRA_COLUMN, column);
89 | args.putInt(EXTRA_COUNT, maxCount);
90 | args.putStringArrayList(EXTRA_ORIGIN, originalPhotos);
91 | args.putBoolean(EXTRA_CROP, isCrop);
92 | args.putBoolean(EXTRA_OPEN_CAMERA, openCamera);
93 |
94 | PhotoPickerFragment fragment = new PhotoPickerFragment();
95 | fragment.setArguments(args);
96 | return fragment;
97 | }
98 |
99 | @Override
100 | public void onCreate(Bundle savedInstanceState) {
101 | super.onCreate(savedInstanceState);
102 |
103 | setRetainInstance(true);
104 |
105 | mGlideRequestManager = Glide.with(this);
106 |
107 | directories = new ArrayList<>();
108 | originalPhotos = getArguments().getStringArrayList(EXTRA_ORIGIN);
109 |
110 | column = getArguments().getInt(EXTRA_COLUMN, DEFAULT_COLUMN_NUMBER);
111 | isCrop = getArguments().getBoolean(EXTRA_CROP, false);
112 | isOpenCamera = getArguments().getBoolean(EXTRA_OPEN_CAMERA, false);
113 |
114 |
115 | boolean showCamera = getArguments().getBoolean(EXTRA_CAMERA, true);
116 | boolean previewEnable = getArguments().getBoolean(EXTRA_PREVIEW_ENABLED, true);
117 |
118 | photoGridAdapter = new PhotoGridAdapter(getActivity(), mGlideRequestManager, directories, originalPhotos, column);
119 | photoGridAdapter.setShowCamera(showCamera);
120 | photoGridAdapter.setPreviewEnable(previewEnable);
121 |
122 | Bundle mediaStoreArgs = new Bundle();
123 |
124 | boolean showGif = getArguments().getBoolean(EXTRA_GIF);
125 | mediaStoreArgs.putBoolean(EXTRA_SHOW_GIF, showGif);
126 | MediaStoreHelper.getPhotoDirs(getActivity(), mediaStoreArgs,
127 | new MediaStoreHelper.PhotosResultCallback() {
128 | @Override
129 | public void onResultCallback(List dirs) {
130 | directories.clear();
131 | directories.addAll(dirs);
132 | photoGridAdapter.notifyDataSetChanged();
133 | listAdapter.notifyDataSetChanged();
134 | adjustHeight();
135 | }
136 | });
137 |
138 | captureManager = new ImageCaptureManager(getActivity());
139 | }
140 |
141 |
142 | @Override
143 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
144 | Bundle savedInstanceState) {
145 |
146 | final View rootView = inflater.inflate(R.layout.__picker_fragment_photo_picker, container, false);
147 |
148 | listAdapter = new PopupDirectoryListAdapter(mGlideRequestManager, directories);
149 |
150 | RecyclerView recyclerView = (RecyclerView) rootView.findViewById(R.id.rv_photos);
151 | StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(column, OrientationHelper.VERTICAL);
152 | layoutManager.setGapStrategy(StaggeredGridLayoutManager.GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS);
153 | recyclerView.setLayoutManager(layoutManager);
154 | recyclerView.setAdapter(photoGridAdapter);
155 | recyclerView.setItemAnimator(new DefaultItemAnimator());
156 |
157 | final Button btSwitchDirectory = (Button) rootView.findViewById(R.id.button);
158 |
159 | listPopupWindow = new ListPopupWindow(getActivity());
160 | listPopupWindow.setWidth(ListPopupWindow.MATCH_PARENT);
161 | listPopupWindow.setAnchorView(btSwitchDirectory);
162 | listPopupWindow.setAdapter(listAdapter);
163 | listPopupWindow.setModal(true);
164 | listPopupWindow.setDropDownGravity(Gravity.BOTTOM);
165 |
166 | listPopupWindow.setOnItemClickListener(new AdapterView.OnItemClickListener() {
167 | @Override
168 | public void onItemClick(AdapterView> parent, View view, int position, long id) {
169 | listPopupWindow.dismiss();
170 |
171 | PhotoDirectory directory = directories.get(position);
172 |
173 | btSwitchDirectory.setText(directory.getName());
174 |
175 | photoGridAdapter.setCurrentDirectoryIndex(position);
176 | photoGridAdapter.notifyDataSetChanged();
177 | }
178 | });
179 |
180 | photoGridAdapter.setOnPhotoClickListener(new OnPhotoClickListener() {
181 | @Override
182 | public void onClick(View v, int position, boolean showCamera) {
183 | final int index = showCamera ? position - 1 : position;
184 |
185 | List photos = photoGridAdapter.getCurrentPhotoPaths();
186 |
187 | int[] screenLocation = new int[2];
188 | v.getLocationOnScreen(screenLocation);
189 | ImagePagerFragment imagePagerFragment =
190 | ImagePagerFragment.newInstance(photos, index, screenLocation, v.getWidth(),
191 | v.getHeight());
192 |
193 | ((PhotoPickerActivity) getActivity()).addImagePagerFragment(imagePagerFragment);
194 | }
195 | });
196 |
197 | photoGridAdapter.setOnCameraClickListener(new OnClickListener() {
198 | @Override
199 | public void onClick(View view) {
200 | if (!PermissionsUtils.checkCameraPermission(PhotoPickerFragment.this)) return;
201 | if (!PermissionsUtils.checkWriteStoragePermission(PhotoPickerFragment.this)) return;
202 | openCamera();
203 | }
204 | });
205 |
206 | btSwitchDirectory.setOnClickListener(new OnClickListener() {
207 | @Override
208 | public void onClick(View v) {
209 |
210 | if (listPopupWindow.isShowing()) {
211 | listPopupWindow.dismiss();
212 | } else if (!getActivity().isFinishing()) {
213 | adjustHeight();
214 | listPopupWindow.show();
215 | }
216 | }
217 | });
218 |
219 |
220 | recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
221 | @Override
222 | public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
223 | super.onScrolled(recyclerView, dx, dy);
224 | // Log.d(">>> Picker >>>", "dy = " + dy);
225 | if (Math.abs(dy) > SCROLL_THRESHOLD) {
226 | mGlideRequestManager.pauseRequests();
227 | } else {
228 | resumeRequestsIfNotDestroyed();
229 | }
230 | }
231 |
232 | @Override
233 | public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
234 | if (newState == RecyclerView.SCROLL_STATE_IDLE) {
235 | resumeRequestsIfNotDestroyed();
236 | }
237 | }
238 | });
239 |
240 | return rootView;
241 | }
242 |
243 | public void activityCamera() {
244 | if (!PermissionsUtils.checkCameraPermission(PhotoPickerFragment.this)) return;
245 | if (!PermissionsUtils.checkWriteStoragePermission(PhotoPickerFragment.this)) return;
246 | openCamera();
247 | }
248 |
249 | public void openCamera() {
250 | try {
251 | Intent intent = captureManager.dispatchTakePictureIntent();
252 | startActivityForResult(intent, ImageCaptureManager.REQUEST_TAKE_PHOTO);
253 | } catch (IOException e) {
254 | e.printStackTrace();
255 | } catch (ActivityNotFoundException e) {
256 | // TODO No Activity Found to handle Intent
257 | e.printStackTrace();
258 | }
259 | }
260 |
261 | @Override
262 | public void onActivityResult(int requestCode, int resultCode, Intent data) {
263 | if (isOpenCamera &&requestCode == ImageCaptureManager.REQUEST_TAKE_PHOTO && resultCode == RESULT_CANCELED) {
264 | getActivity().finish();
265 | }
266 | if (isOpenCamera && requestCode == UCrop.REQUEST_CROP && resultCode == RESULT_CANCELED) {
267 | getActivity().finish();
268 | }
269 | if (requestCode == ImageCaptureManager.REQUEST_TAKE_PHOTO && resultCode == RESULT_OK) {
270 |
271 | if (captureManager == null) {
272 | FragmentActivity activity = getActivity();
273 | captureManager = new ImageCaptureManager(activity);
274 | }
275 | captureManager.galleryAddPic();
276 | if (isCrop) {
277 | String path = captureManager.getCurrentPhotoPath();
278 | ((PhotoPickerActivity) getActivity()).openCropActivity(path);
279 | return;
280 | }
281 | //如果是拍照不裁剪
282 | if (isOpenCamera) {
283 | String path = captureManager.getCurrentPhotoPath();
284 | ((PhotoPickerActivity) getActivity()).PhotoCamear(path);
285 | return;
286 | }
287 | captureManager.galleryAddPic();
288 | if (directories.size() > 0) {
289 | String path = captureManager.getCurrentPhotoPath();
290 | PhotoDirectory directory = directories.get(INDEX_ALL_PHOTOS);
291 | directory.getPhotos().add(INDEX_ALL_PHOTOS, new Photo(path.hashCode(), path));
292 | directory.setCoverPath(path);
293 | photoGridAdapter.notifyDataSetChanged();
294 | }
295 | }
296 |
297 | if (resultCode == RESULT_OK && requestCode == UCrop.REQUEST_CROP) {
298 | Uri resultUri = UCrop.getOutput(data);
299 | ((PhotoPickerActivity) getActivity()).PhotoCamear(resultUri.getPath());
300 |
301 | } else if (resultCode == UCrop.RESULT_ERROR) {
302 | final Throwable cropError = UCrop.getError(data);
303 | Toast.makeText(getActivity(), "裁剪失败", Toast.LENGTH_SHORT).show();
304 | getActivity().finish();
305 | }
306 |
307 | }
308 |
309 | @Override
310 | public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
311 | if (grantResults.length > 0
312 | && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
313 | switch (requestCode) {
314 | case PermissionsConstant.REQUEST_CAMERA:
315 | case PermissionsConstant.REQUEST_EXTERNAL_WRITE:
316 | if (PermissionsUtils.checkWriteStoragePermission(this) &&
317 | PermissionsUtils.checkCameraPermission(this)) {
318 | openCamera();
319 | }
320 | break;
321 | }
322 | }
323 | }
324 |
325 | public PhotoGridAdapter getPhotoGridAdapter() {
326 | return photoGridAdapter;
327 | }
328 |
329 |
330 | @Override
331 | public void onSaveInstanceState(Bundle outState) {
332 | captureManager.onSaveInstanceState(outState);
333 | super.onSaveInstanceState(outState);
334 | }
335 |
336 |
337 | @Override
338 | public void onViewStateRestored(Bundle savedInstanceState) {
339 | captureManager.onRestoreInstanceState(savedInstanceState);
340 | super.onViewStateRestored(savedInstanceState);
341 | }
342 |
343 | public ArrayList getSelectedPhotoPaths() {
344 | return photoGridAdapter.getSelectedPhotoPaths();
345 | }
346 |
347 | public void adjustHeight() {
348 | if (listAdapter == null) return;
349 | int count = listAdapter.getCount();
350 | count = count < COUNT_MAX ? count : COUNT_MAX;
351 | if (listPopupWindow != null) {
352 | listPopupWindow.setHeight(count * getResources().getDimensionPixelOffset(R.dimen.__picker_item_directory_height));
353 | }
354 | }
355 |
356 | @Override
357 | public void onDestroy() {
358 | super.onDestroy();
359 |
360 | if (directories == null) {
361 | return;
362 | }
363 |
364 | for (PhotoDirectory directory : directories) {
365 | directory.getPhotoPaths().clear();
366 | directory.getPhotos().clear();
367 | directory.setPhotos(null);
368 | }
369 | directories.clear();
370 | directories = null;
371 | }
372 |
373 | private void resumeRequestsIfNotDestroyed() {
374 | if (!AndroidLifecycleUtils.canLoadImage(this)) {
375 | return;
376 | }
377 |
378 | mGlideRequestManager.resumeRequests();
379 | }
380 |
381 |
382 | }
383 |
--------------------------------------------------------------------------------
/PhotoPicker/src/main/java/me/iwf/photopicker/utils/AndroidLifecycleUtils.java:
--------------------------------------------------------------------------------
1 | package me.iwf.photopicker.utils;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.os.Build;
6 | import android.support.v4.app.Fragment;
7 | import android.support.v4.app.FragmentActivity;
8 |
9 | public class AndroidLifecycleUtils {
10 | public static boolean canLoadImage(Fragment fragment) {
11 | if (fragment == null) {
12 | return true;
13 | }
14 |
15 | FragmentActivity activity = fragment.getActivity();
16 |
17 | return canLoadImage(activity);
18 | }
19 |
20 | public static boolean canLoadImage(Context context) {
21 | if (context == null) {
22 | return true;
23 | }
24 |
25 | if (!(context instanceof Activity)) {
26 | return true;
27 | }
28 |
29 | Activity activity = (Activity) context;
30 | return canLoadImage(activity);
31 | }
32 |
33 | public static boolean canLoadImage(Activity activity) {
34 | if (activity == null) {
35 | return true;
36 | }
37 |
38 | boolean destroyed = Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 &&
39 | activity.isDestroyed();
40 |
41 | if (destroyed || activity.isFinishing()) {
42 | return false;
43 | }
44 |
45 | return true;
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/PhotoPicker/src/main/java/me/iwf/photopicker/utils/FileUtils.java:
--------------------------------------------------------------------------------
1 | package me.iwf.photopicker.utils;
2 |
3 | import android.util.Log;
4 |
5 | import java.io.File;
6 |
7 | /**
8 | * Created by myc on 2016/12/14.
9 | * More Code on 1101255053@qq.com
10 | * Description:
11 | */
12 | public class FileUtils {
13 | public static boolean fileIsExists(String path) {
14 | if (path == null || path.trim().length() <= 0) {
15 | return false;
16 | }
17 | try {
18 | File f = new File(path);
19 | if (!f.exists()) {
20 | return false;
21 | }
22 | } catch (Exception e) {
23 | return false;
24 | }
25 | Log.e("TMG",path+"file not exists");
26 | return true;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/PhotoPicker/src/main/java/me/iwf/photopicker/utils/ImageCaptureManager.java:
--------------------------------------------------------------------------------
1 | package me.iwf.photopicker.utils;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 | import android.net.Uri;
6 | import android.os.Build;
7 | import android.os.Bundle;
8 | import android.os.Environment;
9 | import android.provider.MediaStore;
10 | import android.support.v4.content.FileProvider;
11 | import android.text.TextUtils;
12 | import android.util.Log;
13 |
14 | import java.io.File;
15 | import java.io.IOException;
16 | import java.text.SimpleDateFormat;
17 | import java.util.Date;
18 | import java.util.Locale;
19 |
20 | /**
21 | * Created by donglua on 15/6/23.
22 | *
23 | *
24 | * http://developer.android.com/training/camera/photobasics.html
25 | */
26 | public class ImageCaptureManager {
27 |
28 | private final static String CAPTURED_PHOTO_PATH_KEY = "mCurrentPhotoPath";
29 | public static final int REQUEST_TAKE_PHOTO = 1;
30 |
31 | private Context mContext;
32 | private String mCurrentPhotoPath;
33 |
34 | public ImageCaptureManager(Context mContext) {
35 | this.mContext = mContext;
36 | }
37 |
38 | private File createImageFile() throws IOException {
39 | // Create an image file name
40 | String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.ENGLISH).format(new Date());
41 | String imageFileName = "JPEG_" + timeStamp + ".jpg";
42 | File storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
43 |
44 | if (!storageDir.exists()) {
45 | if (!storageDir.mkdir()) {
46 | Log.e("TAG", "Throwing Errors....");
47 | throw new IOException();
48 | }
49 | }
50 |
51 | File image = new File(storageDir, imageFileName);
52 |
53 | // Save a file: path for use with ACTION_VIEW intents
54 | mCurrentPhotoPath = image.getAbsolutePath();
55 | return image;
56 | }
57 |
58 |
59 | public Intent dispatchTakePictureIntent() throws IOException {
60 | Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
61 | // Ensure that there's a camera activity to handle the intent
62 | if (takePictureIntent.resolveActivity(mContext.getPackageManager()) != null) {
63 | // Create the File where the photo should go
64 | File file = createImageFile();
65 | Uri photoFile;
66 | if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
67 | String authority = mContext.getApplicationInfo().packageName + ".fileProvider";
68 | photoFile = FileProvider.getUriForFile(this.mContext.getApplicationContext(), authority, file);
69 | } else {
70 | photoFile = Uri.fromFile(file);
71 | }
72 |
73 | // Continue only if the File was successfully created
74 | if (photoFile != null) {
75 | takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoFile);
76 | }
77 | }
78 | return takePictureIntent;
79 | }
80 |
81 |
82 | public void galleryAddPic() {
83 | Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
84 |
85 | if (TextUtils.isEmpty(mCurrentPhotoPath)) {
86 | return;
87 | }
88 |
89 | File f = new File(mCurrentPhotoPath);
90 | Uri contentUri = Uri.fromFile(f);
91 | mediaScanIntent.setData(contentUri);
92 | mContext.sendBroadcast(mediaScanIntent);
93 | }
94 |
95 |
96 | public String getCurrentPhotoPath() {
97 | return mCurrentPhotoPath;
98 | }
99 |
100 |
101 | public void onSaveInstanceState(Bundle savedInstanceState) {
102 | if (savedInstanceState != null && mCurrentPhotoPath != null) {
103 | savedInstanceState.putString(CAPTURED_PHOTO_PATH_KEY, mCurrentPhotoPath);
104 | }
105 | }
106 |
107 | public void onRestoreInstanceState(Bundle savedInstanceState) {
108 | if (savedInstanceState != null && savedInstanceState.containsKey(CAPTURED_PHOTO_PATH_KEY)) {
109 | mCurrentPhotoPath = savedInstanceState.getString(CAPTURED_PHOTO_PATH_KEY);
110 | }
111 | }
112 |
113 | }
114 |
--------------------------------------------------------------------------------
/PhotoPicker/src/main/java/me/iwf/photopicker/utils/MediaStoreHelper.java:
--------------------------------------------------------------------------------
1 | package me.iwf.photopicker.utils;
2 |
3 | import android.content.Context;
4 | import android.database.Cursor;
5 | import android.os.Bundle;
6 | import android.support.v4.app.FragmentActivity;
7 | import android.support.v4.app.LoaderManager;
8 | import android.support.v4.content.Loader;
9 | import java.lang.ref.WeakReference;
10 | import java.util.ArrayList;
11 | import java.util.List;
12 | import me.iwf.photopicker.PhotoPicker;
13 | import me.iwf.photopicker.R;
14 | import me.iwf.photopicker.entity.PhotoDirectory;
15 |
16 | import static android.provider.BaseColumns._ID;
17 | import static android.provider.MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME;
18 | import static android.provider.MediaStore.Images.ImageColumns.BUCKET_ID;
19 | import static android.provider.MediaStore.MediaColumns.DATA;
20 | import static android.provider.MediaStore.MediaColumns.DATE_ADDED;
21 | import static android.provider.MediaStore.MediaColumns.SIZE;
22 |
23 | /**
24 | * Created by donglua on 15/5/31.
25 | */
26 | public class MediaStoreHelper {
27 |
28 | public final static int INDEX_ALL_PHOTOS = 0;
29 |
30 |
31 | public static void getPhotoDirs(FragmentActivity activity, Bundle args, PhotosResultCallback resultCallback) {
32 | activity.getSupportLoaderManager()
33 | .initLoader(0, args, new PhotoDirLoaderCallbacks(activity, resultCallback));
34 | }
35 |
36 | private static class PhotoDirLoaderCallbacks implements LoaderManager.LoaderCallbacks {
37 |
38 | private Context context;
39 | private PhotosResultCallback resultCallback;
40 |
41 | public PhotoDirLoaderCallbacks(Context context, PhotosResultCallback resultCallback) {
42 | this.context = context;
43 | this.resultCallback = resultCallback;
44 | }
45 |
46 | @Override public Loader onCreateLoader(int id, Bundle args) {
47 | return new PhotoDirectoryLoader(context, args.getBoolean(PhotoPicker.EXTRA_SHOW_GIF, false));
48 | }
49 |
50 | @Override public void onLoadFinished(Loader loader, Cursor data) {
51 |
52 | if (data == null) return;
53 | List directories = new ArrayList<>();
54 | PhotoDirectory photoDirectoryAll = new PhotoDirectory();
55 | photoDirectoryAll.setName(context.getString(R.string.__picker_all_image));
56 | photoDirectoryAll.setId("ALL");
57 |
58 | while (data.moveToNext()) {
59 |
60 | int imageId = data.getInt(data.getColumnIndexOrThrow(_ID));
61 | String bucketId = data.getString(data.getColumnIndexOrThrow(BUCKET_ID));
62 | String name = data.getString(data.getColumnIndexOrThrow(BUCKET_DISPLAY_NAME));
63 | String path = data.getString(data.getColumnIndexOrThrow(DATA));
64 | long size = data.getInt(data.getColumnIndexOrThrow(SIZE));
65 |
66 | if (size < 1) continue;
67 |
68 | PhotoDirectory photoDirectory = new PhotoDirectory();
69 | photoDirectory.setId(bucketId);
70 | photoDirectory.setName(name);
71 |
72 | if (!directories.contains(photoDirectory)) {
73 | photoDirectory.setCoverPath(path);
74 | photoDirectory.addPhoto(imageId, path);
75 | photoDirectory.setDateAdded(data.getLong(data.getColumnIndexOrThrow(DATE_ADDED)));
76 | directories.add(photoDirectory);
77 | } else {
78 | directories.get(directories.indexOf(photoDirectory)).addPhoto(imageId, path);
79 | }
80 |
81 | photoDirectoryAll.addPhoto(imageId, path);
82 | }
83 | if (photoDirectoryAll.getPhotoPaths().size() > 0) {
84 | photoDirectoryAll.setCoverPath(photoDirectoryAll.getPhotoPaths().get(0));
85 | }
86 | directories.add(INDEX_ALL_PHOTOS, photoDirectoryAll);
87 | if (resultCallback != null) {
88 | resultCallback.onResultCallback(directories);
89 | }
90 | }
91 |
92 | @Override public void onLoaderReset(Loader loader) {
93 |
94 | }
95 | }
96 |
97 |
98 | public interface PhotosResultCallback {
99 | void onResultCallback(List directories);
100 | }
101 |
102 | }
103 |
--------------------------------------------------------------------------------
/PhotoPicker/src/main/java/me/iwf/photopicker/utils/PermissionsConstant.java:
--------------------------------------------------------------------------------
1 | package me.iwf.photopicker.utils;
2 |
3 | import android.Manifest;
4 | import android.os.Build;
5 | import android.support.annotation.RequiresApi;
6 |
7 | /**
8 | * Created by donglua on 2016/10/19.
9 | */
10 |
11 | public class PermissionsConstant {
12 |
13 | public static final int REQUEST_CAMERA = 1;
14 | public static final int REQUEST_EXTERNAL_READ = 2;
15 | public static final int REQUEST_EXTERNAL_WRITE = 3;
16 |
17 | public static final String[] PERMISSIONS_CAMERA = {
18 | Manifest.permission.CAMERA,
19 | Manifest.permission.WRITE_EXTERNAL_STORAGE
20 | };
21 | public static final String[] PERMISSIONS_EXTERNAL_WRITE = {
22 | Manifest.permission.WRITE_EXTERNAL_STORAGE
23 | };
24 |
25 | @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
26 | public static final String[] PERMISSIONS_EXTERNAL_READ = {
27 | Manifest.permission.READ_EXTERNAL_STORAGE
28 | };
29 | }
30 |
--------------------------------------------------------------------------------
/PhotoPicker/src/main/java/me/iwf/photopicker/utils/PermissionsUtils.java:
--------------------------------------------------------------------------------
1 | package me.iwf.photopicker.utils;
2 |
3 | import android.Manifest;
4 | import android.app.Activity;
5 | import android.content.pm.PackageManager;
6 | import android.os.Build;
7 | import android.support.annotation.RequiresApi;
8 | import android.support.v4.app.ActivityCompat;
9 | import android.support.v4.app.Fragment;
10 | import android.support.v4.content.ContextCompat;
11 |
12 | import static android.Manifest.permission.CAMERA;
13 | import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
14 | import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
15 |
16 | /**
17 | * Created by donglua on 2016/10/19.
18 | */
19 |
20 | public class PermissionsUtils {
21 |
22 | public static boolean checkReadStoragePermission(Activity activity) {
23 | if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN) {
24 | return true;
25 | }
26 | int readStoragePermissionState =
27 | ContextCompat.checkSelfPermission(activity, READ_EXTERNAL_STORAGE);
28 |
29 | boolean readStoragePermissionGranted = readStoragePermissionState == PackageManager.PERMISSION_GRANTED;
30 |
31 | if (!readStoragePermissionGranted) {
32 | ActivityCompat.requestPermissions(activity,
33 | PermissionsConstant.PERMISSIONS_EXTERNAL_READ,
34 | PermissionsConstant.REQUEST_EXTERNAL_READ);
35 | }
36 | return readStoragePermissionGranted;
37 | }
38 |
39 | public static boolean checkWriteStoragePermission(Fragment fragment) {
40 |
41 | int writeStoragePermissionState =
42 | ContextCompat.checkSelfPermission(fragment.getContext(), WRITE_EXTERNAL_STORAGE);
43 |
44 | boolean writeStoragePermissionGranted = writeStoragePermissionState == PackageManager.PERMISSION_GRANTED;
45 |
46 | if (!writeStoragePermissionGranted) {
47 | fragment.requestPermissions(PermissionsConstant.PERMISSIONS_EXTERNAL_WRITE,
48 | PermissionsConstant.REQUEST_EXTERNAL_WRITE);
49 | }
50 | return writeStoragePermissionGranted;
51 | }
52 |
53 | public static boolean checkCameraPermission(Fragment fragment) {
54 | int cameraPermissionState = ContextCompat.checkSelfPermission(fragment.getContext(), CAMERA);
55 |
56 | boolean cameraPermissionGranted = cameraPermissionState == PackageManager.PERMISSION_GRANTED;
57 |
58 | if (!cameraPermissionGranted) {
59 | fragment.requestPermissions(PermissionsConstant.PERMISSIONS_CAMERA,
60 | PermissionsConstant.REQUEST_CAMERA);
61 | }
62 | return cameraPermissionGranted;
63 | }
64 |
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/PhotoPicker/src/main/java/me/iwf/photopicker/utils/PhotoDirectoryLoader.java:
--------------------------------------------------------------------------------
1 | package me.iwf.photopicker.utils;
2 |
3 | import android.content.Context;
4 | import android.net.Uri;
5 | import android.provider.MediaStore.Images.Media;
6 | import android.support.v4.content.CursorLoader;
7 |
8 | import static android.provider.MediaStore.MediaColumns.MIME_TYPE;
9 |
10 | /**
11 | * Created by 黄东鲁 on 15/6/28.
12 | */
13 | public class PhotoDirectoryLoader extends CursorLoader {
14 |
15 | final String[] IMAGE_PROJECTION = {
16 | Media._ID,
17 | Media.DATA,
18 | Media.BUCKET_ID,
19 | Media.BUCKET_DISPLAY_NAME,
20 | Media.DATE_ADDED,
21 | Media.SIZE
22 | };
23 |
24 | public PhotoDirectoryLoader(Context context, boolean showGif) {
25 | super(context);
26 |
27 | setProjection(IMAGE_PROJECTION);
28 | setUri(Media.EXTERNAL_CONTENT_URI);
29 | setSortOrder(Media.DATE_ADDED + " DESC");
30 |
31 | setSelection(
32 | MIME_TYPE + "=? or " + MIME_TYPE + "=? or "+ MIME_TYPE + "=? " + (showGif ? ("or " + MIME_TYPE + "=?") : ""));
33 | String[] selectionArgs;
34 | if (showGif) {
35 | selectionArgs = new String[] { "image/jpeg", "image/png", "image/jpg","image/gif" };
36 | } else {
37 | selectionArgs = new String[] { "image/jpeg", "image/png", "image/jpg" };
38 | }
39 | setSelectionArgs(selectionArgs);
40 | }
41 |
42 |
43 | private PhotoDirectoryLoader(Context context, Uri uri, String[] projection, String selection,
44 | String[] selectionArgs, String sortOrder) {
45 | super(context, uri, projection, selection, selectionArgs, sortOrder);
46 | }
47 |
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/PhotoPicker/src/main/java/me/iwf/photopicker/widget/SquareItemLayout.java:
--------------------------------------------------------------------------------
1 | package me.iwf.photopicker.widget;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.widget.RelativeLayout;
6 |
7 | /**
8 | * Created by donglua on 15/6/21.
9 | */
10 | public class SquareItemLayout extends RelativeLayout {
11 | public SquareItemLayout(Context context, AttributeSet attrs, int defStyle) {
12 | super(context, attrs, defStyle);
13 | }
14 |
15 | public SquareItemLayout(Context context, AttributeSet attrs) {
16 | super(context, attrs);
17 | }
18 |
19 | public SquareItemLayout(Context context) {
20 | super(context);
21 | }
22 |
23 | @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
24 | setMeasuredDimension(getDefaultSize(0, widthMeasureSpec), getDefaultSize(0, heightMeasureSpec));
25 | int childWidthSize = getMeasuredWidth();
26 | heightMeasureSpec =
27 | widthMeasureSpec = MeasureSpec.makeMeasureSpec(childWidthSize, MeasureSpec.EXACTLY);
28 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/drawable-hdpi/__picker_checkbox_marked.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdsjlzx/PhotoPicker/981c91286fd9825cc41619a8e886e9e9f04c78c9/PhotoPicker/src/main/res/drawable-hdpi/__picker_checkbox_marked.png
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/drawable-hdpi/__picker_checkbox_n.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdsjlzx/PhotoPicker/981c91286fd9825cc41619a8e886e9e9f04c78c9/PhotoPicker/src/main/res/drawable-hdpi/__picker_checkbox_n.png
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/drawable-hdpi/__picker_ic_broken_image_black_48dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdsjlzx/PhotoPicker/981c91286fd9825cc41619a8e886e9e9f04c78c9/PhotoPicker/src/main/res/drawable-hdpi/__picker_ic_broken_image_black_48dp.png
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/drawable-hdpi/__picker_ic_camera_n.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdsjlzx/PhotoPicker/981c91286fd9825cc41619a8e886e9e9f04c78c9/PhotoPicker/src/main/res/drawable-hdpi/__picker_ic_camera_n.png
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/drawable-hdpi/__picker_ic_camera_p.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdsjlzx/PhotoPicker/981c91286fd9825cc41619a8e886e9e9f04c78c9/PhotoPicker/src/main/res/drawable-hdpi/__picker_ic_camera_p.png
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/drawable-hdpi/__picker_ic_delete_black_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdsjlzx/PhotoPicker/981c91286fd9825cc41619a8e886e9e9f04c78c9/PhotoPicker/src/main/res/drawable-hdpi/__picker_ic_delete_black_24dp.png
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/drawable-hdpi/__picker_ic_delete_n.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdsjlzx/PhotoPicker/981c91286fd9825cc41619a8e886e9e9f04c78c9/PhotoPicker/src/main/res/drawable-hdpi/__picker_ic_delete_n.png
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/drawable-hdpi/__picker_ic_delete_p.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdsjlzx/PhotoPicker/981c91286fd9825cc41619a8e886e9e9f04c78c9/PhotoPicker/src/main/res/drawable-hdpi/__picker_ic_delete_p.png
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/drawable-hdpi/__picker_ic_photo_black_48dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdsjlzx/PhotoPicker/981c91286fd9825cc41619a8e886e9e9f04c78c9/PhotoPicker/src/main/res/drawable-hdpi/__picker_ic_photo_black_48dp.png
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/drawable-mdpi/__picker_checkbox_marked.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdsjlzx/PhotoPicker/981c91286fd9825cc41619a8e886e9e9f04c78c9/PhotoPicker/src/main/res/drawable-mdpi/__picker_checkbox_marked.png
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/drawable-mdpi/__picker_checkbox_n.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdsjlzx/PhotoPicker/981c91286fd9825cc41619a8e886e9e9f04c78c9/PhotoPicker/src/main/res/drawable-mdpi/__picker_checkbox_n.png
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/drawable-mdpi/__picker_ic_broken_image_black_48dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdsjlzx/PhotoPicker/981c91286fd9825cc41619a8e886e9e9f04c78c9/PhotoPicker/src/main/res/drawable-mdpi/__picker_ic_broken_image_black_48dp.png
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/drawable-mdpi/__picker_ic_camera_n.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdsjlzx/PhotoPicker/981c91286fd9825cc41619a8e886e9e9f04c78c9/PhotoPicker/src/main/res/drawable-mdpi/__picker_ic_camera_n.png
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/drawable-mdpi/__picker_ic_camera_p.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdsjlzx/PhotoPicker/981c91286fd9825cc41619a8e886e9e9f04c78c9/PhotoPicker/src/main/res/drawable-mdpi/__picker_ic_camera_p.png
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/drawable-mdpi/__picker_ic_delete_black_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdsjlzx/PhotoPicker/981c91286fd9825cc41619a8e886e9e9f04c78c9/PhotoPicker/src/main/res/drawable-mdpi/__picker_ic_delete_black_24dp.png
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/drawable-mdpi/__picker_ic_delete_n.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdsjlzx/PhotoPicker/981c91286fd9825cc41619a8e886e9e9f04c78c9/PhotoPicker/src/main/res/drawable-mdpi/__picker_ic_delete_n.png
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/drawable-mdpi/__picker_ic_delete_p.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdsjlzx/PhotoPicker/981c91286fd9825cc41619a8e886e9e9f04c78c9/PhotoPicker/src/main/res/drawable-mdpi/__picker_ic_delete_p.png
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/drawable-mdpi/__picker_ic_photo_black_48dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdsjlzx/PhotoPicker/981c91286fd9825cc41619a8e886e9e9f04c78c9/PhotoPicker/src/main/res/drawable-mdpi/__picker_ic_photo_black_48dp.png
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/drawable-v21/__picker_bg_material_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/drawable-xhdpi/__picker_checkbox_marked.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdsjlzx/PhotoPicker/981c91286fd9825cc41619a8e886e9e9f04c78c9/PhotoPicker/src/main/res/drawable-xhdpi/__picker_checkbox_marked.png
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/drawable-xhdpi/__picker_checkbox_n.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdsjlzx/PhotoPicker/981c91286fd9825cc41619a8e886e9e9f04c78c9/PhotoPicker/src/main/res/drawable-xhdpi/__picker_checkbox_n.png
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/drawable-xhdpi/__picker_ic_broken_image_black_48dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdsjlzx/PhotoPicker/981c91286fd9825cc41619a8e886e9e9f04c78c9/PhotoPicker/src/main/res/drawable-xhdpi/__picker_ic_broken_image_black_48dp.png
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/drawable-xhdpi/__picker_ic_camera_n.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdsjlzx/PhotoPicker/981c91286fd9825cc41619a8e886e9e9f04c78c9/PhotoPicker/src/main/res/drawable-xhdpi/__picker_ic_camera_n.png
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/drawable-xhdpi/__picker_ic_camera_p.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdsjlzx/PhotoPicker/981c91286fd9825cc41619a8e886e9e9f04c78c9/PhotoPicker/src/main/res/drawable-xhdpi/__picker_ic_camera_p.png
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/drawable-xhdpi/__picker_ic_delete_black_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdsjlzx/PhotoPicker/981c91286fd9825cc41619a8e886e9e9f04c78c9/PhotoPicker/src/main/res/drawable-xhdpi/__picker_ic_delete_black_24dp.png
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/drawable-xhdpi/__picker_ic_delete_n.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdsjlzx/PhotoPicker/981c91286fd9825cc41619a8e886e9e9f04c78c9/PhotoPicker/src/main/res/drawable-xhdpi/__picker_ic_delete_n.png
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/drawable-xhdpi/__picker_ic_delete_p.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdsjlzx/PhotoPicker/981c91286fd9825cc41619a8e886e9e9f04c78c9/PhotoPicker/src/main/res/drawable-xhdpi/__picker_ic_delete_p.png
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/drawable-xhdpi/__picker_ic_gf_triangle_arrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdsjlzx/PhotoPicker/981c91286fd9825cc41619a8e886e9e9f04c78c9/PhotoPicker/src/main/res/drawable-xhdpi/__picker_ic_gf_triangle_arrow.png
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/drawable-xhdpi/__picker_ic_photo_black_48dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdsjlzx/PhotoPicker/981c91286fd9825cc41619a8e886e9e9f04c78c9/PhotoPicker/src/main/res/drawable-xhdpi/__picker_ic_photo_black_48dp.png
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/drawable-xxhdpi/__picker_checkbox_marked.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdsjlzx/PhotoPicker/981c91286fd9825cc41619a8e886e9e9f04c78c9/PhotoPicker/src/main/res/drawable-xxhdpi/__picker_checkbox_marked.png
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/drawable-xxhdpi/__picker_checkbox_n.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdsjlzx/PhotoPicker/981c91286fd9825cc41619a8e886e9e9f04c78c9/PhotoPicker/src/main/res/drawable-xxhdpi/__picker_checkbox_n.png
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/drawable-xxhdpi/__picker_ic_broken_image_black_48dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdsjlzx/PhotoPicker/981c91286fd9825cc41619a8e886e9e9f04c78c9/PhotoPicker/src/main/res/drawable-xxhdpi/__picker_ic_broken_image_black_48dp.png
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/drawable-xxhdpi/__picker_ic_camera_n.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdsjlzx/PhotoPicker/981c91286fd9825cc41619a8e886e9e9f04c78c9/PhotoPicker/src/main/res/drawable-xxhdpi/__picker_ic_camera_n.png
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/drawable-xxhdpi/__picker_ic_camera_p.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdsjlzx/PhotoPicker/981c91286fd9825cc41619a8e886e9e9f04c78c9/PhotoPicker/src/main/res/drawable-xxhdpi/__picker_ic_camera_p.png
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/drawable-xxhdpi/__picker_ic_delete_black_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdsjlzx/PhotoPicker/981c91286fd9825cc41619a8e886e9e9f04c78c9/PhotoPicker/src/main/res/drawable-xxhdpi/__picker_ic_delete_black_24dp.png
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/drawable-xxhdpi/__picker_ic_delete_n.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdsjlzx/PhotoPicker/981c91286fd9825cc41619a8e886e9e9f04c78c9/PhotoPicker/src/main/res/drawable-xxhdpi/__picker_ic_delete_n.png
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/drawable-xxhdpi/__picker_ic_delete_p.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdsjlzx/PhotoPicker/981c91286fd9825cc41619a8e886e9e9f04c78c9/PhotoPicker/src/main/res/drawable-xxhdpi/__picker_ic_delete_p.png
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/drawable-xxhdpi/__picker_ic_photo_black_48dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdsjlzx/PhotoPicker/981c91286fd9825cc41619a8e886e9e9f04c78c9/PhotoPicker/src/main/res/drawable-xxhdpi/__picker_ic_photo_black_48dp.png
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/drawable-xxxhdpi/__picker_checkbox_marked.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdsjlzx/PhotoPicker/981c91286fd9825cc41619a8e886e9e9f04c78c9/PhotoPicker/src/main/res/drawable-xxxhdpi/__picker_checkbox_marked.png
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/drawable-xxxhdpi/__picker_checkbox_n.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdsjlzx/PhotoPicker/981c91286fd9825cc41619a8e886e9e9f04c78c9/PhotoPicker/src/main/res/drawable-xxxhdpi/__picker_checkbox_n.png
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/drawable-xxxhdpi/__picker_ic_broken_image_black_48dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdsjlzx/PhotoPicker/981c91286fd9825cc41619a8e886e9e9f04c78c9/PhotoPicker/src/main/res/drawable-xxxhdpi/__picker_ic_broken_image_black_48dp.png
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/drawable-xxxhdpi/__picker_ic_camera_n.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdsjlzx/PhotoPicker/981c91286fd9825cc41619a8e886e9e9f04c78c9/PhotoPicker/src/main/res/drawable-xxxhdpi/__picker_ic_camera_n.png
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/drawable-xxxhdpi/__picker_ic_camera_p.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdsjlzx/PhotoPicker/981c91286fd9825cc41619a8e886e9e9f04c78c9/PhotoPicker/src/main/res/drawable-xxxhdpi/__picker_ic_camera_p.png
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/drawable-xxxhdpi/__picker_ic_delete_black_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdsjlzx/PhotoPicker/981c91286fd9825cc41619a8e886e9e9f04c78c9/PhotoPicker/src/main/res/drawable-xxxhdpi/__picker_ic_delete_black_24dp.png
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/drawable-xxxhdpi/__picker_ic_delete_n.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdsjlzx/PhotoPicker/981c91286fd9825cc41619a8e886e9e9f04c78c9/PhotoPicker/src/main/res/drawable-xxxhdpi/__picker_ic_delete_n.png
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/drawable-xxxhdpi/__picker_ic_delete_p.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdsjlzx/PhotoPicker/981c91286fd9825cc41619a8e886e9e9f04c78c9/PhotoPicker/src/main/res/drawable-xxxhdpi/__picker_ic_delete_p.png
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/drawable-xxxhdpi/__picker_ic_photo_black_48dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdsjlzx/PhotoPicker/981c91286fd9825cc41619a8e886e9e9f04c78c9/PhotoPicker/src/main/res/drawable-xxxhdpi/__picker_ic_photo_black_48dp.png
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/drawable/__picker_bg_dialog.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/drawable/__picker_bg_material_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/drawable/__picker_camera.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/drawable/__picker_checkbox_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | -
5 |
6 |
-
7 |
8 |
9 |
13 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | -
22 |
23 |
-
24 |
25 |
26 |
30 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/drawable/__picker_delete.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/drawable/__picker_item_dialog_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
5 |
6 |
7 | -
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/drawable/__picker_item_dialog_selector_bottom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
7 |
8 |
9 | -
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/drawable/__picker_item_dialog_selector_top.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
5 |
6 |
7 |
10 |
11 |
12 | -
13 |
14 |
15 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/drawable/__picker_photo_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | -
5 |
6 |
8 |
9 |
10 |
11 | -
12 |
13 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/layout/__picker_activity_photo_crop.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
15 |
16 |
22 |
23 |
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/layout/__picker_activity_photo_pager.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
16 |
17 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/layout/__picker_activity_photo_picker.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
10 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/layout/__picker_dialog_photo_pager.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/layout/__picker_fragment_photo_picker.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
14 |
15 |
20 |
29 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/layout/__picker_item_dialog.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/layout/__picker_item_directory.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
17 |
24 |
25 |
31 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/layout/__picker_item_photo.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
16 |
17 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/layout/__picker_picker_fragment_image_pager.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
13 |
14 |
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/layout/__picker_picker_item_pager.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/layout/__picker_toolbar.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/menu/__picker_menu_picker.xml:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/menu/__picker_menu_preview.xml:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/values-es/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Imágenes
4 | Eliminar
5 | Ok
6 | Ok(%1$d/%2$d)
7 | %1$d/%2$d
8 | Deshacer
9 | Eliminar una imagen
10 | ¿Eliminar seguro?
11 | Si
12 | Cancelar
13 | Todas las imágenes
14 | Sólo se pueden seleccionar %1$d imágenes
15 | %1$d
16 |
17 |
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/values-pt/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Imagens
4 | Deletar
5 | @android:string/ok
6 | Ok(%1$d/%2$d)
7 | %1$d/%2$d
8 | Desfazer
9 | Feletar uma imagem
10 | Deseja deletar?
11 | Sim
12 | Cancelar
13 | Todas as images
14 | Apenas %1$d imagens podem ser selecionadas
15 | %1$d
16 |
17 |
18 |
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/values-v21/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #e1e1e1
4 |
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/values-zh/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 图片
5 | 删除
6 | 完成
7 | 完成(%1$d/%2$d)
8 | %1$d/%2$d
9 | 撤消
10 | 删除了一张图片
11 | 确认删除?
12 | 确定
13 | 取消
14 | 所有图片
15 | 你最多可以选择%1$d张图片
16 | %1$d张
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | #CA000000
5 | #38393E
6 | #2F3034
7 |
8 |
9 | #44000000
10 | #282828
11 | #f3f3f3
12 |
13 | #282828
14 | #505050
15 | #787878
16 | #ff99cc00
17 | #33ffffff
18 |
19 |
20 |
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/values/dimen.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 48dip
5 | 80dip
6 | 80dip
7 | 80dp
8 |
9 |
10 |
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Images
4 | Delete
5 | Done
6 | Done(%1$d/%2$d)
7 | %1$d/%2$d
8 | Undo
9 | Deleted a photo
10 | Confirm to delete?
11 | Yes
12 | Cancel
13 | All Images
14 | %1$d
15 | You can only select %1$d images
16 |
17 |
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/PhotoPicker/src/main/res/xml/__picker_provider_paths.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | # PhotoPicker
3 |
4 | 一款Android图片选择器,支持直接拍照、拍照并裁剪、单选裁剪、图片多选、图片放大预览、裁剪比例设置等,满足APP图片拍照、选择等模块需求。
5 | ---
6 |
7 | # Example
8 |
9 |
10 |
11 |
12 |
13 | ---
14 |
15 | # Usage
16 |
17 | ### Gradle
18 |
19 | Step 1. 在你的根build.gradle文件中增加JitPack仓库依赖。
20 |
21 | ```groovy
22 | allprojects {
23 | repositories {
24 | jcenter()
25 | maven { url "https://jitpack.io" }
26 | }
27 | }
28 | ```
29 |
30 | Step 2. 在你的model的build.gradle文件中增加PhotoPicker依赖。
31 |
32 | ```groovy
33 | dependencies {
34 | compile 'com.github.jdsjlzx:PhotoPicker:1.0.4'
35 | }
36 | ```
37 | * ```appcompat-v7```version >= 23.0.0
38 |
39 | ### eclipse
40 | [
41 |
42 | ### 拍照并裁剪
43 | ```java
44 | PhotoPicker.builder()
45 | //直接拍照
46 | .setOpenCamera(true)
47 | //拍照后裁剪
48 | .setCrop(true)
49 | //设置裁剪比例(X,Y)
50 | //.setCropXY(1, 1)
51 | //设置裁剪界面标题栏颜色,设置裁剪界面状态栏颜色
52 | //.setCropColors(R.color.colorPrimary, R.color.colorPrimaryDark)
53 | .start(MainActivity.this);
54 | ```
55 |
56 | ### 单选并裁剪
57 | ```java
58 | PhotoPicker.builder()
59 | //设置图片选择数量
60 | .setPhotoCount(1)
61 | //取消选择时点击图片浏览
62 | .setPreviewEnabled(false)
63 | //开启裁剪
64 | .setCrop(true)
65 | //设置裁剪比例(X,Y)
66 | .setCropXY(1, 1)
67 | //设置裁剪界面标题栏颜色,设置裁剪界面状态栏颜色
68 | .setCropColors(R.color.colorPrimary, R.color.colorPrimaryDark)
69 | .start(MainActivity.this);
70 | ```
71 |
72 | ### 图片多选
73 | ```java
74 | private ArrayList selectedPhotos = new ArrayList<>();
75 | PhotoPicker.builder()
76 | //设置选择个数
77 | .setPhotoCount(9)
78 | //选择界面第一个显示拍照按钮
79 | .setShowCamera(true)
80 | //选择时点击图片放大浏览
81 | .setPreviewEnabled(true)
82 | //附带已经选中过的图片
83 | .setSelected(selectedPhotos)
84 | .start(MainActivity.this);
85 |
86 | //多选返回图片后对ArrayList selectedPhotos里的数据操作可达到删除所选择的图片。
87 | ```
88 |
89 | ### 大图浏览
90 | ```java
91 | //多选选中图片后点击进入大图浏览界面以及标题栏显示删除按钮
92 | PhotoPreview.builder()
93 | //附带已经选中过的图片
94 | .setPhotos(selectedPhotos)
95 | //设置要浏览图片的第position张
96 | .setCurrentItem(position)
97 | .start(MainActivity.this);
98 |
99 |
100 | //图片浏览,全屏模式
101 | ArrayList imgData = new ArrayList<>();
102 | PhotoPreview.builder()
103 | //设置浏览的图片数据
104 | .setPhotos(imgData)
105 | //设置点击后浏览的是第几张图
106 | .setCurrentItem(position)
107 | //浏览时不要标题栏
108 | //setShowDeleteButton浏览时显示删除按钮.
109 | .setShowToolbar(false)
110 | //开启浏览时长按后显示PopuWindow,分享、保存、取消 等,可以自定义。
111 | .setOnLongClickListData(onLongClickListData)
112 | .start(PreViewImgActivity.this);
113 | ```
114 |
115 | ### 大图浏览长按显示PopuWindow
116 | [使用参考类](https://github.com/q805699513/PhotoPicker/blob/master/photopickerdemo/src/main/java/me/iwf/PhotoPickerDemo/PreViewImgActivity.java)
117 | //放大预览后可长按图片进行下载、分享、取消(示例)等(自定义)操作,已将选择事件回调回Activity(可根据需求自定义)
118 | .setOnLongClickListData(onLongClickListData)
119 | ###
120 | ```java
121 | private ArrayList onLongClickListData = new ArrayList<>();
122 | //activity或者fragment里图片浏览时使用
123 | onLongClickListData.add("分享");
124 | onLongClickListData.add("保存");
125 | onLongClickListData.add("取消");
126 | //图片长按后的item点击事件回调
127 | PhotoOnLongClickManager photoOnLongClickManager = PhotoOnLongClickManager.getInstance();
128 | photoOnLongClickManager.setOnLongClickListener(new PhotoOnLongClick() {
129 | @Override
130 | public void sendOnLongClick(int position, String path) {
131 | //自己实现分享或者保存等自定义操作
132 | Toast.makeText(PreViewImgActivity.this, "你点击了:" + onLongClickListData.get(position) + ",图片路径:" + path, Toast.LENGTH_LONG).show();
133 | }
134 | });
135 |
136 | //图片浏览API设置
137 | //.setOnLongClickListData(onLongClickListData)
138 |
139 | ```
140 |
141 | ### 图片返回
142 | ```java
143 | @Override
144 | protected void onActivityResult(int requestCode, int resultCode, Intent data) {
145 | super.onActivityResult(requestCode, resultCode, data);
146 | //选择返回
147 | if (resultCode == RESULT_OK &&
148 | (requestCode == PhotoPicker.REQUEST_CODE || requestCode == PhotoPreview.REQUEST_CODE)) {
149 | iv_crop.setVisibility(View.GONE);
150 | recyclerView.setVisibility(View.VISIBLE);
151 |
152 | List photos = null;
153 | if (data != null) {
154 | photos = data.getStringArrayListExtra(PhotoPicker.KEY_SELECTED_PHOTOS);
155 | }
156 | selectedPhotos.clear();
157 | if (photos != null) {
158 | selectedPhotos.addAll(photos);
159 | }
160 | photoAdapter.notifyDataSetChanged();
161 | }
162 | //拍照功能或者裁剪后返回
163 | if (resultCode == RESULT_OK && requestCode == PhotoPicker.CROP_CODE) {
164 | iv_crop.setVisibility(View.VISIBLE);
165 | recyclerView.setVisibility(View.GONE);
166 | Glide.with(getApplicationContext()).load(Uri.fromFile(new File(data.getStringExtra(PhotoPicker.KEY_CAMEAR_PATH)))).into(iv_crop);
167 | }
168 | }
169 | ```
170 |
171 | ### manifest //设置权限以及注册Activity
172 | ```xml
173 |
175 |
176 |
177 |
178 |
179 |
182 | ...
183 |
184 |
187 |
188 |
191 |
192 |
196 |
197 |
198 |
199 | ```
200 | ### Custom style //设置图片选择界面样式
201 | ```xml
202 |
206 |
207 |
217 | ```
218 |
219 | ### Proguard
220 |
221 | ```
222 | # Glide
223 | -keep public class * implements com.bumptech.glide.module.GlideModule
224 | -keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
225 | **[] $VALUES;
226 | public *;
227 | }
228 | # nineoldandroids
229 | -keep interface com.nineoldandroids.view.** { *; }
230 | -dontwarn com.nineoldandroids.**
231 | -keep class com.nineoldandroids.** { *; }
232 | # support-v7-appcompat
233 | -keep public class android.support.v7.widget.** { *; }
234 | -keep public class android.support.v7.internal.widget.** { *; }
235 | -keep public class android.support.v7.internal.view.menu.** { *; }
236 | -keep public class * extends android.support.v4.view.ActionProvider {
237 | public (android.content.Context);
238 | }
239 | # support-design
240 | -dontwarn android.support.design.**
241 | -keep class android.support.design.** { *; }
242 | -keep interface android.support.design.** { *; }
243 | -keep public class android.support.design.R$* { *; }
244 | # ucrop
245 | -dontwarn com.yalantis.ucrop**
246 | -keep class com.yalantis.ucrop** { *; }
247 | -keep interface com.yalantis.ucrop** { *; }
248 | -ignorewarnings
249 | ```
250 |
251 | ---
252 |
253 | ### 添加两个(多个)FileProvider节点问题
254 |
255 | 参考:http://blog.csdn.net/jdsjlzx/article/details/68487013
256 |
257 | ## Thanks
258 | * [uCrop](https://github.com/Yalantis/uCrop)
259 | * [Glide](https://github.com/bumptech/glide)
260 | * [PhotoPicker](https://github.com/donglua/PhotoPicker)
261 |
262 | ## 声明
263 | 本库是对https://github.com/q805699513/PhotoPicker 的修正,最新版本请访问原始地址。
264 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /photopickerdemo.iml
2 | /build
3 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 |
4 | android {
5 | compileSdkVersion 27
6 | buildToolsVersion "26.0.2"
7 | lintOptions {
8 | abortOnError false
9 | checkReleaseBuilds false
10 | }
11 | defaultConfig {
12 | applicationId "me.iwf.PhotoPickerDemo"
13 | minSdkVersion 15
14 | targetSdkVersion 27
15 | versionCode 15
16 | versionName "0.0.1"
17 | }
18 | buildTypes {
19 | release {
20 | minifyEnabled true
21 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
22 | }
23 | }
24 | compileOptions {
25 | sourceCompatibility JavaVersion.VERSION_1_7
26 | targetCompatibility JavaVersion.VERSION_1_7
27 | }
28 | }
29 |
30 |
31 | dependencies {
32 | compile fileTree(dir: 'libs', include: ['*.jar'])
33 | compile project(':PhotoPicker')
34 | }
35 |
36 |
--------------------------------------------------------------------------------
/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 /usr/local/Cellar/android-sdk/24.0.2/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 | # Glide
19 | -keep public class * implements com.bumptech.glide.module.GlideModule
20 | -keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
21 | **[] $VALUES;
22 | public *;
23 | }
24 | # nineoldandroids
25 | -keep interface com.nineoldandroids.view.** { *; }
26 | -dontwarn com.nineoldandroids.**
27 | -keep class com.nineoldandroids.** { *; }
28 | # support-v7-appcompat
29 | -keep public class android.support.v7.widget.** { *; }
30 | -keep public class android.support.v7.internal.widget.** { *; }
31 | -keep public class android.support.v7.internal.view.menu.** { *; }
32 | -keep public class * extends android.support.v4.view.ActionProvider {
33 | public (android.content.Context);
34 | }
35 | # support-design
36 | -dontwarn android.support.design.**
37 | -keep class android.support.design.** { *; }
38 | -keep interface android.support.design.** { *; }
39 | -keep public class android.support.design.R$* { *; }
40 | # ucrop
41 | -dontwarn com.yalantis.ucrop**
42 | -keep class com.yalantis.ucrop** { *; }
43 | -keep interface com.yalantis.ucrop** { *; }
44 | -ignorewarnings
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
9 |
12 |
15 |
16 |
21 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
34 |
35 |
38 |
39 |
43 |
44 |
45 |
46 |
47 |
50 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/app/src/main/java/me/iwf/PhotoPickerDemo/LineGridView.java:
--------------------------------------------------------------------------------
1 | package me.iwf.PhotoPickerDemo;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.graphics.Paint;
6 | import android.util.AttributeSet;
7 | import android.view.View;
8 | import android.widget.GridView;
9 |
10 |
11 |
12 | /**
13 | * Created by Administrator on 2016/4/6.
14 | */
15 | public class LineGridView extends GridView {
16 | public LineGridView(Context context) {
17 | super(context);
18 | // TODO Auto-generated constructor stub
19 | }
20 | public LineGridView(Context context, AttributeSet attrs) {
21 | super(context, attrs);
22 | }
23 | public LineGridView(Context context, AttributeSet attrs, int defStyle) {
24 | super(context, attrs, defStyle);
25 | }
26 | @Override
27 | protected void dispatchDraw(Canvas canvas){
28 | super.dispatchDraw(canvas);
29 | View localView1 = getChildAt(0);
30 | int column = getWidth() / localView1.getWidth();
31 | int childCount = getChildCount();
32 | Paint localPaint;
33 | localPaint = new Paint();
34 | localPaint.setStyle(Paint.Style.STROKE);
35 | localPaint.setColor(getContext().getResources().getColor(R.color.view_color));
36 | for(int i = 0;i < childCount;i++){
37 | View cellView = getChildAt(i);
38 | if((i + 1) % column == 0){
39 | canvas.drawLine(cellView.getLeft(), cellView.getBottom(), cellView.getRight(), cellView.getBottom(), localPaint);
40 | }else if((i + 1) > (childCount - (childCount % column))){
41 | canvas.drawLine(cellView.getRight(), cellView.getTop(), cellView.getRight(), cellView.getBottom(), localPaint);
42 | }else{
43 | canvas.drawLine(cellView.getRight(), cellView.getTop(), cellView.getRight(), cellView.getBottom(), localPaint);
44 | canvas.drawLine(cellView.getLeft(), cellView.getBottom(), cellView.getRight(), cellView.getBottom(), localPaint);
45 | }
46 | }
47 | if(childCount % column != 0){
48 | for(int j = 0 ;j < (column-childCount % column) ; j++){
49 | View lastView = getChildAt(childCount - 1);
50 | canvas.drawLine(lastView.getRight() + lastView.getWidth() * j, lastView.getTop(), lastView.getRight() + lastView.getWidth()* j, lastView.getBottom(), localPaint);
51 | }
52 | }
53 | }
54 |
55 | @Override
56 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
57 | int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
58 | MeasureSpec.AT_MOST);
59 | super.onMeasure(widthMeasureSpec, expandSpec);
60 | }
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/app/src/main/java/me/iwf/PhotoPickerDemo/MainActivity.java:
--------------------------------------------------------------------------------
1 | package me.iwf.PhotoPickerDemo;
2 |
3 | import android.app.Activity;
4 | import android.content.Intent;
5 | import android.net.Uri;
6 | import android.os.Bundle;
7 | import android.support.v7.widget.OrientationHelper;
8 | import android.support.v7.widget.RecyclerView;
9 | import android.support.v7.widget.StaggeredGridLayoutManager;
10 | import android.util.Log;
11 | import android.view.View;
12 | import android.widget.ImageView;
13 | import android.widget.Toast;
14 |
15 | import com.bumptech.glide.Glide;
16 |
17 | import java.io.File;
18 | import java.util.ArrayList;
19 | import java.util.List;
20 |
21 | import me.iwf.photopicker.PhotoPicker;
22 | import me.iwf.photopicker.PhotoPreview;
23 | import me.iwf.photopicker.event.PhotoOnLongClick;
24 | import me.iwf.photopicker.event.PhotoOnLongClickManager;
25 |
26 |
27 | public class MainActivity extends Activity {
28 |
29 | private PhotoAdapter photoAdapter;
30 |
31 | private ArrayList selectedPhotos = new ArrayList<>();
32 | private ArrayList onLongClickListData = new ArrayList<>();
33 |
34 | private ImageView iv_crop;
35 | private RecyclerView recyclerView;
36 |
37 | @Override
38 | protected void onCreate(Bundle savedInstanceState) {
39 | super.onCreate(savedInstanceState);
40 | setContentView(R.layout.activity_main);
41 | //添加长按事件
42 | // PhotoOnLongClickManager photoOnLongClickManager = PhotoOnLongClickManager.getInstance();
43 | // photoOnLongClickManager.setOnLongClickListener(this);
44 | // onLongClickListData.add("分享");
45 | // onLongClickListData.add("保存");
46 |
47 | iv_crop = (ImageView) findViewById(R.id.iv_crop);
48 |
49 | recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
50 | photoAdapter = new PhotoAdapter(this, selectedPhotos);
51 |
52 | recyclerView.setLayoutManager(new StaggeredGridLayoutManager(4, OrientationHelper.VERTICAL));
53 | recyclerView.setAdapter(photoAdapter);
54 |
55 | findViewById(R.id.button_camera).setOnClickListener(new View.OnClickListener() {
56 | @Override
57 | public void onClick(View view) {
58 | PhotoPicker.builder()
59 | .setOpenCamera(true)
60 | .setCrop(true)
61 | .start(MainActivity.this);
62 | }
63 | });
64 |
65 | findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
66 | @Override
67 | public void onClick(View v) {
68 | PhotoPicker.builder()
69 | .setOpenCamera(true)
70 | .start(MainActivity.this);
71 | }
72 | });
73 |
74 |
75 | findViewById(R.id.button_one_photo).setOnClickListener(new View.OnClickListener() {
76 | @Override
77 | public void onClick(View v) {
78 | PhotoPicker.builder()
79 | .setPhotoCount(1)
80 | .setPreviewEnabled(false)
81 | .setCrop(true)
82 | .setCropXY(1, 1)
83 | .setCropColors(R.color.colorPrimary, R.color.colorPrimaryDark)
84 | .start(MainActivity.this);
85 | }
86 | });
87 |
88 | findViewById(R.id.button_grid).setOnClickListener(new View.OnClickListener() {
89 | @Override
90 | public void onClick(View v) {
91 | Intent intent = new Intent(MainActivity.this, PreViewImgActivity.class);
92 | startActivity(intent);
93 | }
94 | });
95 |
96 | findViewById(R.id.multiselect).setOnClickListener(new View.OnClickListener() {
97 | @Override
98 | public void onClick(View v) {
99 | PhotoPicker.builder()
100 | .setPhotoCount(9)
101 | .setShowCamera(true)
102 | .setPreviewEnabled(true)
103 | .setSelected(selectedPhotos)
104 | .start(MainActivity.this);
105 |
106 | }
107 | });
108 |
109 | recyclerView.addOnItemTouchListener(new RecyclerItemClickListener(this,
110 | new RecyclerItemClickListener.OnItemClickListener() {
111 | @Override
112 | public void onItemClick(View view, int position) {
113 | if (photoAdapter.getItemViewType(position) == PhotoAdapter.TYPE_ADD) {
114 | PhotoPicker.builder()
115 | .setPhotoCount(PhotoAdapter.MAX)
116 | .setShowCamera(true)
117 | .setPreviewEnabled(true)
118 | .setSelected(selectedPhotos)
119 | .start(MainActivity.this);
120 | } else {
121 | PhotoPreview.builder()
122 | .setPhotos(selectedPhotos)
123 | .setCurrentItem(position)
124 | .start(MainActivity.this);
125 | }
126 | }
127 | }));
128 | }
129 |
130 | @Override
131 | protected void onActivityResult(int requestCode, int resultCode, Intent data) {
132 | super.onActivityResult(requestCode, resultCode, data);
133 | //选择返回
134 | if (resultCode == RESULT_OK &&
135 | (requestCode == PhotoPicker.REQUEST_CODE || requestCode == PhotoPreview.REQUEST_CODE)) {
136 | iv_crop.setVisibility(View.GONE);
137 | recyclerView.setVisibility(View.VISIBLE);
138 |
139 | List photos = null;
140 | if (data != null) {
141 | photos = data.getStringArrayListExtra(PhotoPicker.KEY_SELECTED_PHOTOS);
142 | }
143 | selectedPhotos.clear();
144 | if (photos != null) {
145 | selectedPhotos.addAll(photos);
146 | }
147 | photoAdapter.notifyDataSetChanged();
148 | }
149 | //拍照功能或者裁剪功能返回
150 | if (resultCode == RESULT_OK && requestCode == PhotoPicker.CROP_CODE) {
151 | iv_crop.setVisibility(View.VISIBLE);
152 | recyclerView.setVisibility(View.GONE);
153 | Glide.with(getApplicationContext()).load(Uri.fromFile(new File(data.getStringExtra(PhotoPicker.KEY_CAMEAR_PATH)))).into(iv_crop);
154 | }
155 | }
156 |
157 | // @Override
158 | // public void sendOnLongClick(int position, String path) {
159 | // //点击图片url为path,自己根据需要实现下载和分享等。
160 | // Toast.makeText(MainActivity.this, "你点击了:" + onLongClickListData.get(position) + path, Toast.LENGTH_SHORT).show();
161 | // }
162 | }
163 |
--------------------------------------------------------------------------------
/app/src/main/java/me/iwf/PhotoPickerDemo/PhotoAdapter.java:
--------------------------------------------------------------------------------
1 | package me.iwf.PhotoPickerDemo;
2 |
3 | import android.content.Context;
4 | import android.net.Uri;
5 | import android.support.v7.widget.RecyclerView;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 | import android.widget.ImageView;
10 | import com.bumptech.glide.Glide;
11 | import com.bumptech.glide.request.RequestOptions;
12 |
13 | import java.io.File;
14 | import java.util.ArrayList;
15 | import me.iwf.photopicker.R;
16 | import me.iwf.photopicker.utils.AndroidLifecycleUtils;
17 |
18 | public class PhotoAdapter extends RecyclerView.Adapter {
19 |
20 | private ArrayList photoPaths = new ArrayList();
21 | private LayoutInflater inflater;
22 |
23 | private Context mContext;
24 |
25 | final static int TYPE_ADD = 1;
26 | final static int TYPE_PHOTO = 2;
27 |
28 | final static int MAX = 9;
29 |
30 | public PhotoAdapter(Context mContext, ArrayList photoPaths) {
31 | this.photoPaths = photoPaths;
32 | this.mContext = mContext;
33 | inflater = LayoutInflater.from(mContext);
34 |
35 | }
36 |
37 |
38 | @Override public PhotoViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
39 | View itemView = null;
40 | switch (viewType) {
41 | case TYPE_ADD:
42 | itemView = inflater.inflate(me.iwf.PhotoPickerDemo.R.layout.item_add, parent, false);
43 | break;
44 | case TYPE_PHOTO:
45 | itemView = inflater.inflate(R.layout.__picker_item_photo, parent, false);
46 | break;
47 | }
48 | return new PhotoViewHolder(itemView);
49 | }
50 |
51 |
52 | @Override
53 | public void onBindViewHolder(final PhotoViewHolder holder, final int position) {
54 |
55 | if (getItemViewType(position) == TYPE_PHOTO) {
56 | Uri uri = Uri.fromFile(new File(photoPaths.get(position)));
57 |
58 | boolean canLoadImage = AndroidLifecycleUtils.canLoadImage(holder.ivPhoto.getContext());
59 |
60 | if (canLoadImage) {
61 | final RequestOptions options = new RequestOptions();
62 | options.centerCrop()
63 | .placeholder(R.drawable.__picker_ic_photo_black_48dp)
64 | .error(R.drawable.__picker_ic_broken_image_black_48dp);
65 | Glide.with(mContext)
66 | .load(uri)
67 | .apply(options)
68 | .thumbnail(0.1f)
69 | .into(holder.ivPhoto);
70 | }
71 | }
72 | }
73 |
74 |
75 | @Override public int getItemCount() {
76 | int count = photoPaths.size() + 1;
77 | if (count > MAX) {
78 | count = MAX;
79 | }
80 | return count;
81 | }
82 |
83 | @Override
84 | public int getItemViewType(int position) {
85 | return (position == photoPaths.size() && position != MAX) ? TYPE_ADD : TYPE_PHOTO;
86 | }
87 |
88 | public static class PhotoViewHolder extends RecyclerView.ViewHolder {
89 | private ImageView ivPhoto;
90 | private View vSelected;
91 | public PhotoViewHolder(View itemView) {
92 | super(itemView);
93 | ivPhoto = (ImageView) itemView.findViewById(R.id.iv_photo);
94 | vSelected = itemView.findViewById(R.id.v_selected);
95 | if (vSelected != null) vSelected.setVisibility(View.GONE);
96 | }
97 | }
98 |
99 | }
100 |
--------------------------------------------------------------------------------
/app/src/main/java/me/iwf/PhotoPickerDemo/PreViewGridAdapter.java:
--------------------------------------------------------------------------------
1 | package me.iwf.PhotoPickerDemo;
2 |
3 | import android.content.Context;
4 | import android.view.LayoutInflater;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 | import android.widget.BaseAdapter;
8 | import android.widget.ImageView;
9 |
10 | import com.bumptech.glide.Glide;
11 | import com.bumptech.glide.request.RequestOptions;
12 |
13 | import java.util.List;
14 |
15 |
16 | /**
17 | * Created by Administrator on 2016/4/7.
18 | */
19 | public class PreViewGridAdapter extends BaseAdapter {
20 | private List lstImageItem;
21 | private Context mContext;
22 |
23 | public PreViewGridAdapter(Context mContext, List arg0) {
24 | this.lstImageItem = arg0;
25 | this.mContext = mContext;
26 | }
27 |
28 | public int getCount() {
29 | return lstImageItem.size();
30 | }
31 |
32 | public Object getItem(int position) {
33 | return lstImageItem.get(position);
34 | }
35 |
36 | public long getItemId(int position) {
37 | return position;
38 | }
39 |
40 | public View getView(int position, View view, ViewGroup parent) {
41 |
42 |
43 | ViewHolder viewHolder = null;
44 | if (view == null) {
45 | viewHolder = new ViewHolder();
46 | view = LayoutInflater.from(mContext).inflate(R.layout.item_img, null);
47 | viewHolder.img = (ImageView) view.findViewById(R.id.img);
48 |
49 | view.setTag(viewHolder);
50 | } else {
51 | viewHolder = (ViewHolder) view.getTag();
52 | }
53 |
54 | final RequestOptions options = new RequestOptions();
55 | options.centerCrop()
56 | .placeholder(me.iwf.photopicker.R.drawable.__picker_ic_photo_black_48dp)
57 | .error(me.iwf.photopicker.R.drawable.__picker_ic_broken_image_black_48dp);
58 | Glide.with(mContext)
59 | .load(lstImageItem.get(position))
60 | .apply(options)
61 | .thumbnail(0.1f)
62 | .into(viewHolder.img);
63 |
64 | return view;
65 | }
66 |
67 | class ViewHolder {
68 | ImageView img;
69 | }
70 | }
--------------------------------------------------------------------------------
/app/src/main/java/me/iwf/PhotoPickerDemo/PreViewImgActivity.java:
--------------------------------------------------------------------------------
1 | package me.iwf.PhotoPickerDemo;
2 |
3 | import android.app.Activity;
4 | import android.os.Bundle;
5 | import android.view.View;
6 | import android.widget.AdapterView;
7 | import android.widget.GridView;
8 | import android.widget.Toast;
9 |
10 | import java.util.ArrayList;
11 |
12 | import me.iwf.photopicker.PhotoPreview;
13 | import me.iwf.photopicker.event.PhotoOnLongClick;
14 | import me.iwf.photopicker.event.PhotoOnLongClickManager;
15 |
16 | /**
17 | * Created by q805699513 on 2017/1/23.
18 | */
19 |
20 | public class PreViewImgActivity extends Activity {
21 |
22 | private GridView img_grid;
23 | ArrayList imgData = new ArrayList<>();
24 | private ArrayList onLongClickListData = new ArrayList<>();
25 |
26 | @Override
27 | protected void onCreate(Bundle savedInstanceState) {
28 | super.onCreate(savedInstanceState);
29 | setContentView(R.layout.activity_preview_img);
30 | findViewById(R.id.back).setOnClickListener(new View.OnClickListener() {
31 | @Override
32 | public void onClick(View view) {
33 | finish();
34 | }
35 | });
36 |
37 | onLongClickListData.add("分享");
38 | onLongClickListData.add("保存");
39 | onLongClickListData.add("取消");
40 | //图片长按后的item点击事件回调
41 | PhotoOnLongClickManager photoOnLongClickManager = PhotoOnLongClickManager.getInstance();
42 | photoOnLongClickManager.setOnLongClickListener(new PhotoOnLongClick() {
43 | @Override
44 | public void sendOnLongClick(int position, String path) {
45 | Toast.makeText(PreViewImgActivity.this, "你点击了:" + onLongClickListData.get(position) + ",图片路径:" + path, Toast.LENGTH_LONG).show();
46 | }
47 | });
48 | imgData.add("https://images-cn.ssl-images-amazon.com/images/I/61PI88GEqTL.jpg");
49 | imgData.add("https://images-cn.ssl-images-amazon.com/images/I/61m2kJWam5L.jpg");
50 | imgData.add("https://images-cn.ssl-images-amazon.com/images/I/61dQGK0xeuL.jpg");
51 | imgData.add("https://images-cn.ssl-images-amazon.com/images/I/71YuPpF6jKL.jpg");
52 | imgData.add("https://images-cn.ssl-images-amazon.com/images/I/615YYN4q7gL.jpg");
53 | imgData.add("https://images-cn.ssl-images-amazon.com/images/I/61Nriqwg2LL.jpg");
54 | imgData.add("https://images-cn.ssl-images-amazon.com/images/I/615b9gM9GgL.jpg");
55 | imgData.add("https://images-cn.ssl-images-amazon.com/images/I/41fi2pEYkuL.jpg");
56 | img_grid = (GridView) findViewById(R.id.img_grid);
57 | PreViewGridAdapter gridAdapter = new PreViewGridAdapter(PreViewImgActivity.this, imgData);
58 | img_grid.setAdapter(gridAdapter);
59 | img_grid.setOnItemClickListener(new AdapterView.OnItemClickListener() {
60 | @Override
61 | public void onItemClick(AdapterView> adapterView, View view, int position, long l) {
62 | PhotoPreview.builder()
63 | .setPhotos(imgData)
64 | .setCurrentItem(position)
65 | .setShowToolbar(false)
66 | .setOnLongClickListData(onLongClickListData)
67 | .start(PreViewImgActivity.this);
68 | }
69 | });
70 | }
71 |
72 | // @Override
73 | // public void sendOnLongClick(int position, String path) {
74 | // Toast.makeText(PreViewImgActivity.this, "你点击了:" + onLongClickListData.get(position) + ",图片路径:" + path, Toast.LENGTH_LONG).show();
75 | //
76 | // }
77 | }
78 |
--------------------------------------------------------------------------------
/app/src/main/java/me/iwf/PhotoPickerDemo/RecyclerItemClickListener.java:
--------------------------------------------------------------------------------
1 | package me.iwf.PhotoPickerDemo;
2 |
3 | import android.content.Context;
4 | import android.support.v7.widget.RecyclerView;
5 | import android.view.GestureDetector;
6 | import android.view.MotionEvent;
7 | import android.view.View;
8 |
9 | public class RecyclerItemClickListener implements RecyclerView.OnItemTouchListener {
10 | private OnItemClickListener mListener;
11 |
12 | public interface OnItemClickListener {
13 | void onItemClick(View view, int position);
14 | }
15 |
16 | GestureDetector mGestureDetector;
17 |
18 | public RecyclerItemClickListener(Context context, OnItemClickListener listener) {
19 | mListener = listener;
20 | mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
21 | @Override
22 | public boolean onSingleTapUp(MotionEvent e) {
23 | return true;
24 | }
25 | });
26 | }
27 |
28 | @Override
29 | public boolean onInterceptTouchEvent(RecyclerView view, MotionEvent e) {
30 | View childView = view.findChildViewUnder(e.getX(), e.getY());
31 | if (childView != null && mListener != null && mGestureDetector.onTouchEvent(e)) {
32 | mListener.onItemClick(childView, view.getChildLayoutPosition(childView));
33 | return true;
34 | }
35 | return false;
36 | }
37 |
38 | @Override public void onTouchEvent(RecyclerView rv, MotionEvent e) {
39 | }
40 |
41 | @Override public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
42 | }
43 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/actionbar_back.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdsjlzx/PhotoPicker/981c91286fd9825cc41619a8e886e9e9f04c78c9/app/src/main/res/drawable-hdpi/actionbar_back.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bg_item_photo.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
15 |
16 |
17 |
23 |
24 |
25 |
31 |
32 |
38 |
39 |
45 |
46 |
52 |
53 |
58 |
59 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_preview_img.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
11 |
18 |
19 |
28 |
29 |
35 |
36 |
37 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/alert_onlongclick.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
16 |
17 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_add.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_img.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdsjlzx/PhotoPicker/981c91286fd9825cc41619a8e886e9e9f04c78c9/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdsjlzx/PhotoPicker/981c91286fd9825cc41619a8e886e9e9f04c78c9/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdsjlzx/PhotoPicker/981c91286fd9825cc41619a8e886e9e9f04c78c9/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdsjlzx/PhotoPicker/981c91286fd9825cc41619a8e886e9e9f04c78c9/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdsjlzx/PhotoPicker/981c91286fd9825cc41619a8e886e9e9f04c78c9/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/values-zh/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | PhotoPicker
3 | 拍照并裁剪(裁剪可以设置宽高比例)
4 | 选择图片
5 | 选择图片(不带拍照按钮且点击不预览图片)
6 | 选择单张图片并裁剪
7 | 选择gif图片
8 | 多次进入PhotoPicker选择图片
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | #d3d3d3
5 |
6 | #38393E
7 | #2F3034
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 56dip
5 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | PhotoPicker
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
11 |
12 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | buildscript {
3 | repositories {
4 | jcenter()
5 | maven {
6 | url 'https://maven.google.com/'
7 | name 'Google'
8 | }
9 | }
10 | dependencies {
11 | classpath 'com.android.tools.build:gradle:2.3.0'
12 | classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5'
13 |
14 | }
15 | }
16 | allprojects {
17 | repositories {
18 | jcenter()
19 | maven { url "https://jitpack.io" }
20 | maven {
21 | url 'https://maven.google.com/'
22 | name 'Google'
23 | }
24 | }
25 | tasks.withType(Javadoc) {
26 | options.addStringOption('Xdoclint:none', '-quiet')
27 | }
28 | }
29 | task clean(type: Delete) {
30 | delete rootProject.buildDir
31 | }
32 |
--------------------------------------------------------------------------------
/circle.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Fix the CircleCI path
4 | function getAndroidSDK(){
5 | export PATH="$ANDROID_HOME/platform-tools:$ANDROID_HOME/tools:$PATH"
6 |
7 | DEPS="$ANDROID_HOME/installed-dependencies"
8 |
9 | if [ ! -e $DEPS ]; then
10 | cp -r /usr/local/android-sdk-linux $ANDROID_HOME &&
11 | echo y | android update sdk -u -a -t android-25 &&
12 | echo y | android update sdk -u -a -t platform-tools &&
13 | echo y | android update sdk -u -a -t build-tools-25.0.1 &&
14 | touch $DEPS
15 | fi
16 | }
17 |
--------------------------------------------------------------------------------
/circle.yml:
--------------------------------------------------------------------------------
1 | # Build configuration file for Circle CI
2 | # needs to be named `circle.yml` and should be in the top level dir of the repo
3 |
4 | machine:
5 | environment:
6 | ANDROID_HOME: /home/ubuntu/android
7 | java:
8 | version: oraclejdk8
9 |
10 | dependencies:
11 | pre:
12 | - ( sleep 5 && while [ 1 ]; do sleep 1; echo y; done ) | android update sdk --no-ui --all --filter "tools,platform-tools,android-25,extra-google-m2repository,extra-android-m2repository,extra-android-support"
13 | - echo y | android update sdk --no-ui --all --filter "build-tools-25.0.1"
14 | cache_directories:
15 | - ~/.android
16 | - ~/android
17 | override:
18 | - (echo "Downloading Android SDK v24 now!")
19 | - (source circle.sh && getAndroidSDK)
20 |
21 | test:
22 | pre:
23 | - (./gradlew build)
24 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 |
19 | org.gradle.jvmargs=-Xmx512m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
20 | org.gradle.parallel=true
21 | android.enableBuildCache=true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdsjlzx/PhotoPicker/981c91286fd9825cc41619a8e886e9e9f04c78c9/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Feb 22 13:42:21 CST 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn ( ) {
37 | echo "$*"
38 | }
39 |
40 | die ( ) {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
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 Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/image/danxuancaijian.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdsjlzx/PhotoPicker/981c91286fd9825cc41619a8e886e9e9f04c78c9/image/danxuancaijian.gif
--------------------------------------------------------------------------------
/image/duoxuan.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdsjlzx/PhotoPicker/981c91286fd9825cc41619a8e886e9e9f04c78c9/image/duoxuan.gif
--------------------------------------------------------------------------------
/image/paizhao.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdsjlzx/PhotoPicker/981c91286fd9825cc41619a8e886e9e9f04c78c9/image/paizhao.gif
--------------------------------------------------------------------------------
/image/wangtu.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdsjlzx/PhotoPicker/981c91286fd9825cc41619a8e886e9e9f04c78c9/image/wangtu.gif
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':PhotoPicker', ':app'
2 |
--------------------------------------------------------------------------------