├── LICENSE
├── PickPhotoDialog
├── app
│ ├── build.gradle
│ ├── proguard-rules.pro
│ └── src
│ │ ├── androidTest
│ │ └── java
│ │ │ └── com
│ │ │ └── ywl5320
│ │ │ └── csdn
│ │ │ └── pickphoto
│ │ │ └── ExampleInstrumentedTest.java
│ │ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── ywl5320
│ │ │ │ └── csdn
│ │ │ │ └── pickphoto
│ │ │ │ ├── MainActivity.java
│ │ │ │ ├── adapter
│ │ │ │ ├── ImgGridViewAdapter.java
│ │ │ │ └── ImgListViewAdapter.java
│ │ │ │ ├── adviewpager
│ │ │ │ ├── adapter
│ │ │ │ │ └── ImageViewPagerAdapter.java
│ │ │ │ └── adutils
│ │ │ │ │ └── AdViewpagerUtil.java
│ │ │ │ ├── beans
│ │ │ │ ├── ImgBean.java
│ │ │ │ └── ImgFloderBean.java
│ │ │ │ ├── dialog
│ │ │ │ ├── BaseDialog.java
│ │ │ │ ├── ImgShowDialog.java
│ │ │ │ ├── PhotoListDialog.java
│ │ │ │ └── PickPhotoDialog.java
│ │ │ │ └── util
│ │ │ │ └── AppUtil.java
│ │ └── res
│ │ │ ├── anim
│ │ │ ├── dialog_enter.xml
│ │ │ └── dialog_exit.xml
│ │ │ ├── drawable
│ │ │ ├── blue_item.xml
│ │ │ ├── blue_item_r.xml
│ │ │ ├── btn_selector.xml
│ │ │ ├── circle_drawable.xml
│ │ │ ├── circle_drawable_pressed.xml
│ │ │ ├── dot_selector.xml
│ │ │ └── item_selected_folder.xml
│ │ │ ├── layout
│ │ │ ├── activity_main.xml
│ │ │ ├── activity_photo_view_layout.xml
│ │ │ ├── activity_selected_photo_layout.xml
│ │ │ ├── dialog_choice_photo_layout.xml
│ │ │ ├── dialog_photo_list_layout.xml
│ │ │ ├── dialog_photo_show_layout.xml
│ │ │ ├── include_comm_game_text_title.xml
│ │ │ ├── item_img_adapter_layout.xml
│ │ │ └── item_listview_layout.xml
│ │ │ ├── mipmap-hdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-mdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xhdpi
│ │ │ ├── ic_launcher.png
│ │ │ ├── icon_img_bg.png
│ │ │ ├── icon_img_folder_more.png
│ │ │ ├── icon_selected.png
│ │ │ └── icon_unselected.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── values-w820dp
│ │ │ └── dimens.xml
│ │ │ ├── values
│ │ │ ├── colors.xml
│ │ │ ├── dimens.xml
│ │ │ ├── strings.xml
│ │ │ └── styles.xml
│ │ │ └── xml
│ │ │ └── provider_paths.xml
│ │ └── test
│ │ └── java
│ │ └── com
│ │ └── ywl5320
│ │ └── csdn
│ │ └── pickphoto
│ │ └── ExampleUnitTest.java
├── build.gradle
├── gradle.properties
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── photoviewlibrary
│ ├── build.gradle
│ ├── proguard-rules.pro
│ └── src
│ │ ├── androidTest
│ │ └── java
│ │ │ └── uk
│ │ │ └── co
│ │ │ └── senab
│ │ │ └── photoview
│ │ │ └── ExampleInstrumentedTest.java
│ │ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── java
│ │ │ └── uk
│ │ │ │ └── co
│ │ │ │ └── senab
│ │ │ │ └── photoview
│ │ │ │ ├── Compat.java
│ │ │ │ ├── DefaultOnDoubleTapListener.java
│ │ │ │ ├── IPhotoView.java
│ │ │ │ ├── PhotoView.java
│ │ │ │ ├── PhotoViewAttacher.java
│ │ │ │ ├── gestures
│ │ │ │ ├── CupcakeGestureDetector.java
│ │ │ │ ├── EclairGestureDetector.java
│ │ │ │ ├── FroyoGestureDetector.java
│ │ │ │ ├── GestureDetector.java
│ │ │ │ ├── OnGestureListener.java
│ │ │ │ └── VersionedGestureDetector.java
│ │ │ │ ├── log
│ │ │ │ ├── LogManager.java
│ │ │ │ ├── Logger.java
│ │ │ │ └── LoggerDefault.java
│ │ │ │ └── scrollerproxy
│ │ │ │ ├── GingerScroller.java
│ │ │ │ ├── IcsScroller.java
│ │ │ │ ├── PreGingerScroller.java
│ │ │ │ └── ScrollerProxy.java
│ │ └── res
│ │ │ └── values
│ │ │ └── strings.xml
│ │ └── test
│ │ └── java
│ │ └── uk
│ │ └── co
│ │ └── senab
│ │ └── photoview
│ │ └── ExampleUnitTest.java
└── settings.gradle
├── README.md
└── imgs
├── 1.png
├── 2.png
├── 3.png
├── 4.png
└── pickphotodialog.gif
/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 |
--------------------------------------------------------------------------------
/PickPhotoDialog/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 25
5 | buildToolsVersion "25.0.2"
6 | defaultConfig {
7 | applicationId "com.ywl5320.csdn.pickphoto"
8 | minSdkVersion 14
9 | targetSdkVersion 25
10 | versionCode 1
11 | versionName "1.0"
12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
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 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
25 | exclude group: 'com.android.support', module: 'support-annotations'
26 | })
27 | compile 'com.android.support:appcompat-v7:25.2.0'
28 | testCompile 'junit:junit:4.12'
29 | compile 'jp.wasabeef:glide-transformations:2.0.1'
30 | compile project(':photoviewlibrary')
31 | }
32 |
--------------------------------------------------------------------------------
/PickPhotoDialog/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 D:\Android\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 |
--------------------------------------------------------------------------------
/PickPhotoDialog/app/src/androidTest/java/com/ywl5320/csdn/pickphoto/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.ywl5320.csdn.pickphoto;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumentation test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.ywl5320.csdn.pickphoto", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/PickPhotoDialog/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/PickPhotoDialog/app/src/main/java/com/ywl5320/csdn/pickphoto/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.ywl5320.csdn.pickphoto;
2 |
3 | import android.annotation.TargetApi;
4 | import android.content.DialogInterface;
5 | import android.content.Intent;
6 | import android.graphics.Bitmap;
7 | import android.os.Bundle;
8 | import android.support.annotation.Nullable;
9 | import android.support.v4.view.ViewPager;
10 | import android.support.v7.app.AppCompatActivity;
11 | import android.view.Gravity;
12 | import android.view.View;
13 | import android.view.Window;
14 | import android.widget.Button;
15 | import android.widget.LinearLayout;
16 | import android.widget.Toast;
17 |
18 | import com.ywl5320.csdn.pickphoto.adviewpager.adutils.AdViewpagerUtil;
19 | import com.ywl5320.csdn.pickphoto.beans.ImgBean;
20 | import com.ywl5320.csdn.pickphoto.dialog.PickPhotoDialog;
21 |
22 | import java.util.ArrayList;
23 | import java.util.List;
24 |
25 | /**
26 | * Created by ywl on 2016/11/22.
27 | */
28 |
29 | public class MainActivity extends AppCompatActivity {
30 |
31 | private Button btnChoicePhoto;
32 | private ViewPager viewpager;
33 | private LinearLayout lydots;
34 | private AdViewpagerUtil adViewpagerUtil;
35 |
36 | private PickPhotoDialog pickPhotoDialog;
37 |
38 | private List imgBeens = new ArrayList();
39 |
40 | @Override
41 | protected void onCreate(@Nullable final Bundle savedInstanceState) {
42 | super.onCreate(savedInstanceState);
43 | setContentView(R.layout.activity_main);
44 | btnChoicePhoto = (Button) findViewById(R.id.btn_choice_photo);
45 | viewpager = (ViewPager) findViewById(R.id.viewpager);
46 | lydots = (LinearLayout) findViewById(R.id.ly_dots);
47 |
48 | btnChoicePhoto.setOnClickListener(new View.OnClickListener() {
49 | @Override
50 | public void onClick(View view) {
51 | if(adViewpagerUtil != null) {
52 | adViewpagerUtil.stopLoopViewPager();
53 | }
54 | pickPhotoDialog = new PickPhotoDialog(MainActivity.this, MainActivity.this);
55 | Window window = pickPhotoDialog.getWindow();
56 | window.setGravity(Gravity.BOTTOM);
57 | window.setWindowAnimations(R.style.DialogEnter);
58 | pickPhotoDialog.setCutImg(false, 5);//false:不裁剪(数量5生效) true:裁剪,数量不生效
59 | pickPhotoDialog.setSelectedImgs(imgBeens);//已选择的图片,选择时标出
60 | pickPhotoDialog.setOnPhotoResultListener(new PickPhotoDialog.OnPhotoResultListener() {
61 | @Override
62 | public void onCameraResult(String path) {//相机拍照图片路径
63 | imgBeens.clear();
64 | ImgBean imgBean = new ImgBean();
65 | imgBean.setPath(path);
66 | imgBeens.add(imgBean);
67 | adViewpagerUtil = new AdViewpagerUtil(MainActivity.this, viewpager, lydots, 8, 4, imgBeens);
68 | adViewpagerUtil.initVps();
69 | }
70 |
71 | @Override
72 | public void onCutPhotoResult(Bitmap bitmap) {
73 | //图片(相机和相册)裁剪后返回的bitmap
74 | }
75 |
76 | @Override
77 | public void onPhotoResult(List selectedImgs) {//相册多图选择返回图片路径结果集
78 | if(selectedImgs != null && selectedImgs.size() > 0) {
79 | imgBeens.clear();
80 | imgBeens.addAll(selectedImgs);
81 | adViewpagerUtil = new AdViewpagerUtil(MainActivity.this, viewpager, lydots, 8, 4, imgBeens);
82 | adViewpagerUtil.initVps();
83 | }
84 | else
85 | {
86 | if(adViewpagerUtil != null) {
87 | adViewpagerUtil.startLoopViewPager();
88 | }
89 | }
90 | }
91 | });
92 | pickPhotoDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
93 | @Override
94 | public void onDismiss(DialogInterface dialogInterface) {
95 | if(adViewpagerUtil != null) {
96 | adViewpagerUtil.startLoopViewPager();
97 | }
98 | }
99 | });
100 |
101 | pickPhotoDialog.show();
102 | }
103 | });
104 | }
105 |
106 | @TargetApi(23)
107 | @Override
108 | public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
109 | super.onRequestPermissionsResult(requestCode, permissions, grantResults);
110 | if (pickPhotoDialog != null)
111 | {
112 | pickPhotoDialog.onRequestPermissionsResult(requestCode, permissions, grantResults);
113 | }
114 | }
115 |
116 |
117 | @Override
118 | protected void onActivityResult(int requestCode, int resultCode, Intent data) {
119 | // TODO Auto-generated method stub
120 | super.onActivityResult(requestCode, resultCode, data);
121 |
122 | if(pickPhotoDialog != null)
123 | {
124 | pickPhotoDialog.onActivityResult(requestCode, resultCode, data);
125 | }
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/PickPhotoDialog/app/src/main/java/com/ywl5320/csdn/pickphoto/adapter/ImgGridViewAdapter.java:
--------------------------------------------------------------------------------
1 |
2 | package com.ywl5320.csdn.pickphoto.adapter;
3 |
4 |
5 | import android.content.Context;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 | import android.widget.BaseAdapter;
10 | import android.widget.ImageView;
11 |
12 | import com.bumptech.glide.Glide;
13 | import com.ywl5320.csdn.pickphoto.R;
14 | import com.ywl5320.csdn.pickphoto.beans.ImgBean;
15 |
16 | import java.util.ArrayList;
17 | import java.util.List;
18 |
19 |
20 | /**
21 | * @author ywl
22 | *
23 | */
24 | public class ImgGridViewAdapter extends BaseAdapter {
25 | protected Context context;
26 | protected LayoutInflater mlayoutInflate;
27 | protected List mDatas = new ArrayList();
28 | private boolean isaddpath = false;
29 | private String ppath = "";
30 | private OnImgSelectedListener onImgSelectedListener;
31 |
32 | public ImgGridViewAdapter(Context context, List mDatas) {
33 | this.context = context;
34 | this.mDatas = mDatas;
35 | if(this.context!=null)
36 | mlayoutInflate = LayoutInflater.from(this.context);
37 | }
38 |
39 | public void setOnImgSelectedListener(OnImgSelectedListener onImgSelectedListener) {
40 | this.onImgSelectedListener = onImgSelectedListener;
41 | }
42 |
43 | public void setPpath(String ppath) {
44 | this.ppath = ppath;
45 | }
46 |
47 | public void setIsaddpath(boolean isaddpath) {
48 | this.isaddpath = isaddpath;
49 | }
50 |
51 | public boolean isaddpath() {
52 | return isaddpath;
53 | }
54 |
55 | public String getPpath() {
56 | return ppath;
57 | }
58 |
59 | @Override
60 | public int getCount() {
61 | return mDatas.size();
62 | }
63 |
64 | @Override
65 | public Object getItem(int position) {
66 | return mDatas.get(position);
67 | }
68 |
69 | @Override
70 | public long getItemId(int position) {
71 | return position;
72 | }
73 |
74 | @Override
75 | public View getView(int position, View convertView, ViewGroup parent) {
76 | ViewHolder viewHolder;
77 | final ImgBean imgBean = mDatas.get(position);
78 | if(convertView == null)
79 | {
80 | convertView = mlayoutInflate.inflate(R.layout.item_img_adapter_layout, parent, false);
81 | viewHolder = new ViewHolder();
82 | viewHolder.ivImg = (ImageView) convertView.findViewById(R.id.iv_img);
83 | viewHolder.ivSelected = (ImageView) convertView.findViewById(R.id.iv_selected);
84 | viewHolder.vGrayBg = convertView.findViewById(R.id.v_gray_bg);
85 | convertView.setTag(viewHolder);
86 | }
87 | else
88 | {
89 | viewHolder = (ViewHolder) convertView.getTag();
90 | }
91 |
92 | if(!isaddpath) {
93 | Glide.with(context).load(imgBean.getPath()).into(viewHolder.ivImg);
94 | }
95 | else
96 | {
97 | Glide.with(context).load(ppath + "/" + imgBean.getPath()).into(viewHolder.ivImg);
98 | }
99 |
100 | if(imgBean.isSelected())
101 | {
102 | viewHolder.ivSelected.setSelected(true);
103 | viewHolder.vGrayBg.setVisibility(View.VISIBLE);
104 | }
105 | else
106 | {
107 | viewHolder.ivSelected.setSelected(false);
108 | viewHolder.vGrayBg.setVisibility(View.GONE);
109 | }
110 |
111 | viewHolder.ivSelected.setOnClickListener(new View.OnClickListener() {
112 | @Override
113 | public void onClick(View view) {
114 | if(onImgSelectedListener != null)
115 | {
116 | onImgSelectedListener.onSelected(imgBean);
117 | }
118 | }
119 | });
120 |
121 | return convertView;
122 | }
123 |
124 | public class ViewHolder
125 | {
126 | public ImageView ivImg;
127 | public ImageView ivSelected;
128 | public View vGrayBg;
129 |
130 | public ViewHolder(){}
131 | }
132 |
133 | public interface OnImgSelectedListener
134 | {
135 | void onSelected(ImgBean imgBean);
136 | }
137 |
138 | }
139 |
--------------------------------------------------------------------------------
/PickPhotoDialog/app/src/main/java/com/ywl5320/csdn/pickphoto/adapter/ImgListViewAdapter.java:
--------------------------------------------------------------------------------
1 |
2 | package com.ywl5320.csdn.pickphoto.adapter;
3 |
4 |
5 | import android.content.Context;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 | import android.widget.BaseAdapter;
10 | import android.widget.ImageView;
11 | import android.widget.TextView;
12 |
13 | import com.bumptech.glide.Glide;
14 | import com.ywl5320.csdn.pickphoto.R;
15 | import com.ywl5320.csdn.pickphoto.beans.ImgFloderBean;
16 |
17 | import java.util.ArrayList;
18 | import java.util.List;
19 |
20 |
21 | /**
22 | * @author ywl
23 | *
24 | */
25 | public class ImgListViewAdapter extends BaseAdapter {
26 | protected Context context;
27 | protected LayoutInflater mlayoutInflate;
28 | protected List mDatas = new ArrayList();
29 |
30 | public ImgListViewAdapter(Context context, List mDatas) {
31 | this.context = context;
32 | this.mDatas = mDatas;
33 | if(this.context!=null)
34 | mlayoutInflate = LayoutInflater.from(this.context);
35 | }
36 |
37 |
38 | @Override
39 | public int getCount() {
40 | return mDatas.size();
41 | }
42 |
43 | @Override
44 | public Object getItem(int position) {
45 | return mDatas.get(position);
46 | }
47 |
48 | @Override
49 | public long getItemId(int position) {
50 | return position;
51 | }
52 |
53 | @Override
54 | public View getView(int position, View convertView, ViewGroup parent) {
55 | ViewHolder viewHolder;
56 | ImgFloderBean imgFloderBean = mDatas.get(position);
57 | if(convertView == null)
58 | {
59 | convertView = mlayoutInflate.inflate(R.layout.item_listview_layout, parent, false);
60 | viewHolder = new ViewHolder();
61 | viewHolder.ivImg = (ImageView) convertView.findViewById(R.id.iv_img);
62 | viewHolder.tvName = (TextView) convertView.findViewById(R.id.tv_name);
63 | viewHolder.tvNumber = (TextView) convertView.findViewById(R.id.tv_num);
64 | viewHolder.ivSelected = (ImageView) convertView.findViewById(R.id.iv_selected);
65 | convertView.setTag(viewHolder);
66 | }
67 | else
68 | {
69 | viewHolder = (ViewHolder) convertView.getTag();
70 | }
71 |
72 | viewHolder.tvName.setText(imgFloderBean.getDirName());
73 | if(imgFloderBean.getType() == 0)
74 | {
75 | viewHolder.tvNumber.setVisibility(View.GONE);
76 | }
77 | else
78 | {
79 | viewHolder.tvNumber.setVisibility(View.VISIBLE);
80 | viewHolder.tvNumber.setText(imgFloderBean.getSize() + "张");
81 | }
82 |
83 | if(imgFloderBean.isSelected()) {
84 | viewHolder.ivSelected.setSelected(true);
85 | }
86 | else
87 | {
88 | viewHolder.ivSelected.setSelected(false);
89 | }
90 | Glide.with(context).load(imgFloderBean.getFirstImgPath()).into(viewHolder.ivImg);
91 |
92 | return convertView;
93 | }
94 |
95 | public class ViewHolder
96 | {
97 | public ImageView ivImg;
98 | public TextView tvName;
99 | public TextView tvNumber;
100 | public ImageView ivSelected;
101 | public ViewHolder(){}
102 | }
103 |
104 | }
105 |
--------------------------------------------------------------------------------
/PickPhotoDialog/app/src/main/java/com/ywl5320/csdn/pickphoto/adviewpager/adapter/ImageViewPagerAdapter.java:
--------------------------------------------------------------------------------
1 | package com.ywl5320.csdn.pickphoto.adviewpager.adapter;
2 |
3 | import android.content.Context;
4 | import android.support.v4.view.PagerAdapter;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 | import android.widget.ImageView;
8 |
9 | public class ImageViewPagerAdapter extends PagerAdapter {
10 |
11 | private ImageView[] imageViews;
12 | private int size;
13 | private Context context;
14 |
15 | public ImageViewPagerAdapter(Context context, ImageView[] imageViews) {
16 | this.context = context;
17 | this.imageViews = imageViews;
18 | size = imageViews.length;
19 | }
20 |
21 | @Override
22 | public int getCount() {
23 | return imageViews.length;
24 | }
25 |
26 | @Override
27 | public boolean isViewFromObject(View arg0, Object arg1) {
28 | return arg0 == arg1;
29 | }
30 |
31 | @Override
32 | public void destroyItem(ViewGroup container, int position, Object object) {
33 | // ((ViewPager) container).removeView((View) object);// 完全溢出view,避免数据多时出现重复现象
34 | container.removeView(imageViews[position]);//删除页卡
35 | }
36 |
37 | @Override
38 | public Object instantiateItem(ViewGroup container, int position) {
39 | container.addView(imageViews[position], 0);
40 | return imageViews[position];
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/PickPhotoDialog/app/src/main/java/com/ywl5320/csdn/pickphoto/adviewpager/adutils/AdViewpagerUtil.java:
--------------------------------------------------------------------------------
1 | package com.ywl5320.csdn.pickphoto.adviewpager.adutils;
2 |
3 | import android.content.Context;
4 | import android.os.Handler;
5 | import android.support.v4.view.ViewPager;
6 | import android.view.MotionEvent;
7 | import android.view.View;
8 | import android.widget.ImageView;
9 | import android.widget.LinearLayout;
10 |
11 | import com.bumptech.glide.Glide;
12 | import com.ywl5320.csdn.pickphoto.R;
13 | import com.ywl5320.csdn.pickphoto.adviewpager.adapter.ImageViewPagerAdapter;
14 | import com.ywl5320.csdn.pickphoto.beans.ImgBean;
15 |
16 | import java.util.List;
17 |
18 | /**
19 | * Created by ywl on 2016/6/24.
20 | */
21 | public class AdViewpagerUtil {
22 |
23 | private Context context;
24 | private ViewPager viewPager;
25 | private ImageViewPagerAdapter mimageViewPagerAdapter;
26 | private ImageView[] mImageViews;
27 | private List urls;
28 | private LinearLayout dotlayout;
29 | private ImageView[] dotViews;
30 |
31 | private boolean isRight = true; // 判断viewpager是不是向右滑动
32 | private int lastPosition = 1; // 记录viewpager从哪个页面滑动到当前页面,从而区分滑动方向
33 | private int autoIndex = 1; // 自动轮询时自增坐标,能确定导航圆点的位置
34 | private int currentIndex = 0; //当前item
35 | private int delayTime = 5000; //自动轮播的时间间隔
36 | private int imgsize = 0; //图片的数量,item的数量
37 | private boolean isLoop = false;//轮播开关
38 |
39 | private OnAdPageChangeListener onAdPageChangeListener; //pagechange回调
40 | private OnAdItemClickListener onAdItemClickListener; //点击事件回调
41 |
42 | private int dotsize = 8; //小圆点的大小宽度
43 | private int dotoffset = 4; //小圆点的间距
44 |
45 | /**
46 | * 不带小圆点
47 | * @param context
48 | * @param viewPager
49 | * @param urls
50 | */
51 | public AdViewpagerUtil(Context context, ViewPager viewPager, List urls) {
52 | this.context = context;
53 | this.viewPager = viewPager;
54 | this.urls = urls;
55 | }
56 |
57 | /**
58 | * 有小圆点
59 | * @param context
60 | * @param viewPager
61 | * @param dotlayout
62 | * @param dotsize
63 | * @param dotoffset
64 | * @param urls
65 | */
66 | public AdViewpagerUtil(Context context, ViewPager viewPager, LinearLayout dotlayout, int dotsize, int dotoffset, List urls) {
67 | this.context = context;
68 | this.viewPager = viewPager;
69 | this.dotlayout = dotlayout;
70 | this.dotsize = dotsize;
71 | this.urls = urls;
72 | }
73 |
74 | public void setOnAdPageChangeListener(OnAdPageChangeListener onAdPageChangeListener) {
75 | this.onAdPageChangeListener = onAdPageChangeListener;
76 | }
77 |
78 | public void setOnAdItemClickListener(OnAdItemClickListener onAdItemClickListener) {
79 | this.onAdItemClickListener = onAdItemClickListener;
80 | }
81 |
82 | private void initAdimgs(List urls)
83 | {
84 | LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT);
85 | int length = urls.size() + 2;
86 | mImageViews = new ImageView[length];
87 | for (int i = 0; i urls)
97 | {
98 | if (urls.size() > 0) {
99 | imgsize = length;
100 | for (int i = 0; i < length; i++) {
101 | if (i < length - 2) {
102 | final int index = i;
103 | Glide.with(context) .load(urls.get(i).getPath()).into(mImageViews[i + 1]);
104 | mImageViews[i + 1].setOnClickListener(new View.OnClickListener() {
105 |
106 | @Override
107 | public void onClick(View v) {
108 | // TODO Auto-generated method stub
109 | if(onAdItemClickListener != null)
110 | {
111 | onAdItemClickListener.onItemClick(mImageViews[index + 1], index);
112 | }
113 | }
114 | });
115 | }
116 | }
117 | Glide.with(context) .load(urls.get(urls.size() - 1).getPath()).into(mImageViews[0]);
118 | Glide.with(context) .load(urls.get(0).getPath()).into(mImageViews[length - 1]);
119 | }
120 | }
121 |
122 | public void initVps()
123 | {
124 | initAdimgs(urls);
125 | initDots(urls.size());
126 | mimageViewPagerAdapter = new ImageViewPagerAdapter(context, mImageViews);
127 | viewPager.setAdapter(mimageViewPagerAdapter);
128 | viewPager.setOffscreenPageLimit(mImageViews.length);
129 | startLoopViewPager();
130 | viewPager.setOnTouchListener(new View.OnTouchListener() {
131 |
132 | @Override
133 | public boolean onTouch(View v, MotionEvent event) {
134 | // TODO Auto-generated method stub
135 | int action = event.getAction();
136 | switch (action) {
137 | case MotionEvent.ACTION_DOWN:
138 | case MotionEvent.ACTION_MOVE:
139 | isLoop = true;
140 | stopLoopViewPager();
141 | break;
142 | case MotionEvent.ACTION_UP:
143 | case MotionEvent.ACTION_CANCEL:
144 | isLoop = false;
145 | startLoopViewPager();
146 | default:
147 | break;
148 | }
149 | return false;
150 | }
151 | });
152 | viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
153 |
154 | @Override
155 | public void onPageScrollStateChanged(int arg0) {
156 | // TODO Auto-generated method stub
157 | if (isRight) {
158 | if (arg0 != 1) {
159 | if (lastPosition == 0) {
160 | viewPager.setCurrentItem(imgsize - 2, false);
161 | } else if (lastPosition == imgsize - 1) {
162 | viewPager.setCurrentItem(1, false);
163 | }
164 | }
165 | }
166 |
167 | if(onAdPageChangeListener != null)
168 | {
169 | onAdPageChangeListener.onPageScrollStateChanged(arg0);
170 | }
171 | }
172 |
173 | @Override
174 | public void onPageScrolled(int arg0, float arg1, int arg2) {
175 | // TODO Auto-generated method stub
176 | if (!isRight) {
177 | if (arg1 < 0.01) {
178 | if (arg0 == 0) {
179 | viewPager.setCurrentItem(imgsize - 2, false);
180 | } else if (arg0 == imgsize - 1) {
181 | viewPager.setCurrentItem(1, false);
182 | }
183 | }
184 | }
185 | if(onAdPageChangeListener != null)
186 | {
187 | onAdPageChangeListener.onPageScrolled(arg0, arg1, arg2);
188 | }
189 | }
190 |
191 | @Override
192 | public void onPageSelected(int arg0) {
193 | // TODO Auto-generated method stub
194 | autoIndex = arg0;
195 | if (lastPosition < arg0 && lastPosition != 0) {
196 | isRight = true;
197 | } else if (lastPosition == imgsize - 1) {
198 | isRight = true;
199 | }
200 | if (lastPosition > arg0 && lastPosition != imgsize - 1) {
201 | isRight = false;
202 | } else if (lastPosition == 0) {
203 | isRight = false;
204 | }
205 | lastPosition = arg0;
206 |
207 | if (arg0 == 0) {
208 | currentIndex = imgsize - 2;
209 | } else if (arg0 == imgsize - 1) {
210 | currentIndex = 1;
211 | } else {
212 | currentIndex = arg0;
213 | }
214 |
215 | for (int i = 0; i < dotViews.length; i++) {
216 | if (i == currentIndex - 1) {
217 | dotViews[i].setSelected(true);
218 | } else {
219 | dotViews[i].setSelected(false);
220 | }
221 | }
222 |
223 | if(onAdPageChangeListener != null)
224 | {
225 | onAdPageChangeListener.onPageSelected(arg0);
226 | }
227 | }
228 |
229 | });
230 | viewPager.setCurrentItem(1);// 初始化时设置显示第一页(ViewPager中索引为1)
231 | }
232 |
233 | public void initDots(int length)
234 | {
235 | if(dotlayout == null)
236 | return;
237 | dotlayout.removeAllViews();
238 | LinearLayout.LayoutParams mParams = new LinearLayout.LayoutParams(dip2px(context, dotsize), dip2px(context, dotsize));
239 | mParams.setMargins(dip2px(context, dotoffset), 0, dip2px(context, dotoffset), 0);//设置小圆点左右之间的间隔
240 |
241 | dotViews = new ImageView[length];
242 |
243 | for(int i = 0; i < length; i++)
244 | {
245 | ImageView imageView = new ImageView(context);
246 | imageView.setLayoutParams(mParams);
247 | imageView.setImageResource(R.drawable.dot_selector);
248 | if(i== 0)
249 | {
250 | imageView.setSelected(true);//默认启动时,选中第一个小圆点
251 | }
252 | else {
253 | imageView.setSelected(false);
254 | }
255 | dotViews[i] = imageView;//得到每个小圆点的引用,用于滑动页面时,(onPageSelected方法中)更改它们的状态。
256 | dotlayout.addView(imageView);//添加到布局里面显示
257 | }
258 | }
259 |
260 | Handler handler = new Handler();
261 | Runnable runnable = new Runnable() {
262 | @Override
263 | public void run() {
264 | // 要做的事情
265 | if (viewPager.getChildCount() > 0) {
266 | handler.postDelayed(this, delayTime);
267 | autoIndex++;
268 | viewPager.setCurrentItem(autoIndex % imgsize, true);
269 | }
270 | }
271 | };
272 |
273 | public void startLoopViewPager() {
274 | if (!isLoop && viewPager != null) {
275 | handler.postDelayed(runnable, delayTime);// 每两秒执行一次runnable.
276 | isLoop = true;
277 | }
278 |
279 | }
280 |
281 | public void stopLoopViewPager() {
282 | if (isLoop && viewPager != null) {
283 | handler.removeCallbacks(runnable);
284 | isLoop = false;
285 | }
286 | }
287 |
288 | public interface OnAdItemClickListener
289 | {
290 | void onItemClick(View v, int flag);
291 | }
292 |
293 | public interface OnAdPageChangeListener
294 | {
295 | void onPageScrollStateChanged(int arg0);
296 | void onPageScrolled(int arg0, float arg1, int arg2);
297 | void onPageSelected(int arg0);
298 | }
299 |
300 | public int dip2px(Context context, float dipValue) {
301 | final float scale = context.getResources().getDisplayMetrics().density;
302 | return (int) (dipValue * scale + 0.5f);
303 | }
304 |
305 | }
306 |
--------------------------------------------------------------------------------
/PickPhotoDialog/app/src/main/java/com/ywl5320/csdn/pickphoto/beans/ImgBean.java:
--------------------------------------------------------------------------------
1 | package com.ywl5320.csdn.pickphoto.beans;
2 |
3 | /**
4 | * Created by ywl on 2016/11/22.
5 | */
6 |
7 | public class ImgBean {
8 |
9 | private String path;
10 | private boolean isSelected;
11 |
12 | public boolean isSelected() {
13 | return isSelected;
14 | }
15 |
16 | public void setSelected(boolean selected) {
17 | isSelected = selected;
18 | }
19 |
20 | public String getPath() {
21 | return path;
22 | }
23 |
24 | public void setPath(String path) {
25 | this.path = path;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/PickPhotoDialog/app/src/main/java/com/ywl5320/csdn/pickphoto/beans/ImgFloderBean.java:
--------------------------------------------------------------------------------
1 | package com.ywl5320.csdn.pickphoto.beans;
2 |
3 | /**
4 | * Created by ywl on 2016/11/21.
5 | */
6 |
7 | public class ImgFloderBean {
8 |
9 | private String dir;
10 | private String firstImgPath;
11 | private String dirName;
12 | private int size;
13 | private boolean isSelected;
14 | private int type;//0全部 非0文件夹
15 |
16 | public boolean isSelected() {
17 | return isSelected;
18 | }
19 |
20 | public void setSelected(boolean selected) {
21 | isSelected = selected;
22 | }
23 |
24 | public int getType() {
25 | return type;
26 | }
27 |
28 | public void setType(int type) {
29 | this.type = type;
30 | }
31 |
32 | public String getDirName() {
33 | return dirName;
34 | }
35 |
36 | public void setDirName(String dirName) {
37 | this.dirName = dirName;
38 | }
39 |
40 | public int getSize() {
41 | return size;
42 | }
43 |
44 | public void setSize(int size) {
45 | this.size = size;
46 | }
47 |
48 | public String getDir() {
49 | return dir;
50 | }
51 |
52 | public void setDir(String dir) {
53 | this.dir = dir;
54 | }
55 |
56 | public String getFirstImgPath() {
57 | return firstImgPath;
58 | }
59 |
60 | public void setFirstImgPath(String firstImgPath) {
61 | this.firstImgPath = firstImgPath;
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/PickPhotoDialog/app/src/main/java/com/ywl5320/csdn/pickphoto/dialog/BaseDialog.java:
--------------------------------------------------------------------------------
1 | package com.ywl5320.csdn.pickphoto.dialog;
2 |
3 | import android.app.Dialog;
4 | import android.content.Context;
5 | import android.graphics.Color;
6 | import android.os.Build;
7 | import android.view.View;
8 | import android.view.Window;
9 | import android.view.WindowManager;
10 |
11 | import com.ywl5320.csdn.pickphoto.R;
12 |
13 | /**
14 | * Created by window10 on 2016/3/18.
15 | */
16 | public class BaseDialog extends Dialog {
17 |
18 | public Context context;
19 | public BaseDialog(Context context) {
20 | super(context, R.style.StyleDialog);
21 | this.context = context;
22 | if(true) {
23 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {//5.0 全透明实现
24 | Window window = getWindow();
25 | window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
26 | window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
27 | | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
28 | window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
29 | window.setStatusBarColor(Color.TRANSPARENT);
30 | }
31 | //透明状态栏
32 | else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {//4.4全透明
33 | getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
34 | // getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
35 |
36 | }
37 | }
38 |
39 | }
40 |
41 | public BaseDialog(Context context, int style) {
42 | super(context, style);
43 | this.context = context;
44 |
45 | if(true) {
46 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {//5.0 全透明实现
47 | Window window = getWindow();
48 | window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
49 | window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
50 | | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
51 | window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
52 | window.setStatusBarColor(Color.TRANSPARENT);
53 | }
54 | //透明状态栏
55 | else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {//4.4全透明
56 | getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
57 | // getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
58 |
59 | }
60 | }
61 |
62 | }
63 |
64 | @Override
65 | public void setContentView(int layoutResID) {
66 | super.setContentView(layoutResID);
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/PickPhotoDialog/app/src/main/java/com/ywl5320/csdn/pickphoto/dialog/ImgShowDialog.java:
--------------------------------------------------------------------------------
1 | package com.ywl5320.csdn.pickphoto.dialog;
2 |
3 | import android.content.Context;
4 | import android.os.Bundle;
5 | import android.view.View;
6 |
7 | import com.bumptech.glide.Glide;
8 | import com.ywl5320.csdn.pickphoto.R;
9 |
10 | import uk.co.senab.photoview.PhotoView;
11 | import uk.co.senab.photoview.PhotoViewAttacher;
12 |
13 | /**
14 | * Created by ywl on 2016/11/23.
15 | */
16 |
17 | public class ImgShowDialog extends BaseDialog{
18 |
19 | private PhotoView photoView;
20 | private String imgpath;
21 | private PhotoViewAttacher mAttacher;
22 |
23 | public ImgShowDialog(Context context) {
24 | super(context);
25 | }
26 |
27 | public void setImgpath(String imgpath) {
28 | this.imgpath = imgpath;
29 | }
30 |
31 | @Override
32 | protected void onCreate(Bundle savedInstanceState) {
33 | super.onCreate(savedInstanceState);
34 | setContentView(R.layout.dialog_photo_show_layout);
35 | photoView = (PhotoView) findViewById(R.id.photoview);
36 | Glide.with(context).load(imgpath).into(photoView);
37 | mAttacher = new PhotoViewAttacher(photoView);
38 | mAttacher.setOnPhotoTapListener(new PhotoViewAttacher.OnPhotoTapListener() {
39 |
40 | @Override
41 | public void onPhotoTap(View view, float x, float y) {
42 |
43 | }
44 |
45 | @Override
46 | public void onOutsidePhotoTap() {
47 |
48 | }
49 | });
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/PickPhotoDialog/app/src/main/java/com/ywl5320/csdn/pickphoto/dialog/PhotoListDialog.java:
--------------------------------------------------------------------------------
1 | package com.ywl5320.csdn.pickphoto.dialog;
2 |
3 | import android.animation.ValueAnimator;
4 | import android.app.Activity;
5 | import android.app.ProgressDialog;
6 | import android.content.ContentResolver;
7 | import android.content.Context;
8 | import android.database.Cursor;
9 | import android.graphics.Rect;
10 | import android.net.Uri;
11 | import android.os.Build;
12 | import android.os.Bundle;
13 | import android.os.Environment;
14 | import android.os.Handler;
15 | import android.os.Message;
16 | import android.provider.MediaStore;
17 | import android.util.DisplayMetrics;
18 | import android.view.View;
19 | import android.view.ViewGroup;
20 | import android.widget.AdapterView;
21 | import android.widget.GridView;
22 | import android.widget.ImageView;
23 | import android.widget.LinearLayout;
24 | import android.widget.ListView;
25 | import android.widget.RelativeLayout;
26 | import android.widget.TextView;
27 | import android.widget.Toast;
28 |
29 |
30 | import com.ywl5320.csdn.pickphoto.R;
31 | import com.ywl5320.csdn.pickphoto.adapter.ImgGridViewAdapter;
32 | import com.ywl5320.csdn.pickphoto.adapter.ImgListViewAdapter;
33 | import com.ywl5320.csdn.pickphoto.beans.ImgBean;
34 | import com.ywl5320.csdn.pickphoto.beans.ImgFloderBean;
35 |
36 | import java.io.File;
37 | import java.io.FilenameFilter;
38 | import java.lang.reflect.Field;
39 | import java.util.ArrayList;
40 | import java.util.Collections;
41 | import java.util.HashSet;
42 | import java.util.List;
43 | import java.util.Set;
44 |
45 | /**
46 | * Created by ywl on 2016/11/23.
47 | */
48 |
49 | public class PhotoListDialog extends BaseDialog{
50 |
51 | private ProgressDialog progressDialog;
52 |
53 | private LinearLayout lySystemBar;
54 | private ImageView mivBack;
55 | private TextView mtvMenu;
56 | private TextView mtvTitle;
57 | private TextView tvSelected;
58 | private RelativeLayout rlActions;
59 | private RelativeLayout rlSelected;
60 | private View vBg;
61 | private Activity activity;
62 |
63 | private GridView gridView;
64 | private ListView listView;
65 |
66 | private List imgFloderBeens;
67 | private List imgs;
68 | private List tempImgs;
69 | private List selectedImgBeans;
70 | private List alreadySelectedImgs;
71 |
72 | private ImgGridViewAdapter imgGridViewAdapter;
73 | private ImgListViewAdapter imgListViewAdapter;
74 |
75 | private int listviewHeight = 0;
76 | private boolean isShowListView = false;
77 | private int MAX_COUNT = 9;
78 | private String dirPath = "";
79 |
80 | private OnChoicePhotoListener onChoicePhotoListener;
81 |
82 |
83 | public PhotoListDialog(Context context, Activity activity) {
84 | super(context);
85 | this.activity = activity;
86 | }
87 |
88 | public void setAlreadySelectedImgs(List alreadySelectedImgs) {
89 | this.alreadySelectedImgs = alreadySelectedImgs;
90 | }
91 |
92 | public void setOnChoicePhotoListener(OnChoicePhotoListener onChoicePhotoListener) {
93 | this.onChoicePhotoListener = onChoicePhotoListener;
94 | }
95 |
96 |
97 | public void setMAX_COUNT(int MAX_COUNT) {
98 | this.MAX_COUNT = MAX_COUNT;
99 | }
100 |
101 |
102 |
103 | @Override
104 | protected void onCreate(Bundle savedInstanceState) {
105 | super.onCreate(savedInstanceState);
106 | setContentView(R.layout.dialog_photo_list_layout);
107 |
108 | mtvTitle = (TextView) findViewById(R.id.tv_title);
109 | mivBack = (ImageView) findViewById(R.id.iv_back);
110 | mtvMenu = (TextView) findViewById(R.id.tv_right);
111 | lySystemBar = (LinearLayout) findViewById(R.id.ly_system_bar);
112 | initSystembar(lySystemBar);
113 |
114 |
115 | mtvTitle.setText("图片选择");
116 | mivBack.setVisibility(View.VISIBLE);
117 | mivBack.setOnClickListener(new View.OnClickListener() {
118 | @Override
119 | public void onClick(View v) {
120 | dismiss();
121 | }
122 | });
123 |
124 | gridView = (GridView) findViewById(R.id.gridview);
125 | tvSelected = (TextView) findViewById(R.id.tv_selected);
126 | listView = (ListView) findViewById(R.id.listview);
127 | rlActions = (RelativeLayout) findViewById(R.id.rl_actions);
128 | rlSelected = (RelativeLayout) findViewById(R.id.rl_selected);
129 | vBg = findViewById(R.id.v_bg);
130 |
131 | listviewHeight = (int)(getScreenHeight(activity) * 0.70f);
132 | RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, listviewHeight);
133 | lp.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.TRUE);
134 | lp.setMargins(0, 0, 0, dip2px(context, 50));
135 | listView.setLayoutParams(lp);
136 |
137 | rlSelected.setOnClickListener(new View.OnClickListener() {
138 | @Override
139 | public void onClick(View view) {
140 | if(isShowListView) {
141 | hideFloor(listView);
142 | }
143 | else {
144 | showFloor(listView);
145 | }
146 | }
147 | });
148 |
149 | mtvMenu.setOnClickListener(new View.OnClickListener() {
150 | @Override
151 | public void onClick(View view) {
152 | if(imgGridViewAdapter.isaddpath())
153 | {
154 | for(ImgBean imgBean : selectedImgBeans)
155 | {
156 | imgBean.setPath(dirPath + "/" + imgBean.getPath());
157 | }
158 | }
159 |
160 | if(onChoicePhotoListener != null)
161 | {
162 | onChoicePhotoListener.onResult(selectedImgBeans);
163 | }
164 |
165 | dismiss();
166 | }
167 | });
168 |
169 | hideFloor(listView);
170 |
171 | setAdapter();
172 | progressDialog = ProgressDialog.show(context, null, "正在加载...");
173 | new Handler().postDelayed(new Runnable() {
174 | @Override
175 | public void run() {
176 | scanImgs();
177 | }
178 | }, 500);
179 |
180 | }
181 |
182 | public void setAdapter()
183 | {
184 | imgs = new ArrayList<>();
185 | tempImgs = new ArrayList<>();
186 | selectedImgBeans = new ArrayList<>();
187 | imgFloderBeens = new ArrayList<>();
188 | imgGridViewAdapter = new ImgGridViewAdapter(context, imgs);
189 | imgListViewAdapter = new ImgListViewAdapter(context, imgFloderBeens);
190 | gridView.setAdapter(imgGridViewAdapter);
191 | listView.setAdapter(imgListViewAdapter);
192 | mtvMenu.setText("(" + selectedImgBeans.size() + "/" + MAX_COUNT + ")");
193 |
194 | gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
195 | @Override
196 | public void onItemClick(AdapterView> adapterView, View view, int i, long l) {
197 | ImgBean imgBean = (ImgBean) gridView.getItemAtPosition(i);
198 | String imgPath = "";
199 | if(imgGridViewAdapter.isaddpath())
200 | {
201 | imgPath = imgGridViewAdapter.getPpath() + "/" + imgBean.getPath();
202 | }
203 | else {
204 | imgPath = imgBean.getPath();
205 | }
206 | ImgShowDialog imgShowDialog = new ImgShowDialog(context);
207 | imgShowDialog.setImgpath(imgPath);
208 | imgShowDialog.show();
209 |
210 | }
211 | });
212 |
213 | imgGridViewAdapter.setOnImgSelectedListener(new ImgGridViewAdapter.OnImgSelectedListener() {
214 | @Override
215 | public void onSelected(ImgBean imgBean) {
216 | if(selectedImgBeans.size() < MAX_COUNT) {
217 | imgBean.setSelected(!imgBean.isSelected());
218 | if (imgBean.isSelected()) {
219 | if (MAX_COUNT == 1) {
220 | for (ImgBean imb : selectedImgBeans) {
221 | imb.setSelected(false);
222 | }
223 | selectedImgBeans.clear();
224 | selectedImgBeans.add(imgBean);
225 | } else {
226 | if (!selectedImgBeans.contains(imgBean)) {
227 | selectedImgBeans.add(imgBean);
228 | }
229 | }
230 | } else {
231 | if (selectedImgBeans.contains(imgBean)) {
232 | selectedImgBeans.remove(imgBean);
233 | }
234 | }
235 | System.out.println("size:" + selectedImgBeans.size());
236 | mtvMenu.setText("(" + selectedImgBeans.size() + "/" + MAX_COUNT + ")");
237 | imgGridViewAdapter.notifyDataSetChanged();
238 | }
239 | else
240 | {
241 | if(imgBean.isSelected())
242 | {
243 | imgBean.setSelected(false);
244 | if (selectedImgBeans.contains(imgBean)) {
245 | selectedImgBeans.remove(imgBean);
246 | }
247 | }
248 | mtvMenu.setText("(" + selectedImgBeans.size() + "/" + MAX_COUNT + ")");
249 | imgGridViewAdapter.notifyDataSetChanged();
250 | }
251 | }
252 | });
253 |
254 |
255 | listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
256 | @Override
257 | public void onItemClick(AdapterView> adapterView, View view, int i, long l) {
258 | ImgFloderBean imgFloderBean = (ImgFloderBean) listView.getItemAtPosition(i);
259 | if(!imgFloderBean.isSelected()) {
260 | if (imgFloderBean.getType() == 0) {
261 | imgs.clear();
262 | imgs.addAll(tempImgs);
263 | imgGridViewAdapter.setIsaddpath(false);
264 | imgGridViewAdapter.notifyDataSetInvalidated();
265 | } else {
266 | scanChildDirPaths(imgFloderBean.getDir());
267 | }
268 | setSelectedFolder(i);
269 | tvSelected.setText(imgFloderBean.getDirName());
270 | for(ImgBean imb : selectedImgBeans)
271 | {
272 | imb.setSelected(false);
273 | }
274 | selectedImgBeans.clear();
275 | mtvMenu.setText("(" + selectedImgBeans.size() + "/" + MAX_COUNT + ")");
276 | }
277 | hideFloor(listView);
278 | }
279 | });
280 | }
281 |
282 |
283 | public void setSelectedFolder(int position)
284 | {
285 | int size = imgFloderBeens.size();
286 | for(int i = 0; i < size; i++)
287 | {
288 | if(i == position)
289 | {
290 | imgFloderBeens.get(i).setSelected(true);
291 | }
292 | else
293 | {
294 | imgFloderBeens.get(i).setSelected(false);
295 | }
296 | }
297 | imgListViewAdapter.notifyDataSetChanged();
298 | }
299 |
300 | public void scanChildDirPaths(String dirPath)
301 | {
302 | this.dirPath = dirPath;
303 | File file = new File(dirPath);
304 | String[]childFilePaths = file.list(new FilenameFilter() {
305 | @Override
306 | public boolean accept(File file, String s) {
307 | if(s.endsWith(".jpg") || s.endsWith(".jpeg") || s.endsWith(".png"))
308 | return true;
309 | return false;
310 | }
311 | });
312 |
313 | if(childFilePaths != null)
314 | {
315 | imgGridViewAdapter.setIsaddpath(true);
316 | imgGridViewAdapter.setPpath(dirPath);
317 | imgs.clear();
318 | int length = childFilePaths.length;
319 | for(int i = 0; i < length; i++)
320 | {
321 | ImgBean imgBean = new ImgBean();
322 | imgBean.setPath(childFilePaths[i]);
323 | imgs.add(imgBean);
324 | }
325 | Collections.reverse(imgs);
326 | imgGridViewAdapter.notifyDataSetInvalidated();
327 | }
328 |
329 | }
330 |
331 | private void sortSelectedImgs(List imgs)
332 | {
333 | if(alreadySelectedImgs != null)
334 | {
335 | selectedImgBeans.clear();
336 | for(ImgBean img : alreadySelectedImgs)
337 | {
338 | for(ImgBean imgBean : imgs)
339 | {
340 | if(img.getPath().equals(imgBean.getPath()))
341 | {
342 | imgBean.setSelected(true);
343 | selectedImgBeans.add(imgBean);
344 | }
345 | }
346 | }
347 | mtvMenu.setText("(" + selectedImgBeans.size() + "/" + MAX_COUNT + ")");
348 | }
349 | }
350 |
351 |
352 | public void scanImgs()
353 | {
354 | if(!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
355 | {
356 | Toast.makeText(context, "当前存储卡不可用", Toast.LENGTH_SHORT).show();
357 | return;
358 | }
359 | new Thread()
360 | {
361 | @Override
362 | public void run() {
363 | Uri muri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
364 | ContentResolver cr = activity.getContentResolver();
365 |
366 | Cursor cursor = cr.query(muri, null, MediaStore.Images.Media.MIME_TYPE + " = ? or " + MediaStore.Images.Media.MIME_TYPE + " = ? ", new String[]{"image/jpeg", "image/png"}, MediaStore.Images.Media.DATE_MODIFIED);
367 |
368 | Set dirPaths = new HashSet();
369 | int count = cursor.getCount();
370 | for(int i = count - 1; i >= 0; i--) {
371 | cursor.moveToPosition(i);
372 | String path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
373 |
374 | if(i == count - 1)
375 | {
376 | ImgFloderBean imgflder = new ImgFloderBean();
377 | imgflder.setFirstImgPath(path);
378 | imgflder.setDirName("所有图片");
379 | imgflder.setType(0);
380 | imgflder.setSelected(true);
381 | imgFloderBeens.add(imgflder);
382 | }
383 |
384 | ImgBean imgBean = new ImgBean();
385 | imgBean.setPath(path);
386 | imgBean.setSelected(false);
387 | // checkSelectedImgBeans(imgBean);
388 | imgs.add(imgBean);
389 | tempImgs.add(imgBean);
390 | File parentFile = new File(path).getParentFile();
391 |
392 | if (parentFile == null)
393 | continue;
394 | String dirPath = parentFile.getAbsolutePath();
395 | ImgFloderBean imgFloderBean = null;
396 |
397 | if (dirPaths.contains(dirPath)) {
398 | continue;
399 | } else {
400 | dirPaths.add(dirPath);
401 | imgFloderBean = new ImgFloderBean();
402 | imgFloderBean.setDir(dirPath);
403 | imgFloderBean.setFirstImgPath(path);
404 | imgFloderBean.setDirName(parentFile.getName());
405 | imgFloderBean.setType(1);
406 | imgFloderBean.setSelected(false);
407 | imgFloderBeens.add(imgFloderBean);
408 | }
409 |
410 | if (parentFile.list() == null)
411 | continue;
412 |
413 | int picSize = parentFile.list(new FilenameFilter() {
414 | @Override
415 | public boolean accept(File file, String s) {
416 | if (s.endsWith(".jpg") || s.endsWith(".jpeg") || s.endsWith(".png"))
417 | return true;
418 | return false;
419 | }
420 | }).length;
421 |
422 | if (imgFloderBean != null) {
423 | imgFloderBean.setSize(picSize);
424 | }
425 |
426 | }
427 | cursor.close();
428 | Message message = Message.obtain();
429 | message.what = 0x001;
430 | handler.sendMessage(message);
431 | }
432 | }.start();
433 |
434 | }
435 |
436 | Handler handler = new Handler(){
437 | @Override
438 | public void handleMessage(Message msg) {
439 | super.handleMessage(msg);
440 | if(msg.what == 0x001)
441 | {
442 | sortSelectedImgs(imgs);
443 | imgGridViewAdapter.setIsaddpath(false);
444 | imgGridViewAdapter.notifyDataSetInvalidated();
445 | }
446 | progressDialog.dismiss();
447 | }
448 | };
449 |
450 | public void showFloor(final View v) {
451 | isShowListView = true;
452 | ValueAnimator animator;
453 | animator = ValueAnimator.ofFloat(listviewHeight, 0);
454 | animator.setTarget(v);
455 | animator.setDuration(200).start();
456 | animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
457 | @Override
458 | public void onAnimationUpdate(ValueAnimator animation) {
459 | v.setTranslationY((Float) animation.getAnimatedValue());
460 | }
461 | });
462 |
463 | vBg.animate().alpha(1).setDuration(200);
464 | vBg.setVisibility(View.VISIBLE);
465 | }
466 |
467 | public void hideFloor(final View v)
468 | {
469 | isShowListView = false;
470 | ValueAnimator animator;
471 | animator = ValueAnimator.ofFloat(0, listviewHeight);
472 | animator.setTarget(v);
473 | animator.setDuration(200).start();
474 | animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
475 | @Override
476 | public void onAnimationUpdate(ValueAnimator animation) {
477 | v.setTranslationY((Float) animation.getAnimatedValue());
478 | }
479 | });
480 | vBg.animate().alpha(0).setDuration(200);
481 | vBg.setVisibility(View.GONE);
482 |
483 | }
484 |
485 | public void initSystembar(View lySystemBar)
486 | {
487 | if(true) {
488 | if (Build.VERSION.SDK_INT >= 19) {
489 | if (lySystemBar != null) {
490 | lySystemBar.setVisibility(View.VISIBLE);
491 | LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) lySystemBar.getLayoutParams();
492 | lp.height = getStatusHeight(activity);
493 | lySystemBar.requestLayout();
494 | }
495 | } else {
496 | if (lySystemBar != null) {
497 | lySystemBar.setVisibility(View.GONE);
498 | }
499 | }
500 | }
501 | }
502 |
503 | public interface OnChoicePhotoListener
504 | {
505 | void onResult(List imgBeens);
506 | }
507 |
508 | public int getScreenHeight(Activity context)
509 | {
510 | DisplayMetrics dm = new DisplayMetrics();
511 | context.getWindowManager().getDefaultDisplay().getMetrics(dm);
512 | int mScreenHeight = dm.heightPixels;
513 | return mScreenHeight;
514 | }
515 |
516 | public int dip2px(Context context, float dipValue) {
517 | final float scale = context.getResources().getDisplayMetrics().density;
518 | return (int) (dipValue * scale + 0.5f);
519 | }
520 |
521 | public static int getStatusHeight(Activity activity)
522 | {
523 | int statusBarHeight = 0;
524 | try {
525 | Class> c = Class.forName("com.android.internal.R$dimen");
526 | Object o = c.newInstance();
527 | Field field = c.getField("status_bar_height");
528 | int x = (Integer) field.get(o);
529 | statusBarHeight = activity.getResources().getDimensionPixelSize(x);
530 | } catch (Exception e) {
531 | e.printStackTrace();
532 | Rect frame = new Rect();
533 | activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
534 | statusBarHeight = frame.top;
535 | }
536 | return statusBarHeight;
537 | }
538 | }
539 |
--------------------------------------------------------------------------------
/PickPhotoDialog/app/src/main/java/com/ywl5320/csdn/pickphoto/dialog/PickPhotoDialog.java:
--------------------------------------------------------------------------------
1 | package com.ywl5320.csdn.pickphoto.dialog;
2 |
3 | import android.Manifest;
4 | import android.app.Activity;
5 | import android.content.ContentValues;
6 | import android.content.Context;
7 | import android.content.Intent;
8 | import android.content.pm.PackageManager;
9 | import android.database.Cursor;
10 | import android.graphics.Bitmap;
11 | import android.net.Uri;
12 | import android.os.Build;
13 | import android.os.Bundle;
14 | import android.os.Environment;
15 | import android.provider.MediaStore;
16 | import android.support.v4.app.ActivityCompat;
17 | import android.support.v4.content.ContextCompat;
18 | import android.support.v4.content.FileProvider;
19 | import android.view.View;
20 | import android.widget.Button;
21 | import android.widget.Toast;
22 |
23 |
24 | import com.ywl5320.csdn.pickphoto.R;
25 | import com.ywl5320.csdn.pickphoto.beans.ImgBean;
26 | import com.ywl5320.csdn.pickphoto.util.AppUtil;
27 |
28 | import java.io.File;
29 | import java.io.FileNotFoundException;
30 | import java.util.List;
31 |
32 | /**
33 | * Created by ywl on 2016/6/14.
34 | */
35 | public class PickPhotoDialog extends BaseDialog{
36 |
37 | private OnPhotoResultListener onPhotoResultListener;
38 | private static final int REQUEST_CAMERA_CODE = 0x0002;
39 | private static final int REQUEST_EXTERNAL_STORAGE_CODE = 0x0003;
40 | private static final int REQUEST_CAMERA_RESULT_CODE = 0x0004;
41 | private static final int REQUEST_CLICK_PHOTO_CODE = 0x0005;
42 |
43 | private Activity activity;
44 | private File file;
45 | private Uri imageUri;
46 | private String imgname = "";
47 |
48 | private boolean isCutImg = false;
49 | private int maxcount = 1;
50 |
51 | private Button btnCamera;
52 | private Button btnPhoto;
53 |
54 | private List selectedImgs;
55 |
56 | public void setSelectedImgs(List selectedImgs) {
57 | this.selectedImgs = selectedImgs;
58 | }
59 |
60 | public PickPhotoDialog(Context context, Activity activity) {
61 | super(context);
62 | this.activity = activity;
63 | }
64 |
65 | public void setCutImg(boolean cutImg, int maxcount) {
66 | isCutImg = cutImg;
67 | this.maxcount = maxcount;
68 | if(isCutImg)
69 | {
70 | this.maxcount = 1;
71 | }
72 | }
73 |
74 | @Override
75 | protected void onCreate(Bundle savedInstanceState) {
76 | super.onCreate(savedInstanceState);
77 | setContentView(R.layout.dialog_choice_photo_layout);
78 | btnCamera = (Button) findViewById(R.id.btn_takephoto);
79 | btnPhoto = (Button) findViewById(R.id.btn_photo);
80 |
81 | btnCamera.setOnClickListener(new View.OnClickListener() {
82 | @Override
83 | public void onClick(View view) {
84 | if(!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
85 | {
86 | Toast.makeText(context, "当前存储卡不可用", Toast.LENGTH_SHORT).show();
87 | return;
88 | }
89 | if (ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED//相机权限
90 | || ContextCompat.checkSelfPermission(context, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED//读取存储卡权限
91 | || ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED)
92 | {
93 | ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CAMERA_CODE);
94 | }
95 | else
96 | {
97 | file = new File(getImgPath());
98 | if (!file.exists()) {
99 | file.mkdirs();
100 | }
101 | imgname = getHeadImgName();
102 |
103 | Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
104 |
105 | if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M){
106 | imageUri = Uri.fromFile(new File(file, imgname));
107 | }else{
108 | //7.0 调用系统相机拍照不再允许使用Uri方式,应该替换为FileProvider 并且这样可以解决MIUI系统上拍照返回size为0的情况
109 | imageUri = FileProvider.getUriForFile(context, AppUtil.getAppPackName(context) + ".provider", new File(file, imgname));
110 | }
111 | intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
112 | activity.startActivityForResult(intent, REQUEST_CAMERA_RESULT_CODE);
113 | }
114 | }
115 | });
116 |
117 | btnPhoto.setOnClickListener(new View.OnClickListener() {
118 | @Override
119 | public void onClick(View view) {
120 | if(!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
121 | {
122 | Toast.makeText(context, "当前存储卡不可用", Toast.LENGTH_SHORT).show();
123 | return;
124 | }
125 | if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED
126 | || ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED)
127 | {
128 | ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_EXTERNAL_STORAGE_CODE);
129 | }
130 | else
131 | {
132 | PhotoListDialog photoListDialog = new PhotoListDialog(context, activity);
133 | photoListDialog.setMAX_COUNT(maxcount);
134 | photoListDialog.setAlreadySelectedImgs(selectedImgs);
135 | photoListDialog.show();
136 | photoListDialog.setOnChoicePhotoListener(new PhotoListDialog.OnChoicePhotoListener() {
137 | @Override
138 | public void onResult(List imgBeens) {
139 | if(isCutImg && imgBeens != null && imgBeens.size() > 0)
140 | {
141 | try {
142 | Uri photouri = Uri.fromFile(new File(imgBeens.get(0).getPath()));
143 | cropPhoto(photouri);
144 | }
145 | catch(Exception e)
146 | {
147 | e.printStackTrace();
148 | }
149 | }
150 | else {
151 | if (onPhotoResultListener != null) {
152 | onPhotoResultListener.onPhotoResult(imgBeens);
153 | }
154 | dismiss();
155 | }
156 | }
157 | });
158 | }
159 | }
160 | });
161 | }
162 |
163 | public void setOnPhotoResultListener(OnPhotoResultListener onPhotoResultListener) {
164 | this.onPhotoResultListener = onPhotoResultListener;
165 | }
166 |
167 | public interface OnPhotoResultListener
168 | {
169 | void onCameraResult(String path);
170 |
171 | void onCutPhotoResult(Bitmap bitmap);
172 |
173 | void onPhotoResult(List selectedImgs);
174 | }
175 |
176 | public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)
177 | {
178 |
179 | if (requestCode == REQUEST_CAMERA_CODE)
180 | {
181 | if (grantResults[0] == PackageManager.PERMISSION_GRANTED)
182 | {
183 | file = new File(getImgPath());
184 | if (!file.exists()) {
185 | file.mkdirs();
186 | }
187 | imgname = getHeadImgName();
188 | Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
189 |
190 | if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M){
191 | imageUri = Uri.fromFile(new File(file, imgname));
192 | }else{
193 | //7.0 调用系统相机拍照不再允许使用Uri方式,应该替换为FileProvider 并且这样可以解决MIUI系统上拍照返回size为0的情况
194 | imageUri = FileProvider.getUriForFile(context, AppUtil.getAppPackName(context) + ".provider", new File(file, imgname));
195 | }
196 | intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
197 | activity.startActivityForResult(intent, REQUEST_CAMERA_RESULT_CODE);
198 | } else
199 | {
200 | Toast.makeText(context, "请允许打开摄像头权限", Toast.LENGTH_SHORT).show();
201 | }
202 | return;
203 | }
204 | else if(requestCode == REQUEST_EXTERNAL_STORAGE_CODE)
205 | {
206 | if (grantResults[0] == PackageManager.PERMISSION_GRANTED)
207 | {
208 | PhotoListDialog photoListDialog = new PhotoListDialog(context, activity);
209 | photoListDialog.setMAX_COUNT(9);
210 | photoListDialog.show();
211 | } else
212 | {
213 | Toast.makeText(context, "请允许读取存储卡权限", Toast.LENGTH_SHORT).show();
214 | }
215 | return;
216 | }
217 | }
218 |
219 | public void onActivityResult(int requestCode, int resultCode, Intent data) {
220 | if(resultCode!= activity.RESULT_OK)
221 | return;
222 | if(requestCode == REQUEST_CAMERA_RESULT_CODE)
223 | {
224 | try {
225 | MediaStore.Images.Media.insertImage(context.getContentResolver(),
226 | imageUri.getPath(), imgname, null);
227 | } catch (FileNotFoundException e) {
228 | e.printStackTrace();
229 | }
230 | // 最后通知图库更新
231 | context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" + file.getPath())));
232 |
233 | if(!isCutImg) {
234 | if (onPhotoResultListener != null) {
235 | onPhotoResultListener.onCameraResult(imageUri.getPath());
236 | }
237 | dismiss();
238 | }
239 | else
240 | {
241 | cropPhoto(imageUri);
242 | }
243 | }
244 | else if(requestCode == REQUEST_CLICK_PHOTO_CODE)
245 | {
246 | Bitmap photo = data.getParcelableExtra("data");
247 | if(photo!= null){
248 | if (onPhotoResultListener != null) {
249 | onPhotoResultListener.onCutPhotoResult(photo);
250 | }
251 | }
252 | dismiss();
253 | }
254 | }
255 |
256 | public void cropPhoto(Uri uri)
257 | {
258 | Intent intent = new Intent();
259 | intent.setAction("com.android.camera.action.CROP");
260 | if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M){
261 | intent.setDataAndType(uri, "image/*");
262 | }else{
263 | intent.setDataAndType(getImageContentUri(new File(uri.getPath())), "image/*");// mUri是已经选择的图片Uri
264 | }
265 | intent.putExtra("crop", "true");
266 | intent.putExtra("aspectX", 1);// 裁剪框比例
267 | intent.putExtra("aspectY", 1);
268 | intent.putExtra("outputX", 320);// 输出图片大小
269 | intent.putExtra("outputY", 320);
270 | intent.putExtra("return-data", true);
271 | activity.startActivityForResult(intent, REQUEST_CLICK_PHOTO_CODE);
272 | }
273 |
274 | public String getImgPath() {
275 | return Environment.getExternalStorageDirectory().getPath() + "/bdgames/images/";
276 | }
277 |
278 | public String getHeadImgName()
279 | {
280 | return System.currentTimeMillis() + ".jpg";
281 | }
282 |
283 | /**
284 | * 转换 content:// uri
285 | *
286 | * @param imageFile
287 | * @return
288 | */
289 | public Uri getImageContentUri(File imageFile) {
290 | String filePath = imageFile.getAbsolutePath();
291 | Cursor cursor = context.getContentResolver().query(
292 | MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
293 | new String[] { MediaStore.Images.Media._ID },
294 | MediaStore.Images.Media.DATA + "=? ",
295 | new String[] { filePath }, null);
296 |
297 | if (cursor != null && cursor.moveToFirst()) {
298 | int id = cursor.getInt(cursor
299 | .getColumnIndex(MediaStore.MediaColumns._ID));
300 | Uri baseUri = Uri.parse("content://media/external/images/media");
301 | return Uri.withAppendedPath(baseUri, "" + id);
302 | } else {
303 | if (imageFile.exists()) {
304 | ContentValues values = new ContentValues();
305 | values.put(MediaStore.Images.Media.DATA, filePath);
306 | return context.getContentResolver().insert(
307 | MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
308 | } else {
309 | return null;
310 | }
311 | }
312 | }
313 | }
314 |
--------------------------------------------------------------------------------
/PickPhotoDialog/app/src/main/java/com/ywl5320/csdn/pickphoto/util/AppUtil.java:
--------------------------------------------------------------------------------
1 | package com.ywl5320.csdn.pickphoto.util;
2 |
3 | import android.app.ActivityManager;
4 | import android.content.Context;
5 |
6 | import java.util.List;
7 |
8 | /**
9 | * Created by ywl5320 on 2017/8/22.
10 | */
11 |
12 | public class AppUtil {
13 |
14 | /**
15 | * 获取当前应用程序的包名
16 | *
17 | * @param context 上下文对象
18 | * @return 返回包名
19 | */
20 | public static String getAppPackName(Context context) {
21 | //当前应用pid
22 | int pid = android.os.Process.myPid();
23 | //任务管理类
24 | ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
25 | //遍历所有应用
26 | List infos = manager.getRunningAppProcesses();
27 | for (ActivityManager.RunningAppProcessInfo info : infos) {
28 | if (info.pid == pid)//得到当前应用
29 | return info.processName;//返回包名
30 | }
31 | return "";
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/PickPhotoDialog/app/src/main/res/anim/dialog_enter.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
--------------------------------------------------------------------------------
/PickPhotoDialog/app/src/main/res/anim/dialog_exit.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
--------------------------------------------------------------------------------
/PickPhotoDialog/app/src/main/res/drawable/blue_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/PickPhotoDialog/app/src/main/res/drawable/blue_item_r.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/PickPhotoDialog/app/src/main/res/drawable/btn_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
7 |
8 |
9 |
10 | -
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/PickPhotoDialog/app/src/main/res/drawable/circle_drawable.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
--------------------------------------------------------------------------------
/PickPhotoDialog/app/src/main/res/drawable/circle_drawable_pressed.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
--------------------------------------------------------------------------------
/PickPhotoDialog/app/src/main/res/drawable/dot_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/PickPhotoDialog/app/src/main/res/drawable/item_selected_folder.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/PickPhotoDialog/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
10 |
15 |
16 |
25 |
26 |
27 |
28 |
37 |
--------------------------------------------------------------------------------
/PickPhotoDialog/app/src/main/res/layout/activity_photo_view_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
11 |
--------------------------------------------------------------------------------
/PickPhotoDialog/app/src/main/res/layout/activity_selected_photo_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
20 |
27 |
34 |
35 |
42 |
46 |
57 |
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/PickPhotoDialog/app/src/main/res/layout/dialog_choice_photo_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
15 |
24 |
34 |
35 |
--------------------------------------------------------------------------------
/PickPhotoDialog/app/src/main/res/layout/dialog_photo_list_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
21 |
28 |
35 |
36 |
43 |
47 |
58 |
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/PickPhotoDialog/app/src/main/res/layout/dialog_photo_show_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
11 |
--------------------------------------------------------------------------------
/PickPhotoDialog/app/src/main/res/layout/include_comm_game_text_title.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
13 |
14 |
20 |
21 |
25 |
32 |
45 |
46 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/PickPhotoDialog/app/src/main/res/layout/item_img_adapter_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
12 |
17 |
28 |
--------------------------------------------------------------------------------
/PickPhotoDialog/app/src/main/res/layout/item_listview_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
15 |
22 |
29 |
37 |
38 |
47 |
--------------------------------------------------------------------------------
/PickPhotoDialog/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ywl5320/AndroidPickPhotoDialog/d66dcb9bf90c7fb38fa1f72657236b8911813daa/PickPhotoDialog/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/PickPhotoDialog/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ywl5320/AndroidPickPhotoDialog/d66dcb9bf90c7fb38fa1f72657236b8911813daa/PickPhotoDialog/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/PickPhotoDialog/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ywl5320/AndroidPickPhotoDialog/d66dcb9bf90c7fb38fa1f72657236b8911813daa/PickPhotoDialog/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/PickPhotoDialog/app/src/main/res/mipmap-xhdpi/icon_img_bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ywl5320/AndroidPickPhotoDialog/d66dcb9bf90c7fb38fa1f72657236b8911813daa/PickPhotoDialog/app/src/main/res/mipmap-xhdpi/icon_img_bg.png
--------------------------------------------------------------------------------
/PickPhotoDialog/app/src/main/res/mipmap-xhdpi/icon_img_folder_more.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ywl5320/AndroidPickPhotoDialog/d66dcb9bf90c7fb38fa1f72657236b8911813daa/PickPhotoDialog/app/src/main/res/mipmap-xhdpi/icon_img_folder_more.png
--------------------------------------------------------------------------------
/PickPhotoDialog/app/src/main/res/mipmap-xhdpi/icon_selected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ywl5320/AndroidPickPhotoDialog/d66dcb9bf90c7fb38fa1f72657236b8911813daa/PickPhotoDialog/app/src/main/res/mipmap-xhdpi/icon_selected.png
--------------------------------------------------------------------------------
/PickPhotoDialog/app/src/main/res/mipmap-xhdpi/icon_unselected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ywl5320/AndroidPickPhotoDialog/d66dcb9bf90c7fb38fa1f72657236b8911813daa/PickPhotoDialog/app/src/main/res/mipmap-xhdpi/icon_unselected.png
--------------------------------------------------------------------------------
/PickPhotoDialog/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ywl5320/AndroidPickPhotoDialog/d66dcb9bf90c7fb38fa1f72657236b8911813daa/PickPhotoDialog/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/PickPhotoDialog/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ywl5320/AndroidPickPhotoDialog/d66dcb9bf90c7fb38fa1f72657236b8911813daa/PickPhotoDialog/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/PickPhotoDialog/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/PickPhotoDialog/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #131820
4 | #131820
5 | #131820
6 |
7 | #80000000
8 |
9 |
--------------------------------------------------------------------------------
/PickPhotoDialog/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/PickPhotoDialog/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | PickPhotoDialog
3 |
4 |
--------------------------------------------------------------------------------
/PickPhotoDialog/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
21 |
22 |
23 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/PickPhotoDialog/app/src/main/res/xml/provider_paths.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/PickPhotoDialog/app/src/test/java/com/ywl5320/csdn/pickphoto/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.ywl5320.csdn.pickphoto;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/PickPhotoDialog/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:2.3.3'
9 |
10 | // NOTE: Do not place your application dependencies here; they belong
11 | // in the individual module build.gradle files
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | jcenter()
18 | }
19 | }
20 |
21 | task clean(type: Delete) {
22 | delete rootProject.buildDir
23 | }
24 |
--------------------------------------------------------------------------------
/PickPhotoDialog/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
--------------------------------------------------------------------------------
/PickPhotoDialog/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ywl5320/AndroidPickPhotoDialog/d66dcb9bf90c7fb38fa1f72657236b8911813daa/PickPhotoDialog/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/PickPhotoDialog/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Tue Aug 22 09:50:07 CST 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip
7 |
--------------------------------------------------------------------------------
/PickPhotoDialog/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/PickPhotoDialog/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/PickPhotoDialog/photoviewlibrary/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 25
5 | buildToolsVersion "25.0.2"
6 |
7 | defaultConfig {
8 | minSdkVersion 14
9 | targetSdkVersion 25
10 | versionCode 1
11 | versionName "1.0"
12 |
13 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
14 |
15 | }
16 | buildTypes {
17 | release {
18 | minifyEnabled false
19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
20 | }
21 | }
22 | }
23 |
24 | dependencies {
25 | compile fileTree(dir: 'libs', include: ['*.jar'])
26 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
27 | exclude group: 'com.android.support', module: 'support-annotations'
28 | })
29 | compile 'com.android.support:appcompat-v7:25.2.0'
30 | testCompile 'junit:junit:4.12'
31 | }
32 |
--------------------------------------------------------------------------------
/PickPhotoDialog/photoviewlibrary/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 D:\Android\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 |
--------------------------------------------------------------------------------
/PickPhotoDialog/photoviewlibrary/src/androidTest/java/uk/co/senab/photoview/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package uk.co.senab.photoview;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumentation test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("uk.co.senab.photoview.test", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/PickPhotoDialog/photoviewlibrary/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/PickPhotoDialog/photoviewlibrary/src/main/java/uk/co/senab/photoview/Compat.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2011, 2012 Chris Banes.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *******************************************************************************/
16 | package uk.co.senab.photoview;
17 |
18 | import android.annotation.TargetApi;
19 | import android.os.Build.VERSION;
20 | import android.os.Build.VERSION_CODES;
21 | import android.view.MotionEvent;
22 | import android.view.View;
23 |
24 | public class Compat {
25 |
26 | private static final int SIXTY_FPS_INTERVAL = 1000 / 60;
27 |
28 | public static void postOnAnimation(View view, Runnable runnable) {
29 | if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) {
30 | postOnAnimationJellyBean(view, runnable);
31 | } else {
32 | view.postDelayed(runnable, SIXTY_FPS_INTERVAL);
33 | }
34 | }
35 |
36 | @TargetApi(16)
37 | private static void postOnAnimationJellyBean(View view, Runnable runnable) {
38 | view.postOnAnimation(runnable);
39 | }
40 |
41 | public static int getPointerIndex(int action) {
42 | if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB)
43 | return getPointerIndexHoneyComb(action);
44 | else
45 | return getPointerIndexEclair(action);
46 | }
47 |
48 | @SuppressWarnings("deprecation")
49 | @TargetApi(VERSION_CODES.ECLAIR)
50 | private static int getPointerIndexEclair(int action) {
51 | return (action & MotionEvent.ACTION_POINTER_ID_MASK) >> MotionEvent.ACTION_POINTER_ID_SHIFT;
52 | }
53 |
54 | @TargetApi(VERSION_CODES.HONEYCOMB)
55 | private static int getPointerIndexHoneyComb(int action) {
56 | return (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
57 | }
58 |
59 | }
60 |
--------------------------------------------------------------------------------
/PickPhotoDialog/photoviewlibrary/src/main/java/uk/co/senab/photoview/DefaultOnDoubleTapListener.java:
--------------------------------------------------------------------------------
1 | package uk.co.senab.photoview;
2 |
3 | import android.graphics.RectF;
4 | import android.view.GestureDetector;
5 | import android.view.MotionEvent;
6 | import android.widget.ImageView;
7 |
8 | /**
9 | * Provided default implementation of GestureDetector.OnDoubleTapListener, to be overridden with custom behavior, if needed
10 | *
11 | * To be used via {@link uk.co.senab.photoview.PhotoViewAttacher#setOnDoubleTapListener(GestureDetector.OnDoubleTapListener)}
12 | */
13 | public class DefaultOnDoubleTapListener implements GestureDetector.OnDoubleTapListener {
14 |
15 | private PhotoViewAttacher photoViewAttacher;
16 |
17 | /**
18 | * Default constructor
19 | *
20 | * @param photoViewAttacher PhotoViewAttacher to bind to
21 | */
22 | public DefaultOnDoubleTapListener(PhotoViewAttacher photoViewAttacher) {
23 | setPhotoViewAttacher(photoViewAttacher);
24 | }
25 |
26 | /**
27 | * Allows to change PhotoViewAttacher within range of single instance
28 | *
29 | * @param newPhotoViewAttacher PhotoViewAttacher to bind to
30 | */
31 | public void setPhotoViewAttacher(PhotoViewAttacher newPhotoViewAttacher) {
32 | this.photoViewAttacher = newPhotoViewAttacher;
33 | }
34 |
35 | @Override
36 | public boolean onSingleTapConfirmed(MotionEvent e) {
37 | if (this.photoViewAttacher == null)
38 | return false;
39 |
40 | ImageView imageView = photoViewAttacher.getImageView();
41 |
42 | if (null != photoViewAttacher.getOnPhotoTapListener()) {
43 | final RectF displayRect = photoViewAttacher.getDisplayRect();
44 |
45 | if (null != displayRect) {
46 | final float x = e.getX(), y = e.getY();
47 |
48 | // Check to see if the user tapped on the photo
49 | if (displayRect.contains(x, y)) {
50 |
51 | float xResult = (x - displayRect.left)
52 | / displayRect.width();
53 | float yResult = (y - displayRect.top)
54 | / displayRect.height();
55 |
56 | photoViewAttacher.getOnPhotoTapListener().onPhotoTap(imageView, xResult, yResult);
57 | return true;
58 | }else{
59 | photoViewAttacher.getOnPhotoTapListener().onOutsidePhotoTap();
60 | }
61 | }
62 | }
63 | if (null != photoViewAttacher.getOnViewTapListener()) {
64 | photoViewAttacher.getOnViewTapListener().onViewTap(imageView, e.getX(), e.getY());
65 | }
66 |
67 | return false;
68 | }
69 |
70 | @Override
71 | public boolean onDoubleTap(MotionEvent ev) {
72 | if (photoViewAttacher == null)
73 | return false;
74 |
75 | try {
76 | float scale = photoViewAttacher.getScale();
77 | float x = ev.getX();
78 | float y = ev.getY();
79 |
80 | if (scale < photoViewAttacher.getMediumScale()) {
81 | photoViewAttacher.setScale(photoViewAttacher.getMediumScale(), x, y, true);
82 | } else if (scale >= photoViewAttacher.getMediumScale() && scale < photoViewAttacher.getMaximumScale()) {
83 | photoViewAttacher.setScale(photoViewAttacher.getMaximumScale(), x, y, true);
84 | } else {
85 | photoViewAttacher.setScale(photoViewAttacher.getMinimumScale(), x, y, true);
86 | }
87 | } catch (ArrayIndexOutOfBoundsException e) {
88 | // Can sometimes happen when getX() and getY() is called
89 | }
90 |
91 | return true;
92 | }
93 |
94 | @Override
95 | public boolean onDoubleTapEvent(MotionEvent e) {
96 | // Wait for the confirmed onDoubleTap() instead
97 | return false;
98 | }
99 |
100 | }
101 |
--------------------------------------------------------------------------------
/PickPhotoDialog/photoviewlibrary/src/main/java/uk/co/senab/photoview/IPhotoView.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2011, 2012 Chris Banes.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *******************************************************************************/
16 | package uk.co.senab.photoview;
17 |
18 | import android.graphics.Bitmap;
19 | import android.graphics.Matrix;
20 | import android.graphics.RectF;
21 | import android.view.GestureDetector;
22 | import android.view.View;
23 | import android.widget.ImageView;
24 |
25 |
26 | public interface IPhotoView {
27 |
28 | float DEFAULT_MAX_SCALE = 3.0f;
29 | float DEFAULT_MID_SCALE = 1.75f;
30 | float DEFAULT_MIN_SCALE = 1.0f;
31 | int DEFAULT_ZOOM_DURATION = 200;
32 |
33 | /**
34 | * Returns true if the PhotoView is set to allow zooming of Photos.
35 | *
36 | * @return true if the PhotoView allows zooming.
37 | */
38 | boolean canZoom();
39 |
40 | /**
41 | * Gets the Display Rectangle of the currently displayed Drawable. The Rectangle is relative to
42 | * this View and includes all scaling and translations.
43 | *
44 | * @return - RectF of Displayed Drawable
45 | */
46 | RectF getDisplayRect();
47 |
48 | /**
49 | * Sets the Display Matrix of the currently displayed Drawable. The Rectangle is considered
50 | * relative to this View and includes all scaling and translations.
51 | *
52 | * @param finalMatrix target matrix to set PhotoView to
53 | * @return - true if rectangle was applied successfully
54 | */
55 | boolean setDisplayMatrix(Matrix finalMatrix);
56 |
57 | /**
58 | * Copies the Display Matrix of the currently displayed Drawable. The Rectangle is considered
59 | * relative to this View and includes all scaling and translations.
60 | *
61 | * @param matrix target matrix to copy to
62 | */
63 | void getDisplayMatrix(Matrix matrix);
64 |
65 | /**
66 | * @return The current minimum scale level. What this value represents depends on the current
67 | * {@link ImageView.ScaleType}.
68 | */
69 | float getMinimumScale();
70 |
71 | /**
72 | * @return The current medium scale level. What this value represents depends on the current
73 | * {@link ImageView.ScaleType}.
74 | */
75 | float getMediumScale();
76 |
77 | /**
78 | * @return The current maximum scale level. What this value represents depends on the current
79 | * {@link ImageView.ScaleType}.
80 | */
81 | float getMaximumScale();
82 |
83 | /**
84 | * Returns the current scale value
85 | *
86 | * @return float - current scale value
87 | */
88 | float getScale();
89 |
90 | /**
91 | * Return the current scale type in use by the ImageView.
92 | *
93 | * @return current ImageView.ScaleType
94 | */
95 | ImageView.ScaleType getScaleType();
96 |
97 | /**
98 | * Whether to allow the ImageView's parent to intercept the touch event when the photo is scroll
99 | * to it's horizontal edge.
100 | *
101 | * @param allow whether to allow intercepting by parent element or not
102 | */
103 | void setAllowParentInterceptOnEdge(boolean allow);
104 |
105 | /**
106 | * Sets the minimum scale level. What this value represents depends on the current {@link
107 | * ImageView.ScaleType}.
108 | *
109 | * @param minimumScale minimum allowed scale
110 | */
111 | void setMinimumScale(float minimumScale);
112 |
113 | /**
114 | * Sets the medium scale level. What this value represents depends on the current {@link ImageView.ScaleType}.
115 | *
116 | * @param mediumScale medium scale preset
117 | */
118 | void setMediumScale(float mediumScale);
119 |
120 | /**
121 | * Sets the maximum scale level. What this value represents depends on the current {@link
122 | * ImageView.ScaleType}.
123 | *
124 | * @param maximumScale maximum allowed scale preset
125 | */
126 | void setMaximumScale(float maximumScale);
127 |
128 | /**
129 | * Allows to set all three scale levels at once, so you don't run into problem with setting
130 | * medium/minimum scale before the maximum one
131 | *
132 | * @param minimumScale minimum allowed scale
133 | * @param mediumScale medium allowed scale
134 | * @param maximumScale maximum allowed scale preset
135 | */
136 | void setScaleLevels(float minimumScale, float mediumScale, float maximumScale);
137 |
138 | /**
139 | * Register a callback to be invoked when the Photo displayed by this view is long-pressed.
140 | *
141 | * @param listener - Listener to be registered.
142 | */
143 | void setOnLongClickListener(View.OnLongClickListener listener);
144 |
145 | /**
146 | * Register a callback to be invoked when the Matrix has changed for this View. An example would
147 | * be the user panning or scaling the Photo.
148 | *
149 | * @param listener - Listener to be registered.
150 | */
151 | void setOnMatrixChangeListener(PhotoViewAttacher.OnMatrixChangedListener listener);
152 |
153 | /**
154 | * Register a callback to be invoked when the Photo displayed by this View is tapped with a
155 | * single tap.
156 | *
157 | * @param listener - Listener to be registered.
158 | */
159 | void setOnPhotoTapListener(PhotoViewAttacher.OnPhotoTapListener listener);
160 |
161 | /**
162 | * Register a callback to be invoked when the View is tapped with a single tap.
163 | *
164 | * @param listener - Listener to be registered.
165 | */
166 | void setOnViewTapListener(PhotoViewAttacher.OnViewTapListener listener);
167 |
168 | /**
169 | * Enables rotation via PhotoView internal functions.
170 | *
171 | * @param rotationDegree - Degree to rotate PhotoView to, should be in range 0 to 360
172 | */
173 | void setRotationTo(float rotationDegree);
174 |
175 | /**
176 | * Enables rotation via PhotoView internal functions.
177 | *
178 | * @param rotationDegree - Degree to rotate PhotoView by, should be in range 0 to 360
179 | */
180 | void setRotationBy(float rotationDegree);
181 |
182 | /**
183 | * Changes the current scale to the specified value.
184 | *
185 | * @param scale - Value to scale to
186 | */
187 | void setScale(float scale);
188 |
189 | /**
190 | * Changes the current scale to the specified value.
191 | *
192 | * @param scale - Value to scale to
193 | * @param animate - Whether to animate the scale
194 | */
195 | void setScale(float scale, boolean animate);
196 |
197 | /**
198 | * Changes the current scale to the specified value, around the given focal point.
199 | *
200 | * @param scale - Value to scale to
201 | * @param focalX - X Focus Point
202 | * @param focalY - Y Focus Point
203 | * @param animate - Whether to animate the scale
204 | */
205 | void setScale(float scale, float focalX, float focalY, boolean animate);
206 |
207 | /**
208 | * Controls how the image should be resized or moved to match the size of the ImageView. Any
209 | * scaling or panning will happen within the confines of this {@link
210 | * ImageView.ScaleType}.
211 | *
212 | * @param scaleType - The desired scaling mode.
213 | */
214 | void setScaleType(ImageView.ScaleType scaleType);
215 |
216 | /**
217 | * Allows you to enable/disable the zoom functionality on the ImageView. When disable the
218 | * ImageView reverts to using the FIT_CENTER matrix.
219 | *
220 | * @param zoomable - Whether the zoom functionality is enabled.
221 | */
222 | void setZoomable(boolean zoomable);
223 |
224 | /**
225 | * Extracts currently visible area to Bitmap object, if there is no image loaded yet or the
226 | * ImageView is already destroyed, returns {@code null}
227 | *
228 | * @return currently visible area as bitmap or null
229 | */
230 | Bitmap getVisibleRectangleBitmap();
231 |
232 | /**
233 | * Allows to change zoom transition speed, default value is 200 (PhotoViewAttacher.DEFAULT_ZOOM_DURATION).
234 | * Will default to 200 if provided negative value
235 | *
236 | * @param milliseconds duration of zoom interpolation
237 | */
238 | void setZoomTransitionDuration(int milliseconds);
239 |
240 | /**
241 | * Will return instance of IPhotoView (eg. PhotoViewAttacher), can be used to provide better
242 | * integration
243 | *
244 | * @return IPhotoView implementation instance if available, null if not
245 | */
246 | IPhotoView getIPhotoViewImplementation();
247 |
248 | /**
249 | * Sets custom double tap listener, to intercept default given functions. To reset behavior to
250 | * default, you can just pass in "null" or public field of PhotoViewAttacher.defaultOnDoubleTapListener
251 | *
252 | * @param newOnDoubleTapListener custom OnDoubleTapListener to be set on ImageView
253 | */
254 | void setOnDoubleTapListener(GestureDetector.OnDoubleTapListener newOnDoubleTapListener);
255 |
256 | /**
257 | * Will report back about scale changes
258 | *
259 | * @param onScaleChangeListener OnScaleChangeListener instance
260 | */
261 | void setOnScaleChangeListener(PhotoViewAttacher.OnScaleChangeListener onScaleChangeListener);
262 |
263 | /**
264 | * Will report back about fling(single touch)
265 | *
266 | * @param onSingleFlingListener OnSingleFlingListener instance
267 | */
268 | void setOnSingleFlingListener(PhotoViewAttacher.OnSingleFlingListener onSingleFlingListener);
269 | }
270 |
--------------------------------------------------------------------------------
/PickPhotoDialog/photoviewlibrary/src/main/java/uk/co/senab/photoview/PhotoView.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2011, 2012 Chris Banes.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *******************************************************************************/
16 | package uk.co.senab.photoview;
17 |
18 | import android.content.Context;
19 | import android.graphics.Bitmap;
20 | import android.graphics.Matrix;
21 | import android.graphics.RectF;
22 | import android.graphics.drawable.Drawable;
23 | import android.net.Uri;
24 | import android.util.AttributeSet;
25 | import android.view.GestureDetector;
26 | import android.widget.ImageView;
27 |
28 | import uk.co.senab.photoview.PhotoViewAttacher.OnMatrixChangedListener;
29 | import uk.co.senab.photoview.PhotoViewAttacher.OnPhotoTapListener;
30 | import uk.co.senab.photoview.PhotoViewAttacher.OnViewTapListener;
31 |
32 | public class PhotoView extends ImageView implements IPhotoView {
33 |
34 | private PhotoViewAttacher mAttacher;
35 |
36 | private ScaleType mPendingScaleType;
37 |
38 | public PhotoView(Context context) {
39 | this(context, null);
40 | }
41 |
42 | public PhotoView(Context context, AttributeSet attr) {
43 | this(context, attr, 0);
44 | }
45 |
46 | public PhotoView(Context context, AttributeSet attr, int defStyle) {
47 | super(context, attr, defStyle);
48 | super.setScaleType(ScaleType.MATRIX);
49 | init();
50 | }
51 |
52 | protected void init() {
53 | if (null == mAttacher || null == mAttacher.getImageView()) {
54 | mAttacher = new PhotoViewAttacher(this);
55 | }
56 |
57 | if (null != mPendingScaleType) {
58 | setScaleType(mPendingScaleType);
59 | mPendingScaleType = null;
60 | }
61 | }
62 |
63 | @Override
64 | public void setRotationTo(float rotationDegree) {
65 | mAttacher.setRotationTo(rotationDegree);
66 | }
67 |
68 | @Override
69 | public void setRotationBy(float rotationDegree) {
70 | mAttacher.setRotationBy(rotationDegree);
71 | }
72 |
73 | @Override
74 | public boolean canZoom() {
75 | return mAttacher.canZoom();
76 | }
77 |
78 | @Override
79 | public RectF getDisplayRect() {
80 | return mAttacher.getDisplayRect();
81 | }
82 |
83 | @Override
84 | public void getDisplayMatrix(Matrix matrix) {
85 | mAttacher.getDisplayMatrix(matrix);
86 | }
87 |
88 | @Override
89 | public boolean setDisplayMatrix(Matrix finalRectangle) {
90 | return mAttacher.setDisplayMatrix(finalRectangle);
91 | }
92 |
93 | @Override
94 | public float getMinimumScale() {
95 | return mAttacher.getMinimumScale();
96 | }
97 |
98 | @Override
99 | public float getMediumScale() {
100 | return mAttacher.getMediumScale();
101 | }
102 |
103 | @Override
104 | public float getMaximumScale() {
105 | return mAttacher.getMaximumScale();
106 | }
107 |
108 | @Override
109 | public float getScale() {
110 | return mAttacher.getScale();
111 | }
112 |
113 | @Override
114 | public ScaleType getScaleType() {
115 | return mAttacher.getScaleType();
116 | }
117 |
118 | @Override
119 | public Matrix getImageMatrix() {
120 | return mAttacher.getImageMatrix();
121 | }
122 |
123 | @Override
124 | public void setAllowParentInterceptOnEdge(boolean allow) {
125 | mAttacher.setAllowParentInterceptOnEdge(allow);
126 | }
127 |
128 | @Override
129 | public void setMinimumScale(float minimumScale) {
130 | mAttacher.setMinimumScale(minimumScale);
131 | }
132 |
133 | @Override
134 | public void setMediumScale(float mediumScale) {
135 | mAttacher.setMediumScale(mediumScale);
136 | }
137 |
138 | @Override
139 | public void setMaximumScale(float maximumScale) {
140 | mAttacher.setMaximumScale(maximumScale);
141 | }
142 |
143 | @Override
144 | public void setScaleLevels(float minimumScale, float mediumScale, float maximumScale) {
145 | mAttacher.setScaleLevels(minimumScale, mediumScale, maximumScale);
146 | }
147 |
148 | @Override
149 | // setImageBitmap calls through to this method
150 | public void setImageDrawable(Drawable drawable) {
151 | super.setImageDrawable(drawable);
152 | if (null != mAttacher) {
153 | mAttacher.update();
154 | }
155 | }
156 |
157 | @Override
158 | public void setImageResource(int resId) {
159 | super.setImageResource(resId);
160 | if (null != mAttacher) {
161 | mAttacher.update();
162 | }
163 | }
164 |
165 | @Override
166 | public void setImageURI(Uri uri) {
167 | super.setImageURI(uri);
168 | if (null != mAttacher) {
169 | mAttacher.update();
170 | }
171 | }
172 |
173 | @Override
174 | protected boolean setFrame(int l, int t, int r, int b) {
175 | boolean changed = super.setFrame(l, t, r, b);
176 | if (null != mAttacher) {
177 | mAttacher.update();
178 | }
179 | return changed;
180 | }
181 |
182 | @Override
183 | public void setOnMatrixChangeListener(OnMatrixChangedListener listener) {
184 | mAttacher.setOnMatrixChangeListener(listener);
185 | }
186 |
187 | @Override
188 | public void setOnLongClickListener(OnLongClickListener l) {
189 | mAttacher.setOnLongClickListener(l);
190 | }
191 |
192 | @Override
193 | public void setOnPhotoTapListener(OnPhotoTapListener listener) {
194 | mAttacher.setOnPhotoTapListener(listener);
195 | }
196 |
197 | @Override
198 | public void setOnViewTapListener(OnViewTapListener listener) {
199 | mAttacher.setOnViewTapListener(listener);
200 | }
201 |
202 | @Override
203 | public void setScale(float scale) {
204 | mAttacher.setScale(scale);
205 | }
206 |
207 | @Override
208 | public void setScale(float scale, boolean animate) {
209 | mAttacher.setScale(scale, animate);
210 | }
211 |
212 | @Override
213 | public void setScale(float scale, float focalX, float focalY, boolean animate) {
214 | mAttacher.setScale(scale, focalX, focalY, animate);
215 | }
216 |
217 | @Override
218 | public void setScaleType(ScaleType scaleType) {
219 | if (null != mAttacher) {
220 | mAttacher.setScaleType(scaleType);
221 | } else {
222 | mPendingScaleType = scaleType;
223 | }
224 | }
225 |
226 | @Override
227 | public void setZoomable(boolean zoomable) {
228 | mAttacher.setZoomable(zoomable);
229 | }
230 |
231 | @Override
232 | public Bitmap getVisibleRectangleBitmap() {
233 | return mAttacher.getVisibleRectangleBitmap();
234 | }
235 |
236 | @Override
237 | public void setZoomTransitionDuration(int milliseconds) {
238 | mAttacher.setZoomTransitionDuration(milliseconds);
239 | }
240 |
241 | @Override
242 | public IPhotoView getIPhotoViewImplementation() {
243 | return mAttacher;
244 | }
245 |
246 | @Override
247 | public void setOnDoubleTapListener(GestureDetector.OnDoubleTapListener newOnDoubleTapListener) {
248 | mAttacher.setOnDoubleTapListener(newOnDoubleTapListener);
249 | }
250 |
251 | @Override
252 | public void setOnScaleChangeListener(PhotoViewAttacher.OnScaleChangeListener onScaleChangeListener) {
253 | mAttacher.setOnScaleChangeListener(onScaleChangeListener);
254 | }
255 |
256 | @Override
257 | public void setOnSingleFlingListener(PhotoViewAttacher.OnSingleFlingListener onSingleFlingListener) {
258 | mAttacher.setOnSingleFlingListener(onSingleFlingListener);
259 | }
260 |
261 | @Override
262 | protected void onDetachedFromWindow() {
263 | mAttacher.cleanup();
264 | mAttacher = null;
265 | super.onDetachedFromWindow();
266 | }
267 |
268 | @Override
269 | protected void onAttachedToWindow() {
270 | init();
271 | super.onAttachedToWindow();
272 | }
273 | }
274 |
--------------------------------------------------------------------------------
/PickPhotoDialog/photoviewlibrary/src/main/java/uk/co/senab/photoview/PhotoViewAttacher.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2011, 2012 Chris Banes.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *******************************************************************************/
16 | package uk.co.senab.photoview;
17 |
18 | import android.annotation.SuppressLint;
19 | import android.content.Context;
20 | import android.graphics.Bitmap;
21 | import android.graphics.Matrix;
22 | import android.graphics.Matrix.ScaleToFit;
23 | import android.graphics.RectF;
24 | import android.graphics.drawable.Drawable;
25 | import android.support.annotation.Nullable;
26 | import android.support.v4.view.MotionEventCompat;
27 | import android.util.Log;
28 | import android.view.GestureDetector;
29 | import android.view.MotionEvent;
30 | import android.view.View;
31 | import android.view.View.OnLongClickListener;
32 | import android.view.ViewParent;
33 | import android.view.ViewTreeObserver;
34 | import android.view.animation.AccelerateDecelerateInterpolator;
35 | import android.view.animation.Interpolator;
36 | import android.widget.ImageView;
37 | import android.widget.ImageView.ScaleType;
38 |
39 | import java.lang.ref.WeakReference;
40 |
41 | import uk.co.senab.photoview.gestures.OnGestureListener;
42 | import uk.co.senab.photoview.gestures.VersionedGestureDetector;
43 | import uk.co.senab.photoview.log.LogManager;
44 | import uk.co.senab.photoview.scrollerproxy.ScrollerProxy;
45 |
46 | import static android.view.MotionEvent.ACTION_CANCEL;
47 | import static android.view.MotionEvent.ACTION_DOWN;
48 | import static android.view.MotionEvent.ACTION_UP;
49 |
50 | public class PhotoViewAttacher implements IPhotoView, View.OnTouchListener,
51 | OnGestureListener,
52 | ViewTreeObserver.OnGlobalLayoutListener {
53 |
54 | private static final String LOG_TAG = "PhotoViewAttacher";
55 |
56 | // let debug flag be dynamic, but still Proguard can be used to remove from
57 | // release builds
58 | private static final boolean DEBUG = Log.isLoggable(LOG_TAG, Log.DEBUG);
59 |
60 | private Interpolator mInterpolator = new AccelerateDecelerateInterpolator();
61 | int ZOOM_DURATION = DEFAULT_ZOOM_DURATION;
62 |
63 | static final int EDGE_NONE = -1;
64 | static final int EDGE_LEFT = 0;
65 | static final int EDGE_RIGHT = 1;
66 | static final int EDGE_BOTH = 2;
67 |
68 | static int SINGLE_TOUCH = 1;
69 |
70 | private float mMinScale = DEFAULT_MIN_SCALE;
71 | private float mMidScale = DEFAULT_MID_SCALE;
72 | private float mMaxScale = DEFAULT_MAX_SCALE;
73 |
74 | private boolean mAllowParentInterceptOnEdge = true;
75 | private boolean mBlockParentIntercept = false;
76 |
77 | private static void checkZoomLevels(float minZoom, float midZoom,
78 | float maxZoom) {
79 | if (minZoom >= midZoom) {
80 | throw new IllegalArgumentException(
81 | "Minimum zoom has to be less than Medium zoom. Call setMinimumZoom() with a more appropriate value");
82 | } else if (midZoom >= maxZoom) {
83 | throw new IllegalArgumentException(
84 | "Medium zoom has to be less than Maximum zoom. Call setMaximumZoom() with a more appropriate value");
85 | }
86 | }
87 |
88 | /**
89 | * @return true if the ImageView exists, and its Drawable exists
90 | */
91 | private static boolean hasDrawable(ImageView imageView) {
92 | return null != imageView && null != imageView.getDrawable();
93 | }
94 |
95 | /**
96 | * @return true if the ScaleType is supported.
97 | */
98 | private static boolean isSupportedScaleType(final ScaleType scaleType) {
99 | if (null == scaleType) {
100 | return false;
101 | }
102 |
103 | switch (scaleType) {
104 | case MATRIX:
105 | throw new IllegalArgumentException(scaleType.name()
106 | + " is not supported in PhotoView");
107 |
108 | default:
109 | return true;
110 | }
111 | }
112 |
113 | /**
114 | * Sets the ImageView's ScaleType to Matrix.
115 | */
116 | private static void setImageViewScaleTypeMatrix(ImageView imageView) {
117 | /**
118 | * PhotoView sets its own ScaleType to Matrix, then diverts all calls
119 | * setScaleType to this.setScaleType automatically.
120 | */
121 | if (null != imageView && !(imageView instanceof IPhotoView)) {
122 | if (!ScaleType.MATRIX.equals(imageView.getScaleType())) {
123 | imageView.setScaleType(ScaleType.MATRIX);
124 | }
125 | }
126 | }
127 |
128 | private WeakReference mImageView;
129 |
130 | // Gesture Detectors
131 | private GestureDetector mGestureDetector;
132 | private uk.co.senab.photoview.gestures.GestureDetector mScaleDragDetector;
133 |
134 | // These are set so we don't keep allocating them on the heap
135 | private final Matrix mBaseMatrix = new Matrix();
136 | private final Matrix mDrawMatrix = new Matrix();
137 | private final Matrix mSuppMatrix = new Matrix();
138 | private final RectF mDisplayRect = new RectF();
139 | private final float[] mMatrixValues = new float[9];
140 |
141 | // Listeners
142 | private OnMatrixChangedListener mMatrixChangeListener;
143 | private OnPhotoTapListener mPhotoTapListener;
144 | private OnViewTapListener mViewTapListener;
145 | private OnLongClickListener mLongClickListener;
146 | private OnScaleChangeListener mScaleChangeListener;
147 | private OnSingleFlingListener mSingleFlingListener;
148 |
149 | private int mIvTop, mIvRight, mIvBottom, mIvLeft;
150 | private FlingRunnable mCurrentFlingRunnable;
151 | private int mScrollEdge = EDGE_BOTH;
152 | private float mBaseRotation;
153 |
154 | private boolean mZoomEnabled;
155 | private ScaleType mScaleType = ScaleType.FIT_CENTER;
156 |
157 | public PhotoViewAttacher(ImageView imageView) {
158 | this(imageView, true);
159 | }
160 |
161 | public PhotoViewAttacher(ImageView imageView, boolean zoomable) {
162 | mImageView = new WeakReference<>(imageView);
163 |
164 | imageView.setDrawingCacheEnabled(true);
165 | imageView.setOnTouchListener(this);
166 |
167 | ViewTreeObserver observer = imageView.getViewTreeObserver();
168 | if (null != observer)
169 | observer.addOnGlobalLayoutListener(this);
170 |
171 | // Make sure we using MATRIX Scale Type
172 | setImageViewScaleTypeMatrix(imageView);
173 |
174 | if (imageView.isInEditMode()) {
175 | return;
176 | }
177 | // Create Gesture Detectors...
178 | mScaleDragDetector = VersionedGestureDetector.newInstance(
179 | imageView.getContext(), this);
180 |
181 | mGestureDetector = new GestureDetector(imageView.getContext(),
182 | new GestureDetector.SimpleOnGestureListener() {
183 |
184 | // forward long click listener
185 | @Override
186 | public void onLongPress(MotionEvent e) {
187 | if (null != mLongClickListener) {
188 | mLongClickListener.onLongClick(getImageView());
189 | }
190 | }
191 |
192 | @Override
193 | public boolean onFling(MotionEvent e1, MotionEvent e2,
194 | float velocityX, float velocityY) {
195 | if (mSingleFlingListener != null) {
196 | if (getScale() > DEFAULT_MIN_SCALE) {
197 | return false;
198 | }
199 |
200 | if (MotionEventCompat.getPointerCount(e1) > SINGLE_TOUCH
201 | || MotionEventCompat.getPointerCount(e2) > SINGLE_TOUCH) {
202 | return false;
203 | }
204 |
205 | return mSingleFlingListener.onFling(e1, e2, velocityX, velocityY);
206 | }
207 | return false;
208 | }
209 | });
210 |
211 | mGestureDetector.setOnDoubleTapListener(new DefaultOnDoubleTapListener(this));
212 | mBaseRotation = 0.0f;
213 |
214 | // Finally, update the UI so that we're zoomable
215 | setZoomable(zoomable);
216 | }
217 |
218 | @Override
219 | public void setOnDoubleTapListener(GestureDetector.OnDoubleTapListener newOnDoubleTapListener) {
220 | if (newOnDoubleTapListener != null) {
221 | this.mGestureDetector.setOnDoubleTapListener(newOnDoubleTapListener);
222 | } else {
223 | this.mGestureDetector.setOnDoubleTapListener(new DefaultOnDoubleTapListener(this));
224 | }
225 | }
226 |
227 | @Override
228 | public void setOnScaleChangeListener(OnScaleChangeListener onScaleChangeListener) {
229 | this.mScaleChangeListener = onScaleChangeListener;
230 | }
231 |
232 | @Override
233 | public void setOnSingleFlingListener(OnSingleFlingListener onSingleFlingListener) {
234 | this.mSingleFlingListener = onSingleFlingListener;
235 | }
236 |
237 | @Override
238 | public boolean canZoom() {
239 | return mZoomEnabled;
240 | }
241 |
242 | /**
243 | * Clean-up the resources attached to this object. This needs to be called when the ImageView is
244 | * no longer used. A good example is from {@link View#onDetachedFromWindow()} or
245 | * from {@link android.app.Activity#onDestroy()}. This is automatically called if you are using
246 | * {@link uk.co.senab.photoview.PhotoView}.
247 | */
248 | @SuppressWarnings("deprecation")
249 | public void cleanup() {
250 | if (null == mImageView) {
251 | return; // cleanup already done
252 | }
253 |
254 | final ImageView imageView = mImageView.get();
255 |
256 | if (null != imageView) {
257 | // Remove this as a global layout listener
258 | ViewTreeObserver observer = imageView.getViewTreeObserver();
259 | if (null != observer && observer.isAlive()) {
260 | observer.removeGlobalOnLayoutListener(this);
261 | }
262 |
263 | // Remove the ImageView's reference to this
264 | imageView.setOnTouchListener(null);
265 |
266 | // make sure a pending fling runnable won't be run
267 | cancelFling();
268 | }
269 |
270 | if (null != mGestureDetector) {
271 | mGestureDetector.setOnDoubleTapListener(null);
272 | }
273 |
274 | // Clear listeners too
275 | mMatrixChangeListener = null;
276 | mPhotoTapListener = null;
277 | mViewTapListener = null;
278 |
279 | // Finally, clear ImageView
280 | mImageView = null;
281 | }
282 |
283 | @Override
284 | public RectF getDisplayRect() {
285 | checkMatrixBounds();
286 | return getDisplayRect(getDrawMatrix());
287 | }
288 |
289 | @Override
290 | public boolean setDisplayMatrix(Matrix finalMatrix) {
291 | if (finalMatrix == null) {
292 | throw new IllegalArgumentException("Matrix cannot be null");
293 | }
294 |
295 | ImageView imageView = getImageView();
296 | if (null == imageView) {
297 | return false;
298 | }
299 |
300 | if (null == imageView.getDrawable()) {
301 | return false;
302 | }
303 |
304 | mSuppMatrix.set(finalMatrix);
305 | setImageViewMatrix(getDrawMatrix());
306 | checkMatrixBounds();
307 |
308 | return true;
309 | }
310 |
311 | public void setBaseRotation(final float degrees) {
312 | mBaseRotation = degrees % 360;
313 | update();
314 | setRotationBy(mBaseRotation);
315 | checkAndDisplayMatrix();
316 | }
317 |
318 | @Override
319 | public void setRotationTo(float degrees) {
320 | mSuppMatrix.setRotate(degrees % 360);
321 | checkAndDisplayMatrix();
322 | }
323 |
324 | @Override
325 | public void setRotationBy(float degrees) {
326 | mSuppMatrix.postRotate(degrees % 360);
327 | checkAndDisplayMatrix();
328 | }
329 |
330 | public ImageView getImageView() {
331 | ImageView imageView = null;
332 |
333 | if (null != mImageView) {
334 | imageView = mImageView.get();
335 | }
336 |
337 | // If we don't have an ImageView, call cleanup()
338 | if (null == imageView) {
339 | cleanup();
340 | LogManager.getLogger().i(LOG_TAG,
341 | "ImageView no longer exists. You should not use this PhotoViewAttacher any more.");
342 | }
343 |
344 | return imageView;
345 | }
346 |
347 | @Override
348 | public float getMinimumScale() {
349 | return mMinScale;
350 | }
351 |
352 | @Override
353 | public float getMediumScale() {
354 | return mMidScale;
355 | }
356 |
357 | @Override
358 | public float getMaximumScale() {
359 | return mMaxScale;
360 | }
361 |
362 | @Override
363 | public float getScale() {
364 | return (float) Math.sqrt((float) Math.pow(getValue(mSuppMatrix, Matrix.MSCALE_X), 2) + (float) Math.pow(getValue(mSuppMatrix, Matrix.MSKEW_Y), 2));
365 | }
366 |
367 | @Override
368 | public ScaleType getScaleType() {
369 | return mScaleType;
370 | }
371 |
372 | @Override
373 | public void onDrag(float dx, float dy) {
374 | if (mScaleDragDetector.isScaling()) {
375 | return; // Do not drag if we are already scaling
376 | }
377 |
378 | if (DEBUG) {
379 | LogManager.getLogger().d(LOG_TAG,
380 | String.format("onDrag: dx: %.2f. dy: %.2f", dx, dy));
381 | }
382 |
383 | ImageView imageView = getImageView();
384 | mSuppMatrix.postTranslate(dx, dy);
385 | checkAndDisplayMatrix();
386 |
387 | /**
388 | * Here we decide whether to let the ImageView's parent to start taking
389 | * over the touch event.
390 | *
391 | * First we check whether this function is enabled. We never want the
392 | * parent to take over if we're scaling. We then check the edge we're
393 | * on, and the direction of the scroll (i.e. if we're pulling against
394 | * the edge, aka 'overscrolling', let the parent take over).
395 | */
396 | ViewParent parent = imageView.getParent();
397 | if (mAllowParentInterceptOnEdge && !mScaleDragDetector.isScaling() && !mBlockParentIntercept) {
398 | if (mScrollEdge == EDGE_BOTH
399 | || (mScrollEdge == EDGE_LEFT && dx >= 1f)
400 | || (mScrollEdge == EDGE_RIGHT && dx <= -1f)) {
401 | if (null != parent) {
402 | parent.requestDisallowInterceptTouchEvent(false);
403 | }
404 | }
405 | } else {
406 | if (null != parent) {
407 | parent.requestDisallowInterceptTouchEvent(true);
408 | }
409 | }
410 | }
411 |
412 | @Override
413 | public void onFling(float startX, float startY, float velocityX,
414 | float velocityY) {
415 | if (DEBUG) {
416 | LogManager.getLogger().d(
417 | LOG_TAG,
418 | "onFling. sX: " + startX + " sY: " + startY + " Vx: "
419 | + velocityX + " Vy: " + velocityY);
420 | }
421 | ImageView imageView = getImageView();
422 | mCurrentFlingRunnable = new FlingRunnable(imageView.getContext());
423 | mCurrentFlingRunnable.fling(getImageViewWidth(imageView),
424 | getImageViewHeight(imageView), (int) velocityX, (int) velocityY);
425 | imageView.post(mCurrentFlingRunnable);
426 | }
427 |
428 | @Override
429 | public void onGlobalLayout() {
430 | ImageView imageView = getImageView();
431 |
432 | if (null != imageView) {
433 | if (mZoomEnabled) {
434 | final int top = imageView.getTop();
435 | final int right = imageView.getRight();
436 | final int bottom = imageView.getBottom();
437 | final int left = imageView.getLeft();
438 |
439 | /**
440 | * We need to check whether the ImageView's bounds have changed.
441 | * This would be easier if we targeted API 11+ as we could just use
442 | * View.OnLayoutChangeListener. Instead we have to replicate the
443 | * work, keeping track of the ImageView's bounds and then checking
444 | * if the values change.
445 | */
446 | if (top != mIvTop || bottom != mIvBottom || left != mIvLeft
447 | || right != mIvRight) {
448 | // Update our base matrix, as the bounds have changed
449 | updateBaseMatrix(imageView.getDrawable());
450 |
451 | // Update values as something has changed
452 | mIvTop = top;
453 | mIvRight = right;
454 | mIvBottom = bottom;
455 | mIvLeft = left;
456 | }
457 | } else {
458 | updateBaseMatrix(imageView.getDrawable());
459 | }
460 | }
461 | }
462 |
463 | @Override
464 | public void onScale(float scaleFactor, float focusX, float focusY) {
465 | if (DEBUG) {
466 | LogManager.getLogger().d(
467 | LOG_TAG,
468 | String.format("onScale: scale: %.2f. fX: %.2f. fY: %.2f",
469 | scaleFactor, focusX, focusY));
470 | }
471 |
472 | if ((getScale() < mMaxScale || scaleFactor < 1f) && (getScale() > mMinScale || scaleFactor > 1f)) {
473 | if (null != mScaleChangeListener) {
474 | mScaleChangeListener.onScaleChange(scaleFactor, focusX, focusY);
475 | }
476 | mSuppMatrix.postScale(scaleFactor, scaleFactor, focusX, focusY);
477 | checkAndDisplayMatrix();
478 | }
479 | }
480 |
481 | @SuppressLint("ClickableViewAccessibility")
482 | @Override
483 | public boolean onTouch(View v, MotionEvent ev) {
484 | boolean handled = false;
485 |
486 | if (mZoomEnabled && hasDrawable((ImageView) v)) {
487 | ViewParent parent = v.getParent();
488 | switch (ev.getAction()) {
489 | case ACTION_DOWN:
490 | // First, disable the Parent from intercepting the touch
491 | // event
492 | if (null != parent) {
493 | parent.requestDisallowInterceptTouchEvent(true);
494 | } else {
495 | LogManager.getLogger().i(LOG_TAG, "onTouch getParent() returned null");
496 | }
497 |
498 | // If we're flinging, and the user presses down, cancel
499 | // fling
500 | cancelFling();
501 | break;
502 |
503 | case ACTION_CANCEL:
504 | case ACTION_UP:
505 | // If the user has zoomed less than min scale, zoom back
506 | // to min scale
507 | if (getScale() < mMinScale) {
508 | RectF rect = getDisplayRect();
509 | if (null != rect) {
510 | v.post(new AnimatedZoomRunnable(getScale(), mMinScale,
511 | rect.centerX(), rect.centerY()));
512 | handled = true;
513 | }
514 | }
515 | break;
516 | }
517 |
518 | // Try the Scale/Drag detector
519 | if (null != mScaleDragDetector) {
520 | boolean wasScaling = mScaleDragDetector.isScaling();
521 | boolean wasDragging = mScaleDragDetector.isDragging();
522 |
523 | handled = mScaleDragDetector.onTouchEvent(ev);
524 |
525 | boolean didntScale = !wasScaling && !mScaleDragDetector.isScaling();
526 | boolean didntDrag = !wasDragging && !mScaleDragDetector.isDragging();
527 |
528 | mBlockParentIntercept = didntScale && didntDrag;
529 | }
530 |
531 | // Check to see if the user double tapped
532 | if (null != mGestureDetector && mGestureDetector.onTouchEvent(ev)) {
533 | handled = true;
534 | }
535 |
536 | }
537 |
538 | return handled;
539 | }
540 |
541 | @Override
542 | public void setAllowParentInterceptOnEdge(boolean allow) {
543 | mAllowParentInterceptOnEdge = allow;
544 | }
545 |
546 | @Override
547 | public void setMinimumScale(float minimumScale) {
548 | checkZoomLevels(minimumScale, mMidScale, mMaxScale);
549 | mMinScale = minimumScale;
550 | }
551 |
552 | @Override
553 | public void setMediumScale(float mediumScale) {
554 | checkZoomLevels(mMinScale, mediumScale, mMaxScale);
555 | mMidScale = mediumScale;
556 | }
557 |
558 | @Override
559 | public void setMaximumScale(float maximumScale) {
560 | checkZoomLevels(mMinScale, mMidScale, maximumScale);
561 | mMaxScale = maximumScale;
562 | }
563 |
564 | @Override
565 | public void setScaleLevels(float minimumScale, float mediumScale, float maximumScale) {
566 | checkZoomLevels(minimumScale, mediumScale, maximumScale);
567 | mMinScale = minimumScale;
568 | mMidScale = mediumScale;
569 | mMaxScale = maximumScale;
570 | }
571 |
572 | @Override
573 | public void setOnLongClickListener(OnLongClickListener listener) {
574 | mLongClickListener = listener;
575 | }
576 |
577 | @Override
578 | public void setOnMatrixChangeListener(OnMatrixChangedListener listener) {
579 | mMatrixChangeListener = listener;
580 | }
581 |
582 | @Override
583 | public void setOnPhotoTapListener(OnPhotoTapListener listener) {
584 | mPhotoTapListener = listener;
585 | }
586 |
587 | @Nullable
588 | OnPhotoTapListener getOnPhotoTapListener() {
589 | return mPhotoTapListener;
590 | }
591 |
592 | @Override
593 | public void setOnViewTapListener(OnViewTapListener listener) {
594 | mViewTapListener = listener;
595 | }
596 |
597 | @Nullable
598 | OnViewTapListener getOnViewTapListener() {
599 | return mViewTapListener;
600 | }
601 |
602 | @Override
603 | public void setScale(float scale) {
604 | setScale(scale, false);
605 | }
606 |
607 | @Override
608 | public void setScale(float scale, boolean animate) {
609 | ImageView imageView = getImageView();
610 |
611 | if (null != imageView) {
612 | setScale(scale,
613 | (imageView.getRight()) / 2,
614 | (imageView.getBottom()) / 2,
615 | animate);
616 | }
617 | }
618 |
619 | @Override
620 | public void setScale(float scale, float focalX, float focalY,
621 | boolean animate) {
622 | ImageView imageView = getImageView();
623 |
624 | if (null != imageView) {
625 | // Check to see if the scale is within bounds
626 | if (scale < mMinScale || scale > mMaxScale) {
627 | LogManager
628 | .getLogger()
629 | .i(LOG_TAG,
630 | "Scale must be within the range of minScale and maxScale");
631 | return;
632 | }
633 |
634 | if (animate) {
635 | imageView.post(new AnimatedZoomRunnable(getScale(), scale,
636 | focalX, focalY));
637 | } else {
638 | mSuppMatrix.setScale(scale, scale, focalX, focalY);
639 | checkAndDisplayMatrix();
640 | }
641 | }
642 | }
643 |
644 | /**
645 | * Set the zoom interpolator
646 | * @param interpolator the zoom interpolator
647 | */
648 | public void setZoomInterpolator(Interpolator interpolator) {
649 | mInterpolator = interpolator;
650 | }
651 |
652 | @Override
653 | public void setScaleType(ScaleType scaleType) {
654 | if (isSupportedScaleType(scaleType) && scaleType != mScaleType) {
655 | mScaleType = scaleType;
656 |
657 | // Finally update
658 | update();
659 | }
660 | }
661 |
662 | @Override
663 | public void setZoomable(boolean zoomable) {
664 | mZoomEnabled = zoomable;
665 | update();
666 | }
667 |
668 | public void update() {
669 | ImageView imageView = getImageView();
670 |
671 | if (null != imageView) {
672 | if (mZoomEnabled) {
673 | // Make sure we using MATRIX Scale Type
674 | setImageViewScaleTypeMatrix(imageView);
675 |
676 | // Update the base matrix using the current drawable
677 | updateBaseMatrix(imageView.getDrawable());
678 | } else {
679 | // Reset the Matrix...
680 | resetMatrix();
681 | }
682 | }
683 | }
684 |
685 | /**
686 | * Get the display matrix
687 | * @param matrix target matrix to copy to
688 | */
689 | @Override
690 | public void getDisplayMatrix(Matrix matrix) {
691 | matrix.set(getDrawMatrix());
692 | }
693 |
694 | /**
695 | * Get the current support matrix
696 | */
697 | public void getSuppMatrix(Matrix matrix) {
698 | matrix.set(mSuppMatrix);
699 | }
700 |
701 | private Matrix getDrawMatrix() {
702 | mDrawMatrix.set(mBaseMatrix);
703 | mDrawMatrix.postConcat(mSuppMatrix);
704 | return mDrawMatrix;
705 | }
706 |
707 | private void cancelFling() {
708 | if (null != mCurrentFlingRunnable) {
709 | mCurrentFlingRunnable.cancelFling();
710 | mCurrentFlingRunnable = null;
711 | }
712 | }
713 |
714 | public Matrix getImageMatrix() {
715 | return mDrawMatrix;
716 | }
717 |
718 | /**
719 | * Helper method that simply checks the Matrix, and then displays the result
720 | */
721 | private void checkAndDisplayMatrix() {
722 | if (checkMatrixBounds()) {
723 | setImageViewMatrix(getDrawMatrix());
724 | }
725 | }
726 |
727 | private void checkImageViewScaleType() {
728 | ImageView imageView = getImageView();
729 |
730 | /**
731 | * PhotoView's getScaleType() will just divert to this.getScaleType() so
732 | * only call if we're not attached to a PhotoView.
733 | */
734 | if (null != imageView && !(imageView instanceof IPhotoView)) {
735 | if (!ScaleType.MATRIX.equals(imageView.getScaleType())) {
736 | throw new IllegalStateException(
737 | "The ImageView's ScaleType has been changed since attaching a PhotoViewAttacher. You should call setScaleType on the PhotoViewAttacher instead of on the ImageView" );
738 | }
739 | }
740 | }
741 |
742 | private boolean checkMatrixBounds() {
743 | final ImageView imageView = getImageView();
744 | if (null == imageView) {
745 | return false;
746 | }
747 |
748 | final RectF rect = getDisplayRect(getDrawMatrix());
749 | if (null == rect) {
750 | return false;
751 | }
752 |
753 | final float height = rect.height(), width = rect.width();
754 | float deltaX = 0, deltaY = 0;
755 |
756 | final int viewHeight = getImageViewHeight(imageView);
757 | if (height <= viewHeight) {
758 | switch (mScaleType) {
759 | case FIT_START:
760 | deltaY = -rect.top;
761 | break;
762 | case FIT_END:
763 | deltaY = viewHeight - height - rect.top;
764 | break;
765 | default:
766 | deltaY = (viewHeight - height) / 2 - rect.top;
767 | break;
768 | }
769 | } else if (rect.top > 0) {
770 | deltaY = -rect.top;
771 | } else if (rect.bottom < viewHeight) {
772 | deltaY = viewHeight - rect.bottom;
773 | }
774 |
775 | final int viewWidth = getImageViewWidth(imageView);
776 | if (width <= viewWidth) {
777 | switch (mScaleType) {
778 | case FIT_START:
779 | deltaX = -rect.left;
780 | break;
781 | case FIT_END:
782 | deltaX = viewWidth - width - rect.left;
783 | break;
784 | default:
785 | deltaX = (viewWidth - width) / 2 - rect.left;
786 | break;
787 | }
788 | mScrollEdge = EDGE_BOTH;
789 | } else if (rect.left > 0) {
790 | mScrollEdge = EDGE_LEFT;
791 | deltaX = -rect.left;
792 | } else if (rect.right < viewWidth) {
793 | deltaX = viewWidth - rect.right;
794 | mScrollEdge = EDGE_RIGHT;
795 | } else {
796 | mScrollEdge = EDGE_NONE;
797 | }
798 |
799 | // Finally actually translate the matrix
800 | mSuppMatrix.postTranslate(deltaX, deltaY);
801 | return true;
802 | }
803 |
804 | /**
805 | * Helper method that maps the supplied Matrix to the current Drawable
806 | *
807 | * @param matrix - Matrix to map Drawable against
808 | * @return RectF - Displayed Rectangle
809 | */
810 | private RectF getDisplayRect(Matrix matrix) {
811 | ImageView imageView = getImageView();
812 |
813 | if (null != imageView) {
814 | Drawable d = imageView.getDrawable();
815 | if (null != d) {
816 | mDisplayRect.set(0, 0, d.getIntrinsicWidth(),
817 | d.getIntrinsicHeight());
818 | matrix.mapRect(mDisplayRect);
819 | return mDisplayRect;
820 | }
821 | }
822 | return null;
823 | }
824 |
825 | public Bitmap getVisibleRectangleBitmap() {
826 | ImageView imageView = getImageView();
827 | return imageView == null ? null : imageView.getDrawingCache();
828 | }
829 |
830 | @Override
831 | public void setZoomTransitionDuration(int milliseconds) {
832 | if (milliseconds < 0)
833 | milliseconds = DEFAULT_ZOOM_DURATION;
834 | this.ZOOM_DURATION = milliseconds;
835 | }
836 |
837 | @Override
838 | public IPhotoView getIPhotoViewImplementation() {
839 | return this;
840 | }
841 |
842 | /**
843 | * Helper method that 'unpacks' a Matrix and returns the required value
844 | *
845 | * @param matrix - Matrix to unpack
846 | * @param whichValue - Which value from Matrix.M* to return
847 | * @return float - returned value
848 | */
849 | private float getValue(Matrix matrix, int whichValue) {
850 | matrix.getValues(mMatrixValues);
851 | return mMatrixValues[whichValue];
852 | }
853 |
854 | /**
855 | * Resets the Matrix back to FIT_CENTER, and then displays it.s
856 | */
857 | private void resetMatrix() {
858 | mSuppMatrix.reset();
859 | setRotationBy(mBaseRotation);
860 | setImageViewMatrix(getDrawMatrix());
861 | checkMatrixBounds();
862 | }
863 |
864 | private void setImageViewMatrix(Matrix matrix) {
865 | ImageView imageView = getImageView();
866 | if (null != imageView) {
867 |
868 | checkImageViewScaleType();
869 | imageView.setImageMatrix(matrix);
870 |
871 | // Call MatrixChangedListener if needed
872 | if (null != mMatrixChangeListener) {
873 | RectF displayRect = getDisplayRect(matrix);
874 | if (null != displayRect) {
875 | mMatrixChangeListener.onMatrixChanged(displayRect);
876 | }
877 | }
878 | }
879 | }
880 |
881 | /**
882 | * Calculate Matrix for FIT_CENTER
883 | *
884 | * @param d - Drawable being displayed
885 | */
886 | private void updateBaseMatrix(Drawable d) {
887 | ImageView imageView = getImageView();
888 | if (null == imageView || null == d) {
889 | return;
890 | }
891 |
892 | final float viewWidth = getImageViewWidth(imageView);
893 | final float viewHeight = getImageViewHeight(imageView);
894 | final int drawableWidth = d.getIntrinsicWidth();
895 | final int drawableHeight = d.getIntrinsicHeight();
896 |
897 | mBaseMatrix.reset();
898 |
899 | final float widthScale = viewWidth / drawableWidth;
900 | final float heightScale = viewHeight / drawableHeight;
901 |
902 | if (mScaleType == ScaleType.CENTER) {
903 | mBaseMatrix.postTranslate((viewWidth - drawableWidth) / 2F,
904 | (viewHeight - drawableHeight) / 2F);
905 |
906 | } else if (mScaleType == ScaleType.CENTER_CROP) {
907 | float scale = Math.max(widthScale, heightScale);
908 | mBaseMatrix.postScale(scale, scale);
909 | mBaseMatrix.postTranslate((viewWidth - drawableWidth * scale) / 2F,
910 | (viewHeight - drawableHeight * scale) / 2F);
911 |
912 | } else if (mScaleType == ScaleType.CENTER_INSIDE) {
913 | float scale = Math.min(1.0f, Math.min(widthScale, heightScale));
914 | mBaseMatrix.postScale(scale, scale);
915 | mBaseMatrix.postTranslate((viewWidth - drawableWidth * scale) / 2F,
916 | (viewHeight - drawableHeight * scale) / 2F);
917 |
918 | } else {
919 | RectF mTempSrc = new RectF(0, 0, drawableWidth, drawableHeight);
920 | RectF mTempDst = new RectF(0, 0, viewWidth, viewHeight);
921 |
922 | if ((int) mBaseRotation % 180 != 0) {
923 | mTempSrc = new RectF(0, 0, drawableHeight, drawableWidth);
924 | }
925 |
926 | switch (mScaleType) {
927 | case FIT_CENTER:
928 | mBaseMatrix
929 | .setRectToRect(mTempSrc, mTempDst, ScaleToFit.CENTER);
930 | break;
931 |
932 | case FIT_START:
933 | mBaseMatrix.setRectToRect(mTempSrc, mTempDst, ScaleToFit.START);
934 | break;
935 |
936 | case FIT_END:
937 | mBaseMatrix.setRectToRect(mTempSrc, mTempDst, ScaleToFit.END);
938 | break;
939 |
940 | case FIT_XY:
941 | mBaseMatrix.setRectToRect(mTempSrc, mTempDst, ScaleToFit.FILL);
942 | break;
943 |
944 | default:
945 | break;
946 | }
947 | }
948 |
949 | resetMatrix();
950 | }
951 |
952 | private int getImageViewWidth(ImageView imageView) {
953 | if (null == imageView)
954 | return 0;
955 | return imageView.getWidth() - imageView.getPaddingLeft() - imageView.getPaddingRight();
956 | }
957 |
958 | private int getImageViewHeight(ImageView imageView) {
959 | if (null == imageView)
960 | return 0;
961 | return imageView.getHeight() - imageView.getPaddingTop() - imageView.getPaddingBottom();
962 | }
963 |
964 | /**
965 | * Interface definition for a callback to be invoked when the internal Matrix has changed for
966 | * this View.
967 | *
968 | * @author Chris Banes
969 | */
970 | public interface OnMatrixChangedListener {
971 | /**
972 | * Callback for when the Matrix displaying the Drawable has changed. This could be because
973 | * the View's bounds have changed, or the user has zoomed.
974 | *
975 | * @param rect - Rectangle displaying the Drawable's new bounds.
976 | */
977 | void onMatrixChanged(RectF rect);
978 | }
979 |
980 | /**
981 | * Interface definition for callback to be invoked when attached ImageView scale changes
982 | *
983 | * @author Marek Sebera
984 | */
985 | public interface OnScaleChangeListener {
986 | /**
987 | * Callback for when the scale changes
988 | *
989 | * @param scaleFactor the scale factor (less than 1 for zoom out, greater than 1 for zoom in)
990 | * @param focusX focal point X position
991 | * @param focusY focal point Y position
992 | */
993 | void onScaleChange(float scaleFactor, float focusX, float focusY);
994 | }
995 |
996 | /**
997 | * Interface definition for a callback to be invoked when the Photo is tapped with a single
998 | * tap.
999 | *
1000 | * @author Chris Banes
1001 | */
1002 | public interface OnPhotoTapListener {
1003 |
1004 | /**
1005 | * A callback to receive where the user taps on a photo. You will only receive a callback if
1006 | * the user taps on the actual photo, tapping on 'whitespace' will be ignored.
1007 | *
1008 | * @param view - View the user tapped.
1009 | * @param x - where the user tapped from the of the Drawable, as percentage of the
1010 | * Drawable width.
1011 | * @param y - where the user tapped from the top of the Drawable, as percentage of the
1012 | * Drawable height.
1013 | */
1014 | void onPhotoTap(View view, float x, float y);
1015 |
1016 | /**
1017 | * A simple callback where out of photo happened;
1018 | * */
1019 | void onOutsidePhotoTap();
1020 | }
1021 |
1022 | /**
1023 | * Interface definition for a callback to be invoked when the ImageView is tapped with a single
1024 | * tap.
1025 | *
1026 | * @author Chris Banes
1027 | */
1028 | public interface OnViewTapListener {
1029 |
1030 | /**
1031 | * A callback to receive where the user taps on a ImageView. You will receive a callback if
1032 | * the user taps anywhere on the view, tapping on 'whitespace' will not be ignored.
1033 | *
1034 | * @param view - View the user tapped.
1035 | * @param x - where the user tapped from the left of the View.
1036 | * @param y - where the user tapped from the top of the View.
1037 | */
1038 | void onViewTap(View view, float x, float y);
1039 | }
1040 |
1041 | /**
1042 | * Interface definition for a callback to be invoked when the ImageView is fling with a single
1043 | * touch
1044 | *
1045 | * @author tonyjs
1046 | */
1047 | public interface OnSingleFlingListener {
1048 |
1049 | /**
1050 | * A callback to receive where the user flings on a ImageView. You will receive a callback if
1051 | * the user flings anywhere on the view.
1052 | *
1053 | * @param e1 - MotionEvent the user first touch.
1054 | * @param e2 - MotionEvent the user last touch.
1055 | * @param velocityX - distance of user's horizontal fling.
1056 | * @param velocityY - distance of user's vertical fling.
1057 | */
1058 | boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY);
1059 | }
1060 |
1061 | private class AnimatedZoomRunnable implements Runnable {
1062 |
1063 | private final float mFocalX, mFocalY;
1064 | private final long mStartTime;
1065 | private final float mZoomStart, mZoomEnd;
1066 |
1067 | public AnimatedZoomRunnable(final float currentZoom, final float targetZoom,
1068 | final float focalX, final float focalY) {
1069 | mFocalX = focalX;
1070 | mFocalY = focalY;
1071 | mStartTime = System.currentTimeMillis();
1072 | mZoomStart = currentZoom;
1073 | mZoomEnd = targetZoom;
1074 | }
1075 |
1076 | @Override
1077 | public void run() {
1078 | ImageView imageView = getImageView();
1079 | if (imageView == null) {
1080 | return;
1081 | }
1082 |
1083 | float t = interpolate();
1084 | float scale = mZoomStart + t * (mZoomEnd - mZoomStart);
1085 | float deltaScale = scale / getScale();
1086 |
1087 | onScale(deltaScale, mFocalX, mFocalY);
1088 |
1089 | // We haven't hit our target scale yet, so post ourselves again
1090 | if (t < 1f) {
1091 | Compat.postOnAnimation(imageView, this);
1092 | }
1093 | }
1094 |
1095 | private float interpolate() {
1096 | float t = 1f * (System.currentTimeMillis() - mStartTime) / ZOOM_DURATION;
1097 | t = Math.min(1f, t);
1098 | t = mInterpolator.getInterpolation(t);
1099 | return t;
1100 | }
1101 | }
1102 |
1103 | private class FlingRunnable implements Runnable {
1104 |
1105 | private final ScrollerProxy mScroller;
1106 | private int mCurrentX, mCurrentY;
1107 |
1108 | public FlingRunnable(Context context) {
1109 | mScroller = ScrollerProxy.getScroller(context);
1110 | }
1111 |
1112 | public void cancelFling() {
1113 | if (DEBUG) {
1114 | LogManager.getLogger().d(LOG_TAG, "Cancel Fling");
1115 | }
1116 | mScroller.forceFinished(true);
1117 | }
1118 |
1119 | public void fling(int viewWidth, int viewHeight, int velocityX,
1120 | int velocityY) {
1121 | final RectF rect = getDisplayRect();
1122 | if (null == rect) {
1123 | return;
1124 | }
1125 |
1126 | final int startX = Math.round(-rect.left);
1127 | final int minX, maxX, minY, maxY;
1128 |
1129 | if (viewWidth < rect.width()) {
1130 | minX = 0;
1131 | maxX = Math.round(rect.width() - viewWidth);
1132 | } else {
1133 | minX = maxX = startX;
1134 | }
1135 |
1136 | final int startY = Math.round(-rect.top);
1137 | if (viewHeight < rect.height()) {
1138 | minY = 0;
1139 | maxY = Math.round(rect.height() - viewHeight);
1140 | } else {
1141 | minY = maxY = startY;
1142 | }
1143 |
1144 | mCurrentX = startX;
1145 | mCurrentY = startY;
1146 |
1147 | if (DEBUG) {
1148 | LogManager.getLogger().d(
1149 | LOG_TAG,
1150 | "fling. StartX:" + startX + " StartY:" + startY
1151 | + " MaxX:" + maxX + " MaxY:" + maxY);
1152 | }
1153 |
1154 | // If we actually can move, fling the scroller
1155 | if (startX != maxX || startY != maxY) {
1156 | mScroller.fling(startX, startY, velocityX, velocityY, minX,
1157 | maxX, minY, maxY, 0, 0);
1158 | }
1159 | }
1160 |
1161 | @Override
1162 | public void run() {
1163 | if (mScroller.isFinished()) {
1164 | return; // remaining post that should not be handled
1165 | }
1166 |
1167 | ImageView imageView = getImageView();
1168 | if (null != imageView && mScroller.computeScrollOffset()) {
1169 |
1170 | final int newX = mScroller.getCurrX();
1171 | final int newY = mScroller.getCurrY();
1172 |
1173 | if (DEBUG) {
1174 | LogManager.getLogger().d(
1175 | LOG_TAG,
1176 | "fling run(). CurrentX:" + mCurrentX + " CurrentY:"
1177 | + mCurrentY + " NewX:" + newX + " NewY:"
1178 | + newY);
1179 | }
1180 |
1181 | mSuppMatrix.postTranslate(mCurrentX - newX, mCurrentY - newY);
1182 | setImageViewMatrix(getDrawMatrix());
1183 |
1184 | mCurrentX = newX;
1185 | mCurrentY = newY;
1186 |
1187 | // Post On animation
1188 | Compat.postOnAnimation(imageView, this);
1189 | }
1190 | }
1191 | }
1192 | }
1193 |
--------------------------------------------------------------------------------
/PickPhotoDialog/photoviewlibrary/src/main/java/uk/co/senab/photoview/gestures/CupcakeGestureDetector.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2011, 2012 Chris Banes.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *******************************************************************************/
16 | package uk.co.senab.photoview.gestures;
17 |
18 | import android.content.Context;
19 | import android.view.MotionEvent;
20 | import android.view.VelocityTracker;
21 | import android.view.ViewConfiguration;
22 |
23 | import uk.co.senab.photoview.log.LogManager;
24 |
25 | public class CupcakeGestureDetector implements GestureDetector {
26 |
27 | protected OnGestureListener mListener;
28 | private static final String LOG_TAG = "CupcakeGestureDetector";
29 | float mLastTouchX;
30 | float mLastTouchY;
31 | final float mTouchSlop;
32 | final float mMinimumVelocity;
33 |
34 | @Override
35 | public void setOnGestureListener(OnGestureListener listener) {
36 | this.mListener = listener;
37 | }
38 |
39 | public CupcakeGestureDetector(Context context) {
40 | final ViewConfiguration configuration = ViewConfiguration
41 | .get(context);
42 | mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
43 | mTouchSlop = configuration.getScaledTouchSlop();
44 | }
45 |
46 | private VelocityTracker mVelocityTracker;
47 | private boolean mIsDragging;
48 |
49 | float getActiveX(MotionEvent ev) {
50 | return ev.getX();
51 | }
52 |
53 | float getActiveY(MotionEvent ev) {
54 | return ev.getY();
55 | }
56 |
57 | @Override
58 | public boolean isScaling() {
59 | return false;
60 | }
61 |
62 | @Override
63 | public boolean isDragging() {
64 | return mIsDragging;
65 | }
66 |
67 | @Override
68 | public boolean onTouchEvent(MotionEvent ev) {
69 | switch (ev.getAction()) {
70 | case MotionEvent.ACTION_DOWN: {
71 | mVelocityTracker = VelocityTracker.obtain();
72 | if (null != mVelocityTracker) {
73 | mVelocityTracker.addMovement(ev);
74 | } else {
75 | LogManager.getLogger().i(LOG_TAG, "Velocity tracker is null");
76 | }
77 |
78 | mLastTouchX = getActiveX(ev);
79 | mLastTouchY = getActiveY(ev);
80 | mIsDragging = false;
81 | break;
82 | }
83 |
84 | case MotionEvent.ACTION_MOVE: {
85 | final float x = getActiveX(ev);
86 | final float y = getActiveY(ev);
87 | final float dx = x - mLastTouchX, dy = y - mLastTouchY;
88 |
89 | if (!mIsDragging) {
90 | // Use Pythagoras to see if drag length is larger than
91 | // touch slop
92 | mIsDragging = Math.sqrt((dx * dx) + (dy * dy)) >= mTouchSlop;
93 | }
94 |
95 | if (mIsDragging) {
96 | mListener.onDrag(dx, dy);
97 | mLastTouchX = x;
98 | mLastTouchY = y;
99 |
100 | if (null != mVelocityTracker) {
101 | mVelocityTracker.addMovement(ev);
102 | }
103 | }
104 | break;
105 | }
106 |
107 | case MotionEvent.ACTION_CANCEL: {
108 | // Recycle Velocity Tracker
109 | if (null != mVelocityTracker) {
110 | mVelocityTracker.recycle();
111 | mVelocityTracker = null;
112 | }
113 | break;
114 | }
115 |
116 | case MotionEvent.ACTION_UP: {
117 | if (mIsDragging) {
118 | if (null != mVelocityTracker) {
119 | mLastTouchX = getActiveX(ev);
120 | mLastTouchY = getActiveY(ev);
121 |
122 | // Compute velocity within the last 1000ms
123 | mVelocityTracker.addMovement(ev);
124 | mVelocityTracker.computeCurrentVelocity(1000);
125 |
126 | final float vX = mVelocityTracker.getXVelocity(), vY = mVelocityTracker
127 | .getYVelocity();
128 |
129 | // If the velocity is greater than minVelocity, call
130 | // listener
131 | if (Math.max(Math.abs(vX), Math.abs(vY)) >= mMinimumVelocity) {
132 | mListener.onFling(mLastTouchX, mLastTouchY, -vX,
133 | -vY);
134 | }
135 | }
136 | }
137 |
138 | // Recycle Velocity Tracker
139 | if (null != mVelocityTracker) {
140 | mVelocityTracker.recycle();
141 | mVelocityTracker = null;
142 | }
143 | break;
144 | }
145 | }
146 |
147 | return true;
148 | }
149 | }
150 |
--------------------------------------------------------------------------------
/PickPhotoDialog/photoviewlibrary/src/main/java/uk/co/senab/photoview/gestures/EclairGestureDetector.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2011, 2012 Chris Banes.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *******************************************************************************/
16 | package uk.co.senab.photoview.gestures;
17 |
18 | import android.annotation.TargetApi;
19 | import android.content.Context;
20 | import android.view.MotionEvent;
21 |
22 | import uk.co.senab.photoview.Compat;
23 |
24 | @TargetApi(5)
25 | public class EclairGestureDetector extends CupcakeGestureDetector {
26 |
27 | private static final int INVALID_POINTER_ID = -1;
28 | private int mActivePointerId = INVALID_POINTER_ID;
29 | private int mActivePointerIndex = 0;
30 |
31 | public EclairGestureDetector(Context context) {
32 | super(context);
33 | }
34 |
35 | @Override
36 | float getActiveX(MotionEvent ev) {
37 | try {
38 | return ev.getX(mActivePointerIndex);
39 | } catch (Exception e) {
40 | return ev.getX();
41 | }
42 | }
43 |
44 | @Override
45 | float getActiveY(MotionEvent ev) {
46 | try {
47 | return ev.getY(mActivePointerIndex);
48 | } catch (Exception e) {
49 | return ev.getY();
50 | }
51 | }
52 |
53 | @Override
54 | public boolean onTouchEvent(MotionEvent ev) {
55 | final int action = ev.getAction();
56 | switch (action & MotionEvent.ACTION_MASK) {
57 | case MotionEvent.ACTION_DOWN:
58 | mActivePointerId = ev.getPointerId(0);
59 | break;
60 | case MotionEvent.ACTION_CANCEL:
61 | case MotionEvent.ACTION_UP:
62 | mActivePointerId = INVALID_POINTER_ID;
63 | break;
64 | case MotionEvent.ACTION_POINTER_UP:
65 | // Ignore deprecation, ACTION_POINTER_ID_MASK and
66 | // ACTION_POINTER_ID_SHIFT has same value and are deprecated
67 | // You can have either deprecation or lint target api warning
68 | final int pointerIndex = Compat.getPointerIndex(ev.getAction());
69 | final int pointerId = ev.getPointerId(pointerIndex);
70 | if (pointerId == mActivePointerId) {
71 | // This was our active pointer going up. Choose a new
72 | // active pointer and adjust accordingly.
73 | final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
74 | mActivePointerId = ev.getPointerId(newPointerIndex);
75 | mLastTouchX = ev.getX(newPointerIndex);
76 | mLastTouchY = ev.getY(newPointerIndex);
77 | }
78 | break;
79 | }
80 |
81 | mActivePointerIndex = ev
82 | .findPointerIndex(mActivePointerId != INVALID_POINTER_ID ? mActivePointerId
83 | : 0);
84 | try {
85 | return super.onTouchEvent(ev);
86 | } catch (IllegalArgumentException e) {
87 | // Fix for support lib bug, happening when onDestroy is
88 | return true;
89 | }
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/PickPhotoDialog/photoviewlibrary/src/main/java/uk/co/senab/photoview/gestures/FroyoGestureDetector.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2011, 2012 Chris Banes.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *******************************************************************************/
16 | package uk.co.senab.photoview.gestures;
17 |
18 | import android.annotation.TargetApi;
19 | import android.content.Context;
20 | import android.view.MotionEvent;
21 | import android.view.ScaleGestureDetector;
22 |
23 | @TargetApi(8)
24 | public class FroyoGestureDetector extends EclairGestureDetector {
25 |
26 | protected final ScaleGestureDetector mDetector;
27 |
28 | public FroyoGestureDetector(Context context) {
29 | super(context);
30 | ScaleGestureDetector.OnScaleGestureListener mScaleListener = new ScaleGestureDetector.OnScaleGestureListener() {
31 |
32 | @Override
33 | public boolean onScale(ScaleGestureDetector detector) {
34 | float scaleFactor = detector.getScaleFactor();
35 |
36 | if (Float.isNaN(scaleFactor) || Float.isInfinite(scaleFactor))
37 | return false;
38 |
39 | mListener.onScale(scaleFactor,
40 | detector.getFocusX(), detector.getFocusY());
41 | return true;
42 | }
43 |
44 | @Override
45 | public boolean onScaleBegin(ScaleGestureDetector detector) {
46 | return true;
47 | }
48 |
49 | @Override
50 | public void onScaleEnd(ScaleGestureDetector detector) {
51 | // NO-OP
52 | }
53 | };
54 | mDetector = new ScaleGestureDetector(context, mScaleListener);
55 | }
56 |
57 | @Override
58 | public boolean isScaling() {
59 | return mDetector.isInProgress();
60 | }
61 |
62 | @Override
63 | public boolean onTouchEvent(MotionEvent ev) {
64 | try {
65 | mDetector.onTouchEvent(ev);
66 | return super.onTouchEvent(ev);
67 | } catch (IllegalArgumentException e) {
68 | // Fix for support lib bug, happening when onDestroy is
69 | return true;
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/PickPhotoDialog/photoviewlibrary/src/main/java/uk/co/senab/photoview/gestures/GestureDetector.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2011, 2012 Chris Banes.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *******************************************************************************/
16 | package uk.co.senab.photoview.gestures;
17 |
18 | import android.view.MotionEvent;
19 |
20 | public interface GestureDetector {
21 |
22 | boolean onTouchEvent(MotionEvent ev);
23 |
24 | boolean isScaling();
25 |
26 | boolean isDragging();
27 |
28 | void setOnGestureListener(OnGestureListener listener);
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/PickPhotoDialog/photoviewlibrary/src/main/java/uk/co/senab/photoview/gestures/OnGestureListener.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2011, 2012 Chris Banes.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *******************************************************************************/
16 | package uk.co.senab.photoview.gestures;
17 |
18 | public interface OnGestureListener {
19 |
20 | void onDrag(float dx, float dy);
21 |
22 | void onFling(float startX, float startY, float velocityX,
23 | float velocityY);
24 |
25 | void onScale(float scaleFactor, float focusX, float focusY);
26 |
27 | }
--------------------------------------------------------------------------------
/PickPhotoDialog/photoviewlibrary/src/main/java/uk/co/senab/photoview/gestures/VersionedGestureDetector.java:
--------------------------------------------------------------------------------
1 | package uk.co.senab.photoview.gestures;
2 |
3 | /*******************************************************************************
4 | * Copyright 2011, 2012 Chris Banes.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | *******************************************************************************/
18 |
19 | import android.content.Context;
20 | import android.os.Build;
21 |
22 | public final class VersionedGestureDetector {
23 |
24 | public static GestureDetector newInstance(Context context,
25 | OnGestureListener listener) {
26 | final int sdkVersion = Build.VERSION.SDK_INT;
27 | GestureDetector detector;
28 |
29 | if (sdkVersion < Build.VERSION_CODES.ECLAIR) {
30 | detector = new CupcakeGestureDetector(context);
31 | } else if (sdkVersion < Build.VERSION_CODES.FROYO) {
32 | detector = new EclairGestureDetector(context);
33 | } else {
34 | detector = new FroyoGestureDetector(context);
35 | }
36 |
37 | detector.setOnGestureListener(listener);
38 |
39 | return detector;
40 | }
41 |
42 | }
--------------------------------------------------------------------------------
/PickPhotoDialog/photoviewlibrary/src/main/java/uk/co/senab/photoview/log/LogManager.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2011, 2012 Chris Banes.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *******************************************************************************/
16 | package uk.co.senab.photoview.log;
17 |
18 | import android.util.Log;
19 |
20 | /**
21 | * class that holds the {@link Logger} for this library, defaults to {@link LoggerDefault} to send logs to android {@link Log}
22 | */
23 | public final class LogManager {
24 |
25 | private static Logger logger = new LoggerDefault();
26 |
27 | public static void setLogger(Logger newLogger) {
28 | logger = newLogger;
29 | }
30 |
31 | public static Logger getLogger() {
32 | return logger;
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/PickPhotoDialog/photoviewlibrary/src/main/java/uk/co/senab/photoview/log/Logger.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2011, 2012 Chris Banes.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *******************************************************************************/
16 | package uk.co.senab.photoview.log;
17 |
18 | /**
19 | * interface for a logger class to replace the static calls to {@link android.util.Log}
20 | */
21 | public interface Logger {
22 |
23 | int v(String tag, String msg);
24 |
25 | int v(String tag, String msg, Throwable tr);
26 |
27 | int d(String tag, String msg);
28 |
29 | int d(String tag, String msg, Throwable tr);
30 |
31 | int i(String tag, String msg);
32 |
33 | int i(String tag, String msg, Throwable tr);
34 |
35 | int w(String tag, String msg);
36 |
37 | int w(String tag, String msg, Throwable tr);
38 |
39 | int e(String tag, String msg);
40 |
41 | int e(String tag, String msg, Throwable tr);
42 | }
43 |
--------------------------------------------------------------------------------
/PickPhotoDialog/photoviewlibrary/src/main/java/uk/co/senab/photoview/log/LoggerDefault.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2011, 2012 Chris Banes.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *******************************************************************************/
16 | package uk.co.senab.photoview.log;
17 |
18 | import android.util.Log;
19 |
20 | /**
21 | * Helper class to redirect {@link LogManager#logger} to {@link Log}
22 | */
23 | public class LoggerDefault implements Logger {
24 |
25 | @Override
26 | public int v(String tag, String msg) {
27 | return Log.v(tag, msg);
28 | }
29 |
30 | @Override
31 | public int v(String tag, String msg, Throwable tr) {
32 | return Log.v(tag, msg, tr);
33 | }
34 |
35 | @Override
36 | public int d(String tag, String msg) {
37 | return Log.d(tag, msg);
38 | }
39 |
40 | @Override
41 | public int d(String tag, String msg, Throwable tr) {
42 | return Log.d(tag, msg, tr);
43 | }
44 |
45 | @Override
46 | public int i(String tag, String msg) {
47 | return Log.i(tag, msg);
48 | }
49 |
50 | @Override
51 | public int i(String tag, String msg, Throwable tr) {
52 | return Log.i(tag, msg, tr);
53 | }
54 |
55 | @Override
56 | public int w(String tag, String msg) {
57 | return Log.w(tag, msg);
58 | }
59 |
60 | @Override
61 | public int w(String tag, String msg, Throwable tr) {
62 | return Log.w(tag, msg, tr);
63 | }
64 |
65 | @Override
66 | public int e(String tag, String msg) {
67 | return Log.e(tag, msg);
68 | }
69 |
70 | @Override
71 | public int e(String tag, String msg, Throwable tr) {
72 | return Log.e(tag, msg, tr);
73 | }
74 |
75 |
76 | }
77 |
--------------------------------------------------------------------------------
/PickPhotoDialog/photoviewlibrary/src/main/java/uk/co/senab/photoview/scrollerproxy/GingerScroller.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2011, 2012 Chris Banes.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *******************************************************************************/
16 | package uk.co.senab.photoview.scrollerproxy;
17 |
18 | import android.annotation.TargetApi;
19 | import android.content.Context;
20 | import android.widget.OverScroller;
21 |
22 | @TargetApi(9)
23 | public class GingerScroller extends ScrollerProxy {
24 |
25 | protected final OverScroller mScroller;
26 |
27 | public GingerScroller(Context context) {
28 | mScroller = new OverScroller(context);
29 | }
30 |
31 | @Override
32 | public boolean computeScrollOffset() {
33 | return mScroller.computeScrollOffset();
34 | }
35 |
36 | @Override
37 | public void fling(int startX, int startY, int velocityX, int velocityY, int minX, int maxX, int minY, int maxY,
38 | int overX, int overY) {
39 | mScroller.fling(startX, startY, velocityX, velocityY, minX, maxX, minY, maxY, overX, overY);
40 | }
41 |
42 | @Override
43 | public void forceFinished(boolean finished) {
44 | mScroller.forceFinished(finished);
45 | }
46 |
47 | @Override
48 | public boolean isFinished() {
49 | return mScroller.isFinished();
50 | }
51 |
52 | @Override
53 | public int getCurrX() {
54 | return mScroller.getCurrX();
55 | }
56 |
57 | @Override
58 | public int getCurrY() {
59 | return mScroller.getCurrY();
60 | }
61 | }
--------------------------------------------------------------------------------
/PickPhotoDialog/photoviewlibrary/src/main/java/uk/co/senab/photoview/scrollerproxy/IcsScroller.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2011, 2012 Chris Banes.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *******************************************************************************/
16 | package uk.co.senab.photoview.scrollerproxy;
17 |
18 | import android.annotation.TargetApi;
19 | import android.content.Context;
20 |
21 | @TargetApi(14)
22 | public class IcsScroller extends GingerScroller {
23 |
24 | public IcsScroller(Context context) {
25 | super(context);
26 | }
27 |
28 | @Override
29 | public boolean computeScrollOffset() {
30 | return mScroller.computeScrollOffset();
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/PickPhotoDialog/photoviewlibrary/src/main/java/uk/co/senab/photoview/scrollerproxy/PreGingerScroller.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2011, 2012 Chris Banes.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *******************************************************************************/
16 | package uk.co.senab.photoview.scrollerproxy;
17 |
18 | import android.content.Context;
19 | import android.widget.Scroller;
20 |
21 | public class PreGingerScroller extends ScrollerProxy {
22 |
23 | private final Scroller mScroller;
24 |
25 | public PreGingerScroller(Context context) {
26 | mScroller = new Scroller(context);
27 | }
28 |
29 | @Override
30 | public boolean computeScrollOffset() {
31 | return mScroller.computeScrollOffset();
32 | }
33 |
34 | @Override
35 | public void fling(int startX, int startY, int velocityX, int velocityY, int minX, int maxX, int minY, int maxY,
36 | int overX, int overY) {
37 | mScroller.fling(startX, startY, velocityX, velocityY, minX, maxX, minY, maxY);
38 | }
39 |
40 | @Override
41 | public void forceFinished(boolean finished) {
42 | mScroller.forceFinished(finished);
43 | }
44 |
45 | public boolean isFinished() {
46 | return mScroller.isFinished();
47 | }
48 |
49 | @Override
50 | public int getCurrX() {
51 | return mScroller.getCurrX();
52 | }
53 |
54 | @Override
55 | public int getCurrY() {
56 | return mScroller.getCurrY();
57 | }
58 | }
--------------------------------------------------------------------------------
/PickPhotoDialog/photoviewlibrary/src/main/java/uk/co/senab/photoview/scrollerproxy/ScrollerProxy.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2011, 2012 Chris Banes.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *******************************************************************************/
16 | package uk.co.senab.photoview.scrollerproxy;
17 |
18 | import android.content.Context;
19 | import android.os.Build.VERSION;
20 | import android.os.Build.VERSION_CODES;
21 |
22 | public abstract class ScrollerProxy {
23 |
24 | public static ScrollerProxy getScroller(Context context) {
25 | if (VERSION.SDK_INT < VERSION_CODES.GINGERBREAD) {
26 | return new PreGingerScroller(context);
27 | } else if (VERSION.SDK_INT < VERSION_CODES.ICE_CREAM_SANDWICH) {
28 | return new GingerScroller(context);
29 | } else {
30 | return new IcsScroller(context);
31 | }
32 | }
33 |
34 | public abstract boolean computeScrollOffset();
35 |
36 | public abstract void fling(int startX, int startY, int velocityX, int velocityY, int minX, int maxX, int minY,
37 | int maxY, int overX, int overY);
38 |
39 | public abstract void forceFinished(boolean finished);
40 |
41 | public abstract boolean isFinished();
42 |
43 | public abstract int getCurrX();
44 |
45 | public abstract int getCurrY();
46 |
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/PickPhotoDialog/photoviewlibrary/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | PhotoViewLibrary
3 |
4 |
--------------------------------------------------------------------------------
/PickPhotoDialog/photoviewlibrary/src/test/java/uk/co/senab/photoview/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package uk.co.senab.photoview;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/PickPhotoDialog/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':photoviewlibrary'
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ywl5320/AndroidPickPhotoDialog/d66dcb9bf90c7fb38fa1f72657236b8911813daa/README.md
--------------------------------------------------------------------------------
/imgs/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ywl5320/AndroidPickPhotoDialog/d66dcb9bf90c7fb38fa1f72657236b8911813daa/imgs/1.png
--------------------------------------------------------------------------------
/imgs/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ywl5320/AndroidPickPhotoDialog/d66dcb9bf90c7fb38fa1f72657236b8911813daa/imgs/2.png
--------------------------------------------------------------------------------
/imgs/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ywl5320/AndroidPickPhotoDialog/d66dcb9bf90c7fb38fa1f72657236b8911813daa/imgs/3.png
--------------------------------------------------------------------------------
/imgs/4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ywl5320/AndroidPickPhotoDialog/d66dcb9bf90c7fb38fa1f72657236b8911813daa/imgs/4.png
--------------------------------------------------------------------------------
/imgs/pickphotodialog.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ywl5320/AndroidPickPhotoDialog/d66dcb9bf90c7fb38fa1f72657236b8911813daa/imgs/pickphotodialog.gif
--------------------------------------------------------------------------------