├── .gitignore ├── LICENSE ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── lzy │ │ └── imagepickerdemo │ │ ├── GApp.java │ │ ├── ImagePickerActivity.java │ │ ├── SelectDialog.java │ │ ├── imageloader │ │ ├── GlideImageLoader.java │ │ ├── PicassoImageLoader.java │ │ ├── UILImageLoader.java │ │ └── XUtils3ImageLoader.java │ │ └── wxdemo │ │ ├── ImagePickerAdapter.java │ │ └── WxDemoActivity.java │ └── res │ ├── anim │ ├── photo_dialog_in_anim.xml │ └── photo_dialog_out_anim.xml │ ├── drawable │ ├── dialog_item_bg_only.xml │ ├── photo_choose_bg.xml │ ├── select_dialog_item_bg_buttom.xml │ ├── select_dialog_item_bg_center.xml │ ├── select_dialog_item_bg_top.xml │ └── selector_image_add.xml │ ├── layout │ ├── activity_image_picker.xml │ ├── activity_wxdemo.xml │ ├── list_item_image.xml │ ├── view_dialog_item.xml │ └── view_dialog_select.xml │ ├── mipmap-hdpi │ ├── ic_launcher.png │ ├── image_add_nor.png │ └── image_add_sel.png │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── bintray.gradle ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── imagepicker ├── .gitattributes ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── lzy │ │ └── imagepicker │ │ ├── DataHolder.java │ │ ├── ImageDataSource.java │ │ ├── ImagePicker.java │ │ ├── ImagePickerProvider.java │ │ ├── adapter │ │ ├── ImageFolderAdapter.java │ │ ├── ImagePageAdapter.java │ │ └── ImageRecyclerAdapter.java │ │ ├── bean │ │ ├── ImageFolder.java │ │ └── ImageItem.java │ │ ├── loader │ │ └── ImageLoader.java │ │ ├── ui │ │ ├── ImageBaseActivity.java │ │ ├── ImageCropActivity.java │ │ ├── ImageGridActivity.java │ │ ├── ImagePreviewActivity.java │ │ ├── ImagePreviewBaseActivity.java │ │ └── ImagePreviewDelActivity.java │ │ ├── util │ │ ├── BitmapUtil.java │ │ ├── NavigationBarChangeListener.java │ │ ├── ProviderUtil.java │ │ └── Utils.java │ │ └── view │ │ ├── CropImageView.java │ │ ├── FolderPopUpWindow.java │ │ ├── GridSpacingItemDecoration.java │ │ ├── SuperCheckBox.java │ │ ├── SystemBarTintManager.java │ │ └── ViewPagerFixed.java │ └── res │ ├── anim │ ├── fade_in.xml │ ├── fade_out.xml │ ├── hide_to_bottom.xml │ ├── show_from_bottom.xml │ ├── top_in.xml │ └── top_out.xml │ ├── drawable-v21 │ └── bg_folder_item.xml │ ├── drawable │ ├── bg_btn_dis.xml │ ├── bg_btn_nor.xml │ ├── bg_btn_pre.xml │ ├── bg_folder_item.xml │ ├── bg_image_folder.xml │ ├── ic_arrow_back.xml │ ├── ic_cover_shade.xml │ ├── ic_default_image.xml │ ├── ic_vector_check.xml │ ├── ic_vector_delete.xml │ ├── selector_back_press.xml │ ├── selector_grid_camera_bg.xml │ ├── selector_item_checked.xml │ └── selector_top_ok.xml │ ├── layout │ ├── activity_image_crop.xml │ ├── activity_image_grid.xml │ ├── activity_image_preview.xml │ ├── adapter_camera_item.xml │ ├── adapter_folder_list_item.xml │ ├── adapter_image_list_item.xml │ ├── include_top_bar.xml │ └── pop_folder.xml │ ├── mipmap-xxhdpi │ ├── checkbox_checked.png │ ├── checkbox_normal.png │ ├── grid_camera.png │ └── text_indicator.png │ ├── values-v19 │ └── styles.xml │ ├── values │ ├── attrs.xml │ ├── colors.xml │ ├── strings.xml │ └── styles.xml │ └── xml │ └── provider_paths.xml └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | .idea 4 | /local.properties 5 | .DS_Store 6 | /build 7 | /captures 8 | /screenshots 9 | -------------------------------------------------------------------------------- /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 2016 jeasonlzy(廖子尧) 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 | 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ImagePicker 2 | Android自定义相册,完全仿微信UI,实现了拍照、图片选择(单选/多选)、 裁剪 、旋转、等功能。 3 | 4 | ### 由于个人时间有限,该项目停止维护 5 | 如果你发现有bug,或者好的建议,可以提merge request,我测试通过后会立即合并并发布新版本,确保该库处于可用的状态。 6 | 7 | 该项目参考了: 8 | 9 | * [https://github.com/pengjianbo/GalleryFinal](https://github.com/pengjianbo/GalleryFinal) 10 | * [https://github.com/easonline/AndroidImagePicker](https://github.com/easonline/AndroidImagePicker) 11 | 12 | 喜欢原作的可以去使用。同时欢迎大家下载体验本项目,如果使用过程中遇到什么问题,欢迎反馈。 13 | 14 | ## 联系方式 15 | * email: liaojeason@126.com 16 | * QQ群: 489873144 Android 格调小窝(点击图标,可以直接加入,建议使用QQ群,邮箱使用较少,可能看的不及时) 17 | * 如果遇到问题欢迎在群里提问,个人能力也有限,希望一起学习一起进步。 18 | 19 | ## 演示 20 | ![image](https://github.com/jeasonlzy/Screenshots/blob/master/ImagePicker/demo1.png)![image](https://github.com/jeasonlzy/Screenshots/blob/master/ImagePicker/demo2.gif) 21 | ![image](https://github.com/jeasonlzy/Screenshots/blob/master/ImagePicker/demo3.gif)![image](https://github.com/jeasonlzy/Screenshots/blob/master/ImagePicker/demo5.gif) 22 | 23 | ## 1.用法 24 | 25 | 使用前,对于Android Studio的用户,可以选择添加: 26 | ```java 27 | compile 'com.lzy.widget:imagepicker:0.6.1' //指定版本 28 | ``` 29 | 30 | ## 2.功能和参数含义 31 | 32 | ### 温馨提示:目前库中的预览界面有个原图的复选框,暂时只做了UI,还没有做压缩的逻辑 33 | 34 | |配置参数|参数含义| 35 | |:--:|--| 36 | |multiMode|图片选着模式,单选/多选| 37 | |selectLimit|多选限制数量,默认为9| 38 | |showCamera|选择照片时是否显示拍照按钮| 39 | |crop|是否允许裁剪(单选有效)| 40 | |style|有裁剪时,裁剪框是矩形还是圆形| 41 | |focusWidth|矩形裁剪框宽度(圆形自动取宽高最小值)| 42 | |focusHeight|矩形裁剪框高度(圆形自动取宽高最小值)| 43 | |outPutX|裁剪后需要保存的图片宽度| 44 | |outPutY|裁剪后需要保存的图片高度| 45 | |isSaveRectangle|裁剪后的图片是按矩形区域保存还是裁剪框的形状,例如圆形裁剪的时候,该参数给true,那么保存的图片是矩形区域,如果该参数给fale,保存的图片是圆形区域| 46 | |imageLoader|需要使用的图片加载器,自需要实现ImageLoader接口即可| 47 | 48 | ## 3.代码参考 49 | 50 | 更多使用,请下载demo参看源代码 51 | 52 | 1. 首先你需要继承 `com.lzy.imagepicker.loader.ImageLoader` 这个接口,实现其中的方法,比如以下代码是使用 `Picasso` 三方加载库实现的 53 | ```java 54 | public class PicassoImageLoader implements ImageLoader { 55 | 56 | @Override 57 | public void displayImage(Activity activity, String path, ImageView imageView, int width, int height) { 58 | Picasso.with(activity)// 59 |                    .load(Uri.fromFile(new File(path)))// 60 | .placeholder(R.mipmap.default_image)// 61 | .error(R.mipmap.default_image)// 62 | .resize(width, height)// 63 | .centerInside()// 64 | .memoryPolicy(MemoryPolicy.NO_CACHE, MemoryPolicy.NO_STORE)// 65 | .into(imageView); 66 | } 67 | 68 | @Override 69 | public void clearMemoryCache() { 70 | //这里是清除缓存的方法,根据需要自己实现 71 | } 72 | } 73 | ``` 74 | 75 | 2. 然后配置图片选择器,一般在Application初始化配置一次就可以,这里就需要将上面的图片加载器设置进来,其余的配置根据需要设置 76 | ```java 77 | protected void onCreate(Bundle savedInstanceState) { 78 | super.onCreate(savedInstanceState); 79 | setContentView(R.layout.activity_image_picker); 80 | 81 | ImagePicker imagePicker = ImagePicker.getInstance(); 82 | imagePicker.setImageLoader(new PicassoImageLoader()); //设置图片加载器 83 | imagePicker.setShowCamera(true); //显示拍照按钮 84 | imagePicker.setCrop(true); //允许裁剪(单选才有效) 85 | imagePicker.setSaveRectangle(true); //是否按矩形区域保存 86 | imagePicker.setSelectLimit(9); //选中数量限制 87 | imagePicker.setStyle(CropImageView.Style.RECTANGLE); //裁剪框的形状 88 | imagePicker.setFocusWidth(800); //裁剪框的宽度。单位像素(圆形自动取宽高最小值) 89 | imagePicker.setFocusHeight(800); //裁剪框的高度。单位像素(圆形自动取宽高最小值) 90 | imagePicker.setOutPutX(1000);//保存文件的宽度。单位像素 91 | imagePicker.setOutPutY(1000);//保存文件的高度。单位像素 92 | } 93 | ``` 94 | 95 | 3. 以上配置完成后,在适当的方法中开启相册,例如点击按钮时 96 | ```java 97 | public void onClick(View v) { 98 | Intent intent = new Intent(this, ImageGridActivity.class); 99 | startActivityForResult(intent, IMAGE_PICKER); 100 | } 101 | } 102 | ``` 103 | 104 | 4. 如果你想直接调用相机 105 | ```java 106 | Intent intent = new Intent(this, ImageGridActivity.class); 107 | intent.putExtra(ImageGridActivity.EXTRAS_TAKE_PICKERS,true); // 是否是直接打开相机 108 | startActivityForResult(intent, REQUEST_CODE_SELECT); 109 | ``` 110 | 111 | 5. 重写`onActivityResult`方法,回调结果 112 | ```java 113 | @Override 114 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { 115 | super.onActivityResult(requestCode, resultCode, data); 116 | if (resultCode == ImagePicker.RESULT_CODE_ITEMS) { 117 | if (data != null && requestCode == IMAGE_PICKER) { 118 | ArrayList images = (ArrayList) data.getSerializableExtra(ImagePicker.EXTRA_RESULT_ITEMS); 119 | MyAdapter adapter = new MyAdapter(images); 120 | gridView.setAdapter(adapter); 121 | } else { 122 | Toast.makeText(this, "没有数据", Toast.LENGTH_SHORT).show(); 123 | } 124 | } 125 | } 126 | ``` 127 | 128 | ## 更新日志 129 | 130 | V 0.6.1 131 | * [合并] [优化图片选择页UI, 适配预览页的横竖屏切换 #195](https://github.com/jeasonlzy/ImagePicker/pull/195) 132 | 133 | V 0.6.0 134 | * [合并] [调整UI,真正的完全仿微信](https://github.com/jeasonlzy/ImagePicker/pull/193) 135 | * [合并] [fix(location): 解决不合法图片导致的Bug](https://github.com/jeasonlzy/ImagePicker/pull/188) 136 | 137 | V 0.5.5 138 | * [修复]选择图页面进入预览取消选择或者选择后返回列表不更新的问题; 139 | * [修复]6.0动态权限可能导致崩溃的bug; 140 | 141 | V 0.5.4 142 | * [修复]部分内存泄漏问题; 143 | * [修复]新增显示已选中图片的调用方法:详情请查看demo首页的ImagePickerActivity;如果不需要此功能,则WxDemoActivity可能是你想要的。 144 | 145 | V 0.5.3 146 | * [修复]矫正图片旋转导致的oom; 147 | * [修复]部分手机TitleBar和状态栏重复的问题; 148 | 149 | V 0.5.1 150 | * [更正] 由于原图功能其实还没有做,所以本版本隐去了原图的显示。以免用户误解原图问题。 151 | * [修复] 使用RecyclerView替换GridView解决改变选中状态全局刷新的问题; 152 | * [提示] 虽然本次解决了全局刷新,但是如果使用的是Picasso依然会出现重新加载一张图片的问题,这是Picasso自己的问题,建议使用Glide框架。 153 | 154 | V 0.5.0 155 | * [修复] 解决provider冲突问题; 156 | 157 | V 0.4.8 158 | * [修复] 解决demo中直接呼起相机并裁剪不会返回数据的bug,不需要这个功能的可以不更新; 159 | 160 | V 0.4.7 161 | * [新增] 新增可直接调起相机的功能; 162 | * [修复] 解决可能和主项目provider冲突的潜在问题; 163 | * [修复] 点击图片预览空指针崩溃问题; 164 | * [修复] 使用Intent传值限制导致的崩溃问题; 165 | * [修复] 部分机型拍照后图片旋转问题; 166 | * [修复] 更改选择框图片背景为灰色,以免白色图看不清。 167 | 168 | V 0.3.5 169 | * [新增] 提供直接调起相机的方式,并可直接设置牌照是否裁剪; 170 | * [修复] Android7.0设备调系统相机直接崩溃的问题; 171 | * [注意] 如果出现 java.lang.RuntimeException: Unable to get provider android.support.v4.content.FileProvider: java.lang.SecurityException: Provider must not be exported,请直接clean再运行即可。 172 | 173 | ## Licenses 174 | ``` 175 | Copyright 2016 jeasonlzy(廖子尧) 176 | 177 | Licensed under the Apache License, Version 2.0 (the "License"); 178 | you may not use this file except in compliance with the License. 179 | You may obtain a copy of the License at 180 | 181 | http://www.apache.org/licenses/LICENSE-2.0 182 | 183 | Unless required by applicable law or agreed to in writing, software 184 | distributed under the License is distributed on an "AS IS" BASIS, 185 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 186 | See the License for the specific language governing permissions and 187 | limitations under the License. 188 | ``` 189 | 190 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 25 5 | buildToolsVersion "25.0.3" 6 | 7 | defaultConfig { 8 | applicationId "com.lzy.imagepickerdemo" 9 | minSdkVersion 14 10 | targetSdkVersion 25 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(include: ['*.jar'], dir: 'libs') 24 | compile 'com.android.support:appcompat-v7:25.3.1' 25 | compile 'com.android.support:recyclerview-v7:25.3.1' 26 | 27 | compile 'com.github.bumptech.glide:glide:3.7.0' 28 | compile 'com.squareup.picasso:picasso:2.5.2' 29 | compile 'org.xutils:xutils:3.3.36' 30 | compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.5' 31 | 32 | compile 'com.lzy.widget:view-core:0.2.1' 33 | 34 | //compile 'com.lzy.widget:imagepicker:0.6.1' 35 | compile project(':imagepicker') 36 | } 37 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in E:\Android\SDK/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/java/com/lzy/imagepickerdemo/GApp.java: -------------------------------------------------------------------------------- 1 | package com.lzy.imagepickerdemo; 2 | 3 | import android.app.Application; 4 | import android.widget.ImageView; 5 | 6 | import com.nostra13.universalimageloader.core.DisplayImageOptions; 7 | import com.nostra13.universalimageloader.core.ImageLoader; 8 | import com.nostra13.universalimageloader.core.ImageLoaderConfiguration; 9 | 10 | import org.xutils.image.ImageOptions; 11 | import org.xutils.x; 12 | 13 | /** 14 | * ================================================ 15 | * 作 者:jeasonlzy(廖子尧) 16 | * 版 本:1.0 17 | * 创建日期:2016/4/13 18 | * 描 述:我的Github地址 https://github.com/jeasonlzy0216 19 | * 修订历史: 20 | * ================================================ 21 | */ 22 | public class GApp extends Application { 23 | 24 | public static DisplayImageOptions imageLoaderOptions = new DisplayImageOptions.Builder()// 25 | .showImageOnLoading(R.drawable.ic_default_image) //设置图片在下载期间显示的图片 26 | .showImageForEmptyUri(R.drawable.ic_default_image) //设置图片Uri为空或是错误的时候显示的图片 27 | .showImageOnFail(R.drawable.ic_default_image) //设置图片加载/解码过程中错误时候显示的图片 28 | .cacheInMemory(true) //设置下载的图片是否缓存在内存中 29 | .cacheOnDisk(true) //设置下载的图片是否缓存在SD卡中 30 | .build(); //构建完成 31 | 32 | public static ImageOptions xUtilsOptions = new ImageOptions.Builder()// 33 | .setIgnoreGif(false) //是否忽略GIF格式的图片 34 | .setImageScaleType(ImageView.ScaleType.FIT_CENTER) //缩放模式 35 | .setLoadingDrawableId(R.drawable.ic_default_image) //下载中显示的图片 36 | .setFailureDrawableId(R.drawable.ic_default_image) //下载失败显示的图片 37 | .build(); //得到ImageOptions对象 38 | 39 | @Override 40 | public void onCreate() { 41 | super.onCreate(); 42 | ImageLoaderConfiguration config = ImageLoaderConfiguration.createDefault(this); 43 | 44 | ImageLoader.getInstance().init(config); //UniversalImageLoader初始化 45 | x.Ext.init(this); //xUtils3初始化 46 | } 47 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lzy/imagepickerdemo/ImagePickerActivity.java: -------------------------------------------------------------------------------- 1 | package com.lzy.imagepickerdemo; 2 | 3 | import android.content.Intent; 4 | import android.graphics.Color; 5 | import android.os.Bundle; 6 | import android.support.v7.app.AppCompatActivity; 7 | import android.util.TypedValue; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.AbsListView; 11 | import android.widget.BaseAdapter; 12 | import android.widget.Button; 13 | import android.widget.CheckBox; 14 | import android.widget.CompoundButton; 15 | import android.widget.EditText; 16 | import android.widget.GridView; 17 | import android.widget.ImageView; 18 | import android.widget.RadioButton; 19 | import android.widget.SeekBar; 20 | import android.widget.TextView; 21 | import android.widget.Toast; 22 | 23 | import com.lzy.imagepicker.ImagePicker; 24 | import com.lzy.imagepicker.bean.ImageItem; 25 | import com.lzy.imagepicker.ui.ImageGridActivity; 26 | import com.lzy.imagepicker.view.CropImageView; 27 | import com.lzy.imagepickerdemo.imageloader.GlideImageLoader; 28 | import com.lzy.imagepickerdemo.imageloader.PicassoImageLoader; 29 | import com.lzy.imagepickerdemo.imageloader.UILImageLoader; 30 | import com.lzy.imagepickerdemo.imageloader.XUtils3ImageLoader; 31 | import com.lzy.imagepickerdemo.wxdemo.WxDemoActivity; 32 | 33 | import java.util.ArrayList; 34 | import java.util.List; 35 | 36 | /** 37 | * ================================================ 38 | * 作 者:jeasonlzy(廖子尧 Github地址:https://github.com/jeasonlzy0216 39 | * 版 本:1.0 40 | * 创建日期:2016/5/19 41 | * 描 述: 42 | * 修订历史: 43 | * ================================================ 44 | */ 45 | public class ImagePickerActivity extends AppCompatActivity implements SeekBar.OnSeekBarChangeListener, CompoundButton.OnCheckedChangeListener, View.OnClickListener { 46 | 47 | private ImagePicker imagePicker; 48 | 49 | private RadioButton rb_uil; 50 | private RadioButton rb_glide; 51 | private RadioButton rb_picasso; 52 | private RadioButton rb_fresco; 53 | private RadioButton rb_xutils3; 54 | private RadioButton rb_xutils; 55 | private RadioButton rb_single_select; 56 | private RadioButton rb_muti_select; 57 | private RadioButton rb_crop_square; 58 | private RadioButton rb_crop_circle; 59 | private TextView tv_select_limit; 60 | private GridView gridView; 61 | private EditText et_crop_width; 62 | private EditText et_crop_height; 63 | private EditText et_crop_radius; 64 | private EditText et_outputx; 65 | private EditText et_outputy; 66 | 67 | @Override 68 | protected void onCreate(Bundle savedInstanceState) { 69 | super.onCreate(savedInstanceState); 70 | setContentView(R.layout.activity_image_picker); 71 | 72 | imagePicker = ImagePicker.getInstance(); 73 | imagePicker.setImageLoader(new GlideImageLoader()); 74 | 75 | rb_uil = (RadioButton) findViewById(R.id.rb_uil); 76 | rb_glide = (RadioButton) findViewById(R.id.rb_glide); 77 | rb_picasso = (RadioButton) findViewById(R.id.rb_picasso); 78 | rb_fresco = (RadioButton) findViewById(R.id.rb_fresco); 79 | rb_xutils3 = (RadioButton) findViewById(R.id.rb_xutils3); 80 | rb_xutils = (RadioButton) findViewById(R.id.rb_xutils); 81 | rb_single_select = (RadioButton) findViewById(R.id.rb_single_select); 82 | rb_muti_select = (RadioButton) findViewById(R.id.rb_muti_select); 83 | rb_crop_square = (RadioButton) findViewById(R.id.rb_crop_square); 84 | rb_crop_circle = (RadioButton) findViewById(R.id.rb_crop_circle); 85 | rb_glide.setChecked(true); 86 | rb_muti_select.setChecked(true); 87 | rb_crop_square.setChecked(true); 88 | 89 | et_crop_width = (EditText) findViewById(R.id.et_crop_width); 90 | et_crop_width.setText("280"); 91 | et_crop_height = (EditText) findViewById(R.id.et_crop_height); 92 | et_crop_height.setText("280"); 93 | et_crop_radius = (EditText) findViewById(R.id.et_crop_radius); 94 | et_crop_radius.setText("140"); 95 | et_outputx = (EditText) findViewById(R.id.et_outputx); 96 | et_outputx.setText("800"); 97 | et_outputy = (EditText) findViewById(R.id.et_outputy); 98 | et_outputy.setText("800"); 99 | 100 | tv_select_limit = (TextView) findViewById(R.id.tv_select_limit); 101 | SeekBar sb_select_limit = (SeekBar) findViewById(R.id.sb_select_limit); 102 | sb_select_limit.setMax(15); 103 | sb_select_limit.setOnSeekBarChangeListener(this); 104 | sb_select_limit.setProgress(9); 105 | 106 | CheckBox cb_show_camera = (CheckBox) findViewById(R.id.cb_show_camera); 107 | cb_show_camera.setOnCheckedChangeListener(this); 108 | cb_show_camera.setChecked(true); 109 | CheckBox cb_crop = (CheckBox) findViewById(R.id.cb_crop); 110 | cb_crop.setOnCheckedChangeListener(this); 111 | cb_crop.setChecked(true); 112 | CheckBox cb_isSaveRectangle = (CheckBox) findViewById(R.id.cb_isSaveRectangle); 113 | cb_isSaveRectangle.setOnCheckedChangeListener(this); 114 | cb_isSaveRectangle.setChecked(true); 115 | 116 | Button btn_open_gallery = (Button) findViewById(R.id.btn_open_gallery); 117 | btn_open_gallery.setOnClickListener(this); 118 | Button btn_wxDemo = (Button) findViewById(R.id.btn_wxDemo); 119 | btn_wxDemo.setOnClickListener(this); 120 | 121 | gridView = (GridView) findViewById(R.id.gridview); 122 | } 123 | 124 | @Override 125 | public void onClick(View v) { 126 | switch (v.getId()) { 127 | case R.id.btn_open_gallery: 128 | if (rb_uil.isChecked()) imagePicker.setImageLoader(new UILImageLoader()); 129 | else if (rb_glide.isChecked()) imagePicker.setImageLoader(new GlideImageLoader()); 130 | else if (rb_picasso.isChecked()) imagePicker.setImageLoader(new PicassoImageLoader()); 131 | else if (rb_fresco.isChecked()) imagePicker.setImageLoader(new GlideImageLoader()); 132 | else if (rb_xutils3.isChecked()) imagePicker.setImageLoader(new XUtils3ImageLoader()); 133 | else if (rb_xutils.isChecked()) imagePicker.setImageLoader(new GlideImageLoader()); 134 | 135 | if (rb_single_select.isChecked()) imagePicker.setMultiMode(false); 136 | else if (rb_muti_select.isChecked()) imagePicker.setMultiMode(true); 137 | 138 | if (rb_crop_square.isChecked()) { 139 | imagePicker.setStyle(CropImageView.Style.RECTANGLE); 140 | Integer width = Integer.valueOf(et_crop_width.getText().toString()); 141 | Integer height = Integer.valueOf(et_crop_height.getText().toString()); 142 | width = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, width, getResources().getDisplayMetrics()); 143 | height = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, height, getResources().getDisplayMetrics()); 144 | imagePicker.setFocusWidth(width); 145 | imagePicker.setFocusHeight(height); 146 | } else if (rb_crop_circle.isChecked()) { 147 | imagePicker.setStyle(CropImageView.Style.CIRCLE); 148 | Integer radius = Integer.valueOf(et_crop_radius.getText().toString()); 149 | radius = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, radius, getResources().getDisplayMetrics()); 150 | imagePicker.setFocusWidth(radius * 2); 151 | imagePicker.setFocusHeight(radius * 2); 152 | } 153 | 154 | imagePicker.setOutPutX(Integer.valueOf(et_outputx.getText().toString())); 155 | imagePicker.setOutPutY(Integer.valueOf(et_outputy.getText().toString())); 156 | 157 | Intent intent = new Intent(this, ImageGridActivity.class); 158 | intent.putExtra(ImageGridActivity.EXTRAS_IMAGES,images); 159 | //ImagePicker.getInstance().setSelectedImages(images); 160 | startActivityForResult(intent, 100); 161 | break; 162 | case R.id.btn_wxDemo: 163 | startActivity(new Intent(this, WxDemoActivity.class)); 164 | break; 165 | } 166 | } 167 | 168 | @Override 169 | public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 170 | switch (buttonView.getId()) { 171 | case R.id.cb_show_camera: 172 | imagePicker.setShowCamera(isChecked); 173 | break; 174 | case R.id.cb_crop: 175 | imagePicker.setCrop(isChecked); 176 | break; 177 | case R.id.cb_isSaveRectangle: 178 | imagePicker.setSaveRectangle(isChecked); 179 | break; 180 | } 181 | } 182 | 183 | @Override 184 | public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { 185 | tv_select_limit.setText(String.valueOf(progress)); 186 | imagePicker.setSelectLimit(progress); 187 | } 188 | 189 | @Override 190 | public void onStartTrackingTouch(SeekBar seekBar) { 191 | } 192 | 193 | @Override 194 | public void onStopTrackingTouch(SeekBar seekBar) { 195 | } 196 | 197 | 198 | ArrayList images = null; 199 | 200 | @Override 201 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { 202 | super.onActivityResult(requestCode, resultCode, data); 203 | if (resultCode == ImagePicker.RESULT_CODE_ITEMS) { 204 | if (data != null && requestCode == 100) { 205 | images = (ArrayList) data.getSerializableExtra(ImagePicker.EXTRA_RESULT_ITEMS); 206 | MyAdapter adapter = new MyAdapter(images); 207 | gridView.setAdapter(adapter); 208 | } else { 209 | Toast.makeText(this, "没有数据", Toast.LENGTH_SHORT).show(); 210 | } 211 | } 212 | } 213 | 214 | 215 | 216 | private class MyAdapter extends BaseAdapter { 217 | 218 | private List items; 219 | 220 | public MyAdapter(List items) { 221 | this.items = items; 222 | } 223 | 224 | public void setData(List items) { 225 | this.items = items; 226 | notifyDataSetChanged(); 227 | } 228 | 229 | @Override 230 | public int getCount() { 231 | return items.size(); 232 | } 233 | 234 | @Override 235 | public ImageItem getItem(int position) { 236 | return items.get(position); 237 | } 238 | 239 | @Override 240 | public long getItemId(int position) { 241 | return position; 242 | } 243 | 244 | @Override 245 | public View getView(int position, View convertView, ViewGroup parent) { 246 | ImageView imageView; 247 | int size = gridView.getWidth() / 3; 248 | if (convertView == null) { 249 | imageView = new ImageView(ImagePickerActivity.this); 250 | AbsListView.LayoutParams params = new AbsListView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, size); 251 | imageView.setLayoutParams(params); 252 | imageView.setBackgroundColor(Color.parseColor("#88888888")); 253 | } else { 254 | imageView = (ImageView) convertView; 255 | } 256 | imagePicker.getImageLoader().displayImage(ImagePickerActivity.this, getItem(position).path, imageView, size, size); 257 | return imageView; 258 | } 259 | } 260 | } 261 | -------------------------------------------------------------------------------- /app/src/main/java/com/lzy/imagepickerdemo/SelectDialog.java: -------------------------------------------------------------------------------- 1 | package com.lzy.imagepickerdemo; 2 | 3 | import android.app.Activity; 4 | import android.app.Dialog; 5 | import android.os.Bundle; 6 | import android.text.TextUtils; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.View.OnClickListener; 10 | import android.view.ViewGroup; 11 | import android.view.ViewGroup.LayoutParams; 12 | import android.view.Window; 13 | import android.view.WindowManager; 14 | import android.widget.AdapterView; 15 | import android.widget.AdapterView.OnItemClickListener; 16 | import android.widget.BaseAdapter; 17 | import android.widget.Button; 18 | import android.widget.ListView; 19 | import android.widget.TextView; 20 | 21 | import java.util.List; 22 | 23 | /** 24 | * 选择对话框 25 | * 26 | * Author: nanchen 27 | * Email: liushilin520@foxmail.com 28 | * Date: 2017-03-22 11:38 29 | */ 30 | 31 | public class SelectDialog extends Dialog implements OnClickListener,OnItemClickListener { 32 | private SelectDialogListener mListener; 33 | private Activity mActivity; 34 | private Button mMBtn_Cancel; 35 | private TextView mTv_Title; 36 | private List mName; 37 | private String mTitle; 38 | private boolean mUseCustomColor = false; 39 | private int mFirstItemColor; 40 | private int mOtherItemColor; 41 | 42 | public interface SelectDialogListener { 43 | public void onItemClick(AdapterView parent, View view, int position, long id); 44 | } 45 | 46 | 47 | /** 48 | * 取消事件监听接口 49 | * 50 | */ 51 | private SelectDialogCancelListener mCancelListener; 52 | 53 | public interface SelectDialogCancelListener { 54 | public void onCancelClick(View v); 55 | } 56 | 57 | public SelectDialog(Activity activity, int theme, 58 | SelectDialogListener listener,List names) { 59 | super(activity, theme); 60 | mActivity = activity; 61 | mListener = listener; 62 | this.mName=names; 63 | 64 | setCanceledOnTouchOutside(true); 65 | } 66 | 67 | /** 68 | * @param activity 调用弹出菜单的activity 69 | * @param theme 主题 70 | * @param listener 菜单项单击事件 71 | * @param cancelListener 取消事件 72 | * @param names 菜单项名称 73 | * 74 | */ 75 | public SelectDialog(Activity activity, int theme,SelectDialogListener listener,SelectDialogCancelListener cancelListener ,List names) { 76 | super(activity, theme); 77 | mActivity = activity; 78 | mListener = listener; 79 | mCancelListener = cancelListener; 80 | this.mName=names; 81 | 82 | // 设置是否点击外围不解散 83 | setCanceledOnTouchOutside(false); 84 | } 85 | 86 | /** 87 | * @param activity 调用弹出菜单的activity 88 | * @param theme 主题 89 | * @param listener 菜单项单击事件 90 | * @param names 菜单项名称 91 | * @param title 菜单标题文字 92 | * 93 | */ 94 | public SelectDialog(Activity activity, int theme,SelectDialogListener listener,List names,String title) { 95 | super(activity, theme); 96 | mActivity = activity; 97 | mListener = listener; 98 | this.mName=names; 99 | mTitle = title; 100 | 101 | // 设置是否点击外围可解散 102 | setCanceledOnTouchOutside(true); 103 | } 104 | 105 | public SelectDialog(Activity activity, int theme,SelectDialogListener listener,SelectDialogCancelListener cancelListener,List names,String title) { 106 | super(activity, theme); 107 | mActivity = activity; 108 | mListener = listener; 109 | mCancelListener = cancelListener; 110 | this.mName=names; 111 | mTitle = title; 112 | 113 | // 设置是否点击外围可解散 114 | setCanceledOnTouchOutside(true); 115 | } 116 | 117 | @Override 118 | protected void onCreate(Bundle savedInstanceState) { 119 | super.onCreate(savedInstanceState); 120 | View view = getLayoutInflater().inflate(R.layout.view_dialog_select, 121 | null); 122 | setContentView(view, new LayoutParams(LayoutParams.FILL_PARENT, 123 | LayoutParams.WRAP_CONTENT)); 124 | Window window = getWindow(); 125 | // 设置显示动画 126 | window.setWindowAnimations(R.style.main_menu_animstyle); 127 | WindowManager.LayoutParams wl = window.getAttributes(); 128 | wl.x = 0; 129 | wl.y = mActivity.getWindowManager().getDefaultDisplay().getHeight(); 130 | // 以下这两句是为了保证按钮可以水平满屏 131 | wl.width = LayoutParams.MATCH_PARENT; 132 | wl.height = LayoutParams.WRAP_CONTENT; 133 | 134 | // 设置显示位置 135 | onWindowAttributesChanged(wl); 136 | 137 | initViews(); 138 | } 139 | 140 | private void initViews() { 141 | DialogAdapter dialogAdapter=new DialogAdapter(mName); 142 | ListView dialogList=(ListView) findViewById(R.id.dialog_list); 143 | dialogList.setOnItemClickListener(this); 144 | dialogList.setAdapter(dialogAdapter); 145 | mMBtn_Cancel = (Button) findViewById(R.id.mBtn_Cancel); 146 | mTv_Title = (TextView) findViewById(R.id.mTv_Title); 147 | 148 | 149 | mMBtn_Cancel.setOnClickListener(new View.OnClickListener() { 150 | 151 | @Override 152 | public void onClick(View v) { 153 | // TODO Auto-generated method stub 154 | if(mCancelListener != null){ 155 | mCancelListener.onCancelClick(v); 156 | } 157 | dismiss(); 158 | } 159 | }); 160 | 161 | if(!TextUtils.isEmpty(mTitle) && mTv_Title != null){ 162 | mTv_Title.setVisibility(View.VISIBLE); 163 | mTv_Title.setText(mTitle); 164 | }else{ 165 | mTv_Title.setVisibility(View.GONE); 166 | } 167 | } 168 | 169 | @Override 170 | public void onClick(View v) { 171 | dismiss(); 172 | 173 | } 174 | 175 | @Override 176 | public void onItemClick(AdapterView parent, View view, int position, 177 | long id) { 178 | 179 | mListener.onItemClick(parent, view, position, id); 180 | dismiss(); 181 | } 182 | private class DialogAdapter extends BaseAdapter { 183 | private List mStrings; 184 | private Viewholder viewholder; 185 | private LayoutInflater layoutInflater; 186 | public DialogAdapter(List strings) { 187 | this.mStrings = strings; 188 | this.layoutInflater=mActivity.getLayoutInflater(); 189 | } 190 | 191 | @Override 192 | public int getCount() { 193 | // TODO Auto-generated method stub 194 | return mStrings.size(); 195 | } 196 | 197 | @Override 198 | public Object getItem(int position) { 199 | // TODO Auto-generated method stub 200 | return mStrings.get(position); 201 | } 202 | 203 | @Override 204 | public long getItemId(int position) { 205 | // TODO Auto-generated method stub 206 | return position; 207 | } 208 | 209 | @Override 210 | public View getView(int position, View convertView, ViewGroup parent) { 211 | if (null == convertView) { 212 | viewholder=new Viewholder(); 213 | convertView=layoutInflater.inflate(R.layout.view_dialog_item, null); 214 | viewholder.dialogItemButton=(TextView) convertView.findViewById(R.id.dialog_item_bt); 215 | convertView.setTag(viewholder); 216 | }else{ 217 | viewholder=(Viewholder) convertView.getTag(); 218 | } 219 | viewholder.dialogItemButton.setText(mStrings.get(position)); 220 | if (!mUseCustomColor) { 221 | mFirstItemColor = mActivity.getResources().getColor(R.color.blue); 222 | mOtherItemColor = mActivity.getResources().getColor(R.color.blue); 223 | } 224 | if (1 == mStrings.size()) { 225 | viewholder.dialogItemButton.setTextColor(mFirstItemColor); 226 | viewholder.dialogItemButton.setBackgroundResource(R.drawable.dialog_item_bg_only); 227 | } else if (position == 0) { 228 | viewholder.dialogItemButton.setTextColor(mFirstItemColor); 229 | viewholder.dialogItemButton.setBackgroundResource(R.drawable.select_dialog_item_bg_top); 230 | } else if (position == mStrings.size() - 1) { 231 | viewholder.dialogItemButton.setTextColor(mOtherItemColor); 232 | viewholder.dialogItemButton.setBackgroundResource(R.drawable.select_dialog_item_bg_buttom); 233 | } else { 234 | viewholder.dialogItemButton.setTextColor(mOtherItemColor); 235 | viewholder.dialogItemButton.setBackgroundResource(R.drawable.select_dialog_item_bg_center); 236 | } 237 | return convertView; 238 | } 239 | 240 | } 241 | 242 | public static class Viewholder { 243 | public TextView dialogItemButton; 244 | } 245 | 246 | /** 247 | * 设置列表项的文本颜色 248 | */ 249 | public void setItemColor(int firstItemColor, int otherItemColor) { 250 | mFirstItemColor = firstItemColor; 251 | mOtherItemColor = otherItemColor; 252 | mUseCustomColor = true; 253 | } 254 | } 255 | -------------------------------------------------------------------------------- /app/src/main/java/com/lzy/imagepickerdemo/imageloader/GlideImageLoader.java: -------------------------------------------------------------------------------- 1 | package com.lzy.imagepickerdemo.imageloader; 2 | 3 | import android.app.Activity; 4 | import android.net.Uri; 5 | import android.widget.ImageView; 6 | 7 | import com.bumptech.glide.Glide; 8 | import com.bumptech.glide.load.engine.DiskCacheStrategy; 9 | import com.lzy.imagepicker.loader.ImageLoader; 10 | import com.lzy.imagepickerdemo.R; 11 | 12 | import java.io.File; 13 | 14 | /** 15 | * ================================================ 16 | * 作 者:jeasonlzy(廖子尧 Github地址:https://github.com/jeasonlzy0216 17 | * 版 本:1.0 18 | * 创建日期:2016/5/19 19 | * 描 述: 20 | * 修订历史: 21 | * ================================================ 22 | */ 23 | public class GlideImageLoader implements ImageLoader { 24 | 25 | @Override 26 | public void displayImage(Activity activity, String path, ImageView imageView, int width, int height) { 27 | 28 | Glide.with(activity) //配置上下文 29 | .load(Uri.fromFile(new File(path))) //设置图片路径(fix #8,文件名包含%符号 无法识别和显示) 30 | .error(R.drawable.ic_default_image) //设置错误图片 31 | .placeholder(R.drawable.ic_default_image) //设置占位图片 32 | .diskCacheStrategy(DiskCacheStrategy.ALL)//缓存全尺寸 33 | .into(imageView); 34 | } 35 | 36 | @Override 37 | public void displayImagePreview(Activity activity, String path, ImageView imageView, int width, int height) { 38 | Glide.with(activity) //配置上下文 39 | .load(Uri.fromFile(new File(path))) //设置图片路径(fix #8,文件名包含%符号 无法识别和显示) 40 | .diskCacheStrategy(DiskCacheStrategy.ALL)//缓存全尺寸 41 | .into(imageView); 42 | } 43 | 44 | @Override 45 | public void clearMemoryCache() { 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /app/src/main/java/com/lzy/imagepickerdemo/imageloader/PicassoImageLoader.java: -------------------------------------------------------------------------------- 1 | package com.lzy.imagepickerdemo.imageloader; 2 | 3 | /** 4 | * ================================================ 5 | * 作 者:jeasonlzy(廖子尧) 6 | * 版 本:1.0 7 | * 创建日期:2016/3/28 8 | * 描 述:我的Github地址 https://github.com/jeasonlzy0216 9 | * 修订历史: 10 | * ================================================ 11 | */ 12 | 13 | import android.app.Activity; 14 | import android.net.Uri; 15 | import android.widget.ImageView; 16 | 17 | import com.lzy.imagepicker.loader.ImageLoader; 18 | import com.lzy.imagepickerdemo.R; 19 | import com.squareup.picasso.MemoryPolicy; 20 | import com.squareup.picasso.Picasso; 21 | 22 | import java.io.File; 23 | 24 | public class PicassoImageLoader implements ImageLoader { 25 | 26 | @Override 27 | public void displayImage(Activity activity, String path, ImageView imageView, int width, int height) { 28 | Picasso.with(activity)// 29 | .load(Uri.fromFile(new File(path)))// 30 | .placeholder(R.drawable.ic_default_image)// 31 | .error(R.drawable.ic_default_image)// 32 | .resize(width, height)// 33 | .centerInside()// 34 | .memoryPolicy(MemoryPolicy.NO_CACHE, MemoryPolicy.NO_STORE)// 35 | .into(imageView); 36 | } 37 | 38 | @Override 39 | public void displayImagePreview(Activity activity, String path, ImageView imageView, int width, int height) { 40 | Picasso.with(activity)// 41 | .load(Uri.fromFile(new File(path)))// 42 | .resize(width, height)// 43 | .centerInside()// 44 | .memoryPolicy(MemoryPolicy.NO_CACHE, MemoryPolicy.NO_STORE)// 45 | .into(imageView); 46 | } 47 | 48 | @Override 49 | public void clearMemoryCache() { 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /app/src/main/java/com/lzy/imagepickerdemo/imageloader/UILImageLoader.java: -------------------------------------------------------------------------------- 1 | package com.lzy.imagepickerdemo.imageloader; 2 | 3 | /** 4 | * ================================================ 5 | * 作 者:jeasonlzy(廖子尧) 6 | * 版 本:1.0 7 | * 创建日期:2016/3/28 8 | * 描 述:我的Github地址 https://github.com/jeasonlzy0216 9 | * 修订历史: 10 | * ================================================ 11 | */ 12 | 13 | import android.app.Activity; 14 | import android.net.Uri; 15 | import android.widget.ImageView; 16 | 17 | import com.lzy.imagepicker.loader.ImageLoader; 18 | import com.nostra13.universalimageloader.core.assist.ImageSize; 19 | 20 | import java.io.File; 21 | 22 | public class UILImageLoader implements ImageLoader { 23 | 24 | @Override 25 | public void displayImage(Activity activity, String path, ImageView imageView, int width, int height) { 26 | ImageSize size = new ImageSize(width, height); 27 | com.nostra13.universalimageloader.core.ImageLoader.getInstance().displayImage(Uri.fromFile(new File(path)).toString(), imageView, size); 28 | } 29 | 30 | @Override 31 | public void displayImagePreview(Activity activity, String path, ImageView imageView, int width, int height) { 32 | ImageSize size = new ImageSize(width, height); 33 | com.nostra13.universalimageloader.core.ImageLoader.getInstance().displayImage(Uri.fromFile(new File(path)).toString(), imageView, size); 34 | } 35 | 36 | @Override 37 | public void clearMemoryCache() { 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app/src/main/java/com/lzy/imagepickerdemo/imageloader/XUtils3ImageLoader.java: -------------------------------------------------------------------------------- 1 | package com.lzy.imagepickerdemo.imageloader; 2 | 3 | /** 4 | * ================================================ 5 | * 作 者:jeasonlzy(廖子尧) 6 | * 版 本:1.0 7 | * 创建日期:2016/3/28 8 | * 描 述:我的Github地址 https://github.com/jeasonlzy0216 9 | * 修订历史: 10 | * ================================================ 11 | */ 12 | 13 | import android.app.Activity; 14 | import android.graphics.Bitmap; 15 | import android.net.Uri; 16 | import android.widget.ImageView; 17 | 18 | import com.lzy.imagepicker.loader.ImageLoader; 19 | import com.lzy.imagepickerdemo.R; 20 | 21 | import org.xutils.image.ImageOptions; 22 | import org.xutils.x; 23 | 24 | import java.io.File; 25 | 26 | public class XUtils3ImageLoader implements ImageLoader { 27 | @Override 28 | public void displayImage(Activity activity, String path, ImageView imageView, int width, int height) { 29 | ImageOptions options = new ImageOptions.Builder()// 30 | .setLoadingDrawableId(R.drawable.ic_default_image)// 31 | .setFailureDrawableId(R.drawable.ic_default_image)// 32 | .setConfig(Bitmap.Config.RGB_565)// 33 | .setSize(width, height)// 34 | .setCrop(false)// 35 | .setUseMemCache(true)// 36 | .build(); 37 | x.image().bind(imageView, Uri.fromFile(new File(path)).toString(), options); 38 | } 39 | 40 | @Override 41 | public void displayImagePreview(Activity activity, String path, ImageView imageView, int width, int height) { 42 | ImageOptions options = new ImageOptions.Builder()// 43 | .setConfig(Bitmap.Config.RGB_565)// 44 | .setSize(width, height)// 45 | .setCrop(false)// 46 | .setUseMemCache(true)// 47 | .build(); 48 | x.image().bind(imageView, Uri.fromFile(new File(path)).toString(), options); 49 | } 50 | 51 | @Override 52 | public void clearMemoryCache() { 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /app/src/main/java/com/lzy/imagepickerdemo/wxdemo/ImagePickerAdapter.java: -------------------------------------------------------------------------------- 1 | package com.lzy.imagepickerdemo.wxdemo; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.support.v7.widget.RecyclerView; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.widget.ImageView; 10 | 11 | import com.lzy.imagepicker.ImagePicker; 12 | import com.lzy.imagepicker.bean.ImageItem; 13 | import com.lzy.imagepickerdemo.R; 14 | 15 | import java.util.ArrayList; 16 | import java.util.List; 17 | 18 | /** 19 | * ================================================ 20 | * 作 者:ikkong (ikkong@163.com),修改 jeasonlzy(廖子尧) 21 | * 版 本:1.0 22 | * 创建日期:2016/5/19 23 | * 描 述: 24 | * 修订历史:微信图片选择的Adapter, 感谢 ikkong 的提交 25 | * ================================================ 26 | */ 27 | public class ImagePickerAdapter extends RecyclerView.Adapter { 28 | private int maxImgCount; 29 | private Context mContext; 30 | private List mData; 31 | private LayoutInflater mInflater; 32 | private OnRecyclerViewItemClickListener listener; 33 | private boolean isAdded; //是否额外添加了最后一个图片 34 | 35 | public interface OnRecyclerViewItemClickListener { 36 | void onItemClick(View view, int position); 37 | } 38 | 39 | public void setOnItemClickListener(OnRecyclerViewItemClickListener listener) { 40 | this.listener = listener; 41 | } 42 | 43 | public void setImages(List data) { 44 | mData = new ArrayList<>(data); 45 | if (getItemCount() < maxImgCount) { 46 | mData.add(new ImageItem()); 47 | isAdded = true; 48 | } else { 49 | isAdded = false; 50 | } 51 | notifyDataSetChanged(); 52 | } 53 | 54 | public List getImages() { 55 | //由于图片未选满时,最后一张显示添加图片,因此这个方法返回真正的已选图片 56 | if (isAdded) return new ArrayList<>(mData.subList(0, mData.size() - 1)); 57 | else return mData; 58 | } 59 | 60 | public ImagePickerAdapter(Context mContext, List data, int maxImgCount) { 61 | this.mContext = mContext; 62 | this.maxImgCount = maxImgCount; 63 | this.mInflater = LayoutInflater.from(mContext); 64 | setImages(data); 65 | } 66 | 67 | @Override 68 | public SelectedPicViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 69 | return new SelectedPicViewHolder(mInflater.inflate(R.layout.list_item_image, parent, false)); 70 | } 71 | 72 | @Override 73 | public void onBindViewHolder(SelectedPicViewHolder holder, int position) { 74 | holder.bind(position); 75 | } 76 | 77 | @Override 78 | public int getItemCount() { 79 | return mData.size(); 80 | } 81 | 82 | public class SelectedPicViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { 83 | 84 | private ImageView iv_img; 85 | private int clickPosition; 86 | 87 | public SelectedPicViewHolder(View itemView) { 88 | super(itemView); 89 | iv_img = (ImageView) itemView.findViewById(R.id.iv_img); 90 | } 91 | 92 | public void bind(int position) { 93 | //设置条目的点击事件 94 | itemView.setOnClickListener(this); 95 | //根据条目位置设置图片 96 | ImageItem item = mData.get(position); 97 | if (isAdded && position == getItemCount() - 1) { 98 | iv_img.setImageResource(R.drawable.selector_image_add); 99 | clickPosition = WxDemoActivity.IMAGE_ITEM_ADD; 100 | } else { 101 | ImagePicker.getInstance().getImageLoader().displayImage((Activity) mContext, item.path, iv_img, 0, 0); 102 | clickPosition = position; 103 | } 104 | } 105 | 106 | @Override 107 | public void onClick(View v) { 108 | if (listener != null) listener.onItemClick(v, clickPosition); 109 | } 110 | } 111 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lzy/imagepickerdemo/wxdemo/WxDemoActivity.java: -------------------------------------------------------------------------------- 1 | package com.lzy.imagepickerdemo.wxdemo; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.support.v7.widget.GridLayoutManager; 7 | import android.support.v7.widget.RecyclerView; 8 | import android.view.View; 9 | import android.widget.AdapterView; 10 | 11 | import com.lzy.imagepicker.ImagePicker; 12 | import com.lzy.imagepicker.bean.ImageItem; 13 | import com.lzy.imagepicker.ui.ImageGridActivity; 14 | import com.lzy.imagepicker.ui.ImagePreviewDelActivity; 15 | import com.lzy.imagepicker.view.CropImageView; 16 | import com.lzy.imagepickerdemo.R; 17 | import com.lzy.imagepickerdemo.SelectDialog; 18 | import com.lzy.imagepickerdemo.imageloader.GlideImageLoader; 19 | 20 | import java.util.ArrayList; 21 | import java.util.List; 22 | 23 | /** 24 | * ================================================ 25 | * 作 者:ikkong (ikkong@163.com),修改 jeasonlzy(廖子尧) 26 | * 版 本:1.0 27 | * 创建日期:2016/5/19 28 | * 描 述: 29 | * 修订历史:微信图片选择的Adapter, 感谢 ikkong 的提交 30 | * ================================================ 31 | */ 32 | public class WxDemoActivity extends AppCompatActivity implements ImagePickerAdapter.OnRecyclerViewItemClickListener { 33 | 34 | public static final int IMAGE_ITEM_ADD = -1; 35 | public static final int REQUEST_CODE_SELECT = 100; 36 | public static final int REQUEST_CODE_PREVIEW = 101; 37 | 38 | private ImagePickerAdapter adapter; 39 | private ArrayList selImageList; //当前选择的所有图片 40 | private int maxImgCount = 8; //允许选择图片最大数 41 | 42 | @Override 43 | protected void onCreate(Bundle savedInstanceState) { 44 | super.onCreate(savedInstanceState); 45 | setContentView(R.layout.activity_wxdemo); 46 | 47 | //最好放到 Application oncreate执行 48 | initImagePicker(); 49 | initWidget(); 50 | } 51 | 52 | private void initImagePicker() { 53 | ImagePicker imagePicker = ImagePicker.getInstance(); 54 | imagePicker.setImageLoader(new GlideImageLoader()); //设置图片加载器 55 | imagePicker.setShowCamera(true); //显示拍照按钮 56 | imagePicker.setCrop(true); //允许裁剪(单选才有效) 57 | imagePicker.setSaveRectangle(true); //是否按矩形区域保存 58 | imagePicker.setSelectLimit(maxImgCount); //选中数量限制 59 | imagePicker.setStyle(CropImageView.Style.RECTANGLE); //裁剪框的形状 60 | imagePicker.setFocusWidth(800); //裁剪框的宽度。单位像素(圆形自动取宽高最小值) 61 | imagePicker.setFocusHeight(800); //裁剪框的高度。单位像素(圆形自动取宽高最小值) 62 | imagePicker.setOutPutX(1000); //保存文件的宽度。单位像素 63 | imagePicker.setOutPutY(1000); //保存文件的高度。单位像素 64 | } 65 | 66 | private void initWidget() { 67 | RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerView); 68 | selImageList = new ArrayList<>(); 69 | adapter = new ImagePickerAdapter(this, selImageList, maxImgCount); 70 | adapter.setOnItemClickListener(this); 71 | 72 | recyclerView.setLayoutManager(new GridLayoutManager(this, 4)); 73 | recyclerView.setHasFixedSize(true); 74 | recyclerView.setAdapter(adapter); 75 | } 76 | 77 | private SelectDialog showDialog(SelectDialog.SelectDialogListener listener, List names) { 78 | SelectDialog dialog = new SelectDialog(this, R.style 79 | .transparentFrameWindowStyle, 80 | listener, names); 81 | if (!this.isFinishing()) { 82 | dialog.show(); 83 | } 84 | return dialog; 85 | } 86 | 87 | @Override 88 | public void onItemClick(View view, int position) { 89 | switch (position) { 90 | case IMAGE_ITEM_ADD: 91 | List names = new ArrayList<>(); 92 | names.add("拍照"); 93 | names.add("相册"); 94 | showDialog(new SelectDialog.SelectDialogListener() { 95 | @Override 96 | public void onItemClick(AdapterView parent, View view, int position, long id) { 97 | switch (position) { 98 | case 0: // 直接调起相机 99 | /** 100 | * 0.4.7 目前直接调起相机不支持裁剪,如果开启裁剪后不会返回图片,请注意,后续版本会解决 101 | * 102 | * 但是当前直接依赖的版本已经解决,考虑到版本改动很少,所以这次没有上传到远程仓库 103 | * 104 | * 如果实在有所需要,请直接下载源码引用。 105 | */ 106 | //打开选择,本次允许选择的数量 107 | ImagePicker.getInstance().setSelectLimit(maxImgCount - selImageList.size()); 108 | Intent intent = new Intent(WxDemoActivity.this, ImageGridActivity.class); 109 | intent.putExtra(ImageGridActivity.EXTRAS_TAKE_PICKERS, true); // 是否是直接打开相机 110 | startActivityForResult(intent, REQUEST_CODE_SELECT); 111 | break; 112 | case 1: 113 | //打开选择,本次允许选择的数量 114 | ImagePicker.getInstance().setSelectLimit(maxImgCount - selImageList.size()); 115 | Intent intent1 = new Intent(WxDemoActivity.this, ImageGridActivity.class); 116 | /* 如果需要进入选择的时候显示已经选中的图片, 117 | * 详情请查看ImagePickerActivity 118 | * */ 119 | // intent1.putExtra(ImageGridActivity.EXTRAS_IMAGES,images); 120 | startActivityForResult(intent1, REQUEST_CODE_SELECT); 121 | break; 122 | default: 123 | break; 124 | } 125 | 126 | } 127 | }, names); 128 | 129 | 130 | break; 131 | default: 132 | //打开预览 133 | Intent intentPreview = new Intent(this, ImagePreviewDelActivity.class); 134 | intentPreview.putExtra(ImagePicker.EXTRA_IMAGE_ITEMS, (ArrayList) adapter.getImages()); 135 | intentPreview.putExtra(ImagePicker.EXTRA_SELECTED_IMAGE_POSITION, position); 136 | intentPreview.putExtra(ImagePicker.EXTRA_FROM_ITEMS, true); 137 | startActivityForResult(intentPreview, REQUEST_CODE_PREVIEW); 138 | break; 139 | } 140 | } 141 | 142 | ArrayList images = null; 143 | 144 | @Override 145 | public void onActivityResult(int requestCode, int resultCode, Intent data) { 146 | super.onActivityResult(requestCode, resultCode, data); 147 | if (resultCode == ImagePicker.RESULT_CODE_ITEMS) { 148 | //添加图片返回 149 | if (data != null && requestCode == REQUEST_CODE_SELECT) { 150 | images = (ArrayList) data.getSerializableExtra(ImagePicker.EXTRA_RESULT_ITEMS); 151 | if (images != null) { 152 | selImageList.addAll(images); 153 | adapter.setImages(selImageList); 154 | } 155 | } 156 | } else if (resultCode == ImagePicker.RESULT_CODE_BACK) { 157 | //预览图片返回 158 | if (data != null && requestCode == REQUEST_CODE_PREVIEW) { 159 | images = (ArrayList) data.getSerializableExtra(ImagePicker.EXTRA_IMAGE_ITEMS); 160 | if (images != null) { 161 | selImageList.clear(); 162 | selImageList.addAll(images); 163 | adapter.setImages(selImageList); 164 | } 165 | } 166 | } 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /app/src/main/res/anim/photo_dialog_in_anim.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/anim/photo_dialog_out_anim.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/dialog_item_bg_only.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/photo_choose_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/select_dialog_item_bg_buttom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/select_dialog_item_bg_center.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/select_dialog_item_bg_top.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/selector_image_add.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_image_picker.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 10 | 11 | 16 | 17 | 25 | 26 | 30 | 31 | 36 | 37 | 42 | 43 | 48 | 49 | 54 | 55 | 62 | 63 | 68 | 69 | 74 | 75 | 76 | 77 | 78 | 83 | 84 | 92 | 93 | 98 | 99 | 105 | 106 | 112 | 113 | 114 | 115 | 116 | 122 | 123 | 129 | 130 | 139 | 140 | 145 | 146 | 147 | 152 | 153 | 158 | 159 | 164 | 165 | 166 | 172 | 173 | 178 | 179 | 185 | 186 | 194 | 195 | 203 | 204 | 210 | 211 | 219 | 220 | 221 | 226 | 227 | 232 | 233 | 241 | 242 | 247 | 248 | 256 | 257 | 258 |