仿八大行星绕太阳3D旋转效果

android实现八大行星绕太阳3D旋转效果
仿上面效果,采用kotlin实现,逻辑要简单些,注释在源码中,一看就懂

在这里插入图片描述

<com.example.androidxdemo.star.StarGroupView
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" >

        <!-- 增加太阳View -->
        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/ic_launcher_background"
            android:tag="center" />

        <TextView
            android:id="@+id/tv1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@color/colorAccent"
            android:text="1" />

        <TextView
            android:id="@+id/tv2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@android:color/darker_gray"
            android:gravity="center"
            android:text="2" />

        <TextView
            android:id="@+id/tv3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@android:color/holo_green_dark"
            android:gravity="center"
            android:text="3" />

        <TextView
            android:id="@+id/tv4"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@android:color/holo_blue_dark"
            android:gravity="center"
            android:text="4" />

        <TextView
            android:id="@+id/tv5"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@android:color/holo_green_light"
            android:gravity="center"
            android:text="5" />

        <TextView
            android:id="@+id/tv6"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@android:color/holo_orange_light"
            android:gravity="center"
            android:text="6" />

        <TextView
            android:id="@+id/tv7"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="#ff3311"
            android:gravity="center"
            android:text="7" />

        <TextView
            android:id="@+id/tv8"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="#11aa44"
            android:gravity="center"
            android:text="8" />

        <TextView
            android:id="@+id/tv9"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="#ff99cc"
            android:gravity="center"
            android:text="9" />
    </com.example.androidxdemo.star.StarGroupView>
class StarGroupView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : FrameLayout(context, attrs, defStyleAttr) {

    val TAG_CENTER = "center"

    //控件宽高
    var mWidth = 0
    var mHeight = 0
    //中心点
    var centerWidth = 0
    var centerHeight = 0
    private var mRadius = 0
    //子View的大小,默认是1:1正方形
    private var childWidth = 0
    private var childHeight = 0
    //初始角度,扫过的角度
    var sweepAngle = 90

    //值越大,转动越快
    val changedAngle = 2
    //延时delayTime ms,进行一次值的改变
    val delayTime = 100L

    //手指按下时x和角度
    private var downX = 0f
    private var downAngle = 0
    //延时改变view位置和绘制顺序
    private val autoScrollRunnable = object : Runnable {
        override fun run() {
            sweepAngle = (sweepAngle + changedAngle) % 360
            layoutChildren()
            postDelayed(this, delayTime)
        }
    }

    init {
        postDelayed(autoScrollRunnable, delayTime)
    }

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
//        "w: $w h: $h oldw: $oldw oldh: $oldh".log()
        //如果宽度大于两倍高度,则高度决定宽度,宽度 = 2 * 高度
        //否则,宽度小于等于两倍高度,则宽度决定高度,高度 = 1/2 * 宽度
        if (w > h * 2) {
            mHeight = h
            mWidth = mHeight * 2
        } else {
            mWidth = w
            mHeight = mWidth / 2
        }
        //确定中心点的位置,childWidth = heightWidth = mWidth / 6
        centerWidth = mWidth / 2
        centerHeight = mHeight / 2
        childWidth = mWidth / 6
        childHeight = childWidth
        //半径,
        mRadius = mHeight - childWidth
        "w: $w h: $h oldw: $oldw oldh: $oldh mWidth: $mWidth mHeight: $mHeight mRadius: $mRadius childWidth: $childWidth".log()
    }

    override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
        super.onLayout(changed, left, top, right, bottom)
//        "changed $changed left: $left top: $top right: $right bottom: $bottom".log()
        layoutChildren()
    }

    /**
     * 计算view的位置
     * z值范围(0-1)
     * 改变子View的z值以改变子View的绘制优先级,z越大优先级越低(最后绘制)
     */
    private fun layoutChildren() {
        val centerView = findViewWithTag<View>(TAG_CENTER)
        val degree: Float
        if (centerView == null) {
            degree = 360f / childCount
        } else {
            //中心点view的宽高为 2 * childWith
            degree = 360f / (childCount - 1)
            centerView.layout(
                centerWidth - childWidth, centerHeight - childHeight,
                centerWidth + childWidth, centerHeight + childHeight
            )
        }
        for (index in 0 until childCount) {
            val child = getChildAt(index)
            if (child.tag == TAG_CENTER) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                    child.z = 0.5f
                }
                child.rotation = sweepAngle.toFloat()
//                "中心旋转 rotation: $sweepAngle".log()
                continue
            }
            //设置child的大小尺寸和布局, index为0的是centerView
            val radius = (degree * index + sweepAngle) * Math.PI / 180
            val childCenterX = (mRadius * cos(radius)).toInt()
            val childCenterY = (mRadius * sin(radius) / 2).toInt()
