Created
September 1, 2021 20:32
-
-
Save sagarpatel288/aa2bf8c17f80ce5b5d351e4012edf755 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class ZoomableTextureView : TextureRenderView { | |
private var minScale = 1f | |
private var maxScale = 5f | |
private var saveScale = 1f | |
fun setMinScale(scale: Float) { | |
minScale = | |
if (scale < 1.0f || scale > maxScale) throw RuntimeException("minScale can't be lower than 1 or larger than maxScale($maxScale)") else scale | |
} | |
fun setMaxScale(scale: Float) { | |
minScale = | |
if (scale < 1.0f || scale < minScale) throw RuntimeException("maxScale can't be lower than 1 or minScale($minScale)") else scale | |
} | |
private var mode = NONE | |
private var mScaleDetector: ScaleGestureDetector? = null | |
private lateinit var m: FloatArray | |
private val last = PointF() | |
private val start = PointF() | |
private var right = 0f | |
private var bottom = 0f | |
constructor(context: Context) : super(context) { | |
initView(null) | |
} | |
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) { | |
initView(attrs) | |
} | |
constructor(context: Context, attrs: AttributeSet?, defStyle: Int) : super( | |
context, | |
attrs, | |
defStyle | |
) { | |
initView(attrs) | |
} | |
override fun onSaveInstanceState(): Parcelable? { | |
val bundle = Bundle() | |
bundle.putParcelable(SUPERSTATE_KEY, super.onSaveInstanceState()) | |
bundle.putFloat(MIN_SCALE_KEY, minScale) | |
bundle.putFloat(MAX_SCALE_KEY, maxScale) | |
return bundle | |
} | |
public override fun onRestoreInstanceState(state: Parcelable) { | |
var state: Parcelable? = state | |
if (state is Bundle) { | |
val bundle = state | |
minScale = bundle.getInt(MIN_SCALE_KEY).toFloat() | |
minScale = bundle.getInt(MAX_SCALE_KEY).toFloat() | |
state = bundle.getParcelable(SUPERSTATE_KEY) | |
} | |
super.onRestoreInstanceState(state) | |
} | |
private fun initView(attrs: AttributeSet?) { | |
val a = context.theme.obtainStyledAttributes( | |
attrs, | |
R.styleable.ZoomableTextureView, | |
0, 0 | |
) | |
try { | |
minScale = a.getFloat(R.styleable.ZoomableTextureView_minScale, minScale) | |
maxScale = a.getFloat(R.styleable.ZoomableTextureView_maxScale, maxScale) | |
} finally { | |
a.recycle() | |
} | |
setOnTouchListener(ZoomOnTouchListeners()) | |
} | |
private inner class ZoomOnTouchListeners : OnTouchListener { | |
override fun onTouch(view: View, motionEvent: MotionEvent): Boolean { | |
Timber.d(" :$LOG_APP_NAME: ZoomOnTouchListeners: :onTouch: ") | |
mScaleDetector!!.onTouchEvent(motionEvent) | |
matrix.getValues(m) | |
val x = m[Matrix.MTRANS_X] | |
val y = m[Matrix.MTRANS_Y] | |
val curr = PointF(motionEvent.x, motionEvent.y) | |
when (motionEvent.actionMasked) { | |
MotionEvent.ACTION_DOWN -> { | |
last[motionEvent.x] = motionEvent.y | |
start.set(last) | |
mode = DRAG | |
} | |
MotionEvent.ACTION_UP -> mode = NONE | |
MotionEvent.ACTION_POINTER_DOWN -> { | |
last[motionEvent.x] = motionEvent.y | |
start.set(last) | |
mode = ZOOM | |
} | |
MotionEvent.ACTION_MOVE -> if (mode == ZOOM || mode == DRAG && saveScale > minScale) { | |
var deltaX = curr.x - last.x // x difference | |
var deltaY = curr.y - last.y // y difference | |
if (y + deltaY > 0) deltaY = -y else if (y + deltaY < -bottom) deltaY = | |
-(y + bottom) | |
if (x + deltaX > 0) deltaX = -x else if (x + deltaX < -right) deltaX = | |
-(x + right) | |
matrix.postTranslate(deltaX, deltaY) | |
last[curr.x] = curr.y | |
} | |
MotionEvent.ACTION_POINTER_UP -> mode = NONE | |
} | |
setTransform(matrix) | |
this@ZoomableTextureView.invalidate() | |
return true | |
} | |
private inner class ScaleListener : SimpleOnScaleGestureListener() { | |
override fun onScaleBegin(detector: ScaleGestureDetector): Boolean { | |
mode = ZOOM | |
return true | |
} | |
override fun onScale(detector: ScaleGestureDetector): Boolean { | |
var mScaleFactor = detector.scaleFactor | |
val origScale = saveScale | |
saveScale *= mScaleFactor | |
if (saveScale > maxScale) { | |
saveScale = maxScale | |
mScaleFactor = maxScale / origScale | |
} else if (saveScale < minScale) { | |
saveScale = minScale | |
mScaleFactor = minScale / origScale | |
} | |
right = width * saveScale - width | |
bottom = height * saveScale - height | |
if (0 <= width || 0 <= height) { | |
matrix.postScale(mScaleFactor, mScaleFactor, detector.focusX, detector.focusY) | |
if (mScaleFactor < 1) { | |
matrix.getValues(m) | |
val x = m[Matrix.MTRANS_X] | |
val y = m[Matrix.MTRANS_Y] | |
if (mScaleFactor < 1) { | |
if (0 < width) { | |
if (y < -bottom) matrix.postTranslate( | |
0f, | |
-(y + bottom) | |
) else if (y > 0) matrix.postTranslate(0f, -y) | |
} else { | |
if (x < -right) matrix.postTranslate( | |
-(x + right), | |
0f | |
) else if (x > 0) matrix.postTranslate(-x, 0f) | |
} | |
} | |
} | |
} else { | |
matrix.postScale(mScaleFactor, mScaleFactor, detector.focusX, detector.focusY) | |
matrix.getValues(m) | |
val x = m[Matrix.MTRANS_X] | |
val y = m[Matrix.MTRANS_Y] | |
if (mScaleFactor < 1) { | |
if (x < -right) matrix.postTranslate( | |
-(x + right), | |
0f | |
) else if (x > 0) matrix.postTranslate(-x, 0f) | |
if (y < -bottom) matrix.postTranslate( | |
0f, | |
-(y + bottom) | |
) else if (y > 0) matrix.postTranslate(0f, -y) | |
} | |
} | |
return true | |
} | |
} | |
init { | |
m = FloatArray(9) | |
mScaleDetector = ScaleGestureDetector(context, ScaleListener()) | |
} | |
} | |
companion object { | |
private const val SUPERSTATE_KEY = "superState" | |
private const val MIN_SCALE_KEY = "minScale" | |
private const val MAX_SCALE_KEY = "maxScale" | |
private const val NONE = 0 | |
private const val DRAG = 1 | |
private const val ZOOM = 2 | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment