Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Kotlin version #772

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
427 changes: 427 additions & 0 deletions photoview/CircleImageView.kt

Large diffs are not rendered by default.

37 changes: 37 additions & 0 deletions photoview/Compat.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
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 com.github.chrisbanes.photoview

import android.annotation.TargetApi
import android.os.Build.VERSION
import android.os.Build.VERSION_CODES
import android.view.View

internal object Compat {
private const val SIXTY_FPS_INTERVAL = 1000 / 60
fun postOnAnimation(view: View, runnable: Runnable) {
if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) {
postOnAnimationJellyBean(view, runnable)
} else {
view.postDelayed(runnable, SIXTY_FPS_INTERVAL.toLong())
}
}

@TargetApi(16)
private fun postOnAnimationJellyBean(view: View, runnable: Runnable) {
view.postOnAnimation(runnable)
}
}
186 changes: 186 additions & 0 deletions photoview/CustomGestureDetector.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
/*
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 com.github.chrisbanes.photoview

import android.content.Context
import android.view.MotionEvent
import android.view.ScaleGestureDetector
import android.view.ScaleGestureDetector.OnScaleGestureListener
import android.view.VelocityTracker
import android.view.ViewConfiguration

/**
* Does a whole lot of gesture detecting.
*/
internal class CustomGestureDetector() {
private var mActivePointerId = INVALID_POINTER_ID
private var mActivePointerIndex = 0
private var mDetector: ScaleGestureDetector? = null
private var mVelocityTracker: VelocityTracker? = null
var isDragging = false
private set
private var mLastTouchX = 0f
private var mLastTouchY = 0f
private var mTouchSlop: Float = 0.0f
private var mMinimumVelocity: Float = 0.0f
private lateinit var mListener: OnGestureListener
private fun getActiveX(ev: MotionEvent): Float {
return try {
ev.getX(mActivePointerIndex)
} catch (e: Exception) {
ev.x
}
}

private fun getActiveY(ev: MotionEvent): Float {
return try {
ev.getY(mActivePointerIndex)
} catch (e: Exception) {
ev.y
}
}

val isScaling: Boolean
get() = mDetector!!.isInProgress

fun onTouchEvent(ev: MotionEvent): Boolean {
return try {
mDetector!!.onTouchEvent(ev)
processTouchEvent(ev)
} catch (e: IllegalArgumentException) {
// Fix for support lib bug, happening when onDestroy is called
true
}
}

private fun processTouchEvent(ev: MotionEvent): Boolean {
val action = ev.action
when (action and MotionEvent.ACTION_MASK) {
MotionEvent.ACTION_DOWN -> {
mActivePointerId = ev.getPointerId(0)
mVelocityTracker = VelocityTracker.obtain()
if (null != mVelocityTracker) {
mVelocityTracker!!.addMovement(ev)
}
mLastTouchX = getActiveX(ev)
mLastTouchY = getActiveY(ev)
isDragging = false
}
MotionEvent.ACTION_MOVE -> {
val x = getActiveX(ev)
val y = getActiveY(ev)
val dx = x - mLastTouchX
val dy = y - mLastTouchY
if (!isDragging) {
// Use Pythagoras to see if drag length is larger than
// touch slop
isDragging = Math.sqrt(dx * dx + (dy * dy).toDouble()) >= mTouchSlop
}
if (isDragging) {
mListener.onDrag(dx, dy)
mLastTouchX = x
mLastTouchY = y
if (null != mVelocityTracker) {
mVelocityTracker!!.addMovement(ev)
}
}
}
MotionEvent.ACTION_CANCEL -> {
mActivePointerId = INVALID_POINTER_ID
// Recycle Velocity Tracker
if (null != mVelocityTracker) {
mVelocityTracker!!.recycle()
mVelocityTracker = null
}
}
MotionEvent.ACTION_UP -> {
mActivePointerId = INVALID_POINTER_ID
if (isDragging) {
if (null != mVelocityTracker) {
mLastTouchX = getActiveX(ev)
mLastTouchY = getActiveY(ev)

// Compute velocity within the last 1000ms
mVelocityTracker!!.addMovement(ev)
mVelocityTracker!!.computeCurrentVelocity(1000)
val vX = mVelocityTracker!!.xVelocity
val vY = mVelocityTracker!!
.yVelocity

// 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
}
}
MotionEvent.ACTION_POINTER_UP -> {
val pointerIndex = Util.getPointerIndex(ev.action)
val pointerId = ev.getPointerId(pointerIndex)
if (pointerId == mActivePointerId) {
// This was our active pointer going up. Choose a new
// active pointer and adjust accordingly.
val newPointerIndex = if (pointerIndex == 0) 1 else 0
mActivePointerId = ev.getPointerId(newPointerIndex)
mLastTouchX = ev.getX(newPointerIndex)
mLastTouchY = ev.getY(newPointerIndex)
}
}
}
mActivePointerIndex = ev
.findPointerIndex(if (mActivePointerId != INVALID_POINTER_ID) mActivePointerId else 0)
return true
}

companion object {
private const val INVALID_POINTER_ID = -1
}

constructor(context: Context?, listener: OnGestureListener) : this() {
val configuration = ViewConfiguration.get(context)
mMinimumVelocity = configuration.scaledMinimumFlingVelocity.toFloat()
mTouchSlop = configuration.scaledTouchSlop.toFloat()
mListener = listener
val mScaleListener: OnScaleGestureListener = object : OnScaleGestureListener {
override fun onScale(detector: ScaleGestureDetector): Boolean {
val scaleFactor = detector.scaleFactor
if (java.lang.Float.isNaN(scaleFactor) || java.lang.Float.isInfinite(scaleFactor)) return false
if (scaleFactor >= 0) {
mListener.onScale(scaleFactor,
detector.focusX, detector.focusY)
}
return true
}

override fun onScaleBegin(detector: ScaleGestureDetector): Boolean {
return true
}

override fun onScaleEnd(detector: ScaleGestureDetector) {
// NO-OP
}
}
mDetector = ScaleGestureDetector(context, mScaleListener)
}
}
24 changes: 24 additions & 0 deletions photoview/OnGestureListener.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
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 com.github.chrisbanes.photoview

internal interface OnGestureListener {
fun onDrag(dx: Float, dy: Float)
fun onFling(startX: Float, startY: Float, velocityX: Float,
velocityY: Float)

fun onScale(scaleFactor: Float, focusX: Float, focusY: Float)
}
17 changes: 17 additions & 0 deletions photoview/OnMatrixChangedListener.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.github.chrisbanes.photoview

import android.graphics.RectF

/**
* Interface definition for a callback to be invoked when the internal Matrix has changed for
* this View.
*/
interface OnMatrixChangedListener {
/**
* Callback for when the Matrix displaying the Drawable has changed. This could be because
* the View's bounds have changed, or the user has zoomed.
*
* @param rect - Rectangle displaying the Drawable's new bounds.
*/
fun onMatrixChanged(rect: RectF)
}
13 changes: 13 additions & 0 deletions photoview/OnOutsidePhotoTapListener.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.github.chrisbanes.photoview

import android.widget.ImageView

/**
* Callback when the user tapped outside of the photo
*/
interface OnOutsidePhotoTapListener {
/**
* The outside of the photo has been tapped
*/
fun onOutsidePhotoTap(imageView: ImageView?)
}
21 changes: 21 additions & 0 deletions photoview/OnPhotoTapListener.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.github.chrisbanes.photoview

import android.widget.ImageView

/**
* A callback to be invoked when the Photo is tapped with a single
* tap.
*/
interface OnPhotoTapListener {
/**
* A callback to receive where the user taps on a photo. You will only receive a callback if
* the user taps on the actual photo, tapping on 'whitespace' will be ignored.
*
* @param view ImageView the user tapped.
* @param x where the user tapped from the of the Drawable, as percentage of the
* Drawable width.
* @param y where the user tapped from the top of the Drawable, as percentage of the
* Drawable height.
*/
fun onPhotoTap(view: ImageView?, x: Float, y: Float)
}
15 changes: 15 additions & 0 deletions photoview/OnScaleChangedListener.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.github.chrisbanes.photoview

/**
* Interface definition for callback to be invoked when attached ImageView scale changes
*/
interface OnScaleChangedListener {
/**
* Callback for when the scale changes
*
* @param scaleFactor the scale factor (less than 1 for zoom out, greater than 1 for zoom in)
* @param focusX focal point X position
* @param focusY focal point Y position
*/
fun onScaleChange(scaleFactor: Float, focusX: Float, focusY: Float)
}
20 changes: 20 additions & 0 deletions photoview/OnSingleFlingListener.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.github.chrisbanes.photoview

import android.view.MotionEvent

/**
* A callback to be invoked when the ImageView is flung with a single
* touch
*/
interface OnSingleFlingListener {
/**
* A callback to receive where the user flings on a ImageView. You will receive a callback if
* the user flings anywhere on the view.
*
* @param e1 MotionEvent the user first touch.
* @param e2 MotionEvent the user last touch.
* @param velocityX distance of user's horizontal fling.
* @param velocityY distance of user's vertical fling.
*/
fun onFling(e1: MotionEvent?, e2: MotionEvent?, velocityX: Float, velocityY: Float): Boolean
}
15 changes: 15 additions & 0 deletions photoview/OnViewDragListener.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.github.chrisbanes.photoview

/**
* Interface definition for a callback to be invoked when the photo is experiencing a drag event
*/
interface OnViewDragListener {
/**
* Callback for when the photo is experiencing a drag event. This cannot be invoked when the
* user is scaling.
*
* @param dx The change of the coordinates in the x-direction
* @param dy The change of the coordinates in the y-direction
*/
fun onDrag(dx: Float, dy: Float)
}
15 changes: 15 additions & 0 deletions photoview/OnViewTapListener.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.github.chrisbanes.photoview

import android.view.View

interface OnViewTapListener {
/**
* A callback to receive where the user taps on a ImageView. You will receive a callback if
* the user taps anywhere on the view, tapping on 'whitespace' will not be ignored.
*
* @param view - View the user tapped.
* @param x - where the user tapped from the left of the View.
* @param y - where the user tapped from the top of the View.
*/
fun onViewTap(view: View?, x: Float, y: Float)
}
Loading