//            "index:$index degree:${degree * (index - 1)} radius:$radius childCenterX: $childCenterX childCenterY: $childCenterY".log()
            val left = childCenterX - childWidth / 2 + centerWidth
            val top = childCenterY - childHeight / 2 + centerHeight
            val right = childCenterX + childWidth / 2 + centerWidth
            val bottom = childCenterY + childHeight / 2 + centerHeight
            child.layout(left, top, right, bottom)
            val scale = ((sin(radius) + 2) / 3f).toFloat()
            child.scaleX = scale
            child.scaleY = scale
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                child.z = scale
            }
//            "index:$index child left: $left top: $top right: $right bottom: $bottom child.scaleX: ${child.scaleX}".logW()
        }
    }

    override fun onTouchEvent(event: MotionEvent): Boolean {
        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                downX = event.x
                downAngle = sweepAngle
                removeCallbacks(autoScrollRunnable)
                "actionDown downX $downX downAngle: $downAngle ".logW()
                return true
            }
            MotionEvent.ACTION_MOVE -> {
                val dx = event.x - downX
                if (dx != 0f) {
                    sweepAngle = (dx * 0.2 + downAngle).toInt()
                    "actionMove dx $dx sweepAngle: $sweepAngle ".log()
                    layoutChildren()
                }
            }
            MotionEvent.ACTION_UP -> {
                "actionUp ".logW()
                postDelayed(autoScrollRunnable, 16)
            }
        }
        return super.onTouchEvent(event)
    }

}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是使用 CSS3 实现的九大行星太阳周转的动画效果: HTML代码: ```html <div class="sun"></div> <div class="mercury"></div> <div class="venus"></div> <div class="earth"></div> <div class="mars"></div> <div class="jupiter"></div> <div class="saturn"></div> <div class="uranus"></div> <div class="neptune"></div> ``` CSS代码: ```css .sun { width: 200px; height: 200px; border-radius: 50%; background-color: #f9d71c; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); z-index: 1; box-shadow: 0 0 50px #f9d71c, 0 0 100px #f9d71c, 0 0 150px #f9d71c, 0 0 200px #f9d71c; animation: rotate-sun 10s linear infinite; } .mercury { width: 20px; height: 20px; border-radius: 50%; background-color: #b5b5b5; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%) translateX(70px); animation: rotate-mercury 3s linear infinite; } .venus { width: 35px; height: 35px; border-radius: 50%; background-color: #f2b02e; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%) translateX(120px); animation: rotate-venus 5s linear infinite; } .earth { width: 40px; height: 40px; border-radius: 50%; background-color: #3a7cff; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%) translateX(160px); animation: rotate-earth 8s linear infinite; } .mars { width: 25px; height: 25px; border-radius: 50%; background-color: #ff4f4f; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%) translateX(200px); animation: rotate-mars 10s linear infinite; } .jupiter { width: 80px; height: 80px; border-radius: 50%; background-color: #c05c3c; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%) translateX(300px); animation: rotate-jupiter 20s linear infinite; } .saturn { width: 70px; height: 70px; border-radius: 50%; background-color: #d8c58e; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%) translateX(400px); animation: rotate-saturn 30s linear infinite; } .uranus { width: 60px; height: 60px; border-radius: 50%; background-color: #6ecfff; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%) translateX(500px); animation: rotate-uranus 40s linear infinite; } .neptune { width: 55px; height: 55px; border-radius: 50%; background-color: #3456a9; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%) translateX(600px); animation: rotate-neptune 50s linear infinite; } @keyframes rotate-sun { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } @keyframes rotate-mercury { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } @keyframes rotate-venus { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } @keyframes rotate-earth { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } @keyframes rotate-mars { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } @keyframes rotate-jupiter { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } @keyframes rotate-saturn { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } @keyframes rotate-uranus { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } @keyframes rotate-neptune { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } ``` 解释一下代码: 1. `.sun` 代表太阳,使用 `border-radius: 50%` 将其设置为圆形,使用 `box-shadow` 添加光晕效果,使用 `animation` 添加旋转动画。 2. `.mercury` 到 `.neptune` 分别代表九大行星,使用不同的颜色、大小、位置和旋转速度等属性,使用 `animation` 添加旋转动画。 3. `@keyframes` 定义了动画执行的关键帧,从 `0%` 开始,旋转角度为 `0deg`,到 `100%` 结束,旋转角度为 `360deg`。 4. 通过设置 `translateX` 属性实现行星的位置偏移,从而实现太阳周转的效果。 这样就可以实现九大行星太阳周转的动画效果了。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值