use GestureFrameLayout for zooming gifs
This commit is contained in:
parent
fb0cffeb7c
commit
4e47a47c33
|
@ -74,7 +74,7 @@ dependencies {
|
||||||
implementation 'info.androidhive:imagefilters:1.0.7'
|
implementation 'info.androidhive:imagefilters:1.0.7'
|
||||||
implementation 'com.squareup.picasso:picasso:2.71828'
|
implementation 'com.squareup.picasso:picasso:2.71828'
|
||||||
implementation 'com.caverock:androidsvg-aar:1.3'
|
implementation 'com.caverock:androidsvg-aar:1.3'
|
||||||
implementation 'com.github.tibbi:gestureviews:bbad4ebfe6'
|
implementation 'com.github.tibbi:gestureviews:241d14fb68'
|
||||||
implementation 'com.github.tibbi:subsampling-scale-image-view:3ccd2f9c2b'
|
implementation 'com.github.tibbi:subsampling-scale-image-view:3ccd2f9c2b'
|
||||||
kapt 'com.github.bumptech.glide:compiler:4.8.0' // keep it here too, not just in Commons, else loading SVGs wont work
|
kapt 'com.github.bumptech.glide:compiler:4.8.0' // keep it here too, not just in Commons, else loading SVGs wont work
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,10 @@ package com.simplemobiletools.gallery.pro.fragments
|
||||||
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.graphics.*
|
import android.graphics.Bitmap
|
||||||
|
import android.graphics.BitmapFactory
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.graphics.Matrix
|
||||||
import android.graphics.drawable.ColorDrawable
|
import android.graphics.drawable.ColorDrawable
|
||||||
import android.graphics.drawable.PictureDrawable
|
import android.graphics.drawable.PictureDrawable
|
||||||
import android.media.ExifInterface.*
|
import android.media.ExifInterface.*
|
||||||
|
@ -105,6 +108,11 @@ class PhotoFragment : ViewPagerFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context.config.allowDownGesture) {
|
if (context.config.allowDownGesture) {
|
||||||
|
gif_view.setOnTouchListener { v, event ->
|
||||||
|
handleEvent(event)
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
gestures_view.controller.addOnStateChangeListener(object : GestureController.OnStateChangeListener {
|
gestures_view.controller.addOnStateChangeListener(object : GestureController.OnStateChangeListener {
|
||||||
override fun onStateChanged(state: State) {
|
override fun onStateChanged(state: State) {
|
||||||
mCurrentGestureViewZoom = state.zoom
|
mCurrentGestureViewZoom = state.zoom
|
||||||
|
@ -317,13 +325,10 @@ class PhotoFragment : ViewPagerFragment() {
|
||||||
InputSource.FileSource(pathToLoad)
|
InputSource.FileSource(pathToLoad)
|
||||||
}
|
}
|
||||||
|
|
||||||
mView.gestures_view.beGone()
|
mView.apply {
|
||||||
val resolution = mMedium.path.getImageResolution() ?: Point(0, 0)
|
gestures_view.beGone()
|
||||||
mView.gif_view.apply {
|
gif_view.setInputSource(source)
|
||||||
setInputSource(source)
|
gif_view_frame.beVisible()
|
||||||
setupGIFView(resolution.x, resolution.y, mScreenWidth, mScreenHeight) {
|
|
||||||
activity?.supportFinishAfterTransition()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
loadBitmap()
|
loadBitmap()
|
||||||
|
|
|
@ -104,7 +104,7 @@ abstract class ViewPagerFragment : Fragment() {
|
||||||
mTouchDownY = event.y
|
mTouchDownY = event.y
|
||||||
}
|
}
|
||||||
MotionEvent.ACTION_POINTER_DOWN -> mIgnoreCloseDown = true
|
MotionEvent.ACTION_POINTER_DOWN -> mIgnoreCloseDown = true
|
||||||
MotionEvent.ACTION_UP -> {
|
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
|
||||||
val diffX = mTouchDownX - event.x
|
val diffX = mTouchDownX - event.x
|
||||||
val diffY = mTouchDownY - event.y
|
val diffY = mTouchDownY - event.y
|
||||||
|
|
||||||
|
|
|
@ -1,179 +0,0 @@
|
||||||
package com.simplemobiletools.gallery.pro.views
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.graphics.Matrix
|
|
||||||
import android.graphics.RectF
|
|
||||||
import android.util.AttributeSet
|
|
||||||
import android.view.MotionEvent
|
|
||||||
import android.view.ScaleGestureDetector
|
|
||||||
import android.widget.ImageView
|
|
||||||
import com.simplemobiletools.commons.extensions.beVisible
|
|
||||||
import com.simplemobiletools.gallery.pro.extensions.config
|
|
||||||
import com.simplemobiletools.gallery.pro.helpers.*
|
|
||||||
import pl.droidsonroids.gif.GifTextureView
|
|
||||||
|
|
||||||
// allow horizontal swipes through the layout, else it can cause glitches at zoomed in images
|
|
||||||
class MyZoomableGifTextureView(context: Context, attrs: AttributeSet) : GifTextureView(context, attrs) {
|
|
||||||
private var mSaveScale = 1f
|
|
||||||
private var mLastTouchX = 0f
|
|
||||||
private var mLastTouchY = 0f
|
|
||||||
private var mTouchDownTime = 0L
|
|
||||||
private var mTouchDownX = 0f
|
|
||||||
private var mTouchDownY = 0f
|
|
||||||
private var mGifWidth = 0f
|
|
||||||
private var mGifHeight = 0f
|
|
||||||
private var mScreenWidth = 0f
|
|
||||||
private var mScreenHeight = 0f
|
|
||||||
private var mLastFocusX = 0f
|
|
||||||
private var mLastFocusY = 0f
|
|
||||||
private var mCloseDownThreshold = 100f
|
|
||||||
private var mIgnoreCloseDown = false
|
|
||||||
private var mCurrZoomMode = ZOOM_MODE_NONE
|
|
||||||
|
|
||||||
private var mScaleDetector: ScaleGestureDetector? = null
|
|
||||||
private var mMatrices = FloatArray(9)
|
|
||||||
private val mMatrix = Matrix()
|
|
||||||
private var mCurrentViewport = RectF()
|
|
||||||
private var mCloseDownCallback: (() -> Unit)? = null
|
|
||||||
|
|
||||||
init {
|
|
||||||
mScaleDetector = ScaleGestureDetector(context, ScaleListener())
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setupGIFView(gifWidth: Int, gifHeight: Int, screenWidth: Int, screenHeight: Int, callback: () -> Unit) {
|
|
||||||
mCloseDownCallback = callback
|
|
||||||
// if we don't know the gifs' resolution, just display it and disable zooming
|
|
||||||
if (gifWidth == 0 || gifHeight == 0) {
|
|
||||||
scaleType = ImageView.ScaleType.FIT_CENTER
|
|
||||||
mScaleDetector = null
|
|
||||||
beVisible()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
mSaveScale = 1f
|
|
||||||
mGifWidth = gifWidth.toFloat()
|
|
||||||
mGifHeight = gifHeight.toFloat()
|
|
||||||
mScreenWidth = screenWidth.toFloat()
|
|
||||||
mScreenHeight = screenHeight.toFloat()
|
|
||||||
|
|
||||||
// we basically want scaleType fitCenter, but we have to use matrices to reach that
|
|
||||||
val origRect = RectF(0f, 0f, mGifWidth, mGifHeight)
|
|
||||||
val wantedRect = RectF(0f, 0f, mScreenWidth, mScreenHeight)
|
|
||||||
mMatrix.setRectToRect(origRect, wantedRect, Matrix.ScaleToFit.CENTER)
|
|
||||||
mMatrix.getValues(mMatrices)
|
|
||||||
|
|
||||||
val left = mMatrices[Matrix.MTRANS_X]
|
|
||||||
val top = mMatrices[Matrix.MTRANS_Y]
|
|
||||||
val right = mScreenWidth - left
|
|
||||||
val bottom = mScreenHeight - top
|
|
||||||
mCurrentViewport.set(left, top, right, bottom)
|
|
||||||
|
|
||||||
setTransform(mMatrix)
|
|
||||||
invalidate()
|
|
||||||
beVisible()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onTouchEvent(event: MotionEvent): Boolean {
|
|
||||||
mScaleDetector?.onTouchEvent(event)
|
|
||||||
|
|
||||||
when (event.actionMasked) {
|
|
||||||
MotionEvent.ACTION_DOWN -> {
|
|
||||||
mTouchDownTime = System.currentTimeMillis()
|
|
||||||
mCurrZoomMode = ZOOM_MODE_DRAG
|
|
||||||
mLastTouchX = event.x
|
|
||||||
mLastTouchY = event.y
|
|
||||||
|
|
||||||
mTouchDownX = event.x
|
|
||||||
mTouchDownY = event.y
|
|
||||||
}
|
|
||||||
MotionEvent.ACTION_UP -> {
|
|
||||||
val diffX = mTouchDownX - event.x
|
|
||||||
val diffY = mTouchDownY - event.y
|
|
||||||
mCurrZoomMode = ZOOM_MODE_NONE
|
|
||||||
if (Math.abs(diffX) < CLICK_MAX_DISTANCE && Math.abs(diffY) < CLICK_MAX_DISTANCE && System.currentTimeMillis() - mTouchDownTime < CLICK_MAX_DURATION) {
|
|
||||||
performClick()
|
|
||||||
} else {
|
|
||||||
val downGestureDuration = System.currentTimeMillis() - mTouchDownTime
|
|
||||||
val areDiffsOK = Math.abs(diffY) > Math.abs(diffX) && diffY < -mCloseDownThreshold
|
|
||||||
if (mSaveScale == 1f && !mIgnoreCloseDown && areDiffsOK && context.config.allowDownGesture && downGestureDuration < MAX_CLOSE_DOWN_GESTURE_DURATION) {
|
|
||||||
mCloseDownCallback?.invoke()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mIgnoreCloseDown = false
|
|
||||||
}
|
|
||||||
MotionEvent.ACTION_POINTER_DOWN -> {
|
|
||||||
mLastTouchX = event.x
|
|
||||||
mLastTouchY = event.y
|
|
||||||
mCurrZoomMode = ZOOM_MODE_ZOOM
|
|
||||||
mIgnoreCloseDown = true
|
|
||||||
}
|
|
||||||
MotionEvent.ACTION_MOVE -> {
|
|
||||||
if (mCurrZoomMode == ZOOM_MODE_ZOOM || mCurrZoomMode == ZOOM_MODE_DRAG && mSaveScale > MIN_VIDEO_ZOOM_SCALE) {
|
|
||||||
var diffX = event.x - mLastTouchX
|
|
||||||
|
|
||||||
// horizontal bounds
|
|
||||||
if (mCurrentViewport.left >= 0) {
|
|
||||||
diffX = -mCurrentViewport.left
|
|
||||||
} else if (mCurrentViewport.right + diffX >= mScreenWidth * mSaveScale) {
|
|
||||||
diffX = -((mScreenWidth * mSaveScale) - mCurrentViewport.right)
|
|
||||||
}
|
|
||||||
|
|
||||||
mCurrentViewport.left += diffX
|
|
||||||
mCurrentViewport.right += diffX
|
|
||||||
|
|
||||||
mMatrix.postTranslate(diffX, 0f)
|
|
||||||
|
|
||||||
mCurrentViewport.left = Math.max(mCurrentViewport.left, 0f)
|
|
||||||
mCurrentViewport.right = Math.min(mCurrentViewport.right, mScreenWidth)
|
|
||||||
|
|
||||||
mLastTouchX = event.x
|
|
||||||
mLastTouchY = event.y
|
|
||||||
}
|
|
||||||
}
|
|
||||||
MotionEvent.ACTION_POINTER_UP -> {
|
|
||||||
mCurrZoomMode = ZOOM_MODE_NONE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setTransform(mMatrix)
|
|
||||||
invalidate()
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// taken from https://github.com/Manuiq/ZoomableTextureView
|
|
||||||
private inner class ScaleListener : ScaleGestureDetector.SimpleOnScaleGestureListener() {
|
|
||||||
override fun onScaleBegin(detector: ScaleGestureDetector): Boolean {
|
|
||||||
mCurrZoomMode = ZOOM_MODE_ZOOM
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onScale(detector: ScaleGestureDetector): Boolean {
|
|
||||||
if (width <= 0 || height <= 0) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
mLastFocusX = detector.focusX
|
|
||||||
mLastFocusY = detector.focusY
|
|
||||||
var scaleFactor = detector.scaleFactor
|
|
||||||
val origScale = mSaveScale
|
|
||||||
mSaveScale *= scaleFactor
|
|
||||||
|
|
||||||
if (mSaveScale > MAX_VIDEO_ZOOM_SCALE) {
|
|
||||||
mSaveScale = MAX_VIDEO_ZOOM_SCALE
|
|
||||||
scaleFactor = MAX_VIDEO_ZOOM_SCALE / origScale
|
|
||||||
} else if (mSaveScale < MIN_VIDEO_ZOOM_SCALE) {
|
|
||||||
mSaveScale = MIN_VIDEO_ZOOM_SCALE
|
|
||||||
scaleFactor = MIN_VIDEO_ZOOM_SCALE / origScale
|
|
||||||
}
|
|
||||||
|
|
||||||
mMatrix.postScale(scaleFactor, scaleFactor, detector.focusX, detector.focusY)
|
|
||||||
mMatrix.getValues(mMatrices)
|
|
||||||
val left = mMatrices[Matrix.MTRANS_X]
|
|
||||||
val top = mMatrices[Matrix.MTRANS_Y]
|
|
||||||
val right = mScreenWidth - left
|
|
||||||
val bottom = mScreenHeight - top
|
|
||||||
mCurrentViewport.set(left, top, right, bottom)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -11,12 +11,20 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"/>
|
android:layout_height="match_parent"/>
|
||||||
|
|
||||||
<com.simplemobiletools.gallery.pro.views.MyZoomableGifTextureView
|
<com.alexvasilkov.gestures.GestureFrameLayout
|
||||||
android:id="@+id/gif_view"
|
android:id="@+id/gif_view_frame"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:scaleType="matrix"
|
android:layout_centerInParent="true"
|
||||||
android:visibility="gone"/>
|
android:visibility="gone">
|
||||||
|
|
||||||
|
<pl.droidsonroids.gif.GifTextureView
|
||||||
|
android:id="@+id/gif_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:scaleType="fitCenter"/>
|
||||||
|
|
||||||
|
</com.alexvasilkov.gestures.GestureFrameLayout>
|
||||||
|
|
||||||
<com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
|
<com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
|
||||||
android:id="@+id/subsampling_view"
|
android:id="@+id/subsampling_view"
|
||||||
|
|
Loading…
Reference in New Issue