-
Notifications
You must be signed in to change notification settings - Fork 1
/
DragAndPlaceGameView.kt
147 lines (118 loc) · 4.54 KB
/
DragAndPlaceGameView.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
package com.monsterbrain.slideandplaceview
import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.util.Log
import android.view.MotionEvent
import android.view.View
class DragAndPlaceGameView(context: Context, attrs: AttributeSet?) : View(context, attrs) {
private lateinit var imgSrcRect: Rect
private lateinit var dstRect: Rect
private var mPaint: Paint = Paint(Paint.ANTI_ALIAS_FLAG)
private var debugPaint: Paint = Paint(Paint.ANTI_ALIAS_FLAG)
private val numCols = 3
private val numRows = 3
private var imgBitmap: Bitmap? = null
private val pieceRects = mutableListOf<Rect>()
private val pieces = mutableListOf<PuzzlePiece>()
private var movingPiece: PuzzlePiece? = null
private var bufferBitmap: Bitmap? = null
private var bufferCanvas: Canvas? = null
inner class PuzzlePiece(
val srcRect: Rect,
var destRect: Rect
) {
private val initialRect = Rect(destRect)
fun moveToTouchPoint(x: Float, y: Float) {
destRect.offsetTo((x - destRect.width()/2).toInt(), (y -destRect.height()/2).toInt())
}
}
init {
debugPaint.style = Paint.Style.STROKE
debugPaint.color = Color.RED
debugPaint.strokeWidth = 2f
}
fun setBitmap(bmp: Bitmap) {
imgBitmap = bmp
imgSrcRect = Rect(0, 0, bmp.width, bmp.height)
invalidate()
}
private val imgWidthInPercent = 0.60f
private val imgHeightInPercent = 0.90f
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
super.onSizeChanged(w, h, oldw, oldh)
bufferBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888)
bufferCanvas = Canvas(bufferBitmap!!)
var imgWidth = imgWidthInPercent * w
val imgHeight = if (imgWidth > h) h*imgHeightInPercent else imgWidth
imgWidth = imgHeight // h == w
val leftMargin = ((w - imgWidth) / 2f).toInt()
val topMargin = ((h - imgHeight) / 2f).toInt()
dstRect = Rect(leftMargin, topMargin, leftMargin + imgWidth.toInt(), topMargin + imgHeight.toInt())
val numPieces = numCols * numRows
val pieceWidth = (imgWidth / numCols).toInt()
val srcWidth = imgBitmap?.width ?: 0
val srcPieceWidth = srcWidth / numCols
for (i in 0 until numRows) {
for (j in 0 until numCols) {
val rect = Rect(
leftMargin + (j*pieceWidth),
topMargin + (i*pieceWidth),
leftMargin + (j+1)*pieceWidth, topMargin + (i+1)*pieceWidth
)
pieceRects.add(rect)
val srcRect = Rect(
(j*srcPieceWidth), (i*srcPieceWidth),
(j+1)*srcPieceWidth, (i+1)*srcPieceWidth
)
val piece = PuzzlePiece(srcRect, rect)
pieces.add(piece)
}
}
invalidate()
}
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
imgBitmap?.let {
// canvas?.drawBitmap(it, imgSrcRect, dstRect, mPaint) //picture to draw
bufferCanvas?.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR)
for (piece in pieces) {
bufferCanvas?.drawBitmap(it, piece.srcRect, piece.destRect, mPaint) //picture parts to draw
}
}
bufferBitmap?.let { canvas?.drawBitmap(it, 0f, 0f, mPaint) } //buffered bitmap for performance
drawDebugRects(pieceRects, canvas)
}
private fun drawDebugRects(rectList: MutableList<Rect>, canvas: Canvas?) {
canvas?.let {
for (rect in rectList) {
it.drawRect(rect, debugPaint)
}
}
}
// currently touch is handled in the activity
override fun onTouchEvent(event: MotionEvent?): Boolean {
when (event!!.action) {
MotionEvent.ACTION_DOWN -> {
for (piece in pieces) {
if (piece.destRect.contains(event.x.toInt(), event.y.toInt())) {
movingPiece = piece
Log.i("xxy", "touched: $piece")
break
}
}
}
MotionEvent.ACTION_MOVE -> {
movingPiece?.let {
it.moveToTouchPoint(event.x, event.y)
invalidate()
}
invalidate()
}
MotionEvent.ACTION_UP -> {
invalidate()
}
}
return true
}
}