├── .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 |