模仿侧滑效果
XML
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.zasko.library.ui.sliding.SlidingFrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.zasko.library.ui.sliding
android:layout_width="100dp"
android:layout_height="match_parent"
android:background="@color/black" />
</com.zasko.library.ui.sliding.SlidingFrameLayout>
</FrameLayout>
SlidingFrameLayout
import android.animation.ValueAnimator
import android.content.Context
import android.util.AttributeSet
import android.util.Log
import android.view.MotionEvent
import android.view.ViewConfiguration
import android.widget.FrameLayout
import androidx.core.view.forEach
import com.zasko.library.utils.TAG
import kotlin.math.abs
class SlidingFrameLayout @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null
) : FrameLayout(context, attrs) {
private var mTouchSlop: Int = 0
init {
mTouchSlop = ViewConfiguration.get(context).scaledTouchSlop
this.isClickable = true
}
private var allowRightTouch = true
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
Log.d(TAG, "onMeasure: widthMeasureSpec:${widthMeasureSpec} heightMeasureSpec:${heightMeasureSpec} width:${width}")
val widthMode = MeasureSpec.getMode(widthMeasureSpec)
val widthSize = MeasureSpec.getSize(widthMeasureSpec)
when (widthMode) {
MeasureSpec.AT_MOST -> {
Log.d(TAG, "onMeasure: widthMode AT_MOST widthSize:${widthSize}")
}
MeasureSpec.EXACTLY -> { //match_parent
Log.d(TAG, "onMeasure: widthMode EXACTLY widthSize:${widthSize}")
}
MeasureSpec.UNSPECIFIED -> {
Log.d(TAG, "onMeasure: widthMode UNSPECIFIED widthSize:${widthSize}")
}
}
forEach { child ->
// if (child is SlidingRightView) {
// //MeasureSpec.makeMeasureSpec()
// child.measure(widthMeasureSpec, heightMeasureSpec)
// }
}
if (rightViewStart == -1) {
rightViewStart = measuredWidth / 2
}
}
private var mRightScrollLen = 0F
private var rightViewStart = -1
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
super.onLayout(changed, left, top, right, bottom)
Log.d(TAG, "onLayout: left:$left top:$top right:$right bottom:$bottom")
forEach { child ->
if (child is SlidingRightView) {
val l = rightViewStart + mRightScrollLen.toInt()
child.layout(l, top, l + child.measuredWidth, bottom)
}
}
}
private var startX: Float = 0F
private var isStartMoving = false
private var mLastX = 0F
override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean {
if (allowRightTouch && ev != null) {
when (ev.action) {
MotionEvent.ACTION_DOWN -> {
isStartMoving = false
startX = ev.x
}
MotionEvent.ACTION_MOVE -> {
val diff = ev.x - startX
Log.e(TAG, "onInterceptTouchEvent: MotionEvent.ACTION_MOVE diff:${diff}")
if (abs(diff) >= mTouchSlop && diff < 0) {
return true
}
}
MotionEvent.ACTION_UP -> {
startX = 0F
}
}
}
val tmp = super.onInterceptTouchEvent(ev)
Log.d(TAG, "onInterceptTouchEvent: tmp:${tmp} ev:${ev}")
return tmp
}
private var mTmpMoveX = 0F
override fun onTouchEvent(event: MotionEvent?): Boolean {
event?.let { e ->
when (e.action) {
MotionEvent.ACTION_DOWN -> {
Log.d(TAG, "onTouchEvent: ACTION_DOWN")
mLastX = e.x
}
MotionEvent.ACTION_MOVE -> {
Log.d(TAG, "onTouchEvent: ACTION_MOVE")
moveRightView(e)
}
MotionEvent.ACTION_UP -> {
Log.d(TAG, "onTouchEvent: ACTION_UP")
stopRightMove()
}
else -> {
}
}
}
return super.onTouchEvent(event)
}
private fun moveRightView(event: MotionEvent) {
val moveX = event.x
var diffX = moveX - mLastX
if (diffX != mTmpMoveX) {
if (mRightScrollLen + diffX <= (-measuredWidth / 2)) {
diffX = -measuredWidth / 2 - (mRightScrollLen)
}
if (mRightScrollLen + diffX >= 0) {
diffX = 0 - mRightScrollLen
}
mTmpMoveX = diffX
mLastX = moveX
mRightScrollLen += diffX
Log.e(TAG, "onTouchEvent: mRightScrollLen:${mRightScrollLen} diffX:${diffX}")
requestLayout()
}
}
private fun stopRightMove() {
val diffX: Float = if (abs(mRightScrollLen) >= measuredWidth / 4) {
-measuredWidth / 2F
} else {
0F
}
Log.d(TAG, "stopRightMove: mRightScrollLen:${mRightScrollLen} diffX:${diffX}")
val ani = ValueAnimator.ofFloat(mRightScrollLen, diffX)
ani.addUpdateListener { animation ->
mRightScrollLen = animation.animatedValue as Float
requestLayout()
}
val time = 1 - abs(mRightScrollLen / (measuredWidth / 2))
ani.duration = (300 * abs(time)).toLong()
ani.start()
}
}
SlidingRightView
import android.content.Context
import android.util.AttributeSet
import android.widget.FrameLayout
class SlidingRightView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null
) : FrameLayout(context, attrs) {
}