Android中球体碰撞代码分享-kotlin,入门版

复制代码
* 可以产生形变,回弹的小球
*
* 整个view的核心:
* Scroller函数
* 1.调用scroller.public void startScroll(int startX, int startY, int dx, int dy, int duration);
* 在指定时间范围内,startX,startY,会移动dx,dy距离
*
* 2.然后调用:invalidate(); 系统内部会调用onDraw();
*
* 3.在onDraw方法内部又会调用  computeScrollOffset()函数。
* 所以,实现scroll.computeScrollOffset(); //如果还没有完全移动完成,就执行XXXXX
*
* 4.如果返回true 继续调用 invalidate();
*
* 这样就会在位移的过程中,执行你:  if(scroll.computeScrollOffset()){
* //你自己的方法
* }
*
Kotlin 复制代码
class BallViewTwo @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null
) : androidx.appcompat.widget.AppCompatImageView(context, attrs) {
    private var mContext: Context = context

    //屏幕的宽高
    private var displayHeight: Int = 0
    private var displayWidth: Int = 0

    private var changelength = 30 //第一次形变的大小
    private var mCurrentDirection = -1 //碰撞后,此时的方向
    private var mDuration = 450 //变形需要持续的时间

    /**
     * flag=-1 正常移动
     * flag=0 压缩变形
     * flag=1 恢复压缩形变
     * flag=2 往相反的方向弹
     * flag=3 弹回原先的位置
     */
    private var flag = -1
    private var mShotOver: ShotOver? = null //回调函数
    private var moveToLeft = 100 //正常状态下,小球移动到x轴的位置
    private var moveToTop = 100 //正常状态下,小球移动到y轴的位置
    private val centerX = 180 //小球圆心x
    private val centerY = 180 //小球圆心y
    private val radius = 180 //半径
    private val bubbleWidth = radius * 2 //小球的宽
    private val bubbleHeight = radius * 2 //小球的高

    private var paint: Paint // 画笔
    private var scroller: Scroller // 整个view的核心
    private var rectF: RectF? = null //绘制椭圆
    private var ovalLeft = 0
    private var ovalTop = 0
    private var ovalRight = 0
    private var ovalBottom = 0 //椭圆的左上右下
    private var currY = 0
    private var currX = 0
    private var offset = 0 //发生的移动量

    private val shotBackDuration = 100 //回弹执行的时间
    private val shotBackChange = 15 //回弹需要移动的距离
    private var newOvalLeft = 0
    private var newOvalTop = 0
    private var newOvalRight = 0
    private var newOvalBottom = 0

    private var isShotBack = true // 是否开启回弹效果

    init {
        paint = Paint()
        paint.color = Color.RED
        scroller = Scroller(context)
        rectF = RectF()
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        displayHeight = mContext.resources.displayMetrics.heightPixels
        displayWidth = mContext.resources.displayMetrics.widthPixels
        Log.i("qq", "ballview-------displayHeight=-$displayHeight displayWidth=$displayWidth")
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
    }

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
    }

    override fun onDraw(canvas: Canvas) {
        when (flag) {
            -1 -> {
                canvas.translate(moveToLeft.toFloat(), moveToTop.toFloat())
                canvas.drawCircle(centerX.toFloat(), centerY.toFloat(), radius.toFloat(), paint)
                Log.i("qq", "正常移动小球 小球left=$moveToLeft top=$moveToTop")
            }

            0 -> circleToOval(canvas)
            1 -> ovalToCircle(canvas)
            2 -> shotBackLeaveBounds(canvas)
            3 -> shotBackGotoBounds(canvas)
        }
        super.onDraw(canvas)
    }

    /**
     * 小球变形完再回弹,靠近边界
     */
    private fun shotBackGotoBounds(canvas: Canvas) {
        if (scroller.computeScrollOffset()) {
            ovalLeft = scroller.currX
            ovalTop = scroller.currY
            canvas.translate(ovalLeft.toFloat(), ovalTop.toFloat())
            canvas.drawCircle(centerX.toFloat(), centerY.toFloat(), radius.toFloat(), paint)
            invalidate()
            Log.i("shotBack", "远离边界。。moveToLeft=$ovalLeft moveToTop=$ovalTop")
        } else {
            Log.i("shotBack", "所有效果都结束")
            canvas.translate(ovalLeft.toFloat(), ovalTop.toFloat())
            canvas.drawCircle(centerX.toFloat(), centerY.toFloat(), radius.toFloat(), paint)
            isShotBack = false
            startChange(shotBackChange)
        }
    }

    /**
     * 小球变形完再回弹,也就是远离边界
     */
    private fun shotBackLeaveBounds(canvas: Canvas) {
        if (scroller.computeScrollOffset()) {
            ovalLeft = scroller.currX
            ovalTop = scroller.currY
            canvas.translate(ovalLeft.toFloat(), ovalTop.toFloat())
            canvas.drawCircle(centerX.toFloat(), centerY.toFloat(), radius.toFloat(), paint!!)
            invalidate()
            Log.i("shotBack", "远离边界。。moveToLeft=$ovalLeft moveToTop=$ovalTop")
        } else {
            canvas.translate(ovalLeft.toFloat(), ovalTop.toFloat())
            canvas.drawCircle(centerX.toFloat(), centerY.toFloat(), radius.toFloat(), paint!!)
            flag = 3
            finishShotBack()
        }
    }


    /**
     * 将椭圆恢复成圆形
     */
    private fun ovalToCircle(canvas: Canvas) {
        if (scroller!!.computeScrollOffset()) {
            when (mCurrentDirection) {
                0 -> {
                    currY = scroller!!.currY
                    offset = newOvalTop - currY
                    ovalLeft = newOvalLeft + offset
                    ovalTop = currY + offset
                    ovalRight = newOvalRight - offset
                    ovalBottom = newOvalBottom + offset + offset
                    rectF!![ovalLeft.toFloat(), ovalTop.toFloat(), ovalRight.toFloat()] =
                        ovalBottom.toFloat()
                    canvas.drawOval(rectF!!, paint!!)

                    Log.i(
                        "qq",
                        "将椭圆----恢复成圆形,方向向北 currY=$currY offset=$offset"
                    )
                    Log.i(
                        "qq",
                        "将椭圆----恢复成圆形,方向向北 ovalLeft=$ovalLeft ovalTop=$ovalTop ovalRight=$ovalRight ovalBottom=$ovalBottom"
                    )
                }

                1 -> {
                    currX = scroller!!.currX
                    offset = newOvalLeft - currX
                    ovalLeft = currX - offset
                    ovalTop = newOvalTop + offset
                    ovalRight = newOvalRight + offset - offset
                    ovalBottom = newOvalBottom - offset
                    rectF!![ovalLeft.toFloat(), ovalTop.toFloat(), ovalRight.toFloat()] =
                        ovalBottom.toFloat()
                    canvas.drawOval(rectF!!, paint!!)
                }

                2 -> {
                    currY = scroller!!.currY
                    offset = newOvalTop - currY
                    ovalLeft = newOvalLeft + offset
                    ovalTop = currY - offset
                    ovalRight = newOvalRight - offset
                    ovalBottom = newOvalBottom
                    rectF!![ovalLeft.toFloat(), ovalTop.toFloat(), ovalRight.toFloat()] =
                        ovalBottom.toFloat()
                    canvas.drawOval(rectF!!, paint!!)

                    Log.i(
                        "qq",
                        "将椭圆----恢复成圆形,方向向南 currY=$currY offset=$offset"
                    )
                    Log.i(
                        "qq",
                        "将椭圆----恢复成圆形,方向向南 ovalLeft=$ovalLeft ovalTop=$ovalTop ovalRight=$ovalRight ovalBottom=$ovalBottom"
                    )
                }

                3 -> {
                    currX = scroller!!.currX
                    offset = newOvalLeft - currX
                    ovalLeft = currX + offset
                    ovalTop = newOvalTop + offset
                    ovalRight = newOvalRight + offset + offset
                    ovalBottom = newOvalBottom - offset
                    rectF!![ovalLeft.toFloat(), ovalTop.toFloat(), ovalRight.toFloat()] =
                        ovalBottom.toFloat()
                    canvas.drawOval(rectF!!, paint!!)
                }
            }
            invalidate()
        } else {
            canvas.drawOval(rectF!!, paint!!)

//如果需要回弹的话
            if (isShotBack) {
                flag = 2
                startShotBack()
            } else {
                flag = -1
                if (mShotOver != null) {
                    mShotOver!!.bubbleShotEnd()
                }
            }
        }
    }

    /**
     * 圆挤压成椭圆
     */
    private fun circleToOval(canvas: Canvas) {
        if (scroller!!.computeScrollOffset()) {
            when (mCurrentDirection) {
                0 -> {
                    currY = scroller!!.currY
                    offset = currY - ovalTop
                    newOvalLeft = ovalLeft - offset
                    newOvalTop = currY - offset
                    newOvalRight = ovalRight + offset
                    newOvalBottom = ovalBottom - offset - offset
                    rectF!![newOvalLeft.toFloat(), newOvalTop.toFloat(), newOvalRight.toFloat()] =
                        newOvalBottom.toFloat()
                    canvas.drawOval(rectF!!, paint!!)
                }

                1 -> {
                    currX = scroller!!.currX
                    offset = currX - ovalLeft
                    newOvalLeft = currX + offset
                    newOvalTop = ovalTop - offset
                    newOvalRight = ovalRight - offset + offset
                    newOvalBottom = ovalBottom + offset
                    rectF!![newOvalLeft.toFloat(), newOvalTop.toFloat(), newOvalRight.toFloat()] =
                        newOvalBottom.toFloat()
                    canvas.drawOval(rectF!!, paint!!)
                }

                2 -> {
                    currY = scroller!!.currY
                    offset = currY - ovalTop
                    newOvalLeft = ovalLeft - offset
                    newOvalTop = currY + offset
                    newOvalRight = ovalRight + offset
                    newOvalBottom = ovalBottom
                    rectF!![newOvalLeft.toFloat(), newOvalTop.toFloat(), newOvalRight.toFloat()] =
                        newOvalBottom.toFloat()
                    canvas.drawOval(rectF!!, paint!!)

                    Log.i("qq", "圆挤压成椭圆,方向向南 currY=$currY offset=$offset")
                    Log.i(
                        "qq",
                        "圆挤压成椭圆,方向向南 newOvalLeft=$newOvalLeft newOvalTop=$newOvalTop newOvalRight=$newOvalRight newOvalBottom=$newOvalBottom"
                    )
                }

                3 -> {
                    currX = scroller!!.currX
                    offset = currX - ovalLeft
                    newOvalLeft = currX - offset
                    newOvalTop = ovalTop - offset
                    newOvalRight = ovalRight - offset - offset
                    newOvalBottom = ovalBottom + offset
                    rectF!![newOvalLeft.toFloat(), newOvalTop.toFloat(), newOvalRight.toFloat()] =
                        newOvalBottom.toFloat()
                    canvas.drawOval(rectF!!, paint!!)
                }
            }
            invalidate()
        } else {
            canvas.drawOval(rectF!!, paint!!)
            reverse()
        }
    }


    /**
     * 碰撞变形结束后,开启弹一弹效果
     */
    fun startShotBack() {
        when (mCurrentDirection) {
            0 -> scroller!!.startScroll(ovalLeft, ovalTop, 0, shotBackChange, shotBackDuration)
            1 -> scroller!!.startScroll(ovalLeft, ovalTop, -shotBackChange, 0, shotBackDuration)
            2 -> scroller!!.startScroll(ovalLeft, ovalTop, 0, -shotBackChange, shotBackDuration)
            3 -> scroller!!.startScroll(ovalLeft, ovalTop, shotBackChange, 0, shotBackDuration)
        }
        invalidate()
    }

    /**
     * 结束 "弹的一段距离"
     */
    fun finishShotBack() {
        when (mCurrentDirection) {
            0 -> scroller!!.startScroll(ovalLeft, ovalTop, 0, -shotBackChange, shotBackDuration)
            1 -> scroller!!.startScroll(ovalLeft, ovalTop, shotBackChange, 0, shotBackDuration)
            2 -> scroller!!.startScroll(ovalLeft, ovalTop, 0, shotBackChange, shotBackDuration)
            3 -> scroller!!.startScroll(ovalLeft, ovalTop, -shotBackChange, 0, shotBackDuration)
        }
        invalidate()
    }

    /**
     * 移动小球
     */
    fun moveTo(l: Int, t: Int, direction: Int, duration: Int, shotBack: Boolean) {
        isShotBack = shotBack
        mDuration = duration
        mCurrentDirection = direction
        moveToLeft = l
        moveToTop = t

        if (t == 0) {
            mCurrentDirection = 0
            startChange(30)
        } else if (l == displayWidth - bubbleWidth) {
            mCurrentDirection = 1
            startChange(30)
        } else if (t == displayHeight - bubbleHeight) {
            mCurrentDirection = 2
            startChange(30)
        } else if (l == 0) {
            mCurrentDirection = 3
            startChange(30)
        } else {
            invalidate()
        }
    }

    /**
     * 开始变形
     */
    private fun startChange(change: Int) {
        changelength = change
        if (mShotOver != null) {
            mShotOver!!.bubbleShotStart(mCurrentDirection)
        }
        flag = 0
//发生变形时,先初始化椭圆刚发生变形时的位置
        ovalLeft = moveToLeft
        ovalTop = moveToTop
        ovalRight = moveToLeft + bubbleWidth
        ovalBottom = ovalTop + bubbleHeight

        when (mCurrentDirection) {
            0 -> scroller!!.startScroll(moveToLeft, moveToTop, 0, changelength, mDuration)
            1 -> scroller!!.startScroll(moveToLeft, moveToTop, changelength, 0, mDuration)
            2 -> scroller!!.startScroll(moveToLeft, moveToTop, 0, changelength, mDuration)
            3 -> scroller!!.startScroll(moveToLeft, moveToTop, changelength, 0, mDuration)
        }
        Log.i(
            "qq",
            "小球开始变形,方向=$mCurrentDirection 当前小球的坐标ovalLeft=$ovalLeft ovalTop=$ovalTop ovalRight=$ovalRight ovalBottom=$ovalBottom"
        )
        invalidate()
    }

    /**
     * 回复变形前的状态
     */
    private fun reverse() {
        flag = 1
        when (mCurrentDirection) {
            0 -> scroller!!.startScroll(newOvalLeft, newOvalTop, 0, -changelength, mDuration)
            1 -> scroller!!.startScroll(newOvalLeft, newOvalTop, -changelength, 0, mDuration)
            2 -> scroller!!.startScroll(newOvalLeft, newOvalTop, 0, -changelength, mDuration)
            3 -> scroller!!.startScroll(newOvalLeft, newOvalTop, -changelength, 0, mDuration)
        }
        invalidate()
    }

    fun setShotOver(shotOver: ShotOver?) {
        mShotOver = shotOver
    }

    /**
     * 碰撞变形效果完成
     */
    interface ShotOver {
        fun bubbleShotStart(direction: Int)
        fun bubbleShotEnd()
    }
    /**
     * (辅助函数)//没有实现效果
     * 圆挤压成椭圆时,变形加速减少
     */
    /*
    public void circleToOvalAndAcceleratedReduce(Canvas canvas){

    if(gradient == 0){
    newOvalLeft = ovalLeft;
    newOvalTop = ovalTop;
    newOvalRight = ovalRight;
    newOvalBottom = ovalBottom;
    }

    if((offset - oldOffset) >= 10 && gradient == 0){

    Log.i("qq", "移动距离大于10时绘制一次");

    newOvalLeft = ovalLeft - offset;
    newOvalTop = currY - offset;
    newOvalRight = ovalRight + offset;
    newOvalBottom = ovalBottom - offset - offset;
    rectF.set(newOvalLeft, newOvalTop, newOvalRight, newOvalBottom);
    canvas.drawOval(rectF, paint);
    oldOffset = offset;
    gradient = 1;
    }else if((offset - oldOffset) >= 7 && gradient == 1){
    Log.i("qq", "移动距离大于7时绘制一次");
    newOvalLeft = ovalLeft - offset;
    newOvalTop = currY - offset;
    newOvalRight = ovalRight + offset;
    newOvalBottom = ovalBottom - offset - offset;
    rectF.set(newOvalLeft, newOvalTop, newOvalRight, newOvalBottom);
    canvas.drawOval(rectF, paint);
    gradient = 2;
    oldOffset = offset;
    }else if((offset - oldOffset) >= 4 && gradient == 2){
    Log.i("qq","移动距离大于4时绘制一次");
    newOvalLeft = ovalLeft - offset;
    newOvalTop = currY - offset;
    newOvalRight = ovalRight + offset;
    newOvalBottom = ovalBottom - offset - offset;
    rectF.set(newOvalLeft, newOvalTop, newOvalRight, newOvalBottom);
    canvas.drawOval(rectF, paint);
    gradient = 3;
    oldOffset = offset;

    }else if((offset - oldOffset) >= 2 && gradient == 3){
    Log.i("qq","移动距离大于2时绘制一次");
    newOvalLeft = ovalLeft - offset;
    newOvalTop = currY - offset;
    newOvalRight = ovalRight + offset;
    newOvalBottom = ovalBottom - offset - offset;
    rectF.set(newOvalLeft, newOvalTop, newOvalRight, newOvalBottom);
    canvas.drawOval(rectF, paint);
    gradient = -1;
    oldOffset = offset;

    }else{
    Log.i("qq", "移动绘制一次");
    rectF.set(newOvalLeft, newOvalTop, newOvalRight, newOvalBottom);
    canvas.drawOval(rectF, paint);
    }

    Log.i("qq", "圆挤压成椭圆,方向向北 currY=" + currY + " offset=" + offset);
    Log.i("qq", "圆挤压成椭圆,方向向北 newOvalLeft=" + newOvalLeft + " newOvalTop=" + newOvalTop + " newOvalRight=" + newOvalRight + " newOvalBottom=" + newOvalBottom);
    }*/
}
Kotlin 复制代码
/**
 * 1.根据重力感应移动小球
 * 2.一般重力感应使用的重力加速,这样的话每次移动距离不是固定的
 * 3.此应用,将速度固定。
 * 4.小球碰撞到边缘时,会发生形变。(小球压缩形变)
 * 5.可以点击按钮添加,发生形变后回弹效果
 */
