Skip to content

Instantly share code, notes, and snippets.

@seanghay
Created June 18, 2019 09:39
Show Gist options
  • Save seanghay/f992ee0f83f0e252d95268c06f5c492c to your computer and use it in GitHub Desktop.
Save seanghay/f992ee0f83f0e252d95268c06f5c492c to your computer and use it in GitHub Desktop.
PaintView
class PaintView: View, View.OnTouchListener {
@ColorInt
var penColor: Int = Color.BLACK
@ColorInt
var paperColor: Int = Color.WHITE
var penSize: Int = 16f.dp.toInt()
private var bitmapSize = 0 to 0
private val penPaint = Paint(ANTI_ALIAS_FLAG).also {
it.color = penColor
it.strokeCap = Paint.Cap.ROUND
it.style = Paint.Style.STROKE
it.strokeJoin = Paint.Join.MITER
it.strokeWidth = 4f
}
private val bitmapPaint = Paint(Paint.DITHER_FLAG)
private val penPath: Path = Path()
private var _dx: Float = 0f
private var _dy: Float = 0f
private lateinit var bitmap: Bitmap
private lateinit var bitmapCanvas: Canvas
constructor(context: Context): super(context)
constructor(context: Context, attributeSet: AttributeSet): super(context, attributeSet)
constructor(context: Context, attributeSet: AttributeSet, defStyle: Int): super(context, attributeSet, defStyle)
init {
setOnTouchListener(this)
setBackgroundColor(paperColor)
}
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
super.onSizeChanged(w, h, oldw, oldh)
bitmapSize = w to h
clear()
}
fun clear() {
bitmap = Bitmap.createBitmap(bitmapSize.first, bitmapSize.second, Bitmap.Config.ARGB_8888)
bitmapCanvas = Canvas(bitmap)
invalidate()
}
fun saveAsImage(): Bitmap {
return Bitmap.createScaledBitmap(bitmap, bitmapSize.first, bitmapSize.second, true)
}
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
canvas ?: return
canvas.apply {
drawBitmap(bitmap, 0f, 0f, bitmapPaint)
drawPath(penPath, penPaint)
}
}
private fun touchMove(x: Float, y: Float) {
val dx = Math.abs(x - _dx)
val dy = Math.abs(y - _dy)
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
penPath.quadTo(_dx, _dy, (x + _dx)/2, (y + _dy)/2)
_dx = x
_dy = y
}
}
private fun touchStart(x: Float, y: Float) {
with(penPath) {
reset()
moveTo(x, y)
}
_dx = x
_dy = y
}
private fun touchUp() {
penPath.lineTo(_dx, _dy)
bitmapCanvas.drawPath(penPath, penPaint)
penPath.reset()
}
override fun onTouch(v: View?, event: MotionEvent?): Boolean {
return when(event?.action) {
MotionEvent.ACTION_DOWN -> {
touchStart(event.x, event.y)
invalidate()
true
}
MotionEvent.ACTION_UP -> {
touchUp()
invalidate()
true
}
MotionEvent.ACTION_MOVE -> {
touchMove(event.x, event.y)
invalidate()
true
}
else -> false
}
}
private val Float.dp: Float get()
= TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, toFloat(), resources.displayMetrics)
companion object {
const val TOUCH_TOLERANCE = 4f
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment