Lớp học lập trình này nằm trong khoá học Kotlin nâng cao cho Android. Bạn sẽ nhận được nhiều giá trị nhất qua khoá học này nếu thực hiện các lớp học lập trình theo trình tự, nhưng đó không phải là yêu cầu bắt buộc. Tất cả các lớp học lập trình của khoá học đều được liệt kê trên trang đích của lớp học lập trình Kiến thức nâng cao về cách tạo ứng dụng Android bằng Kotlin.
Giới thiệu
Trong Android, bạn có một số kỹ thuật để triển khai ảnh động và đồ hoạ 2D tuỳ chỉnh trong các khung hiển thị.
Ngoài việc sử dụng các thành phần có thể vẽ, bạn có thể tạo bản vẽ 2D bằng các phương thức vẽ của lớp Canvas. Canvas là một bề mặt vẽ 2D cung cấp các phương thức để vẽ. Điều này hữu ích khi ứng dụng của bạn cần thường xuyên vẽ lại chính nó, vì những gì người dùng thấy sẽ thay đổi theo thời gian. Trong lớp học lập trình này, bạn sẽ tìm hiểu cách tạo và vẽ trên một canvas xuất hiện trong View.
Các loại thao tác bạn có thể thực hiện trên canvas bao gồm:
- Tô màu cho toàn bộ canvas.
- Vẽ các hình dạng, chẳng hạn như hình chữ nhật, hình vòng cung và đường dẫn được tạo kiểu như đã xác định trong đối tượng
Paint. Đối tượngPaintlưu giữ thông tin về kiểu và màu sắc của cách vẽ hình học (chẳng hạn như đường thẳng, hình chữ nhật, hình bầu dục và đường dẫn) hoặc ví dụ: kiểu chữ của văn bản. - Áp dụng các phép biến đổi, chẳng hạn như dịch, điều chỉnh tỷ lệ hoặc biến đổi tuỳ chỉnh.
- Cắt, tức là áp dụng một hình dạng hoặc đường dẫn cho canvas để xác định các phần hiển thị của canvas.

Cách bạn có thể hình dung về hoạt động vẽ trên Android (cực kỳ đơn giản!)
Việc vẽ trong Android hoặc trên bất kỳ hệ thống hiện đại nào khác là một quy trình phức tạp bao gồm các lớp trừu tượng và tối ưu hoá cho đến phần cứng. Cách Android vẽ là một chủ đề thú vị mà nhiều người đã viết về, và thông tin chi tiết về chủ đề này nằm ngoài phạm vi của lớp học lập trình này.
Trong bối cảnh của lớp học lập trình này và ứng dụng vẽ trên canvas để hiển thị ở chế độ xem toàn màn hình, bạn có thể nghĩ về nó theo cách sau.

- Bạn cần có một khung hiển thị để hiển thị nội dung bạn đang vẽ. Đây có thể là một trong những khung hiển thị do hệ thống Android cung cấp. Hoặc, trong lớp học lập trình này, bạn sẽ tạo một khung hiển thị tuỳ chỉnh đóng vai trò là khung hiển thị nội dung cho ứng dụng của bạn (
MyCanvasView). - Giống như mọi khung hiển thị khác, khung hiển thị này cũng có canvas riêng (
canvas). - Để vẽ theo cách cơ bản nhất trên canvas của một khung hiển thị, bạn sẽ ghi đè phương thức
onDraw()và vẽ trên canvas của khung hiển thị đó. - Khi tạo bản vẽ, bạn cần lưu vào bộ nhớ đệm những gì đã vẽ trước đó. Có một số cách để lưu dữ liệu vào bộ nhớ đệm, một trong số đó là lưu trong bitmap (
extraBitmap). Một cách khác là lưu nhật ký những gì bạn đã vẽ dưới dạng toạ độ và hướng dẫn. - Để vẽ vào bitmap lưu vào bộ nhớ đệm (
extraBitmap) bằng API vẽ canvas, bạn sẽ tạo một canvas lưu vào bộ nhớ đệm (extraCanvas) cho bitmap lưu vào bộ nhớ đệm. - Sau đó, bạn vẽ trên canvas lưu vào bộ nhớ đệm (
extraCanvas), canvas này sẽ vẽ lên bitmap lưu vào bộ nhớ đệm (extraBitmap). - Để hiển thị mọi thứ được vẽ trên màn hình, bạn yêu cầu canvas của khung hiển thị (
canvas) vẽ bitmap lưu vào bộ nhớ đệm (extraBitmap).
Kiến thức bạn cần có
- Cách tạo một ứng dụng có Hoạt động, bố cục cơ bản và chạy ứng dụng đó bằng Android Studio.
- Cách liên kết trình xử lý sự kiện với các khung hiển thị.
- Cách tạo chế độ xem tuỳ chỉnh.
Kiến thức bạn sẽ học được
- Cách tạo một
Canvasvà vẽ trên đó để phản hồi thao tác chạm của người dùng.
Bạn sẽ thực hiện
- Tạo một ứng dụng vẽ các đường trên màn hình để phản hồi khi người dùng chạm vào màn hình.
- Ghi lại các sự kiện chuyển động và để phản hồi, hãy vẽ các đường trên một canvas xuất hiện trong một khung hiển thị tuỳ chỉnh ở chế độ toàn màn hình trên màn hình.
Ứng dụng MiniPaint sử dụng một khung hiển thị tuỳ chỉnh để hiển thị một đường kẻ nhằm phản hồi các thao tác chạm của người dùng, như minh hoạ trong ảnh chụp màn hình bên dưới.

