Android立体图形的拆解/恢复_自定义view

本文介绍了一个自定义View的实现案例,通过绘制不同颜色的面并使用计时器进行位移,实现了立方体的拆解动画效果。每个面通过Path绘制,并使用Matrix进行坐标变换。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

直接上效果图(下图gif所示)了,自定义View的demo写的是正方体相对简介,手机屏幕不大,右侧和左侧的都超出屏幕了,所以没有截到,当时看了一家公司的抖音,突发奇想写的一个图形拆解/恢复动画,如果该demo对你有帮助的话,给我点个赞吧
在这里插入图片描述

package com.lx.views

import android.content.Context
import android.graphics.*
import android.os.CountDownTimer
import android.util.AttributeSet
import android.view.View

class liuxinCubeSplit : View, View.OnClickListener {
	//6个不同颜色的笔
    private var paint1 = Paint()
    private var paint2 = Paint()
    private var paint3 = Paint()
    private var paint4 = Paint()
    private var paint5 = Paint()
    private var paint6 = Paint()
       //图形的Path
    private var before = Path()
    private var top = Path()
    private var left = Path()
    private var right = Path()
    private var bottom = Path()
    private var after = Path()
    //矩阵
    var mMatrix = Matrix()
    
    private fun beforePath() {
        before.reset()
        before.moveTo(point_before[0], point_before[1])
        before.lineTo(point_before[2], point_before[3])
        before.lineTo(point_before[4], point_before[5])
        before.lineTo(point_before[6], point_before[7])
        before.lineTo(point_before[0], point_before[1])
        before.close()
        paint1.setColor(Color.YELLOW)
    }

    private fun topPath() {
        top.reset()
        top.moveTo(point_top[0], point_top[1])
        top.lineTo(toptop[0], toptop[1])
        top.lineTo(toptop[2], toptop[3])
        top.lineTo(point_top[6], point_top[7])
        top.lineTo(point_top[0], point_top[1])
        top.close()
        paint2.setColor(Color.BLACK)
    }

    private fun leftPath() {
        left.reset()
        left.moveTo(point_left[0], point_left[1])
        left.lineTo(leftleft[0], leftleft[1])
        left.lineTo(leftleft[2], leftleft[3])
        left.lineTo(point_left[6], point_left[7])
        left.lineTo(point_left[0], point_left[1])
        left.close()
        paint3.setColor(Color.BLUE)
    }

    fun rightPath() {
        right.reset()
        right.moveTo(point_right[0], point_right[1])
        right.lineTo(rightleft[0], rightleft[1])
        right.lineTo(rightleft[2], rightleft[3])
        right.lineTo(point_right[6], point_right[7])
        right.lineTo(point_right[0], point_right[1])
        right.close()
        paint4.setColor(Color.RED)
    }
    fun bottomPath(){
        bottom.reset()
        bottom.moveTo(point_bottom[0], point_bottom[1])
        bottom.lineTo(bottomtop[0], bottomtop[1])
        bottom.lineTo(bottomtop[2], bottomtop[3])
        bottom.lineTo(point_bottom[6], point_bottom[7])
        bottom.lineTo(point_bottom[0], point_bottom[1])
        bottom.close()
        paint5.setColor(Color.GRAY);
    }
    fun afterPath(){
        after.reset()
        after.moveTo(bottomtop[0], bottomtop[1])
        after.lineTo(aftertopleft[0], aftertopleft[1])
        after.lineTo(aftertopright[0], aftertopright[1])
        after.lineTo(bottomtop[2], bottomtop[3])
        after.lineTo(bottomtop[0], bottomtop[1])
        after.close()
        paint6.setColor(Color.CYAN)
    }
    fun reMake() {
        setOnClickListener(this)
        beforePath()
        topPath()
        leftPath()
        rightPath()
        bottomPath()
        afterPath()

    }


    private var point_before = floatArrayOf(
            300f, 300f,
            300f, 700f,
            700f, 700f,
            700f, 300f
    )

    private var point_top = floatArrayOf(
            300f, 300f,
            500f, 100f,
            900f, 100f,
            700f, 300f
    )
    //顶部的顶2点
    var toptop = floatArrayOf(500f, 100f,
            900f, 100f
    )
    //左侧的左2点
    var leftleft = floatArrayOf(900f, 100f,
            900f, 500f
    )
    //右侧的左2点
    var rightleft = floatArrayOf(500f, 100f,
            500f, 500f
    )
    //底部的顶2点
    var bottomtop = floatArrayOf(500f, 500f,
            900f, 500f
    )
    var afterbottom = floatArrayOf( 500f, 500f,
            900f, 500f
    )
    //后侧的左上点
    var aftertopleft = floatArrayOf( 500f, 100f
    )
    //后侧的右上点
    var aftertopright = floatArrayOf(
            900f, 100f
    )
    private var point_left = floatArrayOf(
            700f, 300f,
            900f, 100f,
            900f, 500f,
            700f, 700f

    )
    private var point_right = floatArrayOf(
            300f,300f,
            500f,100f,
            500f,500f,
            300f,700f
    )
    private var point_bottom = floatArrayOf(
            300f, 700f,
            500f, 500f,
            900f, 500f,
            700f, 700f
    )
    private var point_after = floatArrayOf(
            500f, 100f,
            500f, 500f,
            900f, 500f,
            900f, 100f
    )
    constructor(context: Context?) : super(context) {
        reMake()
    }

    constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) {
        reMake()
    }

    constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
        reMake()
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        canvas.drawPath(right, paint1)
        canvas.drawPath(after, paint3)
        canvas.drawPath(bottom, paint2)
        canvas.drawPath(top, paint4)
        canvas.drawPath(left, paint5)
        canvas.drawPath(before, paint6)


    }

    var timer: CountDownTimer = object : CountDownTimer(2000, 100) {
        override fun onTick(millisUntilFinished: Long) {
            mMatrix.reset()
            mMatrix.setTranslate(-10f, -10f);
            mMatrix.mapPoints(toptop)
            reMake()
//            invalidate()
        }

        override fun onFinish() {
            invalidate()
            cancel()
        }
    }
    var timer2: CountDownTimer = object : CountDownTimer(2000, 100) {
        override fun onTick(millisUntilFinished: Long) {
            mMatrix.reset()
            mMatrix.setTranslate(10f, 10f);
            mMatrix.mapPoints(leftleft)
            reMake()
//            invalidate()
        }

        override fun onFinish() {
            invalidate()
            cancel()

        }
    }
    var timer3: CountDownTimer = object : CountDownTimer(2000, 100) {
        override fun onTick(millisUntilFinished: Long) {
            mMatrix.reset()
            mMatrix.setTranslate(-35f, 10f);
            mMatrix.mapPoints(rightleft)
            reMake()
            invalidate()
        }

        override fun onFinish() {
            invalidate()
            cancel()
        }
    }
    var timer4: CountDownTimer = object : CountDownTimer(2000, 100) {
        override fun onTick(millisUntilFinished: Long) {
            mMatrix.reset()
            mMatrix.setTranslate(-10f, 30f);
            mMatrix.mapPoints(bottomtop)
            mMatrix.reset()
            mMatrix.setTranslate(-10f, 30f);
            mMatrix.mapPoints(aftertopright);
            mMatrix.mapPoints(aftertopleft);
            reMake()

        }

        override fun onFinish() {
            invalidate()
            cancel()
            timer5.start()
        }
    }
    var timer5: CountDownTimer = object : CountDownTimer(2000, 100) {
        override fun onTick(millisUntilFinished: Long) {
            mMatrix.reset()
            mMatrix.setRotate(9f,bottomtop[2],bottomtop[3]);
            mMatrix.mapPoints(aftertopright)
            mMatrix.reset()
            mMatrix.setRotate(9f,bottomtop[0],bottomtop[1]);
            mMatrix.mapPoints(aftertopleft)
            invalidate()

            reMake()

        }

        override fun onFinish() {
            invalidate()
            cancel()
        }
    }

    override fun onClick(v: View?) {
        timer.start()
        timer2.start()
        timer3.start()
        timer4.start()
        //只做了一次点击事件,点击后还能继续点击(因为懒,就没写恢复事件了,恢复事件就是反着来,你懂我意思吧?)
    }
}

后续待更新

<think>嗯,用户问的是关于这个命令的作用。首先,我需要分解命令的各个部分。看到“exec env”,这应该是在执行exec命令,后面跟着环境变量设置。 然后,PATH被设置为多个目录,看起来是修改了可执行文件的搜索路径,可能是在特定的系统环境下,比如嵌入式系统或者恢复模式。接着是LD_LIBRARY_PATH,指定了动态库的路径,这也支持了可能是特殊环境的猜测。 接下来是“/sbin/init”,这通常是系统的初始化进程,PID 1,负责启动其他进程。所以整个命令可能是在替换当前进程为init,并设置特定的环境变量。 用户可能是系统管理员或者开发人员,在处理启动问题或者系统初始化时遇到这个命令。可能需要了解为什么需要修改PATH和LD_LIBRARY_PATH,或者为什么用exec来启动init。深层需求可能是想了解如何调试系统启动过程,或者如何正确设置环境变量来运行关键进程。 需要注意解释每个部分的作用,特别是exec替换当前进程,环境变量的影响,以及init进程的角色。还要提醒潜在风险,比如错误的路径设置可能导致系统无法启动,或者LD_LIBRARY_PATH的安全性问题。</think>这个命令的作用是替换当前进程环境并启动系统初始化程序`/sbin/init`,具体可以拆解为以下步骤: 1. **`exec`**:替换当前进程(而不是创建新进程) - 特点:当前进程的PID不变,但原有代码段/数据段会被新程序完全覆盖 2. **`env`**:设置临时环境变量 - `PATH="/bin:/sbin:..."`:指定二进制文件搜索路径 - 包含常规路径 `/bin`, `/sbin` 和特殊路径 `/sp_rom` 开头的路径 - 当执行命令时,系统会按此顺序查找可执行文件 - `LD_LIBRARY_PATH="/sp_rom/usr/lib..."`:指定动态链接库路径 - 强制程序优先使用指定目录下的共享库文件(.so) 3. **`/sbin/init`**:系统初始化进程 - Unix/Linux系统的第一个用户态进程(PID 1) - 负责启动系统服务和守护进程 4. **`2>&0`**:I/O重定向 - 将标准错误(stderr, 文件描述符2)重定向到标准输入(stdin, 文件描述符0) - 这种用法较少见,通常用于特殊调试场景 **典型应用场景**: - 系统恢复/救援模式 - 嵌入式系统启动 - 容器初始化过程 - 调试系统启动流程 **注意事项**: 1. 修改`PATH`可能影响命令执行结果 2. 覆盖`LD_LIBRARY_PATH`存在安全隐患 3. 使用`exec`后原进程无法恢复 4. 此命令需要root权限执行 完整命令结构示意图: ``` 当前进程 │ ├─ 被exec替换 │ │ │ └─ 新环境变量 │ ├─ PATH: 定制搜索路径 │ └─ LD_LIBRARY_PATH: 指定库路径 │ └─ 最终执行目标 └─ /sbin/init (系统初始化进程) ```
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值