26 |
27 |
--------------------------------------------------------------------------------
/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 | public void onDrag(float dx, float dy);
21 |
22 | public void onFling(float startX, float startY, float velocityX,
23 | float velocityY);
24 |
25 | public void onScale(float scaleFactor, float focusX, float focusY);
26 |
27 | }
--------------------------------------------------------------------------------
/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 | public boolean onTouchEvent(MotionEvent ev);
23 |
24 | public boolean isScaling();
25 |
26 | public boolean isDragging();
27 |
28 | public void setOnGestureListener(OnGestureListener listener);
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 | }
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/trojx/mytouchgallery/PictureSlideFragment.java:
--------------------------------------------------------------------------------
1 | package com.trojx.mytouchgallery;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.Nullable;
5 | import android.support.v4.app.Fragment;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 | import android.widget.ImageView;
10 |
11 | import com.bumptech.glide.Glide;
12 | import com.bumptech.glide.load.resource.drawable.GlideDrawable;
13 | import com.bumptech.glide.request.animation.GlideAnimation;
14 | import com.bumptech.glide.request.target.GlideDrawableImageViewTarget;
15 |
16 | import uk.co.senab.photoview.PhotoViewAttacher;
17 |
18 | /**
19 | * Created by Administrator on 2016/1/3.
20 | */
21 | public class PictureSlideFragment extends Fragment {
22 | private String url;
23 | private PhotoViewAttacher mAttacher;
24 | private ImageView imageView;
25 |
26 | public static PictureSlideFragment newInstance(String url) {
27 | PictureSlideFragment f = new PictureSlideFragment();
28 |
29 | Bundle args = new Bundle();
30 | args.putString("url", url);
31 | f.setArguments(args);
32 |
33 | return f;
34 | }
35 |
36 | @Override
37 | public void onCreate(Bundle savedInstanceState) {
38 | super.onCreate(savedInstanceState);
39 | url = getArguments() != null ? getArguments().getString("url") : "http://www.zhagame.com/wp-content/uploads/2016/01/JarvanIV_6.jpg";
40 |
41 | }
42 |
43 | @Nullable
44 | @Override
45 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
46 | View v=inflater.inflate(R.layout.fragment_picture_slide,container,false);
47 |
48 | imageView= (ImageView) v.findViewById(R.id.iv_main_pic);
49 | mAttacher = new PhotoViewAttacher(imageView);
50 |
51 | Glide.with(getActivity()).load(url).crossFade().into(new GlideDrawableImageViewTarget(imageView) {
52 | @Override
53 | public void onResourceReady(GlideDrawable resource, GlideAnimation super GlideDrawable> animation) {
54 | super.onResourceReady(resource, animation);
55 | mAttacher.update();
56 | }
57 | });
58 | return v;
59 | }
60 |
61 |
62 |
63 | }
64 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
--------------------------------------------------------------------------------
/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 |
203 |
--------------------------------------------------------------------------------
/PhotoViewlibrary/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | Apache License
3 | Version 2.0, January 2004
4 | http://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | END OF TERMS AND CONDITIONS
178 |
179 | APPENDIX: How to apply the Apache License to your work.
180 |
181 | To apply the Apache License to your work, attach the following
182 | boilerplate notice, with the fields enclosed by brackets "[]"
183 | replaced with your own identifying information. (Don't include
184 | the brackets!) The text should be enclosed in the appropriate
185 | comment syntax for the file format. We also recommend that a
186 | file or class name and description of purpose be included on the
187 | same "printed page" as the copyright notice for easier
188 | identification within third-party archives.
189 |
190 | Copyright [yyyy] [name of copyright owner]
191 |
192 | Licensed under the Apache License, Version 2.0 (the "License");
193 | you may not use this file except in compliance with the License.
194 | You may obtain a copy of the License at
195 |
196 | http://www.apache.org/licenses/LICENSE-2.0
197 |
198 | Unless required by applicable law or agreed to in writing, software
199 | distributed under the License is distributed on an "AS IS" BASIS,
200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201 | See the License for the specific language governing permissions and
202 | limitations under the License.
203 |
--------------------------------------------------------------------------------
/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 | public static final float DEFAULT_MAX_SCALE = 3.0f;
29 | public static final float DEFAULT_MID_SCALE = 1.75f;
30 | public static final float DEFAULT_MIN_SCALE = 1.0f;
31 | public static final 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 | * Gets 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 | * @return - true if rectangle was applied successfully
62 | */
63 | Matrix getDisplayMatrix();
64 |
65 | /**
66 | * Use {@link #getMinimumScale()} instead, this will be removed in future release
67 | *
68 | * @return The current minimum scale level. What this value represents depends on the current
69 | * {@link android.widget.ImageView.ScaleType}.
70 | */
71 | @Deprecated
72 | float getMinScale();
73 |
74 | /**
75 | * @return The current minimum scale level. What this value represents depends on the current
76 | * {@link android.widget.ImageView.ScaleType}.
77 | */
78 | float getMinimumScale();
79 |
80 | /**
81 | * Use {@link #getMediumScale()} instead, this will be removed in future release
82 | *
83 | * @return The current middle scale level. What this value represents depends on the current
84 | * {@link android.widget.ImageView.ScaleType}.
85 | */
86 | @Deprecated
87 | float getMidScale();
88 |
89 | /**
90 | * @return The current medium scale level. What this value represents depends on the current
91 | * {@link android.widget.ImageView.ScaleType}.
92 | */
93 | float getMediumScale();
94 |
95 | /**
96 | * Use {@link #getMaximumScale()} instead, this will be removed in future release
97 | *
98 | * @return The current maximum scale level. What this value represents depends on the current
99 | * {@link android.widget.ImageView.ScaleType}.
100 | */
101 | @Deprecated
102 | float getMaxScale();
103 |
104 | /**
105 | * @return The current maximum scale level. What this value represents depends on the current
106 | * {@link android.widget.ImageView.ScaleType}.
107 | */
108 | float getMaximumScale();
109 |
110 | /**
111 | * Returns the current scale value
112 | *
113 | * @return float - current scale value
114 | */
115 | float getScale();
116 |
117 | /**
118 | * Return the current scale type in use by the ImageView.
119 | *
120 | * @return current ImageView.ScaleType
121 | */
122 | ImageView.ScaleType getScaleType();
123 |
124 | /**
125 | * Whether to allow the ImageView's parent to intercept the touch event when the photo is scroll
126 | * to it's horizontal edge.
127 | *
128 | * @param allow whether to allow intercepting by parent element or not
129 | */
130 | void setAllowParentInterceptOnEdge(boolean allow);
131 |
132 | /**
133 | * Use {@link #setMinimumScale(float minimumScale)} instead, this will be removed in future
134 | * release
135 | *
136 | * Sets the minimum scale level. What this value represents depends on the current {@link
137 | * android.widget.ImageView.ScaleType}.
138 | *
139 | * @param minScale minimum allowed scale
140 | */
141 | @Deprecated
142 | void setMinScale(float minScale);
143 |
144 | /**
145 | * Sets the minimum scale level. What this value represents depends on the current {@link
146 | * android.widget.ImageView.ScaleType}.
147 | *
148 | * @param minimumScale minimum allowed scale
149 | */
150 | void setMinimumScale(float minimumScale);
151 |
152 | /**
153 | * Use {@link #setMediumScale(float mediumScale)} instead, this will be removed in future
154 | * release
155 | *
156 | * Sets the middle scale level. What this value represents depends on the current {@link
157 | * android.widget.ImageView.ScaleType}.
158 | *
159 | * @param midScale medium scale preset
160 | */
161 | @Deprecated
162 | void setMidScale(float midScale);
163 |
164 | /*
165 | * Sets the medium scale level. What this value represents depends on the current {@link android.widget.ImageView.ScaleType}.
166 | *
167 | * @param mediumScale medium scale preset
168 | */
169 | void setMediumScale(float mediumScale);
170 |
171 | /**
172 | * Use {@link #setMaximumScale(float maximumScale)} instead, this will be removed in future
173 | * release
174 | *
175 | * Sets the maximum scale level. What this value represents depends on the current {@link
176 | * android.widget.ImageView.ScaleType}.
177 | *
178 | * @param maxScale maximum allowed scale preset
179 | */
180 | @Deprecated
181 | void setMaxScale(float maxScale);
182 |
183 | /**
184 | * Sets the maximum scale level. What this value represents depends on the current {@link
185 | * android.widget.ImageView.ScaleType}.
186 | *
187 | * @param maximumScale maximum allowed scale preset
188 | */
189 | void setMaximumScale(float maximumScale);
190 |
191 | /**
192 | * Allows to set all three scale levels at once, so you don't run into problem with setting
193 | * medium/minimum scale before the maximum one
194 | *
195 | * @param minimumScale minimum allowed scale
196 | * @param mediumScale medium allowed scale
197 | * @param maximumScale maximum allowed scale preset
198 | */
199 | void setScaleLevels(float minimumScale, float mediumScale, float maximumScale);
200 |
201 | /**
202 | * Register a callback to be invoked when the Photo displayed by this view is long-pressed.
203 | *
204 | * @param listener - Listener to be registered.
205 | */
206 | void setOnLongClickListener(View.OnLongClickListener listener);
207 |
208 | /**
209 | * Register a callback to be invoked when the Matrix has changed for this View. An example would
210 | * be the user panning or scaling the Photo.
211 | *
212 | * @param listener - Listener to be registered.
213 | */
214 | void setOnMatrixChangeListener(PhotoViewAttacher.OnMatrixChangedListener listener);
215 |
216 | /**
217 | * Register a callback to be invoked when the Photo displayed by this View is tapped with a
218 | * single tap.
219 | *
220 | * @param listener - Listener to be registered.
221 | */
222 | void setOnPhotoTapListener(PhotoViewAttacher.OnPhotoTapListener listener);
223 |
224 | /**
225 | * Returns a listener to be invoked when the Photo displayed by this View is tapped with a
226 | * single tap.
227 | *
228 | * @return PhotoViewAttacher.OnPhotoTapListener currently set, may be null
229 | */
230 | PhotoViewAttacher.OnPhotoTapListener getOnPhotoTapListener();
231 |
232 | /**
233 | * Register a callback to be invoked when the View is tapped with a single tap.
234 | *
235 | * @param listener - Listener to be registered.
236 | */
237 | void setOnViewTapListener(PhotoViewAttacher.OnViewTapListener listener);
238 |
239 | /**
240 | * Enables rotation via PhotoView internal functions.
241 | *
242 | * @param rotationDegree - Degree to rotate PhotoView to, should be in range 0 to 360
243 | */
244 | void setRotationTo(float rotationDegree);
245 |
246 | /**
247 | * Enables rotation via PhotoView internal functions.
248 | *
249 | * @param rotationDegree - Degree to rotate PhotoView by, should be in range 0 to 360
250 | */
251 | void setRotationBy(float rotationDegree);
252 |
253 | /**
254 | * Returns a callback listener to be invoked when the View is tapped with a single tap.
255 | *
256 | * @return PhotoViewAttacher.OnViewTapListener currently set, may be null
257 | */
258 | PhotoViewAttacher.OnViewTapListener getOnViewTapListener();
259 |
260 | /**
261 | * Changes the current scale to the specified value.
262 | *
263 | * @param scale - Value to scale to
264 | */
265 | void setScale(float scale);
266 |
267 | /**
268 | * Changes the current scale to the specified value.
269 | *
270 | * @param scale - Value to scale to
271 | * @param animate - Whether to animate the scale
272 | */
273 | void setScale(float scale, boolean animate);
274 |
275 | /**
276 | * Changes the current scale to the specified value, around the given focal point.
277 | *
278 | * @param scale - Value to scale to
279 | * @param focalX - X Focus Point
280 | * @param focalY - Y Focus Point
281 | * @param animate - Whether to animate the scale
282 | */
283 | void setScale(float scale, float focalX, float focalY, boolean animate);
284 |
285 | /**
286 | * Controls how the image should be resized or moved to match the size of the ImageView. Any
287 | * scaling or panning will happen within the confines of this {@link
288 | * android.widget.ImageView.ScaleType}.
289 | *
290 | * @param scaleType - The desired scaling mode.
291 | */
292 | void setScaleType(ImageView.ScaleType scaleType);
293 |
294 | /**
295 | * Allows you to enable/disable the zoom functionality on the ImageView. When disable the
296 | * ImageView reverts to using the FIT_CENTER matrix.
297 | *
298 | * @param zoomable - Whether the zoom functionality is enabled.
299 | */
300 | void setZoomable(boolean zoomable);
301 |
302 | /**
303 | * Enables rotation via PhotoView internal functions. Name is chosen so it won't collide with
304 | * View.setRotation(float) in API since 11
305 | *
306 | * @param rotationDegree - Degree to rotate PhotoView to, should be in range 0 to 360
307 | * @deprecated use {@link #setRotationTo(float)}
308 | */
309 | void setPhotoViewRotation(float rotationDegree);
310 |
311 | /**
312 | * Extracts currently visible area to Bitmap object, if there is no image loaded yet or the
313 | * ImageView is already destroyed, returns {@code null}
314 | *
315 | * @return currently visible area as bitmap or null
316 | */
317 | Bitmap getVisibleRectangleBitmap();
318 |
319 | /**
320 | * Allows to change zoom transition speed, default value is 200 (PhotoViewAttacher.DEFAULT_ZOOM_DURATION).
321 | * Will default to 200 if provided negative value
322 | *
323 | * @param milliseconds duration of zoom interpolation
324 | */
325 | void setZoomTransitionDuration(int milliseconds);
326 |
327 | /**
328 | * Will return instance of IPhotoView (eg. PhotoViewAttacher), can be used to provide better
329 | * integration
330 | *
331 | * @return IPhotoView implementation instance if available, null if not
332 | */
333 | IPhotoView getIPhotoViewImplementation();
334 |
335 | /**
336 | * Sets custom double tap listener, to intercept default given functions. To reset behavior to
337 | * default, you can just pass in "null" or public field of PhotoViewAttacher.defaultOnDoubleTapListener
338 | *
339 | * @param newOnDoubleTapListener custom OnDoubleTapListener to be set on ImageView
340 | */
341 | void setOnDoubleTapListener(GestureDetector.OnDoubleTapListener newOnDoubleTapListener);
342 |
343 | /**
344 | * Will report back about scale changes
345 | *
346 | * @param onScaleChangeListener OnScaleChangeListener instance
347 | */
348 | void setOnScaleChangeListener(PhotoViewAttacher.OnScaleChangeListener onScaleChangeListener);
349 | }
350 |
--------------------------------------------------------------------------------
/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.util.Log;
26 | import android.view.GestureDetector;
27 | import android.view.MotionEvent;
28 | import android.view.View;
29 | import android.view.View.OnLongClickListener;
30 | import android.view.ViewParent;
31 | import android.view.ViewTreeObserver;
32 | import android.view.animation.AccelerateDecelerateInterpolator;
33 | import android.view.animation.Interpolator;
34 | import android.widget.ImageView;
35 | import android.widget.ImageView.ScaleType;
36 |
37 | import java.lang.ref.WeakReference;
38 |
39 | import uk.co.senab.photoview.gestures.OnGestureListener;
40 | import uk.co.senab.photoview.gestures.VersionedGestureDetector;
41 | import uk.co.senab.photoview.log.LogManager;
42 | import uk.co.senab.photoview.scrollerproxy.ScrollerProxy;
43 |
44 | import static android.view.MotionEvent.ACTION_CANCEL;
45 | import static android.view.MotionEvent.ACTION_DOWN;
46 | import static android.view.MotionEvent.ACTION_UP;
47 |
48 | public class PhotoViewAttacher implements IPhotoView, View.OnTouchListener,
49 | OnGestureListener,
50 | ViewTreeObserver.OnGlobalLayoutListener {
51 |
52 | private static final String LOG_TAG = "PhotoViewAttacher";
53 |
54 | // let debug flag be dynamic, but still Proguard can be used to remove from
55 | // release builds
56 | private static final boolean DEBUG = Log.isLoggable(LOG_TAG, Log.DEBUG);
57 |
58 | static final Interpolator sInterpolator = new AccelerateDecelerateInterpolator();
59 | int ZOOM_DURATION = DEFAULT_ZOOM_DURATION;
60 |
61 | static final int EDGE_NONE = -1;
62 | static final int EDGE_LEFT = 0;
63 | static final int EDGE_RIGHT = 1;
64 | static final int EDGE_BOTH = 2;
65 |
66 | private float mMinScale = DEFAULT_MIN_SCALE;
67 | private float mMidScale = DEFAULT_MID_SCALE;
68 | private float mMaxScale = DEFAULT_MAX_SCALE;
69 |
70 | private boolean mAllowParentInterceptOnEdge = true;
71 | private boolean mBlockParentIntercept = false;
72 |
73 | private static void checkZoomLevels(float minZoom, float midZoom,
74 | float maxZoom) {
75 | if (minZoom >= midZoom) {
76 | throw new IllegalArgumentException(
77 | "MinZoom has to be less than MidZoom");
78 | } else if (midZoom >= maxZoom) {
79 | throw new IllegalArgumentException(
80 | "MidZoom has to be less than MaxZoom");
81 | }
82 | }
83 |
84 | /**
85 | * @return true if the ImageView exists, and it's Drawable existss
86 | */
87 | private static boolean hasDrawable(ImageView imageView) {
88 | return null != imageView && null != imageView.getDrawable();
89 | }
90 |
91 | /**
92 | * @return true if the ScaleType is supported.
93 | */
94 | private static boolean isSupportedScaleType(final ScaleType scaleType) {
95 | if (null == scaleType) {
96 | return false;
97 | }
98 |
99 | switch (scaleType) {
100 | case MATRIX:
101 | throw new IllegalArgumentException(scaleType.name()
102 | + " is not supported in PhotoView");
103 |
104 | default:
105 | return true;
106 | }
107 | }
108 |
109 | /**
110 | * Set's the ImageView's ScaleType to Matrix.
111 | */
112 | private static void setImageViewScaleTypeMatrix(ImageView imageView) {
113 | /**
114 | * PhotoView sets it's own ScaleType to Matrix, then diverts all calls
115 | * setScaleType to this.setScaleType automatically.
116 | */
117 | if (null != imageView && !(imageView instanceof IPhotoView)) {
118 | if (!ScaleType.MATRIX.equals(imageView.getScaleType())) {
119 | imageView.setScaleType(ScaleType.MATRIX);
120 | }
121 | }
122 | }
123 |
124 | private WeakReference mImageView;
125 |
126 | // Gesture Detectors
127 | private GestureDetector mGestureDetector;
128 | private uk.co.senab.photoview.gestures.GestureDetector mScaleDragDetector;
129 |
130 | // These are set so we don't keep allocating them on the heap
131 | private final Matrix mBaseMatrix = new Matrix();
132 | private final Matrix mDrawMatrix = new Matrix();
133 | private final Matrix mSuppMatrix = new Matrix();
134 | private final RectF mDisplayRect = new RectF();
135 | private final float[] mMatrixValues = new float[9];
136 |
137 | // Listeners
138 | private OnMatrixChangedListener mMatrixChangeListener;
139 | private OnPhotoTapListener mPhotoTapListener;
140 | private OnViewTapListener mViewTapListener;
141 | private OnLongClickListener mLongClickListener;
142 | private OnScaleChangeListener mScaleChangeListener;
143 |
144 | private int mIvTop, mIvRight, mIvBottom, mIvLeft;
145 | private FlingRunnable mCurrentFlingRunnable;
146 | private int mScrollEdge = EDGE_BOTH;
147 |
148 | private boolean mZoomEnabled;
149 | private ScaleType mScaleType = ScaleType.FIT_CENTER;
150 |
151 | public PhotoViewAttacher(ImageView imageView) {
152 | this(imageView, true);
153 | }
154 |
155 | public PhotoViewAttacher(ImageView imageView, boolean zoomable) {
156 | mImageView = new WeakReference<>(imageView);
157 |
158 | imageView.setDrawingCacheEnabled(true);
159 | imageView.setOnTouchListener(this);
160 |
161 | ViewTreeObserver observer = imageView.getViewTreeObserver();
162 | if (null != observer)
163 | observer.addOnGlobalLayoutListener(this);
164 |
165 | // Make sure we using MATRIX Scale Type
166 | setImageViewScaleTypeMatrix(imageView);
167 |
168 | if (imageView.isInEditMode()) {
169 | return;
170 | }
171 | // Create Gesture Detectors...
172 | mScaleDragDetector = VersionedGestureDetector.newInstance(
173 | imageView.getContext(), this);
174 |
175 | mGestureDetector = new GestureDetector(imageView.getContext(),
176 | new GestureDetector.SimpleOnGestureListener() {
177 |
178 | // forward long click listener
179 | @Override
180 | public void onLongPress(MotionEvent e) {
181 | if (null != mLongClickListener) {
182 | mLongClickListener.onLongClick(getImageView());
183 | }
184 | }
185 | });
186 |
187 | mGestureDetector.setOnDoubleTapListener(new DefaultOnDoubleTapListener(this));
188 |
189 | // Finally, update the UI so that we're zoomable
190 | setZoomable(zoomable);
191 | }
192 |
193 | @Override
194 | public void setOnDoubleTapListener(GestureDetector.OnDoubleTapListener newOnDoubleTapListener) {
195 | if (newOnDoubleTapListener != null) {
196 | this.mGestureDetector.setOnDoubleTapListener(newOnDoubleTapListener);
197 | } else {
198 | this.mGestureDetector.setOnDoubleTapListener(new DefaultOnDoubleTapListener(this));
199 | }
200 | }
201 |
202 | @Override
203 | public void setOnScaleChangeListener(OnScaleChangeListener onScaleChangeListener) {
204 | this.mScaleChangeListener = onScaleChangeListener;
205 | }
206 |
207 | @Override
208 | public boolean canZoom() {
209 | return mZoomEnabled;
210 | }
211 |
212 | /**
213 | * Clean-up the resources attached to this object. This needs to be called when the ImageView is
214 | * no longer used. A good example is from {@link android.view.View#onDetachedFromWindow()} or
215 | * from {@link android.app.Activity#onDestroy()}. This is automatically called if you are using
216 | * {@link uk.co.senab.photoview.PhotoView}.
217 | */
218 | @SuppressWarnings("deprecation")
219 | public void cleanup() {
220 | if (null == mImageView) {
221 | return; // cleanup already done
222 | }
223 |
224 | final ImageView imageView = mImageView.get();
225 |
226 | if (null != imageView) {
227 | // Remove this as a global layout listener
228 | ViewTreeObserver observer = imageView.getViewTreeObserver();
229 | if (null != observer && observer.isAlive()) {
230 | observer.removeGlobalOnLayoutListener(this);
231 | }
232 |
233 | // Remove the ImageView's reference to this
234 | imageView.setOnTouchListener(null);
235 |
236 | // make sure a pending fling runnable won't be run
237 | cancelFling();
238 | }
239 |
240 | if (null != mGestureDetector) {
241 | mGestureDetector.setOnDoubleTapListener(null);
242 | }
243 |
244 | // Clear listeners too
245 | mMatrixChangeListener = null;
246 | mPhotoTapListener = null;
247 | mViewTapListener = null;
248 |
249 | // Finally, clear ImageView
250 | mImageView = null;
251 | }
252 |
253 | @Override
254 | public RectF getDisplayRect() {
255 | checkMatrixBounds();
256 | return getDisplayRect(getDrawMatrix());
257 | }
258 |
259 | @Override
260 | public boolean setDisplayMatrix(Matrix finalMatrix) {
261 | if (finalMatrix == null)
262 | throw new IllegalArgumentException("Matrix cannot be null");
263 |
264 | ImageView imageView = getImageView();
265 | if (null == imageView)
266 | return false;
267 |
268 | if (null == imageView.getDrawable())
269 | return false;
270 |
271 | mSuppMatrix.set(finalMatrix);
272 | setImageViewMatrix(getDrawMatrix());
273 | checkMatrixBounds();
274 |
275 | return true;
276 | }
277 |
278 | /**
279 | * @deprecated use {@link #setRotationTo(float)}
280 | */
281 | @Override
282 | public void setPhotoViewRotation(float degrees) {
283 | mSuppMatrix.setRotate(degrees % 360);
284 | checkAndDisplayMatrix();
285 | }
286 |
287 | @Override
288 | public void setRotationTo(float degrees) {
289 | mSuppMatrix.setRotate(degrees % 360);
290 | checkAndDisplayMatrix();
291 | }
292 |
293 | @Override
294 | public void setRotationBy(float degrees) {
295 | mSuppMatrix.postRotate(degrees % 360);
296 | checkAndDisplayMatrix();
297 | }
298 |
299 | public ImageView getImageView() {
300 | ImageView imageView = null;
301 |
302 | if (null != mImageView) {
303 | imageView = mImageView.get();
304 | }
305 |
306 | // If we don't have an ImageView, call cleanup()
307 | if (null == imageView) {
308 | cleanup();
309 | LogManager.getLogger().i(LOG_TAG,
310 | "ImageView no longer exists. You should not use this PhotoViewAttacher any more.");
311 | }
312 |
313 | return imageView;
314 | }
315 |
316 | @Override
317 | @Deprecated
318 | public float getMinScale() {
319 | return getMinimumScale();
320 | }
321 |
322 | @Override
323 | public float getMinimumScale() {
324 | return mMinScale;
325 | }
326 |
327 | @Override
328 | @Deprecated
329 | public float getMidScale() {
330 | return getMediumScale();
331 | }
332 |
333 | @Override
334 | public float getMediumScale() {
335 | return mMidScale;
336 | }
337 |
338 | @Override
339 | @Deprecated
340 | public float getMaxScale() {
341 | return getMaximumScale();
342 | }
343 |
344 | @Override
345 | public float getMaximumScale() {
346 | return mMaxScale;
347 | }
348 |
349 | @Override
350 | public float getScale() {
351 | return (float) Math.sqrt((float) Math.pow(getValue(mSuppMatrix, Matrix.MSCALE_X), 2) + (float) Math.pow(getValue(mSuppMatrix, Matrix.MSKEW_Y), 2));
352 | }
353 |
354 | @Override
355 | public ScaleType getScaleType() {
356 | return mScaleType;
357 | }
358 |
359 | @Override
360 | public void onDrag(float dx, float dy) {
361 | if (mScaleDragDetector.isScaling()) {
362 | return; // Do not drag if we are already scaling
363 | }
364 |
365 | if (DEBUG) {
366 | LogManager.getLogger().d(LOG_TAG,
367 | String.format("onDrag: dx: %.2f. dy: %.2f", dx, dy));
368 | }
369 |
370 | ImageView imageView = getImageView();
371 | mSuppMatrix.postTranslate(dx, dy);
372 | checkAndDisplayMatrix();
373 |
374 | /**
375 | * Here we decide whether to let the ImageView's parent to start taking
376 | * over the touch event.
377 | *
378 | * First we check whether this function is enabled. We never want the
379 | * parent to take over if we're scaling. We then check the edge we're
380 | * on, and the direction of the scroll (i.e. if we're pulling against
381 | * the edge, aka 'overscrolling', let the parent take over).
382 | */
383 | ViewParent parent = imageView.getParent();
384 | if (mAllowParentInterceptOnEdge && !mScaleDragDetector.isScaling() && !mBlockParentIntercept) {
385 | if (mScrollEdge == EDGE_BOTH
386 | || (mScrollEdge == EDGE_LEFT && dx >= 1f)
387 | || (mScrollEdge == EDGE_RIGHT && dx <= -1f)) {
388 | if (null != parent)
389 | parent.requestDisallowInterceptTouchEvent(false);
390 | }
391 | } else {
392 | if (null != parent) {
393 | parent.requestDisallowInterceptTouchEvent(true);
394 | }
395 | }
396 | }
397 |
398 | @Override
399 | public void onFling(float startX, float startY, float velocityX,
400 | float velocityY) {
401 | if (DEBUG) {
402 | LogManager.getLogger().d(
403 | LOG_TAG,
404 | "onFling. sX: " + startX + " sY: " + startY + " Vx: "
405 | + velocityX + " Vy: " + velocityY);
406 | }
407 | ImageView imageView = getImageView();
408 | mCurrentFlingRunnable = new FlingRunnable(imageView.getContext());
409 | mCurrentFlingRunnable.fling(getImageViewWidth(imageView),
410 | getImageViewHeight(imageView), (int) velocityX, (int) velocityY);
411 | imageView.post(mCurrentFlingRunnable);
412 | }
413 |
414 | @Override
415 | public void onGlobalLayout() {
416 | ImageView imageView = getImageView();
417 |
418 | if (null != imageView) {
419 | if (mZoomEnabled) {
420 | final int top = imageView.getTop();
421 | final int right = imageView.getRight();
422 | final int bottom = imageView.getBottom();
423 | final int left = imageView.getLeft();
424 |
425 | /**
426 | * We need to check whether the ImageView's bounds have changed.
427 | * This would be easier if we targeted API 11+ as we could just use
428 | * View.OnLayoutChangeListener. Instead we have to replicate the
429 | * work, keeping track of the ImageView's bounds and then checking
430 | * if the values change.
431 | */
432 | if (top != mIvTop || bottom != mIvBottom || left != mIvLeft
433 | || right != mIvRight) {
434 | // Update our base matrix, as the bounds have changed
435 | updateBaseMatrix(imageView.getDrawable());
436 |
437 | // Update values as something has changed
438 | mIvTop = top;
439 | mIvRight = right;
440 | mIvBottom = bottom;
441 | mIvLeft = left;
442 | }
443 | } else {
444 | updateBaseMatrix(imageView.getDrawable());
445 | }
446 | }
447 | }
448 |
449 | @Override
450 | public void onScale(float scaleFactor, float focusX, float focusY) {
451 | if (DEBUG) {
452 | LogManager.getLogger().d(
453 | LOG_TAG,
454 | String.format("onScale: scale: %.2f. fX: %.2f. fY: %.2f",
455 | scaleFactor, focusX, focusY));
456 | }
457 |
458 | if (getScale() < mMaxScale || scaleFactor < 1f) {
459 | if (null != mScaleChangeListener) {
460 | mScaleChangeListener.onScaleChange(scaleFactor, focusX, focusY);
461 | }
462 | mSuppMatrix.postScale(scaleFactor, scaleFactor, focusX, focusY);
463 | checkAndDisplayMatrix();
464 | }
465 | }
466 |
467 | @SuppressLint("ClickableViewAccessibility")
468 | @Override
469 | public boolean onTouch(View v, MotionEvent ev) {
470 | boolean handled = false;
471 |
472 | if (mZoomEnabled && hasDrawable((ImageView) v)) {
473 | ViewParent parent = v.getParent();
474 | switch (ev.getAction()) {
475 | case ACTION_DOWN:
476 | // First, disable the Parent from intercepting the touch
477 | // event
478 | if (null != parent) {
479 | parent.requestDisallowInterceptTouchEvent(true);
480 | } else {
481 | LogManager.getLogger().i(LOG_TAG, "onTouch getParent() returned null");
482 | }
483 |
484 | // If we're flinging, and the user presses down, cancel
485 | // fling
486 | cancelFling();
487 | break;
488 |
489 | case ACTION_CANCEL:
490 | case ACTION_UP:
491 | // If the user has zoomed less than min scale, zoom back
492 | // to min scale
493 | if (getScale() < mMinScale) {
494 | RectF rect = getDisplayRect();
495 | if (null != rect) {
496 | v.post(new AnimatedZoomRunnable(getScale(), mMinScale,
497 | rect.centerX(), rect.centerY()));
498 | handled = true;
499 | }
500 | }
501 | break;
502 | }
503 |
504 | // Try the Scale/Drag detector
505 | if (null != mScaleDragDetector) {
506 | boolean wasScaling = mScaleDragDetector.isScaling();
507 | boolean wasDragging = mScaleDragDetector.isDragging();
508 |
509 | handled = mScaleDragDetector.onTouchEvent(ev);
510 |
511 | boolean didntScale = !wasScaling && !mScaleDragDetector.isScaling();
512 | boolean didntDrag = !wasDragging && !mScaleDragDetector.isDragging();
513 |
514 | mBlockParentIntercept = didntScale && didntDrag;
515 | }
516 |
517 | // Check to see if the user double tapped
518 | if (null != mGestureDetector && mGestureDetector.onTouchEvent(ev)) {
519 | handled = true;
520 | }
521 |
522 | }
523 |
524 | return handled;
525 | }
526 |
527 | @Override
528 | public void setAllowParentInterceptOnEdge(boolean allow) {
529 | mAllowParentInterceptOnEdge = allow;
530 | }
531 |
532 | @Override
533 | @Deprecated
534 | public void setMinScale(float minScale) {
535 | setMinimumScale(minScale);
536 | }
537 |
538 | @Override
539 | public void setMinimumScale(float minimumScale) {
540 | checkZoomLevels(minimumScale, mMidScale, mMaxScale);
541 | mMinScale = minimumScale;
542 | }
543 |
544 | @Override
545 | @Deprecated
546 | public void setMidScale(float midScale) {
547 | setMediumScale(midScale);
548 | }
549 |
550 | @Override
551 | public void setMediumScale(float mediumScale) {
552 | checkZoomLevels(mMinScale, mediumScale, mMaxScale);
553 | mMidScale = mediumScale;
554 | }
555 |
556 | @Override
557 | @Deprecated
558 | public void setMaxScale(float maxScale) {
559 | setMaximumScale(maxScale);
560 | }
561 |
562 | @Override
563 | public void setMaximumScale(float maximumScale) {
564 | checkZoomLevels(mMinScale, mMidScale, maximumScale);
565 | mMaxScale = maximumScale;
566 | }
567 |
568 | @Override
569 | public void setScaleLevels(float minimumScale, float mediumScale, float maximumScale) {
570 | checkZoomLevels(minimumScale, mediumScale, maximumScale);
571 | mMinScale = minimumScale;
572 | mMidScale = mediumScale;
573 | mMaxScale = maximumScale;
574 | }
575 |
576 | @Override
577 | public void setOnLongClickListener(OnLongClickListener listener) {
578 | mLongClickListener = listener;
579 | }
580 |
581 | @Override
582 | public void setOnMatrixChangeListener(OnMatrixChangedListener listener) {
583 | mMatrixChangeListener = listener;
584 | }
585 |
586 | @Override
587 | public void setOnPhotoTapListener(OnPhotoTapListener listener) {
588 | mPhotoTapListener = listener;
589 | }
590 |
591 | @Override
592 | public OnPhotoTapListener getOnPhotoTapListener() {
593 | return mPhotoTapListener;
594 | }
595 |
596 | @Override
597 | public void setOnViewTapListener(OnViewTapListener listener) {
598 | mViewTapListener = listener;
599 | }
600 |
601 | @Override
602 | public OnViewTapListener getOnViewTapListener() {
603 | return mViewTapListener;
604 | }
605 |
606 | @Override
607 | public void setScale(float scale) {
608 | setScale(scale, false);
609 | }
610 |
611 | @Override
612 | public void setScale(float scale, boolean animate) {
613 | ImageView imageView = getImageView();
614 |
615 | if (null != imageView) {
616 | setScale(scale,
617 | (imageView.getRight()) / 2,
618 | (imageView.getBottom()) / 2,
619 | animate);
620 | }
621 | }
622 |
623 | @Override
624 | public void setScale(float scale, float focalX, float focalY,
625 | boolean animate) {
626 | ImageView imageView = getImageView();
627 |
628 | if (null != imageView) {
629 | // Check to see if the scale is within bounds
630 | if (scale < mMinScale || scale > mMaxScale) {
631 | LogManager
632 | .getLogger()
633 | .i(LOG_TAG,
634 | "Scale must be within the range of minScale and maxScale");
635 | return;
636 | }
637 |
638 | if (animate) {
639 | imageView.post(new AnimatedZoomRunnable(getScale(), scale,
640 | focalX, focalY));
641 | } else {
642 | mSuppMatrix.setScale(scale, scale, focalX, focalY);
643 | checkAndDisplayMatrix();
644 | }
645 | }
646 | }
647 |
648 | @Override
649 | public void setScaleType(ScaleType scaleType) {
650 | if (isSupportedScaleType(scaleType) && scaleType != mScaleType) {
651 | mScaleType = scaleType;
652 |
653 | // Finally update
654 | update();
655 | }
656 | }
657 |
658 | @Override
659 | public void setZoomable(boolean zoomable) {
660 | mZoomEnabled = zoomable;
661 | update();
662 | }
663 |
664 | public void update() {
665 | ImageView imageView = getImageView();
666 |
667 | if (null != imageView) {
668 | if (mZoomEnabled) {
669 | // Make sure we using MATRIX Scale Type
670 | setImageViewScaleTypeMatrix(imageView);
671 |
672 | // Update the base matrix using the current drawable
673 | updateBaseMatrix(imageView.getDrawable());
674 | } else {
675 | // Reset the Matrix...
676 | resetMatrix();
677 | }
678 | }
679 | }
680 |
681 | @Override
682 | public Matrix getDisplayMatrix() {
683 | return new Matrix(getDrawMatrix());
684 | }
685 |
686 | public Matrix getDrawMatrix() {
687 | mDrawMatrix.set(mBaseMatrix);
688 | mDrawMatrix.postConcat(mSuppMatrix);
689 | return mDrawMatrix;
690 | }
691 |
692 | private void cancelFling() {
693 | if (null != mCurrentFlingRunnable) {
694 | mCurrentFlingRunnable.cancelFling();
695 | mCurrentFlingRunnable = null;
696 | }
697 | }
698 |
699 | /**
700 | * Helper method that simply checks the Matrix, and then displays the result
701 | */
702 | private void checkAndDisplayMatrix() {
703 | if (checkMatrixBounds()) {
704 | setImageViewMatrix(getDrawMatrix());
705 | }
706 | }
707 |
708 | private void checkImageViewScaleType() {
709 | ImageView imageView = getImageView();
710 |
711 | /**
712 | * PhotoView's getScaleType() will just divert to this.getScaleType() so
713 | * only call if we're not attached to a PhotoView.
714 | */
715 | if (null != imageView && !(imageView instanceof IPhotoView)) {
716 | if (!ScaleType.MATRIX.equals(imageView.getScaleType())) {
717 | throw new IllegalStateException(
718 | "The ImageView's ScaleType has been changed since attaching a PhotoViewAttacher");
719 | }
720 | }
721 | }
722 |
723 | private boolean checkMatrixBounds() {
724 | final ImageView imageView = getImageView();
725 | if (null == imageView) {
726 | return false;
727 | }
728 |
729 | final RectF rect = getDisplayRect(getDrawMatrix());
730 | if (null == rect) {
731 | return false;
732 | }
733 |
734 | final float height = rect.height(), width = rect.width();
735 | float deltaX = 0, deltaY = 0;
736 |
737 | final int viewHeight = getImageViewHeight(imageView);
738 | if (height <= viewHeight) {
739 | switch (mScaleType) {
740 | case FIT_START:
741 | deltaY = -rect.top;
742 | break;
743 | case FIT_END:
744 | deltaY = viewHeight - height - rect.top;
745 | break;
746 | default:
747 | deltaY = (viewHeight - height) / 2 - rect.top;
748 | break;
749 | }
750 | } else if (rect.top > 0) {
751 | deltaY = -rect.top;
752 | } else if (rect.bottom < viewHeight) {
753 | deltaY = viewHeight - rect.bottom;
754 | }
755 |
756 | final int viewWidth = getImageViewWidth(imageView);
757 | if (width <= viewWidth) {
758 | switch (mScaleType) {
759 | case FIT_START:
760 | deltaX = -rect.left;
761 | break;
762 | case FIT_END:
763 | deltaX = viewWidth - width - rect.left;
764 | break;
765 | default:
766 | deltaX = (viewWidth - width) / 2 - rect.left;
767 | break;
768 | }
769 | mScrollEdge = EDGE_BOTH;
770 | } else if (rect.left > 0) {
771 | mScrollEdge = EDGE_LEFT;
772 | deltaX = -rect.left;
773 | } else if (rect.right < viewWidth) {
774 | deltaX = viewWidth - rect.right;
775 | mScrollEdge = EDGE_RIGHT;
776 | } else {
777 | mScrollEdge = EDGE_NONE;
778 | }
779 |
780 | // Finally actually translate the matrix
781 | mSuppMatrix.postTranslate(deltaX, deltaY);
782 | return true;
783 | }
784 |
785 | /**
786 | * Helper method that maps the supplied Matrix to the current Drawable
787 | *
788 | * @param matrix - Matrix to map Drawable against
789 | * @return RectF - Displayed Rectangle
790 | */
791 | private RectF getDisplayRect(Matrix matrix) {
792 | ImageView imageView = getImageView();
793 |
794 | if (null != imageView) {
795 | Drawable d = imageView.getDrawable();
796 | if (null != d) {
797 | mDisplayRect.set(0, 0, d.getIntrinsicWidth(),
798 | d.getIntrinsicHeight());
799 | matrix.mapRect(mDisplayRect);
800 | return mDisplayRect;
801 | }
802 | }
803 | return null;
804 | }
805 |
806 | public Bitmap getVisibleRectangleBitmap() {
807 | ImageView imageView = getImageView();
808 | return imageView == null ? null : imageView.getDrawingCache();
809 | }
810 |
811 | @Override
812 | public void setZoomTransitionDuration(int milliseconds) {
813 | if (milliseconds < 0)
814 | milliseconds = DEFAULT_ZOOM_DURATION;
815 | this.ZOOM_DURATION = milliseconds;
816 | }
817 |
818 | @Override
819 | public IPhotoView getIPhotoViewImplementation() {
820 | return this;
821 | }
822 |
823 | /**
824 | * Helper method that 'unpacks' a Matrix and returns the required value
825 | *
826 | * @param matrix - Matrix to unpack
827 | * @param whichValue - Which value from Matrix.M* to return
828 | * @return float - returned value
829 | */
830 | private float getValue(Matrix matrix, int whichValue) {
831 | matrix.getValues(mMatrixValues);
832 | return mMatrixValues[whichValue];
833 | }
834 |
835 | /**
836 | * Resets the Matrix back to FIT_CENTER, and then displays it.s
837 | */
838 | private void resetMatrix() {
839 | mSuppMatrix.reset();
840 | setImageViewMatrix(getDrawMatrix());
841 | checkMatrixBounds();
842 | }
843 |
844 | private void setImageViewMatrix(Matrix matrix) {
845 | ImageView imageView = getImageView();
846 | if (null != imageView) {
847 |
848 | checkImageViewScaleType();
849 | imageView.setImageMatrix(matrix);
850 |
851 | // Call MatrixChangedListener if needed
852 | if (null != mMatrixChangeListener) {
853 | RectF displayRect = getDisplayRect(matrix);
854 | if (null != displayRect) {
855 | mMatrixChangeListener.onMatrixChanged(displayRect);
856 | }
857 | }
858 | }
859 | }
860 |
861 | /**
862 | * Calculate Matrix for FIT_CENTER
863 | *
864 | * @param d - Drawable being displayed
865 | */
866 | private void updateBaseMatrix(Drawable d) {
867 | ImageView imageView = getImageView();
868 | if (null == imageView || null == d) {
869 | return;
870 | }
871 |
872 | final float viewWidth = getImageViewWidth(imageView);
873 | final float viewHeight = getImageViewHeight(imageView);
874 | final int drawableWidth = d.getIntrinsicWidth();
875 | final int drawableHeight = d.getIntrinsicHeight();
876 |
877 | mBaseMatrix.reset();
878 |
879 | final float widthScale = viewWidth / drawableWidth;
880 | final float heightScale = viewHeight / drawableHeight;
881 |
882 | if (mScaleType == ScaleType.CENTER) {
883 | mBaseMatrix.postTranslate((viewWidth - drawableWidth) / 2F,
884 | (viewHeight - drawableHeight) / 2F);
885 |
886 | } else if (mScaleType == ScaleType.CENTER_CROP) {
887 | float scale = Math.max(widthScale, heightScale);
888 | mBaseMatrix.postScale(scale, scale);
889 | mBaseMatrix.postTranslate((viewWidth - drawableWidth * scale) / 2F,
890 | (viewHeight - drawableHeight * scale) / 2F);
891 |
892 | } else if (mScaleType == ScaleType.CENTER_INSIDE) {
893 | float scale = Math.min(1.0f, Math.min(widthScale, heightScale));
894 | mBaseMatrix.postScale(scale, scale);
895 | mBaseMatrix.postTranslate((viewWidth - drawableWidth * scale) / 2F,
896 | (viewHeight - drawableHeight * scale) / 2F);
897 |
898 | } else {
899 | RectF mTempSrc = new RectF(0, 0, drawableWidth, drawableHeight);
900 | RectF mTempDst = new RectF(0, 0, viewWidth, viewHeight);
901 |
902 | switch (mScaleType) {
903 | case FIT_CENTER:
904 | mBaseMatrix
905 | .setRectToRect(mTempSrc, mTempDst, ScaleToFit.CENTER);
906 | break;
907 |
908 | case FIT_START:
909 | mBaseMatrix.setRectToRect(mTempSrc, mTempDst, ScaleToFit.START);
910 | break;
911 |
912 | case FIT_END:
913 | mBaseMatrix.setRectToRect(mTempSrc, mTempDst, ScaleToFit.END);
914 | break;
915 |
916 | case FIT_XY:
917 | mBaseMatrix.setRectToRect(mTempSrc, mTempDst, ScaleToFit.FILL);
918 | break;
919 |
920 | default:
921 | break;
922 | }
923 | }
924 |
925 | resetMatrix();
926 | }
927 |
928 | private int getImageViewWidth(ImageView imageView) {
929 | if (null == imageView)
930 | return 0;
931 | return imageView.getWidth() - imageView.getPaddingLeft() - imageView.getPaddingRight();
932 | }
933 |
934 | private int getImageViewHeight(ImageView imageView) {
935 | if (null == imageView)
936 | return 0;
937 | return imageView.getHeight() - imageView.getPaddingTop() - imageView.getPaddingBottom();
938 | }
939 |
940 | /**
941 | * Interface definition for a callback to be invoked when the internal Matrix has changed for
942 | * this View.
943 | *
944 | * @author Chris Banes
945 | */
946 | public static interface OnMatrixChangedListener {
947 | /**
948 | * Callback for when the Matrix displaying the Drawable has changed. This could be because
949 | * the View's bounds have changed, or the user has zoomed.
950 | *
951 | * @param rect - Rectangle displaying the Drawable's new bounds.
952 | */
953 | void onMatrixChanged(RectF rect);
954 | }
955 |
956 | /**
957 | * Interface definition for callback to be invoked when attached ImageView scale changes
958 | *
959 | * @author Marek Sebera
960 | */
961 | public static interface OnScaleChangeListener {
962 | /**
963 | * Callback for when the scale changes
964 | *
965 | * @param scaleFactor the scale factor (less than 1 for zoom out, greater than 1 for zoom in)
966 | * @param focusX focal point X position
967 | * @param focusY focal point Y position
968 | */
969 | void onScaleChange(float scaleFactor, float focusX, float focusY);
970 | }
971 |
972 | /**
973 | * Interface definition for a callback to be invoked when the Photo is tapped with a single
974 | * tap.
975 | *
976 | * @author Chris Banes
977 | */
978 | public static interface OnPhotoTapListener {
979 |
980 | /**
981 | * A callback to receive where the user taps on a photo. You will only receive a callback if
982 | * the user taps on the actual photo, tapping on 'whitespace' will be ignored.
983 | *
984 | * @param view - View the user tapped.
985 | * @param x - where the user tapped from the of the Drawable, as percentage of the
986 | * Drawable width.
987 | * @param y - where the user tapped from the top of the Drawable, as percentage of the
988 | * Drawable height.
989 | */
990 | void onPhotoTap(View view, float x, float y);
991 | }
992 |
993 | /**
994 | * Interface definition for a callback to be invoked when the ImageView is tapped with a single
995 | * tap.
996 | *
997 | * @author Chris Banes
998 | */
999 | public static interface OnViewTapListener {
1000 |
1001 | /**
1002 | * A callback to receive where the user taps on a ImageView. You will receive a callback if
1003 | * the user taps anywhere on the view, tapping on 'whitespace' will not be ignored.
1004 | *
1005 | * @param view - View the user tapped.
1006 | * @param x - where the user tapped from the left of the View.
1007 | * @param y - where the user tapped from the top of the View.
1008 | */
1009 | void onViewTap(View view, float x, float y);
1010 | }
1011 |
1012 | private class AnimatedZoomRunnable implements Runnable {
1013 |
1014 | private final float mFocalX, mFocalY;
1015 | private final long mStartTime;
1016 | private final float mZoomStart, mZoomEnd;
1017 |
1018 | public AnimatedZoomRunnable(final float currentZoom, final float targetZoom,
1019 | final float focalX, final float focalY) {
1020 | mFocalX = focalX;
1021 | mFocalY = focalY;
1022 | mStartTime = System.currentTimeMillis();
1023 | mZoomStart = currentZoom;
1024 | mZoomEnd = targetZoom;
1025 | }
1026 |
1027 | @Override
1028 | public void run() {
1029 | ImageView imageView = getImageView();
1030 | if (imageView == null) {
1031 | return;
1032 | }
1033 |
1034 | float t = interpolate();
1035 | float scale = mZoomStart + t * (mZoomEnd - mZoomStart);
1036 | float deltaScale = scale / getScale();
1037 |
1038 | onScale(deltaScale, mFocalX, mFocalY);
1039 |
1040 | // We haven't hit our target scale yet, so post ourselves again
1041 | if (t < 1f) {
1042 | Compat.postOnAnimation(imageView, this);
1043 | }
1044 | }
1045 |
1046 | private float interpolate() {
1047 | float t = 1f * (System.currentTimeMillis() - mStartTime) / ZOOM_DURATION;
1048 | t = Math.min(1f, t);
1049 | t = sInterpolator.getInterpolation(t);
1050 | return t;
1051 | }
1052 | }
1053 |
1054 | private class FlingRunnable implements Runnable {
1055 |
1056 | private final ScrollerProxy mScroller;
1057 | private int mCurrentX, mCurrentY;
1058 |
1059 | public FlingRunnable(Context context) {
1060 | mScroller = ScrollerProxy.getScroller(context);
1061 | }
1062 |
1063 | public void cancelFling() {
1064 | if (DEBUG) {
1065 | LogManager.getLogger().d(LOG_TAG, "Cancel Fling");
1066 | }
1067 | mScroller.forceFinished(true);
1068 | }
1069 |
1070 | public void fling(int viewWidth, int viewHeight, int velocityX,
1071 | int velocityY) {
1072 | final RectF rect = getDisplayRect();
1073 | if (null == rect) {
1074 | return;
1075 | }
1076 |
1077 | final int startX = Math.round(-rect.left);
1078 | final int minX, maxX, minY, maxY;
1079 |
1080 | if (viewWidth < rect.width()) {
1081 | minX = 0;
1082 | maxX = Math.round(rect.width() - viewWidth);
1083 | } else {
1084 | minX = maxX = startX;
1085 | }
1086 |
1087 | final int startY = Math.round(-rect.top);
1088 | if (viewHeight < rect.height()) {
1089 | minY = 0;
1090 | maxY = Math.round(rect.height() - viewHeight);
1091 | } else {
1092 | minY = maxY = startY;
1093 | }
1094 |
1095 | mCurrentX = startX;
1096 | mCurrentY = startY;
1097 |
1098 | if (DEBUG) {
1099 | LogManager.getLogger().d(
1100 | LOG_TAG,
1101 | "fling. StartX:" + startX + " StartY:" + startY
1102 | + " MaxX:" + maxX + " MaxY:" + maxY);
1103 | }
1104 |
1105 | // If we actually can move, fling the scroller
1106 | if (startX != maxX || startY != maxY) {
1107 | mScroller.fling(startX, startY, velocityX, velocityY, minX,
1108 | maxX, minY, maxY, 0, 0);
1109 | }
1110 | }
1111 |
1112 | @Override
1113 | public void run() {
1114 | if (mScroller.isFinished()) {
1115 | return; // remaining post that should not be handled
1116 | }
1117 |
1118 | ImageView imageView = getImageView();
1119 | if (null != imageView && mScroller.computeScrollOffset()) {
1120 |
1121 | final int newX = mScroller.getCurrX();
1122 | final int newY = mScroller.getCurrY();
1123 |
1124 | if (DEBUG) {
1125 | LogManager.getLogger().d(
1126 | LOG_TAG,
1127 | "fling run(). CurrentX:" + mCurrentX + " CurrentY:"
1128 | + mCurrentY + " NewX:" + newX + " NewY:"
1129 | + newY);
1130 | }
1131 |
1132 | mSuppMatrix.postTranslate(mCurrentX - newX, mCurrentY - newY);
1133 | setImageViewMatrix(getDrawMatrix());
1134 |
1135 | mCurrentX = newX;
1136 | mCurrentY = newY;
1137 |
1138 | // Post On animation
1139 | Compat.postOnAnimation(imageView, this);
1140 | }
1141 | }
1142 | }
1143 | }
1144 |
--------------------------------------------------------------------------------