Bước 1. Tạo dự án MiniPaint
- Tạo một dự án Kotlin mới có tên là MiniPaint bằng mẫu Empty Activity (Hoạt động trống).
- Mở tệp
app/res/values/colors.xmlrồi thêm 2 màu sau.
<color name="colorBackground">#FFFF5500</color>
<color name="colorPaint">#FFFFEB3B</color>- Mở
styles.xml - Trong phần tử mẹ của kiểu
AppThemeđã cho, hãy thay thếDarkActionBarbằngNoActionBar. Thao tác này sẽ xoá thanh thao tác để bạn có thể vẽ ở chế độ toàn màn hình.
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">Bước 2. Tạo lớp MyCanvasView
Trong bước này, bạn sẽ tạo một khung hiển thị tuỳ chỉnh, MyCanvasView, để vẽ.
- Trong gói
app/java/com.example.android.minipaint, hãy tạo một New > Kotlin File/Class (Mới > Lớp/Tệp Kotlin) có tên làMyCanvasView. - Mở rộng lớp
MyCanvasViewthành lớpViewvà truyền vàocontext: Context. Chấp nhận các mục nhập được đề xuất.
import android.content.Context
import android.view.View
class MyCanvasView(context: Context) : View(context) {
}Bước 3. Đặt MyCanvasView làm thành phần hiển thị nội dung
Để hiển thị nội dung bạn sẽ vẽ trong MyCanvasView, bạn phải đặt nội dung đó làm khung hiển thị nội dung của MainActivity.
- Mở
strings.xmlvà xác định một chuỗi để dùng cho nội dung mô tả của khung hiển thị.
<string name="canvasContentDescription">Mini Paint is a simple line drawing app.
Drag your fingers to draw. Rotate the phone to clear.</string>- Mở
MainActivity.kt - Trong
onCreate(), hãy xoásetContentView(R.layout.activity_main). - Tạo một thực thể của
MyCanvasView.
val myCanvasView = MyCanvasView(this)- Bên dưới, hãy yêu cầu chế độ toàn màn hình cho bố cục của
myCanvasView. Thực hiện việc này bằng cách đặt cờSYSTEM_UI_FLAG_FULLSCREENtrênmyCanvasView. Bằng cách này, khung hiển thị sẽ lấp đầy hoàn toàn màn hình.
myCanvasView.systemUiVisibility = SYSTEM_UI_FLAG_FULLSCREEN- Thêm nội dung mô tả.
myCanvasView.contentDescription = getString(R.string.canvasContentDescription)- Bên dưới, hãy đặt thành phần hiển thị nội dung thành
myCanvasView.
setContentView(myCanvasView)- Chạy ứng dụng. Bạn sẽ thấy một màn hình hoàn toàn màu trắng, vì canvas không có kích thước và bạn chưa vẽ gì cả.
Bước 1. Ghi đè onSizeChanged()
Phương thức onSizeChanged() được hệ thống Android gọi bất cứ khi nào một khung hiển thị thay đổi kích thước. Vì khung hiển thị bắt đầu mà không có kích thước, nên phương thức onSizeChanged() của khung hiển thị cũng được gọi sau khi Hoạt động tạo và mở rộng khung hiển thị lần đầu tiên. Do đó, phương thức onSizeChanged() này là nơi lý tưởng để tạo và thiết lập canvas của khung hiển thị.
- Trong
MyCanvasView, ở cấp lớp, hãy xác định các biến cho một canvas và một bitmap. Gọi họ làextraCanvasvàextraBitmap. Đây là bitmap và canvas của bạn để lưu vào bộ nhớ đệm những nội dung đã được vẽ trước đó.
private lateinit var extraCanvas: Canvas
private lateinit var extraBitmap: Bitmap- Xác định biến cấp lớp
backgroundColorcho màu nền của canvas và khởi tạo biến đó thànhcolorBackgroundmà bạn đã xác định trước đó.
private val backgroundColor = ResourcesCompat.getColor(resources, R.color.colorBackground, null)- Trong
MyCanvasView, hãy ghi đè phương thứconSizeChanged(). Phương thức gọi lại này được hệ thống Android gọi với kích thước màn hình đã thay đổi, tức là với chiều rộng và chiều cao mới (để thay đổi thành) và chiều rộng và chiều cao cũ (để thay đổi từ).
override fun onSizeChanged(width: Int, height: Int, oldWidth: Int, oldHeight: Int) {
super.onSizeChanged(width, height, oldWidth, oldHeight)
}- Trong
onSizeChanged(), hãy tạo một thực thể củaBitmapvới chiều rộng và chiều cao mới (là kích thước màn hình) rồi chỉ định thực thể đó choextraBitmap. Đối số thứ ba là cấu hình màu bitmap.ARGB_8888lưu trữ mỗi màu trong 4 byte và được đề xuất.
extraBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)- Tạo một thực thể
CanvastừextraBitmapvà chỉ định thực thể đó choextraCanvas.
extraCanvas = Canvas(extraBitmap)- Chỉ định màu nền để tô
extraCanvas.
extraCanvas.drawColor(backgroundColor)- Nhìn vào
onSizeChanged(), một bitmap và canvas mới sẽ được tạo mỗi khi hàm thực thi. Bạn cần một bitmap mới vì kích thước đã thay đổi. Tuy nhiên, đây là một lỗi rò rỉ bộ nhớ, khiến các bitmap cũ vẫn còn. Để khắc phục vấn đề này, hãy tái chếextraBitmaptrước khi tạoextraBitmaptiếp theo bằng cách thêm mã này ngay sau lệnh gọi đếnsuper.
if (::extraBitmap.isInitialized) extraBitmap.recycle()Bước 2. Ghi đè onDraw()
Mọi thao tác vẽ cho MyCanvasView đều diễn ra trong onDraw().
Để bắt đầu, hãy hiển thị canvas, lấp đầy màn hình bằng màu nền mà bạn đã đặt trong onSizeChanged().
- Ghi đè
onDraw()và vẽ nội dung củaextraBitmapđược lưu vào bộ nhớ đệm trên canvas liên kết với khung hiển thị. Phương thứcdrawBitmap()Canvascó nhiều phiên bản. Trong mã này, bạn cung cấp bitmap, toạ độ x và y (tính bằng pixel) của góc trên cùng bên trái vànullchoPaint, vì bạn sẽ đặt giá trị này sau.
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
canvas.drawBitmap(extraBitmap, 0f, 0f, null)
}
Xin lưu ý rằng canvas được truyền đến onDraw() và được hệ thống dùng để hiển thị bitmap khác với canvas mà bạn đã tạo trong phương thức onSizeChanged() và bạn dùng để vẽ trên bitmap.
- Chạy ứng dụng. Bạn sẽ thấy toàn bộ màn hình được tô bằng màu nền đã chỉ định.