class AnimationActivity : Activity(), View.OnClickListener {

    private var sensorManager: SensorManager? = null
    private var sensor: Sensor? = null
    private var init = false

    // 因为布局是填充父窗体的,且设置了出掉状态栏,所有求出的宽高就是屏幕的宽高。
    private var containerWidth = 0
    private var containerHeight = 0

    // 小球的宽高
    private val ballWidth = 360
    private val ballHeight = 360

    // 自定义球
    private lateinit var ball: BallViewTwo

    // 小球的起始位置
    private var ballX = 100f
    private var ballY = 100f

    private var currentState = -1 // 初始方向
    private var shotDirection = -1 // 小球发生碰撞时的那刻的方向

    // 初始化 东 西 南 北 四个方向
    private val NORTH = 0
    private val EAST = 1
    private val SOUTH = 2
    private val WEST = 3

    private var constantsSpeed = 100 // 每次斜边移动的距离
    private val SPEED = 10 // 比例
    private var canMove = true // 小球是否可以移动

    private val durationPiece = 150 // 执行动画的时间块
    private var duration = 450 // 初始速度下的执行时间
    private var isShotBack = false

    /**
     * -1: 小球正常移动
     * 0: 小球正在碰撞
     * 1: 小球碰撞刚结束
     */
    private var shot = -1

