import android.animation.ObjectAnimator
import android.util.SparseArray
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import android.view.animation.DecelerateInterpolator
import com.xiaolei.library.Exts.onAnim
import java.util.LinkedHashMap
/**
* @param view 需要阻尼滑动的控件
* @param damping 阻尼值,越小越难拉动
*/
class DampTouchListener(val view: ViewGroup, var damping: Float = 10f) : View.OnTouchListener
{
private val juli = SparseArray<Float>()
private var translationCount = 0.0f
private val childAnimMap = LinkedHashMap<View, ObjectAnimator>()
override fun onTouch(v: View, ev: MotionEvent): Boolean
{
// 没有子节点还阻尼滚动个毛啊
if (view.childCount == 0)
{
return false
}
// 子控件数量不对,肯定要清空重新添加一次啊
if (view.childCount != childAnimMap.size)
{
childAnimMap.clear()
for (index in 0 until view.childCount)
{
val childView = view.getChildAt(index)
childAnimMap[childView] = generateViewAnim(childView).apply {
onAnim(onStart = {
v.setOnTouchListener(null)
}, onEnd = {
v.setOnTouchListener(this@DampTouchListener)
})
}
}
}
// 能不能往上推了
val canUp = view.canScrollVertically(1)
// 能不能往下拉了
val canDown = view.canScrollVertically(-1)
when (ev.actionMasked)
{
// 每个手指按下,记录下每个手指ID,以及记录每个手指的位置
MotionEvent.ACTION_DOWN, MotionEvent.ACTION_POINTER_DOWN ->
{
val index = ev.actionIndex
val id = ev.getPointerId(index)
for (entry in childAnimMap)
{
entry.value.cancel()
}
juli.put(id, ev.getY(index))
}
MotionEvent.ACTION_MOVE ->
{
if (!canDown || !canUp)
{
var tmpCount = translationCount
/**
* 在屏幕上滑动的时候,
* 记录下每个手指的位置,
* 算出每个手指一动的距离juli,
* 并且所有子控件都往那边移动
* 考虑到两个手指爬来爬去
*/
for (index in 0 until ev.pointerCount) // 屏幕上指头的数量
{
val pointerId = ev.getPointerId(index) // 每个指头的ID
val lastY = juli.get(pointerId) // 根据每个指头ID,获取它上一个位置
tmpCount += ev.getY(index) - lastY // 需要移动总数,把所有指头移动的距离加起来
if (Math.abs(tmpCount) <= Math.abs(translationCount))
{
continue
}
for (entry in childAnimMap) // 循环所有子控件
{
val childView = entry.key
// 将所有子控件往那边移动,距离通过阻尼计算出值
childView.translationY = calDampValue(tmpCount)
}
// 更新所有的指头的现在的值
juli.put(pointerId, ev.getY(index))
}
return if (Math.abs(tmpCount) > Math.abs(translationCount))
{
translationCount = tmpCount
false
} else
{
true
}
}
}
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL ->
{
// 手指一松开,或者移动开位置(取消),则将使用属性动画,将所有控件位置还原
translationCount = 0f
// juli.clear()
for (entry in childAnimMap)
{
val childView = entry.key
val animator = entry.value
animator.setFloatValues(childView.translationY, 0f)
animator.start()
}
}
}
return false
}
/**
* 计算阻尼值
*
* @param value
* @return
*/
private fun calDampValue(value: Float): Float
{
return if (value < 0)
-Math.sqrt((2f * damping * Math.abs(value)).toDouble()).toFloat()
else
Math.sqrt((2f * damping * value).toDouble()).toFloat()
}
/**
* 生成一个动画
*/
private fun generateViewAnim(view: View) = ObjectAnimator().apply {
duration = 200
propertyName = "translationY"
target = view
interpolator = DecelerateInterpolator()
}
}
转载于:https://my.oschina.net/xiaolei123/blog/2999706