Để vẽ, bạn cần có một đối tượng Paint chỉ định cách tạo kiểu cho các đối tượng khi vẽ và một đối tượng Path chỉ định nội dung đang được vẽ.
Bước 1. Khởi chạy đối tượng Paint
- Trong MyCanvasView.kt, ở cấp tệp trên cùng, hãy xác định một hằng số cho độ rộng nét vẽ.
private const val STROKE_WIDTH = 12f // has to be float- Ở cấp lớp của
MyCanvasView, hãy xác định một biếndrawColorđể lưu giữ màu cần vẽ và khởi tạo biến đó bằng tài nguyêncolorPaintmà bạn đã xác định trước đó.
private val drawColor = ResourcesCompat.getColor(resources, R.color.colorPaint, null)- Ở cấp lớp, bên dưới, hãy thêm một biến
paintcho đối tượngPaintvà khởi tạo biến đó như sau.
// Set up the paint with which to draw.
private val paint = Paint().apply {
color = drawColor
// Smooths out edges of what is drawn without affecting shape.
isAntiAlias = true
// Dithering affects how colors with higher-precision than the device are down-sampled.
isDither = true
style = Paint.Style.STROKE // default: FILL
strokeJoin = Paint.Join.ROUND // default: MITER
strokeCap = Paint.Cap.ROUND // default: BUTT
strokeWidth = STROKE_WIDTH // default: Hairline-width (really thin)
}colorcủapaintlàdrawColormà bạn đã xác định trước đó.isAntiAliasxác định xem có áp dụng tính năng làm mịn cạnh hay không. Khi đặtisAntiAliasthànhtrue, các cạnh của nội dung được vẽ sẽ trở nên mượt mà mà không ảnh hưởng đến hình dạng.isDither, khitrue, ảnh hưởng đến cách lấy mẫu xuống các màu có độ chính xác cao hơn thiết bị. Ví dụ: phương pháp tạo hiệu ứng chuyển màu là cách phổ biến nhất để giảm dải màu của hình ảnh xuống còn 256 màu (hoặc ít hơn).styleđặt loại hoạt động vẽ sẽ được thực hiện cho một nét vẽ, về cơ bản là một đường thẳng.Paint.Stylechỉ định xem phần tử cơ bản đang được vẽ là được tô màu, được vẽ đường viền hay cả hai (cùng màu). Theo mặc định, đối tượng mà bạn áp dụng sơn sẽ được tô. ("Fill" (Tô màu) cho phần bên trong hình dạng, trong khi "stroke" (đường viền) theo đường viền của hình dạng.)strokeJoincủaPaint.Joinchỉ định cách các đường và đoạn cong kết hợp trên một đường có nét vẽ. Giá trị mặc định làMITER.strokeCapđặt hình dạng của phần cuối đường kẻ thành một nắp.Paint.Capchỉ định cách bắt đầu và kết thúc các đường kẻ và đường dẫn được vẽ bằng nét. Giá trị mặc định làBUTT.strokeWidthchỉ định chiều rộng của nét vẽ bằng pixel. Theo mặc định, chiều rộng là rất nhỏ, vì vậy, bạn nên đặt thành hằng sốSTROKE_WIDTHmà bạn đã xác định trước đó.
Bước 2. Khởi tạo một đối tượng Đường dẫn
Path là đường dẫn của nội dung mà người dùng đang vẽ.
- Trong
MyCanvasView, hãy thêm một biếnpathvà khởi tạo biến đó bằng một đối tượngPathđể lưu trữ đường dẫn đang được vẽ khi theo dõi thao tác chạm của người dùng trên màn hình. Nhậpandroid.graphics.PathchoPath.
private var path = Path()Bước 1. Phản hồi chuyển động trên màn hình
Phương thức onTouchEvent() trên một khung hiển thị được gọi mỗi khi người dùng chạm vào màn hình.
- Trong
MyCanvasView, hãy ghi đè phương thứconTouchEvent()để lưu vào bộ nhớ đệm toạ độxvàycủaeventđã truyền vào. Sau đó, hãy dùng biểu thứcwhenđể xử lý các sự kiện chuyển động khi chạm xuống màn hình, di chuyển trên màn hình và nhấc tay khỏi màn hình. Đây là những sự kiện cần thiết để vẽ một đường thẳng trên màn hình. Đối với mỗi loại sự kiện, hãy gọi một phương thức tiện ích, như minh hoạ trong mã dưới đây. Hãy xem tài liệu về lớpMotionEventđể biết danh sách đầy đủ các sự kiện chạm.
override fun onTouchEvent(event: MotionEvent): Boolean {
motionTouchEventX = event.x
motionTouchEventY = event.y
when (event.action) {
MotionEvent.ACTION_DOWN -> touchStart()
MotionEvent.ACTION_MOVE -> touchMove()
MotionEvent.ACTION_UP -> touchUp()
}
return true
}- Ở cấp lớp, hãy thêm các biến
motionTouchEventXvàmotionTouchEventYcòn thiếu để lưu vào bộ nhớ đệm toạ độ x và y của sự kiện chạm hiện tại (toạ độMotionEvent). Khởi tạo chúng thành0f.
private var motionTouchEventX = 0f
private var motionTouchEventY = 0f- Tạo các phần giữ chỗ cho 3 hàm
touchStart(),touchMove()vàtouchUp().
private fun touchStart() {}
private fun touchMove() {}
private fun touchUp() {}- Mã của bạn sẽ được tạo và chạy, nhưng bạn sẽ chưa thấy gì khác ngoài nền có màu.
Bước 2. Triển khai touchStart()
Phương thức này được gọi khi người dùng chạm vào màn hình lần đầu tiên.
- Ở cấp lớp, hãy thêm các biến để lưu vào bộ nhớ đệm các giá trị x và y mới nhất. Sau khi người dùng ngừng di chuyển và nhấc ngón tay lên, đây là điểm bắt đầu cho đường dẫn tiếp theo (đoạn tiếp theo của đường kẻ cần vẽ).
private var currentX = 0f
private var currentY = 0f- Triển khai phương thức
touchStart()như sau. Đặt lạipath, di chuyển đến toạ độ x-y của sự kiện chạm (motionTouchEventXvàmotionTouchEventY), rồi chỉ địnhcurrentXvàcurrentYcho giá trị đó.
private fun touchStart() {
path.reset()
path.moveTo(motionTouchEventX, motionTouchEventY)
currentX = motionTouchEventX
currentY = motionTouchEventY
}Bước 3. Triển khai touchMove()
- Ở cấp lớp, hãy thêm một biến
touchTolerancerồi đặt biến đó thànhViewConfiguration.get(context).scaledTouchSlop.
private val touchTolerance = ViewConfiguration.get(context).scaledTouchSlopKhi sử dụng đường dẫn, bạn không cần vẽ từng pixel và mỗi lần yêu cầu làm mới màn hình. Thay vào đó, bạn có thể (và sẽ) nội suy một đường dẫn giữa các điểm để có hiệu suất tốt hơn nhiều.
- Nếu ngón tay hầu như không di chuyển, bạn không cần vẽ.
- Nếu ngón tay di chuyển ít hơn khoảng cách
touchTolerance, thì không vẽ. scaledTouchSloptrả về khoảng cách tính bằng pixel mà một thao tác chạm có thể di chuyển trước khi hệ thống cho rằng người dùng đang di chuyển.
- Xác định phương thức
touchMove(). Tính khoảng cách đã đi (dx,dy), tạo một đường cong giữa hai điểm và lưu trữ đường cong đó trongpath, cập nhật tổng sốcurrentXvàcurrentYđang chạy, đồng thời vẽpath. Sau đó, hãy gọiinvalidate()để buộc vẽ lại màn hình bằngpathđã cập nhật.
private fun touchMove() {
val dx = Math.abs(motionTouchEventX - currentX)
val dy = Math.abs(motionTouchEventY - currentY)
if (dx >= touchTolerance || dy >= touchTolerance) {
// QuadTo() adds a quadratic bezier from the last point,
// approaching control point (x1,y1), and ending at (x2,y2).
path.quadTo(currentX, currentY, (motionTouchEventX + currentX) / 2, (motionTouchEventY + currentY) / 2)
currentX = motionTouchEventX
currentY = motionTouchEventY
// Draw the path in the extra bitmap to cache it.
extraCanvas.drawPath(path, paint)
}
invalidate()
}Chi tiết hơn về phương thức này:
- Tính khoảng cách đã di chuyển (
dx, dy). - Nếu chuyển động vượt quá ngưỡng dung sai chạm, hãy thêm một đoạn vào đường dẫn.
- Đặt điểm bắt đầu cho phân đoạn tiếp theo thành điểm cuối của phân đoạn này.
- Sử dụng
quadTo()thay vìlineTo()để tạo một đường kẻ được vẽ mượt mà mà không có góc. Xem phần Đường cong Bezier. - Gọi
invalidate()để (cuối cùng gọionDraw()và) vẽ lại khung hiển thị.
Bước 4: Triển khai touchUp()
Khi người dùng nhấc ngón tay lên, bạn chỉ cần đặt lại đường dẫn để đường dẫn không được vẽ lại. Không có gì được vẽ, nên không cần phải vô hiệu hoá.
- Triển khai phương thức
touchUp().
private fun touchUp() {
// Reset the path so it doesn't get drawn again.
path.reset()
}- Chạy mã và dùng ngón tay để vẽ trên màn hình. Lưu ý rằng nếu bạn xoay thiết bị, màn hình sẽ bị xoá vì trạng thái vẽ không được lưu. Đối với ứng dụng mẫu này, đây là theo thiết kế, nhằm mang đến cho người dùng một cách đơn giản để xoá màn hình.