    /** Called when the activity is first created. */
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        window.setFlags(
            WindowManager.LayoutParams.FLAG_FULLSCREEN,
            WindowManager.LayoutParams.FLAG_FULLSCREEN
        )
        setContentView(R.layout.activity_animation)

        // 初始化重力感应
        sensorManager = getSystemService(SENSOR_SERVICE) as SensorManager
        sensor = sensorManager!!.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
    }

    private fun init() {
        val container = findViewById<View>(R.id.ball_container)
        findViewById<View>(R.id.accelerate).setOnClickListener(this) // 加速移动
        findViewById<View>(R.id.reduce).setOnClickListener(this) // 减少移动
        findViewById<View>(R.id.normal).setOnClickListener(this) // 正常速度移动
        findViewById<View>(R.id.isShowBack).setOnClickListener(this) // 是否弹一弹

        containerWidth = container.width
        containerHeight = container.height
        ball = findViewById(R.id.ball)

        /**
         * 碰撞监听
         */
        ball.setShotOver(object : BallViewTwo.ShotOver {
            override fun bubbleShotStart(direction: Int) {
                shotDirection = direction
                shot = 0 // 正在压缩变形
                canMove = false
                // Log.i("shotDirection", "小球发生碰撞时的方向==" + shotDirection);
            }

            override fun bubbleShotEnd() {
                shot = 1 // 刚压缩变形结束
            }
        })
    }

    /**
     * 移动小球
     * @param x
     * @param y
     */
    private fun moveTo(x: Float, y: Float) {
        ballX += x
        ballY += y

        if (ballX < 0) {
            ballX = 0f
        }

        if (ballY < 0) {
            ballY = 0f
        }

        if (ballX > containerWidth - ballWidth) {
            ballX = (containerWidth - ballWidth).toFloat()
        }

        if (ballY > containerHeight - ballHeight) {
            ballY = (containerHeight - ballHeight).toFloat()
        }

        ball.moveTo(ballX.toInt(), ballY.toInt(), currentState, duration, isShotBack)
    }

    private val listener = object : SensorEventListener {
        override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) {
            // TODO Auto-generated method stub
        }

        override fun onSensorChanged(event: SensorEvent) {
            if (!init) return

            currentState = calc(event)

            // 如果当前方向不等于碰撞方向 并且圆刚碰撞结束
            if (shotDirection != currentState && shot == 1) {
                canMove = true
            }
            Log.i("direction", "当前方向==$currentState canMove=$canMove")

            // 可以移动的话才计算移动速度,调用移动方法
            if (canMove) {

                // 如果刚碰撞结束,根据位置,将其挪动一段距离
                if (shot == 1) {
                    when (shotDirection) {
                        0 -> moveTo(0f, 20f)
                        1 -> moveTo(-20f, 0f)
                        2 -> moveTo(0f, -20f)
                        3 -> moveTo(20f, 0f)
                    }
                    shot = -1

                    // 直接移动小球
                } else {
                    constantSpeed(event)
                }

            } else {
                Log.i("qq", "正在执行"弹",所以先不移动小球")
            }
        }
    }

    /**
     * 计算x,y轴应该移动的值(为了使每次移动距离保持不变)
     * @param event
     */
    private fun constantSpeed(event: SensorEvent) {
        val x = event.values[SensorManager.DATA_X] * SPEED
        val y = event.values[SensorManager.DATA_Y] * SPEED
        val tan = x / y
        val movey: Double
        val movex: Double

        if (x == 0f && y != 0f) {
            movex = 0.0
            movey = constantsSpeed.toDouble()
        } else if (x != 0f && y == 0f) {
            movex = constantsSpeed.toDouble()
            movey = 0.0
        } else if (x == 0f && y == 0f) {
            movex = 0.0
            movey = 0.0
        } else {
            val temp = constantsSpeed / (tan * tan + 1)
            movey = Math.sqrt(temp.toDouble()) // 开根号
            movex = movey * tan
        }

        moveTo(
            (if (x < 0) -Math.abs(movex) else Math.abs(movex)).toFloat(),
            (if (y < 0) -Math.abs(movey) else Math.abs(movey)).toFloat()
        )
    }

    // 注册重力感应监听
    private fun register() {
        sensorManager?.registerListener(listener, sensor, SensorManager.SENSOR_DELAY_GAME)
    }

    // 解除重力感应监听
    private fun unregister() {
        sensorManager?.unregisterListener(listener)
        Log.i("vv", "结束监听")
    }

    override fun onWindowFocusChanged(hasFocus: Boolean) {
        super.onWindowFocusChanged(hasFocus)
        if (hasFocus && !init) {
            init()
            init = true
        }
    }

    /**
     * 计算当前球的方向
     */
    private fun calc(event: SensorEvent): Int {
        val x = event.values[0]
        val y = event.values[1]
        val tempVertical: Int
        val tempHorizontal: Int

        tempHorizontal = when {
            x > 0 -> WEST
            x < 0 -> EAST
            else -> -1
        }

        tempVertical = when {
            y > 0 -> SOUTH
            y < 0 -> NORTH
            else -> -1
        }

        currentState = when {
            tempHorizontal == EAST && tempVertical == NORTH ->
                if (Math.abs(x) > Math.abs(y)) EAST else NORTH

            tempHorizontal == EAST && tempVertical == SOUTH ->
                if (Math.abs(x) > Math.abs(y)) EAST else SOUTH

            tempHorizontal == WEST && tempVertical == NORTH ->
                if (Math.abs(x) > Math.abs(y)) WEST else NORTH

            tempHorizontal == WEST && tempVertical == SOUTH ->
                if (Math.abs(x) > Math.abs(y)) WEST else SOUTH

            else -> currentState
        }
        return currentState
    }

    override fun onDestroy() {
        super.onDestroy()
        unregister()
    }

    override fun onPause() {
        super.onPause()
        unregister()
    }

    override fun onRestart() {
        super.onRestart()
        register()
    }

    override fun onResume() {
        super.onResume()
        register()
    }

    override fun onClick(v: View) {
        when (v.id) {
            R.id.accelerate -> adjustSpeedAndDuration(5)
            R.id.reduce -> adjustSpeedAndDuration(-5)
            R.id.normal -> {
                constantsSpeed = 10
                duration = 450
            }
            R.id.isShowBack -> isShotBack = !isShotBack
        }
    }

    /**
     * 改变小球的移动速度和变形时间
     * 因为移动速度越快,碰撞时间越短
     */
    private fun adjustSpeedAndDuration(change: Int) {
        constantsSpeed += change

        duration = if (change < 0) {
            duration + durationPiece
        } else {
            duration - durationPiece
        }

        when {
            constantsSpeed <= 5 -> {
                constantsSpeed = 5
                duration = 750
            }
            constantsSpeed >= 25 -> {
                constantsSpeed = 25
                duration = 150
            }
        }
    }
}

