use GestureFrameLayout for zooming gifs

This commit is contained in:
tibbi 2019-01-29 10:21:10 +01:00
parent fb0cffeb7c
commit 4e47a47c33
5 changed files with 27 additions and 193 deletions

View file

@ -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

View file

@ -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()

View file

@ -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

View file

@ -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
}
}
}

View file

@ -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"