如何实现转圈圈动画效果

        之前大家一定看到过Windows10开启启动的转圈圈效果,那能不能用Android也手撸一个类似的效果呢?

        答案当然是肯定的。可以看下最终的效果。

        

 

        这里其实非常简单,只要会ValueAnimator就够了。多个球延迟执行动画,然后动画无限循环就行了。这里也用到了极坐标的知识,类似的效果你还可以进行扩展和包装。例如改改颜色,包装成自定义View或者进度加载组件啥的都行,放开手脚用处还是很多的。

        实现起来也是非常简单,就一个Activity和一个对应的布局就搞定。

        

package com.openld.seniorui.testrotate

import android.animation.AnimatorSet
import android.animation.ValueAnimator
import android.os.Bundle
import android.view.animation.AccelerateDecelerateInterpolator
import android.widget.ImageView
import androidx.appcompat.app.AppCompatActivity
import com.openld.seniorui.R
import kotlin.math.cos
import kotlin.math.sin

class TestRotateActivity : AppCompatActivity() {
    companion object {
        private val RADIUS = 300F
        private val DURATION = 1800
        private val INTERPOLATOR = AccelerateDecelerateInterpolator()
    }


    private lateinit var mImage1: ImageView;
    private lateinit var mImage2: ImageView;
    private lateinit var mImage3: ImageView;
    private lateinit var mImage4: ImageView;
    private lateinit var mImage5: ImageView;
    private lateinit var mImage6: ImageView;
    private lateinit var mImage7: ImageView;

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_test_rotate)

        initWidgets()

        startRotate()
    }

    private fun startRotate() {
        val anim1 = ValueAnimator.ofFloat(0F, 360F).apply {
            repeatCount = ValueAnimator.INFINITE
            startDelay = 0
            addUpdateListener {
                val value: Double = (it.animatedValue as Float) * 1.0
                val radians = Math.toRadians(value)
                val cos = cos(radians)
                val sin = sin(radians)

                mImage1.translationX = (RADIUS * cos).toFloat()
                mImage1.translationY = (RADIUS * sin).toFloat()
            }
        }


        val anim2 = ValueAnimator.ofFloat(0F, 360F).apply {
            repeatCount = ValueAnimator.INFINITE
            startDelay = 100
            addUpdateListener {
                val value: Double = (it.animatedValue as Float) * 1.0
                val radians = Math.toRadians(value)
                val cos = cos(radians)
                val sin = sin(radians)

                mImage2.translationX = (RADIUS * cos).toFloat()
                mImage2.translationY = (RADIUS * sin).toFloat()
            }
        }

        val anim3 = ValueAnimator.ofFloat(0F, 360F).apply {
            repeatCount = ValueAnimator.INFINITE
            startDelay = 200
            addUpdateListener {
                val value: Double = (it.animatedValue as Float) * 1.0
                val radians = Math.toRadians(value)
                val cos = cos(radians)
                val sin = sin(radians)

                mImage3.translationX = (RADIUS * cos).toFloat()
                mImage3.translationY = (RADIUS * sin).toFloat()
            }
        }

        val anim4 = ValueAnimator.ofFloat(0F, 360F).apply {
            repeatCount = ValueAnimator.INFINITE
            startDelay = 300
            addUpdateListener {
                val value: Double = (it.animatedValue as Float) * 1.0
                val radians = Math.toRadians(value)
                val cos = cos(radians)
                val sin = sin(radians)

                mImage4.translationX = (RADIUS * cos).toFloat()
                mImage4.translationY = (RADIUS * sin).toFloat()
            }
        }

        val anim5 = ValueAnimator.ofFloat(0F, 360F).apply {
            repeatCount = ValueAnimator.INFINITE
            startDelay = 400
            addUpdateListener {
                val value: Double = (it.animatedValue as Float) * 1.0
                val radians = Math.toRadians(value)
                val cos = cos(radians)
                val sin = sin(radians)

                mImage5.translationX = (RADIUS * cos).toFloat()
                mImage5.translationY = (RADIUS * sin).toFloat()
            }
        }


        val anim6 = ValueAnimator.ofFloat(0F, 360F).apply {
            repeatCount = ValueAnimator.INFINITE
            startDelay = 500
            addUpdateListener {
                val value: Double = (it.animatedValue as Float) * 1.0
                val radians = Math.toRadians(value)
                val cos = cos(radians)
                val sin = sin(radians)

                mImage6.translationX = (RADIUS * cos).toFloat()
                mImage6.translationY = (RADIUS * sin).toFloat()
            }
        }

        val anim7 = ValueAnimator.ofFloat(0F, 360F).apply {
            repeatCount = ValueAnimator.INFINITE
            startDelay = 600
            addUpdateListener {
                val value: Double = (it.animatedValue as Float) * 1.0
                val radians = Math.toRadians(value)
                val cos = cos(radians)
                val sin = sin(radians)

                mImage7.translationX = (RADIUS * cos).toFloat()
                mImage7.translationY = (RADIUS * sin).toFloat()
            }
        }

        val animSet = AnimatorSet().apply {
            duration = DURATION.toLong()
            interpolator = INTERPOLATOR
            playTogether(anim1, anim2, anim3, anim4, anim5, anim6, anim7)
            start()
        }
    }

    private fun initWidgets() {
        mImage1 = findViewById(R.id.img1);
        mImage2 = findViewById(R.id.img2);
        mImage3 = findViewById(R.id.img3);
        mImage4 = findViewById(R.id.img4);
        mImage5 = findViewById(R.id.img5);
        mImage6 = findViewById(R.id.img6);
        mImage7 = findViewById(R.id.img7);

        mImage1.translationX = RADIUS
        mImage2.translationX = RADIUS
        mImage3.translationX = RADIUS
        mImage4.translationX = RADIUS
        mImage5.translationX = RADIUS
        mImage6.translationX = RADIUS
        mImage7.translationX = RADIUS
    }
}
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".testrotate.TestRotateActivity">

    <ImageView
        android:id="@+id/img1"
        android:layout_width="30dp"
        android:layout_height="30dp"
        android:src="@drawable/dot1"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:ignore="ContentDescription" />

    <ImageView
        android:id="@+id/img2"
        android:layout_width="30dp"
        android:layout_height="30dp"
        android:src="@drawable/dot2"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:ignore="ContentDescription" />

    <ImageView
        android:id="@+id/img3"
        android:layout_width="30dp"
        android:layout_height="30dp"
        android:src="@drawable/dot3"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:ignore="ContentDescription" />

    <ImageView
        android:id="@+id/img4"
        android:layout_width="30dp"
        android:layout_height="30dp"
        android:src="@drawable/dot4"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:ignore="ContentDescription" />

    <ImageView
        android:id="@+id/img5"
        android:layout_width="30dp"
        android:layout_height="30dp"
        android:src="@drawable/dot5"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:ignore="ContentDescription" />

    <ImageView
        android:id="@+id/img6"
        android:layout_width="30dp"
        android:layout_height="30dp"
        android:src="@drawable/dot6"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:ignore="ContentDescription" />

    <ImageView
        android:id="@+id/img7"
        android:layout_width="30dp"
        android:layout_height="30dp"
        android:src="@drawable/dot7"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:ignore="ContentDescription" />
</androidx.constraintlayout.widget.ConstraintLayout>

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值