[go: nahoru, domu]

blob: 96f09113b0b523a7bc44c87f463b524fef652b52 [file] [log] [blame]
/*
* Copyright 2019 The Android Open Source Project
*
* 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 androidx.ui.core.gesture
import androidx.compose.remember
import androidx.ui.core.Modifier
import androidx.ui.core.composed
/**
* Observes various events sent by [scaleGestureFilter]. Implement and pass into
* [scaleGestureFilter] so that [scaleGestureFilter] may call the functions when events occur.
*/
interface ScaleObserver {
/**
* Override to be notified when scaling has started.
*
* This will be called when scaling occurs and a single pointer moves far enough to suggest
* the user intends to perform scaling (the required drag distance is defined by
* [TouchSlop]). Always called just before [onScale] and isn't called again until
* after [onStop].
*
* @see scaleGestureFilter
* @see onScale
* @see onStop
*/
fun onStart() {}
/**
* Override to be notified when scaling has occurred.
*
* Always called just after [onStart] (and for every subsequent scale).
*
* @param scaleFactor The ratio of newSize / oldSize that the scaling gesture has expressed
* between pointers last position and current position (this value is not cumulative over the
* lifetime of of the gesture). For example, if 2 fingers are 10 pixel apart, and then move
* such that they are 20 pixels apart, the scaleFactor will be 2. If 2 fingers that are 20
* pixels apart move such that they are 10 pixels apart, the scaleFactor will be .5.
*
* @see scaleGestureFilter
* @see onStart
* @see onStop
*
*/
fun onScale(scaleFactor: Float)
/**
* Override to be notified when scaling has stopped.
*
* This is called once less than 2 pointers remain.
*
* Only called after [onStart] and one or more calls to [onScale]
*
* @see scaleGestureFilter
* @see onStart
* @see onScale
*/
fun onStop() {}
/**
* Override to be notified when the scale has been cancelled.
*
* This is called if [onStart] has ben called and then a cancellation event has occurs
* (for example, due to the gesture detector being removed from the tree) before [onStop] is
* called.
*/
fun onCancel() {}
}
/**
* This gesture detector detects scaling.
*
* Scaling is when the average distance between a set of pointers changes over time. It is
* also known as pinch, or pinch to zoom.
*
* Scaling begins when the average distance between a set of pointers changes and at least 1 pointer
* moves beyond the touch slop distance (currently defined by [TouchSlop]). When scaling begins,
* [ScaleObserver.onStart] is called followed immediately by a call to [ScaleObserver.onScale].
* [ScaleObserver.onScale] is then continuously called whenever the movement of pointers denotes
* scaling. The gesture stops with either a call to [RawScaleObserver.onStop] or
* [RawScaleObserver.onCancel], either of which will only be called if [RawScaleObserver.onStart]
* was previously called. [RawScaleObserver.onStop] is called when no pointers remain.
* [RawScaleObserver.onCancel] is called due to a system cancellation event.
*
* This gesture detector is similar to [rawScaleGestureFilter] except that it is made for more
* standard use cases where touch slop should likely be respected and no "nested scaling" is
* needed.
*
* @param scaleObserver The callback interface to report all events related to scaling.
*/
fun Modifier.scaleGestureFilter(
scaleObserver: ScaleObserver
): Modifier = composed {
val glue = remember { TouchSlopScaleGestureDetectorGlue() }
glue.scaleObserver = scaleObserver
rawScaleGestureFilter(glue.rawScaleObserver, glue::scaleEnabled)
.scaleSlopExceededGestureFilter(glue::enableScale)
}
/**
* Glues together the logic of RawScaleGestureDetector and TouchSlopExceededGestureDetector.
*/
private class TouchSlopScaleGestureDetectorGlue {
lateinit var scaleObserver: ScaleObserver
var scaleEnabled = false
fun enableScale() {
scaleEnabled = true
}
val rawScaleObserver: RawScaleObserver =
object : RawScaleObserver {
override fun onStart() {
scaleObserver.onStart()
}
override fun onScale(scaleFactor: Float): Float {
scaleObserver.onScale(scaleFactor)
return scaleFactor
}
override fun onStop() {
scaleEnabled = false
scaleObserver.onStop()
}
override fun onCancel() {
scaleEnabled = false
scaleObserver.onCancel()
}
}
}