xml

Kotlin 复制代码
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:tools="http://schemas.android.com/tools"
    tools:context=".ui.activity.AnimationActivity">

    <FrameLayout
        android:id="@+id/ball_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <com.hjq.demo.animationdemo.BallViewTwo
            android:id="@+id/ball"
            android:layout_width="360dp"
            android:layout_height="360dp" />

    </FrameLayout>

    <Button
        android:id="@+id/accelerate"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="加速" />

    <Button
        android:id="@+id/reduce"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/accelerate"
        android:text="减速" />

    <Button
        android:id="@+id/normal"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/reduce"
        android:text="正常速度" />

    <Button
        android:id="@+id/isShowBack"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/normal"
        android:text="是否弹一弹" />
</RelativeLayout>
相关推荐
ᥬ 小月亮1 小时前
Layui表格的分页下拉框新增“全部”选项
android·javascript·layui
sunly_11 小时前
Flutter:启动屏逻辑处理02:启动页
android·javascript·flutter
Sgq丶11 小时前
Android Studio 配置 proto
android·ide·android studio
_小马快跑_15 小时前
ConstraintLayout 中的ImageFilterView探索:处理图片圆角、亮度、饱和度、图片重叠等
android
IT-sec15 小时前
jquery-picture-cut 任意文件上传(CVE-2018-9208)
android·前端·javascript·安全·web安全·网络安全·jquery
xiaoduyyy17 小时前
【Android】RecyclerView回收复用机制
android
林北芒大果17 小时前
【Flutter】搭建Flutter开发环境,安卓开发
android·flutter
m0_7482302119 小时前
MySQL 数据库连接池爆满问题排查与解决
android·数据库·mysql
SunshineBrother19 小时前
Flutter求职、面试20+面试官总结:Dart篇
android·前端·flutter
鸿儒51719 小时前
利用adb工具安装卸载安卓平板(手机)软件
android·adb·智能手机