Skip to content

Instantly share code, notes, and snippets.

@sagarpatel288
Created September 1, 2021 20:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sagarpatel288/aa2bf8c17f80ce5b5d351e4012edf755 to your computer and use it in GitHub Desktop.
Save sagarpatel288/aa2bf8c17f80ce5b5d351e4012edf755 to your computer and use it in GitHub Desktop.
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