- 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
() - }
-
- 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
? - private val mSavePathList: ArrayList
? -
- 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
? { - return mDrawPathList
- }
- }
- "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>