IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android动态画线 坐标画线动画 -> 正文阅读

[移动开发]Android动态画线 坐标画线动画

效果图如下

根据相对于图片本身的坐标xy数组 基于view的左上角为原点 在图片上动态画线?

//参考数据类型

//pointList
[PointEntity(pointX=1, pointY=1), PointEntity(pointX=2, pointY=2), PointEntity(pointX=3, pointY=3)]

//lineList
[LinePointEntity(startX=1, startY=1, endX=2, endY=2), LinePointEntity(startX=2, startY=2, endX=3, endY=3)]
//协程
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.5"
import android.content.Context
import android.graphics.Canvas
import android.graphics.Paint
import android.util.AttributeSet
import android.util.Log
import android.widget.FrameLayout
import kotlinx.coroutines.*
import java.util.concurrent.CopyOnWriteArrayList
import kotlin.math.absoluteValue


class DrawLineView : FrameLayout {

    private val TAG = "DrawLineView"

    private var mWidth = 0
    private var mHeight = 0

    private var drawJob: Job? = null

    private var threadWorking = false

    private var mPaint: Paint? = null

    //线的端点
    private val linePointList: MutableList<LinePointEntity> = ArrayList()

    //线的点
    private var drawPointList: CopyOnWriteArrayList<PointEntity> = CopyOnWriteArrayList()

    constructor(context: Context) : super(context)

    constructor(context: Context, attributeSet: AttributeSet) : super(context, attributeSet)

    constructor(context: Context, attributeSet: AttributeSet, defStyleAttr: Int) : super(
        context,
        attributeSet,
        defStyleAttr
    )

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        setMeasuredDimension(mWidth, mHeight)
    }

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        if (drawJob == null && linePointList.isNotEmpty()) {
            startDrawLine()
        } else {
            drawPoint(canvas)
        }
    }

    fun setBackgroundImage(res: Int): DrawLineView {
        setBackgroundResource(res)
        return this
    }

    fun setPaint(paint: Paint): DrawLineView {
        this.mPaint = paint
        return this
    }

    fun updateView(width: Int, height: Int): DrawLineView {
        this.mWidth = width
        this.mHeight = height
        return this
    }

    fun drawLine(list: List<LinePointEntity>) {
        drawJob?.cancel()
        drawJob = null
        linePointList.clear()
        linePointList.addAll(list)
        invalidate()
    }

    private fun drawPoint(canvas: Canvas?) {
        for (entity in drawPointList) {
            mPaint?.let {
                canvas?.drawPoint(entity.pointX, entity.pointY, it)
            }
        }
    }

    //添加需要画的点
    private fun addPoint(pointX: Float, pointY: Float) {
        drawPointList.add(PointEntity(pointX, pointY))
    }

    private fun startDrawLine() {
        Log.d(TAG, "startDrawLine...")
        drawJob = GlobalScope.launch {
            for (entity in linePointList) {

                entity.apply {
                    //两点之间的距离
                    val distanceX = (endX - startX).absoluteValue
                    val distanceY = (endY - startY).absoluteValue
                    //每个单位偏移量
                    var offsetX = 0f
                    var offsetY = 0f
                    //避免在横向或竖向描点过快 通过距离大小使用不同方向为基本1个单位的偏移量
                    if (distanceX > distanceY) {
                        offsetX = if (startX < endX) {
                            1f
                        } else {
                            -1f
                        }
                        offsetY = if (startY < endY) {
                            1f * distanceY / distanceX * offsetX.absoluteValue
                        } else {
                            -1f * distanceY / distanceX * offsetX.absoluteValue
                        }
                    } else {
                        offsetY = if (startY < endY) {
                            1f
                        } else {
                            -1f
                        }
                        offsetX = if (startX < endX) {
                            1f * distanceX / distanceY * offsetY.absoluteValue
                        } else {
                            -1f * distanceX / distanceY * offsetY.absoluteValue
                        }
                    }
                    var currentX = 1f * startX
                    var currentY = 1f * startY
                    while (true) {
                        if (
                            isActive && if (distanceX > distanceY) {
                                if (offsetX > 0) {
                                    currentX < endX
                                } else {
                                    currentX > endX
                                }
                            } else {
                                if (offsetY > 0) {
                                    currentY < endY
                                } else {
                                    currentY > endY
                                }
                            }
                        ) {

                            currentX += offsetX
                            currentY += offsetY
                            addPoint(currentX, currentY)
                            delay(1)
                            invalidate()
                        } else {
                            Log.w(TAG, "end draw ----> break")
                            break
                        }
                    }
                }

            }
        }
        drawJob?.start()
    }

    override fun onDetachedFromWindow() {
        super.onDetachedFromWindow()
        Log.d(TAG, "onDetachedFromWindow job cancel...")
        drawJob?.cancel()
    }


}

data class LinePointEntity(
    val startX: Float,
    val startY: Float,
    val endX: Float,
    val endY: Float
)

