Android图片涂鸦,Kotlin(1)

Android图片涂鸦,Kotlin(1)

Kotlin 复制代码
import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.Path
import android.graphics.PointF
import android.util.AttributeSet
import android.util.Log
import android.view.MotionEvent
import androidx.appcompat.widget.AppCompatImageView


class PaintView @JvmOverloads constructor(
    context: Context?,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : AppCompatImageView(context!!, attrs, defStyleAttr) {

    class DrawPath {
        var id: Long = 0L

        var path: Path? = null
        var paint: Paint? = null
        var points = ArrayList<PointF>()
    }

    private var mPaint: Paint? = null
    private var mPath: Path? = null

    private var mDownX = 0f
    private var mDownY = 0f
    private var mTempX = 0f
    private var mTempY = 0f

    //默认的画笔宽度
    private var mPaintWidth = 10

    //默认画笔的颜色
    private var mColor = Color.RED

    private val mDrawPathList: ArrayList<DrawPath>?
    private val mSavePathList: ArrayList<DrawPath>?

    companion object {
        var WIDTH_INCREMENT = 15
        const val TAG = "PaintView"
    }

    init {
        mDrawPathList = ArrayList()
        mSavePathList = ArrayList()
        initPaint()
    }

    private fun initPaint() {
        mPaint = Paint()

        mPaint?.color = mColor
        mPaint?.isAntiAlias = true
        mPaint?.strokeWidth = mPaintWidth.toFloat()
        mPaint?.style = Paint.Style.STROKE
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)

        if (!mDrawPathList.isNullOrEmpty()) {
            for (drawPath in mDrawPathList) {
                if (drawPath.path != null) {
                    canvas.drawPath(drawPath.path!!, drawPath.paint!!)
                }

                drawPath.points.forEach {
                    Log.d(TAG, "onDraw ${drawPath.id} ${it.x} ${it.y}")
                }
            }
        }
    }

    override fun onTouchEvent(event: MotionEvent): Boolean {
        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                Log.d(TAG, "ACTION_DOWN ${event.x} ${event.y}")

                mDownX = event.x
                mDownY = event.y

                //每次手指点下去作为一条新路径。
                mPath = Path()
                mPath?.moveTo(mDownX, mDownY)

                val drawPath = DrawPath()
                drawPath.id = System.currentTimeMillis()
                drawPath.paint = mPaint
                drawPath.path = mPath
                mDrawPathList?.add(drawPath)

                //新一轮绘制开始,保存点。
                drawPath.points.add(PointF(event.x, event.y))

                invalidate()
                mTempX = mDownX
                mTempY = mDownY
            }

            MotionEvent.ACTION_MOVE -> {
                //Log.d(TAG, "ACTION_MOVE ${event.x} ${event.y}")

                val moveX = event.x
                val moveY = event.y

                mPath?.quadTo(mTempX, mTempY, moveX, moveY)

                mDrawPathList?.filter {
                    it.path == mPath
                }?.forEach {
                    it.points.add(PointF(event.x, event.y))
                }

                invalidate()
                mTempX = moveX
                mTempY = moveY
            }

            //每次手指抬起重置画笔,不然画笔会保存之前设置的属性会引起bug。
            MotionEvent.ACTION_UP -> {
                Log.d(TAG, "ACTION_UP ${event.x} ${event.y}")
                initPaint()
            }
        }

        return true
    }

    /**
     * 撤销。
     */
    fun undo() {
        if (mDrawPathList != null && mDrawPathList.size >= 1) {
            mSavePathList?.add(mDrawPathList[mDrawPathList.size - 1])
            mDrawPathList.removeAt(mDrawPathList.size - 1)

            invalidate()
        }
    }

    /**
     * 反撤销,重新生效。
     */
    fun reundo() {
        if (!mSavePathList.isNullOrEmpty()) {
            mDrawPathList?.add(mSavePathList[mSavePathList.size - 1])
            mSavePathList.removeAt(mSavePathList.size - 1)

            invalidate()
        }
    }

    /**
     * 画笔颜色。
     *
     * @param color
     */
    fun setPaintColor(color: Int) {
        this.mColor = color
        mPaint?.color = this.mColor
    }

    /**
     * 画笔的宽度。
     */
    fun setPaintWidth(size: Int) {
        mPaintWidth += size
        mPaint?.strokeWidth = mPaintWidth.toFloat()
    }

    /**
     * 放大,改变画笔的宽度。线条变粗。
     */
    fun enlargePaintWidth() {
        mPaintWidth += WIDTH_INCREMENT
        mPaint?.strokeWidth = mPaintWidth.toFloat()
    }

    fun getDrawPath(): ArrayList<DrawPath>? {
        return mDrawPathList
    }
}
XML 复制代码
<?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=".MainActivity">

    <com.pkg1115.PaintView
        android:id="@+id/paint_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="fitCenter"
        android:src="@mipmap/p1"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <RelativeLayout
        android:id="@+id/rl_left"
        android:layout_width="100dp"
        android:layout_height="wrap_content"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <Button
            android:id="@+id/btn_undo"
            android:layout_width="match_parent"
            android:layout_height="60dp"
            android:text="撤销" />

        <Button
            android:id="@+id/btn_red"
            android:layout_width="match_parent"
            android:layout_height="60dp"
            android:layout_below="@id/btn_undo"
            android:text="红色" />

        <Button
            android:id="@+id/btn_green"
            android:layout_width="match_parent"
            android:layout_height="60dp"
            android:layout_below="@id/btn_red"
            android:text="绿色" />

        <Button
            android:id="@+id/btn_enlarge"
            android:layout_width="match_parent"
            android:layout_height="60dp"
            android:layout_below="@id/btn_green"
            android:text="放大" />
    </RelativeLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

Android图形图像处理:添加涂鸦文字_android 在图片上涂鸦-CSDN博客文章浏览阅读2k次。先看运行效果: 关键的PaintView:package com.zhangphil;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graph..._android 在图片上涂鸦https://blog.csdn.net/zhangphil/article/details/87810653

相关推荐
晨春计1 小时前
【git】
android·linux·git
标标大人2 小时前
c语言中的局部跳转以及全局跳转
android·c语言·开发语言
木鬼与槐3 小时前
MySQL高阶1783-大满贯数量
android·数据库·mysql
iofomo3 小时前
【Abyss】Android 平台应用级系统调用拦截框架
android·开发工具·移动端
AirDroid_cn5 小时前
在家找不到手机?除了语音助手,还可以用远程控制!
android·智能手机·远程控制·手机使用技巧·远程控制手机
Good_tea_h13 小时前
Android中如何处理运行时权限?
android
冬田里的一把火313 小时前
[Android][Reboot/Shutdown] 重启/关机 分析
android·gitee
大海..13 小时前
Android 系统开发人员的权限说明文档
android
技术无疆17 小时前
ButterKnife:Android视图绑定的简化专家
android·java·android studio·android-studio·androidx·butterknife·视图绑定
JohnsonXin18 小时前
【兼容性记录】video标签在 IOS 和 安卓中的问题
android·前端·css·ios·h5·兼容性