parent
92f605bca9
commit
881ece18b2
@ -0,0 +1,60 @@ |
||||
/******************************************************************************* |
||||
* Copyright 2011, 2012 Chris Banes. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*******************************************************************************/ |
||||
package uk.co.senab.photoview; |
||||
|
||||
import android.annotation.TargetApi; |
||||
import android.os.Build; |
||||
import android.os.Build.VERSION; |
||||
import android.os.Build.VERSION_CODES; |
||||
import android.view.MotionEvent; |
||||
import android.view.View; |
||||
|
||||
public class Compat { |
||||
|
||||
private static final int SIXTY_FPS_INTERVAL = 1000 / 60; |
||||
|
||||
public static void postOnAnimation(View view, Runnable runnable) { |
||||
if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) { |
||||
postOnAnimationJellyBean(view, runnable); |
||||
} else { |
||||
view.postDelayed(runnable, SIXTY_FPS_INTERVAL); |
||||
} |
||||
} |
||||
|
||||
@TargetApi(16) |
||||
private static void postOnAnimationJellyBean(View view, Runnable runnable) { |
||||
view.postOnAnimation(runnable); |
||||
} |
||||
|
||||
public static int getPointerIndex(int action) { |
||||
if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB) |
||||
return getPointerIndexHoneyComb(action); |
||||
else |
||||
return getPointerIndexEclair(action); |
||||
} |
||||
|
||||
@SuppressWarnings("deprecation") |
||||
@TargetApi(Build.VERSION_CODES.ECLAIR) |
||||
private static int getPointerIndexEclair(int action) { |
||||
return (action & MotionEvent.ACTION_POINTER_ID_MASK) >> MotionEvent.ACTION_POINTER_ID_SHIFT; |
||||
} |
||||
|
||||
@TargetApi(Build.VERSION_CODES.HONEYCOMB) |
||||
private static int getPointerIndexHoneyComb(int action) { |
||||
return (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,100 @@ |
||||
package uk.co.senab.photoview; |
||||
|
||||
import android.graphics.RectF; |
||||
import android.view.GestureDetector; |
||||
import android.view.MotionEvent; |
||||
import android.widget.ImageView; |
||||
|
||||
/** |
||||
* Provided default implementation of GestureDetector.OnDoubleTapListener, to be overridden with custom behavior, if needed |
||||
* <p> </p> |
||||
* To be used via {@link uk.co.senab.photoview.PhotoViewAttacher#setOnDoubleTapListener(android.view.GestureDetector.OnDoubleTapListener)} |
||||
*/ |
||||
public class DefaultOnDoubleTapListener implements GestureDetector.OnDoubleTapListener { |
||||
|
||||
private PhotoViewAttacher photoViewAttacher; |
||||
|
||||
/** |
||||
* Default constructor |
||||
* |
||||
* @param photoViewAttacher PhotoViewAttacher to bind to |
||||
*/ |
||||
public DefaultOnDoubleTapListener(PhotoViewAttacher photoViewAttacher) { |
||||
setPhotoViewAttacher(photoViewAttacher); |
||||
} |
||||
|
||||
/** |
||||
* Allows to change PhotoViewAttacher within range of single instance |
||||
* |
||||
* @param newPhotoViewAttacher PhotoViewAttacher to bind to |
||||
*/ |
||||
public void setPhotoViewAttacher(PhotoViewAttacher newPhotoViewAttacher) { |
||||
this.photoViewAttacher = newPhotoViewAttacher; |
||||
} |
||||
|
||||
@Override |
||||
public boolean onSingleTapConfirmed(MotionEvent e) { |
||||
if (this.photoViewAttacher == null) |
||||
return false; |
||||
|
||||
ImageView imageView = photoViewAttacher.getImageView(); |
||||
|
||||
if (null != photoViewAttacher.getOnPhotoTapListener()) { |
||||
final RectF displayRect = photoViewAttacher.getDisplayRect(); |
||||
|
||||
if (null != displayRect) { |
||||
final float x = e.getX(), y = e.getY(); |
||||
|
||||
// Check to see if the user tapped on the photo
|
||||
if (displayRect.contains(x, y)) { |
||||
|
||||
float xResult = (x - displayRect.left) |
||||
/ displayRect.width(); |
||||
float yResult = (y - displayRect.top) |
||||
/ displayRect.height(); |
||||
|
||||
photoViewAttacher.getOnPhotoTapListener().onPhotoTap(imageView, xResult, yResult); |
||||
return true; |
||||
}else{ |
||||
photoViewAttacher.getOnPhotoTapListener().onOutsidePhotoTap(); |
||||
} |
||||
} |
||||
} |
||||
if (null != photoViewAttacher.getOnViewTapListener()) { |
||||
photoViewAttacher.getOnViewTapListener().onViewTap(imageView, e.getX(), e.getY()); |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
@Override |
||||
public boolean onDoubleTap(MotionEvent ev) { |
||||
if (photoViewAttacher == null) |
||||
return false; |
||||
|
||||
try { |
||||
float scale = photoViewAttacher.getScale(); |
||||
float x = ev.getX(); |
||||
float y = ev.getY(); |
||||
|
||||
if (scale < photoViewAttacher.getMediumScale()) { |
||||
photoViewAttacher.setScale(photoViewAttacher.getMediumScale(), x, y, true); |
||||
} else if (scale >= photoViewAttacher.getMediumScale() && scale < photoViewAttacher.getMaximumScale()) { |
||||
photoViewAttacher.setScale(photoViewAttacher.getMaximumScale(), x, y, true); |
||||
} else { |
||||
photoViewAttacher.setScale(photoViewAttacher.getMinimumScale(), x, y, true); |
||||
} |
||||
} catch (ArrayIndexOutOfBoundsException e) { |
||||
// Can sometimes happen when getX() and getY() is called
|
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
@Override |
||||
public boolean onDoubleTapEvent(MotionEvent e) { |
||||
// Wait for the confirmed onDoubleTap() instead
|
||||
return false; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,285 @@ |
||||
/** |
||||
* **************************************************************************** |
||||
* Copyright 2011, 2012 Chris Banes. |
||||
* <p> |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* <p> |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p> |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* ***************************************************************************** |
||||
*/ |
||||
package uk.co.senab.photoview; |
||||
|
||||
import android.graphics.Bitmap; |
||||
import android.graphics.Matrix; |
||||
import android.graphics.RectF; |
||||
import android.view.GestureDetector; |
||||
import android.view.View; |
||||
import android.widget.ImageView; |
||||
|
||||
|
||||
public interface IPhotoView { |
||||
|
||||
float DEFAULT_MAX_SCALE = 3.0f; |
||||
float DEFAULT_MID_SCALE = 1.75f; |
||||
float DEFAULT_MIN_SCALE = 1.0f; |
||||
int DEFAULT_ZOOM_DURATION = 200; |
||||
|
||||
/** |
||||
* Returns true if the PhotoView is set to allow zooming of Photos. |
||||
* |
||||
* @return true if the PhotoView allows zooming. |
||||
*/ |
||||
boolean canZoom(); |
||||
|
||||
/** |
||||
* Gets the Display Rectangle of the currently displayed Drawable. The Rectangle is relative to |
||||
* this View and includes all scaling and translations. |
||||
* |
||||
* @return - RectF of Displayed Drawable |
||||
*/ |
||||
RectF getDisplayRect(); |
||||
|
||||
/** |
||||
* Sets the Display Matrix of the currently displayed Drawable. The Rectangle is considered |
||||
* relative to this View and includes all scaling and translations. |
||||
* |
||||
* @param finalMatrix target matrix to set PhotoView to |
||||
* @return - true if rectangle was applied successfully |
||||
*/ |
||||
boolean setDisplayMatrix(Matrix finalMatrix); |
||||
|
||||
/** |
||||
* Copies the Display Matrix of the currently displayed Drawable. The Rectangle is considered |
||||
* relative to this View and includes all scaling and translations. |
||||
* |
||||
* @param matrix target matrix to copy to |
||||
*/ |
||||
void getDisplayMatrix(Matrix matrix); |
||||
|
||||
/** |
||||
* @return The current minimum scale level. What this value represents depends on the current |
||||
* {@link android.widget.ImageView.ScaleType}. |
||||
*/ |
||||
float getMinimumScale(); |
||||
|
||||
/** |
||||
* @return The current medium scale level. What this value represents depends on the current |
||||
* {@link android.widget.ImageView.ScaleType}. |
||||
*/ |
||||
float getMediumScale(); |
||||
|
||||
/** |
||||
* @return The current maximum scale level. What this value represents depends on the current |
||||
* {@link android.widget.ImageView.ScaleType}. |
||||
*/ |
||||
float getMaximumScale(); |
||||
|
||||
/** |
||||
* Returns the current scale value |
||||
* |
||||
* @return float - current scale value |
||||
*/ |
||||
float getScale(); |
||||
|
||||
/** |
||||
* Return the current scale type in use by the ImageView. |
||||
* |
||||
* @return current ImageView.ScaleType |
||||
*/ |
||||
ImageView.ScaleType getScaleType(); |
||||
|
||||
/** |
||||
* Whether to allow the ImageView's parent to intercept the touch event when the photo is scroll |
||||
* to it's horizontal edge. |
||||
* |
||||
* @param allow whether to allow intercepting by parent element or not |
||||
*/ |
||||
void setAllowParentInterceptOnEdge(boolean allow); |
||||
|
||||
/** |
||||
* Sets the minimum scale level. What this value represents depends on the current {@link |
||||
* android.widget.ImageView.ScaleType}. |
||||
* |
||||
* @param minimumScale minimum allowed scale |
||||
*/ |
||||
void setMinimumScale(float minimumScale); |
||||
|
||||
/** |
||||
* Sets the medium scale level. What this value represents depends on the current {@link android.widget.ImageView.ScaleType}. |
||||
* |
||||
* @param mediumScale medium scale preset |
||||
*/ |
||||
void setMediumScale(float mediumScale); |
||||
|
||||
/** |
||||
* Sets the maximum scale level. What this value represents depends on the current {@link |
||||
* android.widget.ImageView.ScaleType}. |
||||
* |
||||
* @param maximumScale maximum allowed scale preset |
||||
*/ |
||||
void setMaximumScale(float maximumScale); |
||||
|
||||
/** |
||||
* Allows to set all three scale levels at once, so you don't run into problem with setting |
||||
* medium/minimum scale before the maximum one |
||||
* |
||||
* @param minimumScale minimum allowed scale |
||||
* @param mediumScale medium allowed scale |
||||
* @param maximumScale maximum allowed scale preset |
||||
*/ |
||||
void setScaleLevels(float minimumScale, float mediumScale, float maximumScale); |
||||
|
||||
/** |
||||
* Register a callback to be invoked when the Photo displayed by this view is long-pressed. |
||||
* |
||||
* @param listener - Listener to be registered. |
||||
*/ |
||||
void setOnLongClickListener(View.OnLongClickListener listener); |
||||
|
||||
/** |
||||
* Register a callback to be invoked when the Matrix has changed for this View. An example would |
||||
* be the user panning or scaling the Photo. |
||||
* |
||||
* @param listener - Listener to be registered. |
||||
*/ |
||||
void setOnMatrixChangeListener(PhotoViewAttacher.OnMatrixChangedListener listener); |
||||
|
||||
/** |
||||
* Register a callback to be invoked when the Photo displayed by this View is tapped with a |
||||
* single tap. |
||||
* |
||||
* @param listener - Listener to be registered. |
||||
*/ |
||||
void setOnPhotoTapListener(PhotoViewAttacher.OnPhotoTapListener listener); |
||||
|
||||
/** |
||||
* Register a callback to be invoked when the View is tapped with a single tap. |
||||
* |
||||
* @param onRotateListener |
||||
*/ |
||||
void setOnRotateListener(PhotoViewAttacher.OnRotateListener onRotateListener); |
||||
|
||||
/** |
||||
* Enables rotation via PhotoView internal functions. |
||||
* |
||||
* @param rotationDegree - Degree to rotate PhotoView to, should be in range 0 to 360 |
||||
*/ |
||||
void setRotationTo(float rotationDegree); |
||||
|
||||
/** |
||||
* Enables rotation via PhotoView internal functions. |
||||
* |
||||
* @param rotationDegree - Degree to rotate PhotoView by, should be in range 0 to 360 |
||||
*/ |
||||
void setRotationBy(float rotationDegree); |
||||
|
||||
/** |
||||
* Changes the current scale to the specified value. |
||||
* |
||||
* @param scale - Value to scale to |
||||
*/ |
||||
void setScale(float scale); |
||||
|
||||
/** |
||||
* Returns a callback listener to be invoked when the View is tapped with a single tap. |
||||
* |
||||
* @return PhotoViewAttacher.OnViewTapListener currently set, may be null |
||||
*/ |
||||
PhotoViewAttacher.OnViewTapListener getOnViewTapListener(); |
||||
|
||||
/** |
||||
* Register a callback to be invoked when the View is tapped with a single tap. |
||||
* |
||||
* @param listener - Listener to be registered. |
||||
*/ |
||||
void setOnViewTapListener(PhotoViewAttacher.OnViewTapListener listener); |
||||
|
||||
/** |
||||
* Changes the current scale to the specified value. |
||||
* |
||||
* @param scale - Value to scale to |
||||
* @param animate - Whether to animate the scale |
||||
*/ |
||||
void setScale(float scale, boolean animate); |
||||
|
||||
/** |
||||
* Changes the current scale to the specified value, around the given focal point. |
||||
* |
||||
* @param scale - Value to scale to |
||||
* @param focalX - X Focus Point |
||||
* @param focalY - Y Focus Point |
||||
* @param animate - Whether to animate the scale |
||||
*/ |
||||
void setScale(float scale, float focalX, float focalY, boolean animate); |
||||
|
||||
/** |
||||
* Controls how the image should be resized or moved to match the size of the ImageView. Any |
||||
* scaling or panning will happen within the confines of this {@link |
||||
* android.widget.ImageView.ScaleType}. |
||||
* |
||||
* @param scaleType - The desired scaling mode. |
||||
*/ |
||||
void setScaleType(ImageView.ScaleType scaleType); |
||||
|
||||
/** |
||||
* Allows you to enable/disable the zoom functionality on the ImageView. When disable the |
||||
* ImageView reverts to using the FIT_CENTER matrix. |
||||
* |
||||
* @param zoomable - Whether the zoom functionality is enabled. |
||||
*/ |
||||
void setZoomable(boolean zoomable); |
||||
|
||||
/** |
||||
* Extracts currently visible area to Bitmap object, if there is no image loaded yet or the |
||||
* ImageView is already destroyed, returns {@code null} |
||||
* |
||||
* @return currently visible area as bitmap or null |
||||
*/ |
||||
Bitmap getVisibleRectangleBitmap(); |
||||
|
||||
/** |
||||
* Allows to change zoom transition speed, default value is 200 (PhotoViewAttacher.DEFAULT_ZOOM_DURATION). |
||||
* Will default to 200 if provided negative value |
||||
* |
||||
* @param milliseconds duration of zoom interpolation |
||||
*/ |
||||
void setZoomTransitionDuration(int milliseconds); |
||||
|
||||
/** |
||||
* Will return instance of IPhotoView (eg. PhotoViewAttacher), can be used to provide better |
||||
* integration |
||||
* |
||||
* @return IPhotoView implementation instance if available, null if not |
||||
*/ |
||||
IPhotoView getIPhotoViewImplementation(); |
||||
|
||||
/** |
||||
* Sets custom double tap listener, to intercept default given functions. To reset behavior to |
||||
* default, you can just pass in "null" or public field of PhotoViewAttacher.defaultOnDoubleTapListener |
||||
* |
||||
* @param newOnDoubleTapListener custom OnDoubleTapListener to be set on ImageView |
||||
*/ |
||||
void setOnDoubleTapListener(GestureDetector.OnDoubleTapListener newOnDoubleTapListener); |
||||
|
||||
/** |
||||
* Will report back about scale changes |
||||
* |
||||
* @param onScaleChangeListener OnScaleChangeListener instance |
||||
*/ |
||||
void setOnScaleChangeListener(PhotoViewAttacher.OnScaleChangeListener onScaleChangeListener); |
||||
|
||||
/** |
||||
* Will report back about fling(single touch) |
||||
* |
||||
* @param onSingleFlingListener OnSingleFlingListener instance |
||||
*/ |
||||
void setOnSingleFlingListener(PhotoViewAttacher.OnSingleFlingListener onSingleFlingListener); |
||||
} |
@ -0,0 +1,284 @@ |
||||
/******************************************************************************* |
||||
* Copyright 2011, 2012 Chris Banes. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*******************************************************************************/ |
||||
package uk.co.senab.photoview; |
||||
|
||||
import android.content.Context; |
||||
import android.graphics.Bitmap; |
||||
import android.graphics.Matrix; |
||||
import android.graphics.RectF; |
||||
import android.graphics.drawable.Drawable; |
||||
import android.net.Uri; |
||||
import android.util.AttributeSet; |
||||
import android.view.GestureDetector; |
||||
|
||||
import androidx.appcompat.widget.AppCompatImageView; |
||||
import uk.co.senab.photoview.PhotoViewAttacher.OnMatrixChangedListener; |
||||
import uk.co.senab.photoview.PhotoViewAttacher.OnPhotoTapListener; |
||||
import uk.co.senab.photoview.PhotoViewAttacher.OnViewTapListener; |
||||
|
||||
public class PhotoView extends AppCompatImageView implements IPhotoView { |
||||
|
||||
private PhotoViewAttacher mAttacher; |
||||
|
||||
private ScaleType mPendingScaleType; |
||||
|
||||
public PhotoView(Context context) { |
||||
this(context, null); |
||||
} |
||||
|
||||
public PhotoView(Context context, AttributeSet attr) { |
||||
this(context, attr, 0); |
||||
} |
||||
|
||||
public PhotoView(Context context, AttributeSet attr, int defStyle) { |
||||
super(context, attr, defStyle); |
||||
super.setScaleType(ScaleType.MATRIX); |
||||
init(); |
||||
} |
||||
|
||||
protected void init() { |
||||
if (null == mAttacher || null == mAttacher.getImageView()) { |
||||
mAttacher = new PhotoViewAttacher(this); |
||||
} |
||||
|
||||
if (null != mPendingScaleType) { |
||||
setScaleType(mPendingScaleType); |
||||
mPendingScaleType = null; |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void setRotationTo(float rotationDegree) { |
||||
mAttacher.setRotationTo(rotationDegree); |
||||
} |
||||
|
||||
@Override |
||||
public void setRotationBy(float rotationDegree) { |
||||
mAttacher.setRotationBy(rotationDegree); |
||||
} |
||||
|
||||
@Override |
||||
public boolean canZoom() { |
||||
return mAttacher.canZoom(); |
||||
} |
||||
|
||||
@Override |
||||
public RectF getDisplayRect() { |
||||
return mAttacher.getDisplayRect(); |
||||
} |
||||
|
||||
@Override |
||||
public void getDisplayMatrix(Matrix matrix) { |
||||
mAttacher.getDisplayMatrix(matrix); |
||||
} |
||||
|
||||
@Override |
||||
public boolean setDisplayMatrix(Matrix finalRectangle) { |
||||
return mAttacher.setDisplayMatrix(finalRectangle); |
||||
} |
||||
|
||||
@Override |
||||
public float getMinimumScale() { |
||||
return mAttacher.getMinimumScale(); |
||||
} |
||||
|
||||
@Override |
||||
public float getMediumScale() { |
||||
return mAttacher.getMediumScale(); |
||||
} |
||||
|
||||
@Override |
||||
public float getMaximumScale() { |
||||
return mAttacher.getMaximumScale(); |
||||
} |
||||
|
||||
@Override |
||||
public float getScale() { |
||||
return mAttacher.getScale(); |
||||
} |
||||
|
||||
@Override |
||||
public ScaleType getScaleType() { |
||||
return mAttacher.getScaleType(); |
||||
} |
||||
|
||||
@Override |
||||
public Matrix getImageMatrix() { |
||||
return mAttacher.getImageMatrix(); |
||||
} |
||||
|
||||
@Override |
||||
public void setAllowParentInterceptOnEdge(boolean allow) { |
||||
mAttacher.setAllowParentInterceptOnEdge(allow); |
||||
} |
||||
|
||||
@Override |
||||
public void setMinimumScale(float minimumScale) { |
||||
mAttacher.setMinimumScale(minimumScale); |
||||
} |
||||
|
||||
@Override |
||||
public void setMediumScale(float mediumScale) { |
||||
mAttacher.setMediumScale(mediumScale); |
||||
} |
||||
|
||||
@Override |
||||
public void setMaximumScale(float maximumScale) { |
||||
mAttacher.setMaximumScale(maximumScale); |
||||
} |
||||
|
||||
@Override |
||||
public void setScaleLevels(float minimumScale, float mediumScale, float maximumScale) { |
||||
mAttacher.setScaleLevels(minimumScale, mediumScale, maximumScale); |
||||
} |
||||
|
||||
@Override |
||||
// setImageBitmap calls through to this method
|
||||
public void setImageDrawable(Drawable drawable) { |
||||
super.setImageDrawable(drawable); |
||||
if (null != mAttacher) { |
||||
mAttacher.update(); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void setImageResource(int resId) { |
||||
super.setImageResource(resId); |
||||
if (null != mAttacher) { |
||||
mAttacher.update(); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void setImageURI(Uri uri) { |
||||
super.setImageURI(uri); |
||||
if (null != mAttacher) { |
||||
mAttacher.update(); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
protected boolean setFrame(int l, int t, int r, int b) { |
||||
boolean changed = super.setFrame(l, t, r, b); |
||||
if (null != mAttacher) { |
||||
mAttacher.update(); |
||||
} |
||||
return changed; |
||||
} |
||||
|
||||
@Override |
||||
public void setOnMatrixChangeListener(OnMatrixChangedListener listener) { |
||||
mAttacher.setOnMatrixChangeListener(listener); |
||||
} |
||||
|
||||
@Override |
||||
public void setOnLongClickListener(OnLongClickListener l) { |
||||
mAttacher.setOnLongClickListener(l); |
||||
} |
||||
|
||||
@Override |
||||
public void setOnPhotoTapListener(OnPhotoTapListener listener) { |
||||
mAttacher.setOnPhotoTapListener(listener); |
||||
} |
||||
|
||||
@Override |
||||
public void setOnRotateListener(PhotoViewAttacher.OnRotateListener onRotateListener) { |
||||
mAttacher.setOnRotateListener(onRotateListener); |
||||
} |
||||
|
||||
@Override |
||||
public OnViewTapListener getOnViewTapListener() { |
||||
return mAttacher.getOnViewTapListener(); |
||||
} |
||||
|
||||
@Override |
||||
public void setOnViewTapListener(OnViewTapListener listener) { |
||||
mAttacher.setOnViewTapListener(listener); |
||||
} |
||||
|
||||
@Override |
||||
public void setScale(float scale) { |
||||
mAttacher.setScale(scale); |
||||
} |
||||
|
||||
@Override |
||||
public void setScale(float scale, boolean animate) { |
||||
mAttacher.setScale(scale, animate); |
||||
} |
||||
|
||||
@Override |
||||
public void setScale(float scale, float focalX, float focalY, boolean animate) { |
||||
mAttacher.setScale(scale, focalX, focalY, animate); |
||||
} |
||||
|
||||
@Override |
||||
public void setScaleType(ScaleType scaleType) { |
||||
if (null != mAttacher) { |
||||
mAttacher.setScaleType(scaleType); |
||||
} else { |
||||
mPendingScaleType = scaleType; |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void setZoomable(boolean zoomable) { |
||||
mAttacher.setZoomable(zoomable); |
||||
} |
||||
|
||||
@Override |
||||
public Bitmap getVisibleRectangleBitmap() { |
||||
return mAttacher.getVisibleRectangleBitmap(); |
||||
} |
||||
|
||||
@Override |
||||
public void setZoomTransitionDuration(int milliseconds) { |
||||
mAttacher.setZoomTransitionDuration(milliseconds); |
||||
} |
||||
|
||||
@Override |
||||
public IPhotoView getIPhotoViewImplementation() { |
||||
return mAttacher; |
||||
} |
||||
|
||||
@Override |
||||
public void setOnDoubleTapListener(GestureDetector.OnDoubleTapListener newOnDoubleTapListener) { |
||||
mAttacher.setOnDoubleTapListener(newOnDoubleTapListener); |
||||
} |
||||
|
||||
@Override |
||||
public void setOnScaleChangeListener(PhotoViewAttacher.OnScaleChangeListener onScaleChangeListener) { |
||||
mAttacher.setOnScaleChangeListener(onScaleChangeListener); |
||||
} |
||||
|
||||
@Override |
||||
public void setOnSingleFlingListener(PhotoViewAttacher.OnSingleFlingListener onSingleFlingListener) { |
||||
mAttacher.setOnSingleFlingListener(onSingleFlingListener); |
||||
} |
||||
|
||||
@Override |
||||
protected void onDetachedFromWindow() { |
||||
mAttacher.cleanup(); |
||||
mAttacher = null; |
||||
super.onDetachedFromWindow(); |
||||
} |
||||
|
||||
@Override |
||||
protected void onAttachedToWindow() { |
||||
init(); |
||||
super.onAttachedToWindow(); |
||||
} |
||||
|
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,149 @@ |
||||
/******************************************************************************* |
||||
* Copyright 2011, 2012 Chris Banes. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*******************************************************************************/ |
||||
package uk.co.senab.photoview.gestures; |
||||
|
||||
import android.content.Context; |
||||
import android.view.MotionEvent; |
||||
import android.view.VelocityTracker; |
||||
import android.view.ViewConfiguration; |
||||
|
||||
import uk.co.senab.photoview.log.LogManager; |
||||
|
||||
public class CupcakeGestureDetector implements GestureDetector { |
||||
|
||||
protected OnGestureListener mListener; |
||||
private static final String LOG_TAG = "CupcakeGestureDetector"; |
||||
float mLastTouchX; |
||||
float mLastTouchY; |
||||
final float mTouchSlop; |
||||
final float mMinimumVelocity; |
||||
|
||||
@Override |
||||
public void setOnGestureListener(OnGestureListener listener) { |
||||
this.mListener = listener; |
||||
} |
||||
|
||||
public CupcakeGestureDetector(Context context) { |
||||
final ViewConfiguration configuration = ViewConfiguration |
||||
.get(context); |
||||
mMinimumVelocity = configuration.getScaledMinimumFlingVelocity(); |
||||
mTouchSlop = configuration.getScaledTouchSlop(); |
||||
} |
||||
|
||||
private VelocityTracker mVelocityTracker; |
||||
private boolean mIsDragging; |
||||
|
||||
float getActiveX(MotionEvent ev) { |
||||
return ev.getX(); |
||||
} |
||||
|
||||
float getActiveY(MotionEvent ev) { |
||||
return ev.getY(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean isScaling() { |
||||
return false; |
||||
} |
||||
|
||||
@Override |
||||
public boolean isDragging() { |
||||
return mIsDragging; |
||||
} |
||||
|
||||
@Override |
||||
public boolean onTouchEvent(MotionEvent ev) { |
||||
switch (ev.getAction()) { |
||||
case MotionEvent.ACTION_DOWN: { |
||||
mVelocityTracker = VelocityTracker.obtain(); |
||||
if (null != mVelocityTracker) { |
||||
mVelocityTracker.addMovement(ev); |
||||
} else { |
||||
LogManager.getLogger().i(LOG_TAG, "Velocity tracker is null"); |
||||
} |
||||
|
||||
mLastTouchX = getActiveX(ev); |
||||
mLastTouchY = getActiveY(ev); |
||||
mIsDragging = false; |
||||
break; |
||||
} |
||||
|
||||
case MotionEvent.ACTION_MOVE: { |
||||
final float x = getActiveX(ev); |
||||
final float y = getActiveY(ev); |
||||
final float dx = x - mLastTouchX, dy = y - mLastTouchY; |
||||
|
||||
if (!mIsDragging) { |
||||
// Use Pythagoras to see if drag length is larger than
|
||||
// touch slop
|
||||
mIsDragging = Math.sqrt((dx * dx) + (dy * dy)) >= mTouchSlop; |
||||
} |
||||
|
||||
if (mIsDragging) { |
||||
mListener.onDrag(dx, dy); |
||||
mLastTouchX = x; |
||||
mLastTouchY = y; |
||||
|
||||
if (null != mVelocityTracker) { |
||||
mVelocityTracker.addMovement(ev); |
||||
} |
||||
} |
||||
break; |
||||
} |
||||
|
||||
case MotionEvent.ACTION_CANCEL: { |
||||
// Recycle Velocity Tracker
|
||||
if (null != mVelocityTracker) { |
||||
mVelocityTracker.recycle(); |
||||
mVelocityTracker = null; |
||||
} |
||||
break; |
||||
} |
||||
|
||||
case MotionEvent.ACTION_UP: { |
||||
if (mIsDragging) { |
||||
if (null != mVelocityTracker) { |
||||
mLastTouchX = getActiveX(ev); |
||||
mLastTouchY = getActiveY(ev); |
||||
|
||||
// Compute velocity within the last 1000ms
|
||||
mVelocityTracker.addMovement(ev); |
||||
mVelocityTracker.computeCurrentVelocity(1000); |
||||
|
||||
final float vX = mVelocityTracker.getXVelocity(), vY = mVelocityTracker |
||||
.getYVelocity(); |
||||
|
||||
// If the velocity is greater than minVelocity, call
|
||||
// listener
|
||||
if (Math.max(Math.abs(vX), Math.abs(vY)) >= mMinimumVelocity) { |
||||
mListener.onFling(mLastTouchX, mLastTouchY, -vX, |
||||
-vY); |
||||
} |
||||
} |
||||
} |
||||
|
||||
// Recycle Velocity Tracker
|
||||
if (null != mVelocityTracker) { |
||||
mVelocityTracker.recycle(); |
||||
mVelocityTracker = null; |
||||
} |
||||
break; |
||||
} |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
} |
@ -0,0 +1,92 @@ |
||||
/** |
||||
* **************************************************************************** |
||||
* Copyright 2011, 2012 Chris Banes. |
||||
* <p> |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* <p> |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p> |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*******************************************************************************/ |
||||
package uk.co.senab.photoview.gestures; |
||||
|
||||
import android.annotation.TargetApi; |
||||
import android.content.Context; |
||||
import android.view.MotionEvent; |
||||
|
||||
import uk.co.senab.photoview.Compat; |
||||
|
||||
@TargetApi(5) |
||||
public class EclairGestureDetector extends CupcakeGestureDetector { |
||||
|
||||
private static final int INVALID_POINTER_ID = -1; |
||||
private int mActivePointerId = INVALID_POINTER_ID; |
||||
private int mActivePointerIndex = 0; |
||||
|
||||
public EclairGestureDetector(Context context) { |
||||
super(context); |
||||
} |
||||
|
||||
@Override |
||||
float getActiveX(MotionEvent ev) { |
||||
try { |
||||
return ev.getX(mActivePointerIndex); |
||||
} catch (Exception e) { |
||||
return ev.getX(); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
float getActiveY(MotionEvent ev) { |
||||
try { |
||||
return ev.getY(mActivePointerIndex); |
||||
} catch (Exception e) { |
||||
return ev.getY(); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public boolean onTouchEvent(MotionEvent ev) { |
||||
final int action = ev.getAction(); |
||||
switch (action & MotionEvent.ACTION_MASK) { |
||||
case MotionEvent.ACTION_DOWN: |
||||
mActivePointerId = ev.getPointerId(0); |
||||
break; |
||||
case MotionEvent.ACTION_CANCEL: |
||||
case MotionEvent.ACTION_UP: |
||||
mActivePointerId = INVALID_POINTER_ID; |
||||
break; |
||||
case MotionEvent.ACTION_POINTER_UP: |
||||
// Ignore deprecation, ACTION_POINTER_ID_MASK and
|
||||
// ACTION_POINTER_ID_SHIFT has same value and are deprecated
|
||||
// You can have either deprecation or lint target api warning
|
||||
final int pointerIndex = Compat.getPointerIndex(ev.getAction()); |
||||
final int pointerId = ev.getPointerId(pointerIndex); |
||||
if (pointerId == mActivePointerId) { |
||||
// This was our active pointer going up. Choose a new
|
||||
// active pointer and adjust accordingly.
|
||||
final int newPointerIndex = pointerIndex == 0 ? 1 : 0; |
||||
mActivePointerId = ev.getPointerId(newPointerIndex); |
||||
mLastTouchX = ev.getX(newPointerIndex); |
||||
mLastTouchY = ev.getY(newPointerIndex); |
||||
} |
||||
break; |
||||
} |
||||
|
||||
mActivePointerIndex = ev |
||||
.findPointerIndex(mActivePointerId != INVALID_POINTER_ID ? mActivePointerId |
||||
: 0); |
||||
try { |
||||
return super.onTouchEvent(ev); |
||||
} catch (IllegalArgumentException e) { |
||||
// Fix for support lib bug, happening when onDestroy is
|
||||
return true; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,73 @@ |
||||
/******************************************************************************* |
||||
* Copyright 2011, 2012 Chris Banes. |
||||
* <p/> |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* <p/> |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p/> |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*******************************************************************************/ |
||||
package uk.co.senab.photoview.gestures; |
||||
|
||||
import android.annotation.TargetApi; |
||||
import android.content.Context; |
||||
import android.view.MotionEvent; |
||||
import android.view.ScaleGestureDetector; |
||||
|
||||
@TargetApi(8) |
||||
public class FroyoGestureDetector extends EclairGestureDetector { |
||||
|
||||
protected final ScaleGestureDetector mDetector; |
||||
|
||||
public FroyoGestureDetector(Context context) { |
||||
super(context); |
||||
ScaleGestureDetector.OnScaleGestureListener mScaleListener = new ScaleGestureDetector.OnScaleGestureListener() { |
||||
|
||||
@Override |
||||
public boolean onScale(ScaleGestureDetector detector) { |
||||
float scaleFactor = detector.getScaleFactor(); |
||||
|
||||
if (Float.isNaN(scaleFactor) || Float.isInfinite(scaleFactor)) |
||||
return false; |
||||
|
||||
mListener.onScale(scaleFactor, |
||||
detector.getFocusX(), detector.getFocusY()); |
||||
return true; |
||||
} |
||||
|
||||
@Override |
||||
public boolean onScaleBegin(ScaleGestureDetector detector) { |
||||
return true; |
||||
} |
||||
|
||||
@Override |
||||
public void onScaleEnd(ScaleGestureDetector detector) { |
||||
// NO-OP
|
||||
} |
||||
}; |
||||
mDetector = new ScaleGestureDetector(context, mScaleListener); |
||||
} |
||||
|
||||
@Override |
||||
public boolean isScaling() { |
||||
return mDetector.isInProgress(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean onTouchEvent(MotionEvent ev) { |
||||
try { |
||||
mDetector.onTouchEvent(ev); |
||||
return super.onTouchEvent(ev); |
||||
} catch (IllegalArgumentException e) { |
||||
// Fix for support lib bug, happening when onDestroy is
|
||||
return true; |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,30 @@ |
||||
/******************************************************************************* |
||||
* Copyright 2011, 2012 Chris Banes. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*******************************************************************************/ |
||||
package uk.co.senab.photoview.gestures; |
||||
|
||||
import android.view.MotionEvent; |
||||
|
||||
public interface GestureDetector { |
||||
|
||||
boolean onTouchEvent(MotionEvent ev); |
||||
|
||||
boolean isScaling(); |
||||
|
||||
boolean isDragging(); |
||||
|
||||
void setOnGestureListener(OnGestureListener listener); |
||||
|
||||
} |
@ -0,0 +1,24 @@ |
||||
package uk.co.senab.photoview.gestures; |
||||
|
||||
import android.view.MotionEvent; |
||||
|
||||
/** |
||||
* Interface to detect rotation |
||||
* Created by ChenSL on 2015/9/16. |
||||
*/ |
||||
public interface IRotateDetector { |
||||
/** |
||||
* handle rotation in onTouchEvent |
||||
* |
||||
* @param event The motion event. |
||||
* @return True if the event was handled, false otherwise. |
||||
*/ |
||||
boolean onTouchEvent(MotionEvent event); |
||||
|
||||
/** |
||||
* is the Gesture Rotate |
||||
* |
||||
* @return true:rotating;false,otherwise |
||||
*/ |
||||
boolean isRotating(); |
||||
} |
@ -0,0 +1,20 @@ |
||||
package uk.co.senab.photoview.gestures; |
||||
|
||||
/** |
||||
* Interface for a callback for rotation |
||||
* Created by ChenSL on 2015/9/16. |
||||
*/ |
||||
public interface IRotateListener { |
||||
/** |
||||
* callback for rotation |
||||
* |
||||
* @param degree degree of rotation |
||||
*/ |
||||
void rotate(int degree, int pivotX, int pivotY); |
||||
|
||||
/** |
||||
* MotionEvent.ACTION_POINTER_UP happens when two finger minus to only one |
||||
* change the ImageView to 0,90,180,270 |
||||
*/ |
||||
void upRotate(int pivotX, int pivotY); |
||||
} |
@ -0,0 +1,27 @@ |
||||
/******************************************************************************* |
||||
* Copyright 2011, 2012 Chris Banes. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*******************************************************************************/ |
||||
package uk.co.senab.photoview.gestures; |
||||
|
||||
public interface OnGestureListener { |
||||
|
||||
void onDrag(float dx, float dy); |
||||
|
||||
void onFling(float startX, float startY, float velocityX, |
||||
float velocityY); |
||||
|
||||
void onScale(float scaleFactor, float focusX, float focusY); |
||||
|
||||
} |
@ -0,0 +1,113 @@ |
||||
package uk.co.senab.photoview.gestures; |
||||
|
||||
import android.view.MotionEvent; |
||||
|
||||
/** |
||||
* Handle ImageView rotate event with two fingers |
||||
* Created by ChenSL on 2015/9/16. |
||||
*/ |
||||
public class RotateGestureDetector implements IRotateDetector { |
||||
private int mLastAngle = 0; |
||||
private IRotateListener mListener; |
||||
private boolean mIsRotate; |
||||
|
||||
/** |
||||
* set rotation listener for callback |
||||
* |
||||
* @param listener a rotation listener |
||||
*/ |
||||
public void setRotateListener(IRotateListener listener) { |
||||
this.mListener = listener; |
||||
} |
||||
|
||||
@Override |
||||
public boolean onTouchEvent(MotionEvent event) { |
||||
return doRotate(event); |
||||
} |
||||
|
||||
@Override |
||||
public boolean isRotating() { |
||||
return mIsRotate; |
||||
} |
||||
|
||||
/** |
||||
* handle rotation |
||||
* |
||||
* @param ev Motion event |
||||
* @return always true. |
||||
*/ |
||||
private boolean doRotate(MotionEvent ev) { |
||||
if (ev.getPointerCount() != 2) { |
||||
return false; |
||||
} |
||||
//Calculate the angle between the two fingers
|
||||
int pivotX = (int) (ev.getX(0) + ev.getX(1)) / 2; |
||||
int pivotY = (int) (ev.getY(0) + ev.getY(1)) / 2; |
||||
float deltaX = ev.getX(0) - ev.getX(1); |
||||
float deltaY = ev.getY(0) - ev.getY(1); |
||||
double radians = Math.atan(deltaY / deltaX); |
||||
//Convert to degrees
|
||||
int degrees = (int) (radians * 180 / Math.PI); |
||||
/* |
||||
* Must use getActionMasked() for switching to pick up pointer events. |
||||
* These events have the pointer index encoded in them so the return |
||||
* from getAction() won't match the exact action constant. |
||||
*/ |
||||
switch (ev.getActionMasked()) { |
||||
case MotionEvent.ACTION_DOWN: |
||||
mLastAngle = degrees; |
||||
mIsRotate = false; |
||||
break; |
||||
case MotionEvent.ACTION_UP: |
||||
mIsRotate = false; |
||||
break; |
||||
case MotionEvent.ACTION_POINTER_DOWN: |
||||
mLastAngle = degrees; |
||||
mIsRotate = false; |
||||
break; |
||||
case MotionEvent.ACTION_CANCEL: |
||||
case MotionEvent.ACTION_POINTER_UP: |
||||
mIsRotate = false; |
||||
upRotate(pivotX, pivotY); |
||||
mLastAngle = degrees; |
||||
break; |
||||
case MotionEvent.ACTION_MOVE: |
||||
mIsRotate = true; |
||||
int degreesValue = degrees - mLastAngle; |
||||
if (degreesValue > 45) { |
||||
//Going CCW across the boundary
|
||||
rotate(-5, pivotX, pivotY); |
||||
} else if (degreesValue < -45) { |
||||
//Going CW across the boundary
|
||||
rotate(5, pivotX, pivotY); |
||||
} else { |
||||
//Normal rotation, rotate the difference
|
||||
rotate(degreesValue, pivotX, pivotY); |
||||
} |
||||
//Save the current angle
|
||||
mLastAngle = degrees; |
||||
break; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* to invoke the callback |
||||
* |
||||
* @param degree degree to rotate |
||||
*/ |
||||
private void rotate(int degree, int pivotX, int pivotY) { |
||||
if (mListener != null) { |
||||
mListener.rotate(degree, pivotX, pivotY); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* to invoke the finger up action |
||||
*/ |
||||
private void upRotate(int pivotX, int pivotY) { |
||||
if (mListener != null) { |
||||
mListener.upRotate(pivotX, pivotY); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,42 @@ |
||||
package uk.co.senab.photoview.gestures; |
||||
|
||||
/******************************************************************************* |
||||
* Copyright 2011, 2012 Chris Banes. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*******************************************************************************/ |
||||
|
||||
import android.content.Context; |
||||
import android.os.Build; |
||||
|
||||
public final class VersionedGestureDetector { |
||||
|
||||
public static GestureDetector newInstance(Context context, |
||||
OnGestureListener listener) { |
||||
final int sdkVersion = Build.VERSION.SDK_INT; |
||||
GestureDetector detector; |
||||
|
||||
if (sdkVersion < Build.VERSION_CODES.ECLAIR) { |
||||
detector = new CupcakeGestureDetector(context); |
||||
} else if (sdkVersion < Build.VERSION_CODES.FROYO) { |
||||
detector = new EclairGestureDetector(context); |
||||
} else { |
||||
detector = new FroyoGestureDetector(context); |
||||
} |
||||
|
||||
detector.setOnGestureListener(listener); |
||||
|
||||
return detector; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,35 @@ |
||||
/******************************************************************************* |
||||
* Copyright 2011, 2012 Chris Banes. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*******************************************************************************/ |
||||
package uk.co.senab.photoview.log; |
||||
|
||||
import android.util.Log; |
||||
|
||||
/** |
||||
* class that holds the {@link Logger} for this library, defaults to {@link LoggerDefault} to send logs to android {@link Log} |
||||
*/ |
||||
public final class LogManager { |
||||
|
||||
private static Logger logger = new LoggerDefault(); |
||||
|
||||
public static void setLogger(Logger newLogger) { |
||||
logger = newLogger; |
||||
} |
||||
|
||||
public static Logger getLogger() { |
||||
return logger; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,116 @@ |
||||
/******************************************************************************* |
||||
* Copyright 2011, 2012 Chris Banes. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*******************************************************************************/ |
||||
package uk.co.senab.photoview.log; |
||||
|
||||
/** |
||||
* interface for a logger class to replace the static calls to {@link android.util.Log} |
||||
*/ |
||||
public interface Logger { |
||||
/** |
||||
* Send a {@link android.util.Log#VERBOSE} log message. |
||||
* |
||||
* @param tag Used to identify the source of a log message. It usually identifies |
||||
* the class or activity where the log call occurs. |
||||
* @param msg The message you would like logged. |
||||
*/ |
||||
int v(String tag, String msg); |
||||
|
||||
/** |
||||
* Send a {@link android.util.Log#VERBOSE} log message and log the exception. |
||||
* |
||||
* @param tag Used to identify the source of a log message. It usually identifies |
||||
* the class or activity where the log call occurs. |
||||
* @param msg The message you would like logged. |
||||
* @param tr An exception to log |
||||
*/ |
||||
int v(String tag, String msg, Throwable tr); |
||||
|
||||
/** |
||||
* Send a {@link android.util.Log#DEBUG} log message. |
||||
* |
||||
* @param tag Used to identify the source of a log message. It usually identifies |
||||
* the class or activity where the log call occurs. |
||||
* @param msg The message you would like logged. |
||||
*/ |
||||
int d(String tag, String msg); |
||||
|
||||
/** |
||||
* Send a {@link android.util.Log#DEBUG} log message and log the exception. |
||||
* |
||||
* @param tag Used to identify the source of a log message. It usually identifies |
||||
* the class or activity where the log call occurs. |
||||
* @param msg The message you would like logged. |
||||
* @param tr An exception to log |
||||
*/ |
||||
int d(String tag, String msg, Throwable tr); |
||||
|
||||
/** |
||||
* Send an {@link android.util.Log#INFO} log message. |
||||
* |
||||
* @param tag Used to identify the source of a log message. It usually identifies |
||||
* the class or activity where the log call occurs. |
||||
* @param msg The message you would like logged. |
||||
*/ |
||||
int i(String tag, String msg); |
||||
|
||||
/** |
||||
* Send a {@link android.util.Log#INFO} log message and log the exception. |
||||
* |
||||
* @param tag Used to identify the source of a log message. It usually identifies |
||||
* the class or activity where the log call occurs. |
||||
* @param msg The message you would like logged. |
||||
* @param tr An exception to log |
||||
*/ |
||||
int i(String tag, String msg, Throwable tr); |
||||
|
||||
/** |
||||
* Send a {@link android.util.Log#WARN} log message. |
||||
* |
||||
* @param tag Used to identify the source of a log message. It usually identifies |
||||
* the class or activity where the log call occurs. |
||||
* @param msg The message you would like logged. |
||||
*/ |
||||
int w(String tag, String msg); |
||||
|
||||
/** |
||||
* Send a {@link android.util.Log#WARN} log message and log the exception. |
||||
* |
||||
* @param tag Used to identify the source of a log message. It usually identifies |
||||
* the class or activity where the log call occurs. |
||||
* @param msg The message you would like logged. |
||||
* @param tr An exception to log |
||||
*/ |
||||
int w(String tag, String msg, Throwable tr); |
||||
|
||||
/** |
||||
* Send an {@link android.util.Log#ERROR} log message. |
||||
* |
||||
* @param tag Used to identify the source of a log message. It usually identifies |
||||
* the class or activity where the log call occurs. |
||||
* @param msg The message you would like logged. |
||||
*/ |
||||
int e(String tag, String msg); |
||||
|
||||
/** |
||||
* Send a {@link android.util.Log#ERROR} log message and log the exception. |
||||
* |
||||
* @param tag Used to identify the source of a log message. It usually identifies |
||||
* the class or activity where the log call occurs. |
||||
* @param msg The message you would like logged. |
||||
* @param tr An exception to log |
||||
*/ |
||||
int e(String tag, String msg, Throwable tr); |
||||
} |
@ -0,0 +1,76 @@ |
||||
/******************************************************************************* |
||||
* Copyright 2011, 2012 Chris Banes. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*******************************************************************************/ |
||||
package uk.co.senab.photoview.log; |
||||
|
||||
import android.util.Log; |
||||
|
||||
/** |
||||
* Helper class to redirect {@link LogManager#logger} to {@link Log} |
||||
*/ |
||||
public class LoggerDefault implements Logger { |
||||
|
||||
@Override |
||||
public int v(String tag, String msg) { |
||||
return Log.v(tag, msg); |
||||
} |
||||
|
||||
@Override |
||||
public int v(String tag, String msg, Throwable tr) { |
||||
return Log.v(tag, msg, tr); |
||||
} |
||||
|
||||
@Override |
||||
public int d(String tag, String msg) { |
||||
return Log.d(tag, msg); |
||||
} |
||||
|
||||
@Override |
||||
public int d(String tag, String msg, Throwable tr) { |
||||
return Log.d(tag, msg, tr); |
||||
} |
||||
|
||||
@Override |
||||
public int i(String tag, String msg) { |
||||
return Log.i(tag, msg); |
||||
} |
||||
|
||||
@Override |
||||
public int i(String tag, String msg, Throwable tr) { |
||||
return Log.i(tag, msg, tr); |
||||
} |
||||
|
||||
@Override |
||||
public int w(String tag, String msg) { |
||||
return Log.w(tag, msg); |
||||
} |
||||
|
||||
@Override |
||||
public int w(String tag, String msg, Throwable tr) { |
||||
return Log.w(tag, msg, tr); |
||||
} |
||||
|
||||
@Override |
||||
public int e(String tag, String msg) { |
||||
return Log.e(tag, msg); |
||||
} |
||||
|
||||
@Override |
||||
public int e(String tag, String msg, Throwable tr) { |
||||
return Log.e(tag, msg, tr); |
||||
} |
||||
|
||||
|
||||
} |
@ -0,0 +1,61 @@ |
||||
/******************************************************************************* |
||||
* Copyright 2011, 2012 Chris Banes. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*******************************************************************************/ |
||||
package uk.co.senab.photoview.scrollerproxy; |
||||
|
||||
import android.annotation.TargetApi; |
||||
import android.content.Context; |
||||
import android.widget.OverScroller; |
||||
|
||||
@TargetApi(9) |
||||
public class GingerScroller extends ScrollerProxy { |
||||
|
||||
protected final OverScroller mScroller; |
||||
|
||||
public GingerScroller(Context context) { |
||||
mScroller = new OverScroller(context); |
||||
} |
||||
|
||||
@Override |
||||
public boolean computeScrollOffset() { |
||||
return mScroller.computeScrollOffset(); |
||||
} |
||||
|
||||
@Override |
||||
public void fling(int startX, int startY, int velocityX, int velocityY, int minX, int maxX, int minY, int maxY, |
||||
int overX, int overY) { |
||||
mScroller.fling(startX, startY, velocityX, velocityY, minX, maxX, minY, maxY, overX, overY); |
||||
} |
||||
|
||||
@Override |
||||
public void forceFinished(boolean finished) { |
||||
mScroller.forceFinished(finished); |
||||
} |
||||
|
||||
@Override |
||||
public boolean isFinished() { |
||||
return mScroller.isFinished(); |
||||
} |
||||
|
||||
@Override |
||||
public int getCurrX() { |
||||
return mScroller.getCurrX(); |
||||
} |
||||
|
||||
@Override |
||||
public int getCurrY() { |
||||
return mScroller.getCurrY(); |
||||
} |
||||
} |
@ -0,0 +1,33 @@ |
||||
/******************************************************************************* |
||||
* Copyright 2011, 2012 Chris Banes. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*******************************************************************************/ |
||||
package uk.co.senab.photoview.scrollerproxy; |
||||
|
||||
import android.annotation.TargetApi; |
||||
import android.content.Context; |
||||
|
||||
@TargetApi(14) |
||||
public class IcsScroller extends GingerScroller { |
||||
|
||||
public IcsScroller(Context context) { |
||||
super(context); |
||||
} |
||||
|
||||
@Override |
||||
public boolean computeScrollOffset() { |
||||
return mScroller.computeScrollOffset(); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,58 @@ |
||||
/******************************************************************************* |
||||
* Copyright 2011, 2012 Chris Banes. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*******************************************************************************/ |
||||
package uk.co.senab.photoview.scrollerproxy; |
||||
|
||||
import android.content.Context; |
||||
import android.widget.Scroller; |
||||
|
||||
public class PreGingerScroller extends ScrollerProxy { |
||||
|
||||
private final Scroller mScroller; |
||||
|
||||
public PreGingerScroller(Context context) { |
||||
mScroller = new Scroller(context); |
||||
} |
||||
|
||||
@Override |
||||
public boolean computeScrollOffset() { |
||||
return mScroller.computeScrollOffset(); |
||||
} |
||||
|
||||
@Override |
||||
public void fling(int startX, int startY, int velocityX, int velocityY, int minX, int maxX, int minY, int maxY, |
||||
int overX, int overY) { |
||||
mScroller.fling(startX, startY, velocityX, velocityY, minX, maxX, minY, maxY); |
||||
} |
||||
|
||||
@Override |
||||
public void forceFinished(boolean finished) { |
||||
mScroller.forceFinished(finished); |
||||
} |
||||
|
||||
public boolean isFinished() { |
||||
return mScroller.isFinished(); |
||||
} |
||||
|
||||
@Override |
||||
public int getCurrX() { |
||||
return mScroller.getCurrX(); |
||||
} |
||||
|
||||
@Override |
||||
public int getCurrY() { |
||||
return mScroller.getCurrY(); |
||||
} |
||||
} |
@ -0,0 +1,48 @@ |
||||
/******************************************************************************* |
||||
* Copyright 2011, 2012 Chris Banes. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*******************************************************************************/ |
||||
package uk.co.senab.photoview.scrollerproxy; |
||||
|
||||
import android.content.Context; |
||||
import android.os.Build.VERSION; |
||||
import android.os.Build.VERSION_CODES; |
||||
|
||||
public abstract class ScrollerProxy { |
||||
|
||||
public static ScrollerProxy getScroller(Context context) { |
||||
if (VERSION.SDK_INT < VERSION_CODES.GINGERBREAD) { |
||||
return new PreGingerScroller(context); |
||||
} else if (VERSION.SDK_INT < VERSION_CODES.ICE_CREAM_SANDWICH) { |
||||
return new GingerScroller(context); |
||||
} else { |
||||
return new IcsScroller(context); |
||||
} |
||||
} |
||||
|
||||
public abstract boolean computeScrollOffset(); |
||||
|
||||
public abstract void fling(int startX, int startY, int velocityX, int velocityY, int minX, int maxX, int minY, |
||||
int maxY, int overX, int overY); |
||||
|
||||
public abstract void forceFinished(boolean finished); |
||||
|
||||
public abstract boolean isFinished(); |
||||
|
||||
public abstract int getCurrX(); |
||||
|
||||
public abstract int getCurrY(); |
||||
|
||||
|
||||
} |
@ -0,0 +1,5 @@ |
||||
<resources> |
||||
<!-- Default screen margins, per the Android Design guidelines. --> |
||||
<dimen name="activity_horizontal_margin">16dp</dimen> |
||||
<dimen name="activity_vertical_margin">16dp</dimen> |
||||
</resources> |
@ -0,0 +1,3 @@ |
||||
<resources> |
||||
<string name="hello_world">Hello world!</string> |
||||
</resources> |
@ -1,3 +1,3 @@ |
||||
## 二维码扫描库 |
||||
# 二维码扫描库 |
||||
|
||||
修改自 [BGAQRCode-Android](https://github.com/bingoogolapple/BGAQRCode-Android) |
Binary file not shown.
@ -1,4 +1,4 @@ |
||||
package com.android.sdk.qrcode.zxing; |
||||
package com.android.sdk.qrcode; |
||||
|
||||
import android.graphics.Bitmap; |
||||
import android.graphics.BitmapFactory; |
@ -1,4 +1,4 @@ |
||||
package com.android.sdk.qrcode.zxing; |
||||
package com.android.sdk.qrcode; |
||||
|
||||
import android.graphics.Bitmap; |
||||
import android.graphics.Canvas; |
@ -1,11 +1,9 @@ |
||||
package com.android.sdk.qrcode.zxing; |
||||
package com.android.sdk.qrcode; |
||||
|
||||
import android.content.Context; |
||||
import android.graphics.Rect; |
||||
import android.util.AttributeSet; |
||||
|
||||
import com.android.sdk.qrcode.QRCodeView; |
||||
import com.android.sdk.qrcode.Debug; |
||||
import com.google.zxing.BinaryBitmap; |
||||
import com.google.zxing.MultiFormatReader; |
||||
import com.google.zxing.PlanarYUVLuminanceSource; |
Loading…
Reference in new issue