Bước 5: Vẽ một khung xung quanh bản phác thảo
Khi người dùng vẽ trên màn hình, ứng dụng của bạn sẽ tạo đường dẫn và lưu đường dẫn đó vào bitmap extraBitmap. Phương thức onDraw() hiển thị bitmap bổ sung trong canvas của khung hiển thị. Bạn có thể vẽ thêm trong onDraw(). Ví dụ: bạn có thể vẽ các hình dạng sau khi vẽ bitmap.
Ở bước này, bạn vẽ một khung xung quanh rìa của bức ảnh.
- Trong
MyCanvasView, hãy thêm một biến có tên làframechứa một đối tượngRect.
private lateinit var frame: Rect- Ở cuối
onSizeChanged(), hãy xác định một phần lồng ghép và thêm mã để tạoRectsẽ được dùng cho khung, sử dụng kích thước mới và phần lồng ghép.
// Calculate a rectangular frame around the picture.
val inset = 40
frame = Rect(inset, inset, width - inset, height - inset)- Trong
onDraw(), sau khi vẽ bitmap, hãy vẽ một hình chữ nhật.
// Draw a frame around the canvas.
canvas.drawRect(frame, paint)- Chạy ứng dụng của bạn. Chú ý đến khung hình.

Nhiệm vụ (không bắt buộc): Lưu trữ dữ liệu trong một Đường dẫn
Trong ứng dụng hiện tại, thông tin vẽ được lưu trữ trong một bitmap. Mặc dù đây là một giải pháp hay, nhưng không phải là cách duy nhất có thể dùng để lưu trữ thông tin bản vẽ. Cách bạn lưu trữ nhật ký vẽ sẽ tuỳ thuộc vào ứng dụng và các yêu cầu của bạn. Ví dụ: nếu đang vẽ hình dạng, bạn có thể lưu danh sách các hình dạng cùng với vị trí và kích thước của chúng. Đối với ứng dụng MiniPaint, bạn có thể lưu đường dẫn dưới dạng Path. Dưới đây là hướng dẫn chung về cách thực hiện việc đó (nếu bạn muốn thử).
- Trong
MyCanvasView, hãy xoá tất cả mã choextraCanvasvàextraBitmap. - Thêm các biến cho đường dẫn cho đến thời điểm hiện tại và đường dẫn đang được vẽ.
// Path representing the drawing so far
private val drawing = Path()
// Path representing what's currently being drawn
private val curPath = Path()- Trong
onDraw(), thay vì vẽ bitmap, hãy vẽ các đường dẫn đã lưu và đường dẫn hiện tại.
// Draw the drawing so far
canvas.drawPath(drawing, paint)
// Draw any current squiggle
canvas.drawPath(curPath, paint)
// Draw a frame around the canvas
canvas.drawRect(frame, paint)- Trong
touchUp(), hãy thêm đường dẫn hiện tại vào đường dẫn trước đó và đặt lại đường dẫn hiện tại.
// Add the current path to the drawing so far
drawing.addPath(curPath)
// Rewind the current path for the next touch
curPath.reset()- Chạy ứng dụng của bạn và chắc chắn là sẽ không có sự khác biệt nào.
Tải mã xuống cho lớp học lập trình đã hoàn thành.
$ git clone https://github.com/googlecodelabs/android-kotlin-drawing-canvas
Ngoài ra, bạn có thể tải kho lưu trữ xuống dưới dạng tệp ZIP, sau đó giải nén và mở tệp đó trong Android Studio.
Canvaslà một bề mặt vẽ 2D cung cấp các phương thức vẽ.Canvascó thể được liên kết với một thực thểViewhiển thị thực thể đó.- Đối tượng
Paintlưu giữ thông tin về kiểu và màu sắc về cách vẽ các hình học (chẳng hạn như đường thẳng, hình chữ nhật, hình bầu dục và đường dẫn) và văn bản. - Một mẫu phổ biến để làm việc với canvas là tạo một khung hiển thị tuỳ chỉnh và ghi đè các phương thức
onDraw()vàonSizeChanged(). - Ghi đè phương thức
onTouchEvent()để ghi lại các thao tác chạm của người dùng và phản hồi các thao tác đó bằng cách vẽ các đối tượng. - Bạn có thể sử dụng một bitmap bổ sung để lưu thông tin vào bộ nhớ đệm cho các bản vẽ thay đổi theo thời gian. Ngoài ra, bạn có thể lưu trữ các hình dạng hoặc một đường dẫn.
Khoá học của Udacity:
Tài liệu dành cho nhà phát triển Android:
- Lớp
Canvas - Lớp
Bitmap - Lớp
View - Lớp
Paint - Cấu hình
Bitmap.config - Lớp
Path - Trang Wikipedia về đường cong Bezier
- Canvas và đối tượng có thể vẽ
- Loạt bài viết về Cấu trúc đồ hoạ (nâng cao)
- drawables
- onDraw()
- onSizeChanged()
MotionEventViewConfiguration.get(context).scaledTouchSlop
Phần này liệt kê các bài tập về nhà cho học viên của lớp học lập trình này trong phạm vi khoá học có người hướng dẫn. Người hướng dẫn phải thực hiện các việc sau đây:
- Giao bài tập về nhà nếu cần.
- Trao đổi với học viên về cách nộp bài tập về nhà.
- Chấm điểm bài tập về nhà.
Người hướng dẫn có thể sử dụng các đề xuất này ít hoặc nhiều tuỳ ý và nên giao cho học viên bất kỳ bài tập về nhà nào khác mà họ cảm thấy phù hợp.
Nếu bạn đang tự học các lớp học lập trình, hãy sử dụng những bài tập về nhà này để kiểm tra kiến thức của mình.
Trả lời các câu hỏi sau
Câu hỏi 1
Bạn cần có những thành phần nào sau đây để làm việc với Canvas? Hãy chọn mọi câu trả lời phù hợp.
▢ Bitmap
▢ Paint
▢ Path
▢ View
Câu hỏi 2
Lệnh gọi đến invalidate() có chức năng gì (nói chung)?
▢ Vô hiệu hoá và khởi động lại ứng dụng của bạn.
▢ Xoá bản vẽ khỏi bitmap.
▢ Cho biết bạn không nên chạy mã trước đó.
▢ Yêu cầu hệ thống vẽ lại màn hình.
Câu hỏi 3
Chức năng của các đối tượng Canvas, Bitmap và Paint là gì?
▢ Bề mặt vẽ 2D, bitmap hiển thị trên màn hình, thông tin định kiểu để vẽ.
▢ Bề mặt vẽ 3D, bitmap để lưu vào bộ nhớ đệm đường dẫn, thông tin định kiểu để vẽ.
▢ Nền tảng vẽ 2D, bitmap hiển thị trên màn hình, tạo kiểu cho khung hiển thị.
▢ Bộ nhớ đệm cho thông tin vẽ, bitmap để vẽ, thông tin định kiểu để vẽ.
Để biết đường liên kết đến các lớp học lập trình khác trong khoá học này, hãy xem trang đích của các lớp học lập trình trong khoá học Kiến thức nâng cao về cách tạo ứng dụng Android bằng Kotlin.