data class PointEntity(
    val pointX: Float,
    val pointY: Float
)
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <androidx.appcompat.widget.AppCompatButton
        android:id="@+id/btn_start_draw"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="画线" />

    <com.znan.androidtest.screen.widget.view.DrawLineView
        android:id="@+id/view_draw_line"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</androidx.appcompat.widget.LinearLayoutCompat>
    private fun initDrawLineView() {
        val screenWidth = resources.displayMetrics.widthPixels

        //原图大小
        val imageWidth = 3480
        val imageHeight = 2160

        val viewHeight = 1f * imageHeight / imageWidth * screenWidth

        //坐标在手机屏幕上对应的缩放比例
        val rateX = 1f * screenWidth / imageWidth
        val rateY = 1f * viewHeight / imageHeight

        //随机需要画线的点
        val pointList: MutableList<PointEntity> = ArrayList()
        repeat(8) {
            pointList.add(
                PointEntity(
                    rateX * getRandomNumber(imageWidth),
                    rateY * getRandomNumber(imageHeight)
                )
            )
        }
        //将画线点格式化线数组的端点
        val lineList: MutableList<LinePointEntity> = ArrayList()
        for (i in pointList.indices) {
            if (i < pointList.size - 1) {
                lineList.add(
                    LinePointEntity(
                        pointList[i].pointX,
                        pointList[i].pointY,
                        pointList[i+1].pointX,
                        pointList[i+1].pointY
                    )
                )

            }
        }

        val paint = Paint()
        paint.color = Color.WHITE
        paint.strokeWidth = 5f
        paint.isAntiAlias = true
        paint.isDither = true
        paint.style = Paint.Style.STROKE

        //画线
        view_draw_line.updateView(screenWidth, viewHeight.toInt())
            .setPaint(paint)
            .setBackgroundImage(R.mipmap.bg_map_3m)
            .drawLine(lineList)

    }

 
    fun getRandomNumber(maxNumber: Int = 10000): Int {
        return (0..maxNumber).random()
    }

//以下可忽略

    inner class DrawThread : Thread() {
        override fun run() {
            super.run()
            threadWorking = true
            Log.d(TAG, "DrawThread run...")
            for (entity in linePointList) {
                entity.apply {
                    //两点之间的距离
                    val distanceX = (endX - startX).absoluteValue
                    val distanceY = (endY - startY).absoluteValue
                    //每个单位偏移量
                    var offsetX = 0f
                    var offsetY = 0f
                    //避免在横向或竖向描点过快 通过距离大小使用不同方向为基本1个单位的便宜量
                    if (distanceX > distanceY) {
                        offsetX = if (startX < endX) {
                            1f
                        } else {
                            -1f
                        }
                        offsetY = if (startY < endY) {
                            1f * distanceY / distanceX * offsetX.absoluteValue
                        } else {
                            -1f * distanceY / distanceX * offsetX.absoluteValue
                        }
                    } else {
                        offsetY = if (startY < endY) {
                            1f
                        } else {
                            -1f
                        }
                        offsetX = if (startX < endX) {
                            1f * distanceX / distanceY * offsetY.absoluteValue
                        } else {
                            -1f * distanceX / distanceY * offsetY.absoluteValue
                        }
                    }
                    var currentX = 1f * startX
                    var currentY = 1f * startY

                    while (true) {
                        if (
                            isAlive && threadWorking && if (distanceX > distanceY) {
                                if (offsetX > 0) currentX < endX else currentX > endX
                            } else {
                                if (offsetY > 0) currentY < endY else currentY > endY
                            }
                        ) {
                            currentX += offsetX
                            currentY += offsetY
                            addPoint(currentX, currentY)

                        } else {
                            break
                        }
                    }
                }

            }
        }
    }
    //计算点位的线程
    protected class DrawThread extends Thread {

        @Override
        public void run() {
            super.run();

            Log.d(TAG, "DrawThread run :" + linePointList.size());
            for (LinePointEntity entity : linePointList) {
                //两点之间横向距离
                int distanceX = Math.abs((entity.getEndX() - entity.getStartX()));
                //两点之间竖向距离
                int distanceY = Math.abs(entity.getEndY() - entity.getStartY());

                //避免在横向或竖向描点过快 通过距离大小使用不同方向为基本1个单位的便宜量
                if (distanceX > distanceY) {

                    //横向偏移量
                    int offsetX;
                    //竖向偏移量
                    Float offsetY;
                    if (entity.getStartX() < entity.getEndX()) {
                        offsetX = 1;
                    } else {
                        offsetX = -1;
                    }

                    if (entity.getStartY() < entity.getEndY()) {
                        offsetY = 1f * distanceY / distanceX * Math.abs(offsetX);
                    } else {
                        offsetY = -1f * distanceY / distanceX * Math.abs(offsetX);
                    }

                    //当前绘制位置x y 坐标
                    int currentX = entity.getStartX();
                    Float currentY = 1f * entity.getStartY();

                    while (true) {
                        //偏移量的正负影响结束位置条件判断
                        if (this.isAlive() && threadWorking && offsetX > 0 ? currentX < entity.getEndX() : currentX > entity.getEndX()) {
                            currentX += offsetX;
                            currentY += offsetY;
                            addPoint(currentX, currentY.intValue());
                            try {
                                Thread.sleep(1);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                                break;
                            }
                            invalidate();
                        } else {
                            break;
                        }
                    }
                } else {

                    //横向偏移量
                    Float offsetX;
                    //竖向偏移量
                    int offsetY;
                    if (entity.getStartY() < entity.getEndY()) {
                        offsetY = 1;
                    } else {
                        offsetY = -1;
                    }

                    if (entity.getStartX() < entity.getEndX()) {
                        offsetX = 1f * distanceX / distanceY * Math.abs(offsetY);
                    } else {
                        offsetX = -1f * distanceX / distanceY * Math.abs(offsetY);
                    }

                    //当前绘制位置x y 坐标
                    Float currentX = 1f * entity.getStartX();
                    int currentY = entity.getStartY();

                    while (true) {
                        //偏移量的正负影响结束位置条件判断
                        if (this.isAlive() && offsetY > 0 ? currentY < entity.getEndY() : currentY > entity.getEndY()) {
                            currentX += offsetX;
                            currentY += offsetY;
                            addPoint(currentX.intValue(), currentY);
                            try {
                                Thread.sleep(1);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                                break;
                            }
                            invalidate();
                        } else {
                            break;
                        }
                    }
                }

            }
        }
    }

The end ...

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-12-11 15:50:25  更:2021-12-11 15:52:34 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 7:28:18-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码