blob: c08b9cb17965e006fcb9278d98687156eace2b3b [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.viewpager2.widget.swipe
import android.os.SystemClock
import android.view.animation.AccelerateInterpolator
import android.view.animation.Interpolator
import android.view.animation.LinearInterpolator
import androidx.core.view.ViewCompat
import androidx.viewpager2.widget.ViewPager2
import androidx.viewpager2.widget.ViewPager2.ORIENTATION_HORIZONTAL
import kotlin.math.max
import kotlin.math.roundToInt
class PageSwiperFakeDrag(private val viewPager: ViewPager2) : PageSwiper {
companion object {
// 60 fps
private const val FRAME_LENGTH_MS = 1000L / 60
private const val FLING_DURATION_MS = 100L
}
private val ViewPager2.pageSize: Int
get() {
return if (orientation == ORIENTATION_HORIZONTAL) {
measuredWidth - paddingLeft - paddingRight
} else {
measuredHeight - paddingTop - paddingBottom
}
}
private val needsRtlModifier
get() = viewPager.orientation == ORIENTATION_HORIZONTAL &&
ViewCompat.getLayoutDirection(viewPager) == ViewCompat.LAYOUT_DIRECTION_RTL
override fun swipeNext() {
fakeDrag(.5f, interpolator = AccelerateInterpolator())
}
override fun swipePrevious() {
fakeDrag(-.5f, interpolator = AccelerateInterpolator())
}
fun fakeDrag(
relativeDragDistance: Float,
duration: Long = FLING_DURATION_MS,
interpolator: Interpolator = LinearInterpolator()
) {
// Generate the deltas to feed to fakeDragBy()
val rtlModifier = if (needsRtlModifier) -1 else 1
val steps = max(1, (duration / FRAME_LENGTH_MS.toFloat()).roundToInt())
val distancePx = viewPager.pageSize * -relativeDragDistance * rtlModifier
val deltas = List(steps) { i ->
val currDistance = interpolator.getInterpolation((i + 1f) / steps) * distancePx
val prevDistance = interpolator.getInterpolation((i + 0f) / steps) * distancePx
currDistance - prevDistance
}
// Send the fakeDrag events
var eventTime = SystemClock.uptimeMillis()
val delayMs = { eventTime - SystemClock.uptimeMillis() }
viewPager.post { viewPager.beginFakeDrag() }
for (delta in deltas) {
eventTime += FRAME_LENGTH_MS
viewPager.postDelayed({ viewPager.fakeDragBy(delta) }, delayMs())
}
eventTime++
viewPager.postDelayed({ viewPager.endFakeDrag() }, delayMs())
}
}