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>
相关推荐
雨白8 小时前
Jetpack系列(二):Lifecycle与LiveData结合,打造响应式UI
android·android jetpack
kk爱闹9 小时前
【挑战14天学完python和pytorch】- day01
android·pytorch·python
每次的天空11 小时前
Android-自定义View的实战学习总结
android·学习·kotlin·音视频
恋猫de小郭11 小时前
Flutter Widget Preview 功能已合并到 master,提前在体验毛坯的预览支持
android·flutter·ios
断剑重铸之日12 小时前
Android自定义相机开发(类似OCR扫描相机)
android
随心最为安12 小时前
Android Library Maven 发布完整流程指南
android
岁月玲珑12 小时前
【使用Android Studio调试手机app时候手机老掉线问题】
android·ide·android studio
还鮟17 小时前
CTF Web的数组巧用
android
小蜜蜂嗡嗡18 小时前
Android Studio flutter项目运行、打包时间太长
android·flutter·android studio
aqi0018 小时前
FFmpeg开发笔记(七十一)使用国产的QPlayer2实现双播放器观看视频
android·ffmpeg·音视频·流媒体