Android

Canvas trong Android (Phần 2)

Giới thiệu

Tiếp nối bài viết Canvas trong Android (Phần 1) thì bài viết hôm nay tôi sẽ giới thiệu vẽ những thành phần còn lại còn lại lên canvas đó là vẽ Bitmap và vẽ Text chuyên sâu. Và sau đó là giới thiệu những các phép biến đổi cơ bản trên canvas (translate, rotate, scale) và cách sử dụng save, restore canvas trong Android.

Vẽ các đối tượng hình ảnh, text lên canvas

Vẽ Bitmap

Các phương thức dùng để vẽ bitmap lên Canvas

drawBitmap(@NonNull Bitmap bitmap, @NonNull Matrix matrix, @Nullable Paint paint)

Vẽ bitmap lên canvas có apply matrix.

drawBitmap(@NonNull Bitmap bitmap, @Nullable Rect src, @NonNull RectF dst, @Nullable Paint paint)

Vẽ bitmap lên canvas với các đối số là

bitmap: source bitmap dùng để vẽ lên canvas

src: là hình chữ nhật cắt bitmap để vẽ. Ví dụ bạn muốn gắt một phần nào đó của bitmap để vẽ chứ không muốn vẽ toàn bộ hình ảnh. Trường hợp vẽ toàn hình ảnh sẽ truyền vào null.

dst: là hình chữ nhật mô tả toạ độ để vẽ lên canvas.

Lưu ý: Kiểu dữ liệu của các thuộc tính của dst đều là số thực float (left, top, right, bottom).

drawBitmap(@NonNull Bitmap bitmap, @Nullable Rect src, @NonNull Rect dst, @Nullable Paint paint)

Giống như phương thức trên nhưng kiểu dữ liệu của các thuộc tính dst đều kiểu nguyên (left, top, right, bottom).

drawBitmap(@NonNull Bitmap bitmapfloat leftfloat top, @Nullable Paint paint)

Vẽ bitmap bắt đầu ở vị trí left và top xác định trên màn hình. Và điểm vẽ tính từ góc trái trên của bitmap.

Ví dụ mình sẽ vẽ một bitmap ở dưới giữa màn hình như sau:

Trước tiên chúng ta sẽ chuẩn bị 1 bitmap để vẽ:

Trong method onDraw ta hiện thực như sau:

Kết quả sau khi run chương trình

canvas-android-ss-14

Bây giờ tôi muốn cắt 1/4 góc trái bên của bitmap và vẽ nó ở right-bottom của màn hình:

canvas-android-ss-15

Ví dụ cuối cùng về vẽ bitmap là tôi sẽ vẽ một bitmap full (không có cắt xén) và vẽ nó ở chính giữa màn hình.

canvas-android-ss-16

Vậy là chúng ta đã đi qua xong phần vẽ bitmap lên canvas. Và dưới đây là một phần khá hứng thú đã là vẽ text lên canvas.

Vẽ text

Việc vẽ text được sử dụng khá nhiều trong Android. Vì với bất kì ứng dụng nào, bạn cũng thấy text có mặt bất cứ ở đâu. Và việc vẽ những đoạn text phức tạp cũng sẽ được đề cập ở ngay phần dưới đây.

Với việc vẽ text Android có cung cấp cho chúng ta class có tên là TextPaint kế thừa từ Paint giúp chúng ta vẽ text lên canvas mạnh mẽ hơn. Và khi và text tôi khuyến khích các bạn nên sử dụng TextPaint thay vì sử dụng Paint.

Trong method initPaint() đã viết ở phần 1 tôi thêm vào phần khởi tạo TextPaint sử dụng để vẽ text.

Vẽ text thông thường

Các phương thức để vẽ text

drawText(@NonNull String textfloat xfloat y, @NonNull Paint paint)

Vẽ string với vị trí bắt đầu vẽ x, y.

drawText(@NonNull String text, int start, int end, float x, float y, @NonNull Paint paint)

Vẽ String với các đối số start, end xác định vẽ từ vị trí nào tới vị trí nào của string với vị trí bắt đầu x, y.

drawText(@NonNull char[] text, int index, int count, float x, float y, @NonNull Paint paint)

Vẽ một mảng char, bắt đầu với index và số lượng phần tử cần vẽ và vẽ ở vị trí x, y.

drawText(@NonNull CharSequence text, int start, int end, float x, float y, @NonNull Paint paint)

Vẽ CharSequence với vị trí bắt đầu và kết thúc ở vị trí x, y.

Ví dụ tôi muốn vẽ chuỗi “Eitguide Android” ở vị trí x = 100, y = 400:

canvas-android-ss-17

Tuy nhiên tôi ví dụ tiếp theo tôi muốn sử dụng đoạn text “Eitguide Android” để vẽ nhưng chỉ muốn vẽ đoạn “guide Androi” thì tôi làm như sau:

canvas-android-ss-18

Trường hợp đoạn text quá dài so với view. Ví dụ chuỗi “We can actually use any custom font that we’d like within our applications.” Và tôi muốn hiển thị chuỗi “…” khi chuỗi chạm mép của view thì tôi làm như sau:

canvas-android-ss-19

Tiếp theo chúng ta sẽ tìm hiểu các vẽ text phức tạp hơn đó là trong 1 text chúng ta có thể vẽ như sau

Vẽ text với Spanable.

Tôi muốn vẽ text đủ các style như hình dưới đây:

canvas-android-ss-20

  • Đoạn text đầu tiên tôi cho in đậm text
  • Đoạn tiếp theo sẽ có background màu đỏ
  • Đoạn tiết có foreground màu xanh
  • Đoạn tiếp nữa có style chữ in nghiêng
  • Và đoạn cuối sẽ là chữ bình thường và gạch chân

Và làm sao chúng ta làm được chuyện đó. Giải pháp là chúng ta sử dụng StaticLayout.

Với việc sử dụng Spanable để setSpan cho CharSequence chúng ta có thể set bất cứ style nào cho text. Và sử dụng StaticLayout để vẽ lên cavas.

Các tính năng nâng cao của Canvas

Canvas cho chúng ta thực hiện các phép biến đổi hình học như translate, scale, rotate để giúp chúng ta vẽ các đối tượng một cách linh hoạt hơn.

Translate

Thực hiện dịch chuyển canvas một đoạn dx, và dy:

Việc translate canvas được hiểu như là thay đổi gốc toạ độ để vẻ. Mặt định góc toạ độ sẽ nằm ở gốc trái trên của View. Sau khi tịnh tiến một khoảng dx, dy thì gốc toạ độ sẽ nằm ở dx, và dy.

Ví dụ khi bạn chưa translate canvas và bạn vẽ một điểm ở vị trí (x, y) = (200, 400) sẽ có kết quả giống với

kết quả bạn translate canvas một đoạn dx = 200, dy = 400 và ngay sau đó vẽ một điểm tại vị trí (x, y) = (0, 0).

Scale

Scale là phép biến đổi thay đổi kích thước của vật thể. Trương trường hợp này là thay đổi kích thước của các đối tượng vẻ trên canvas.

Mặc định scale sx, sy có giá trị 1. Nếu chúng ta set sx = 2, sy = 4 thì đối tượng sẽ có kích thước theo chiều x lớn hơn 2 lần và kích thước lớn hơn chiều y là 4 lần.

Rotate

Rotate là phép biển đổi xoay đối tượng theo một góc xác định

Ví dụ khi muốn xoay các đối tượng vẽ 45 độ. Ta set dễ dàng như sau:

Save và Restore Canvas

Thử set trường hợp tôi muốn vẽ hai đối tượng. Tôi muốn vẽ đối tượng thứ nhất lớn hơn đối tượng thứ đối tượng gốc của nó hơn 4 lần cả chiều x và chiều y. Và đối tượng thứ 2 tôi vẽ y nguyên giống hình dạng của nó không có scale. Các bước là như sau:

Bước 1:

Set Scale cho canvas sx, sy = 4;

Bước 2: 

Vẽ đối tượng thứ nhất

Bước 3:

Scale canvas về lại trạng thái ban đầu

Bước 4:

Vẽ đối tượng thứ 2

Bước 5:

Kết thúc

Các bạn thấy rằng mỗi khi thay đổi trạng thái của canvas(translate, scale, rotate), muốn đưa về trạng thái củ chúng ta phải nhớ những thông số mà chúng ta làm thay đổi trạng thái và set ngược lại giá trị đó để đưa canvas về trạng thái cũ.

Save Canvas

Trước khi bạn thay đổi trạng thái của canvas gọi canvas.Save(); để lưu lại trạng thái hiện tại của canvas.

Khi đã save trạng thái thì bạn cứ thoải mái sử dụng các phép biến đổi canvas.

Restore Canvas

Gọi canvas.Restore(); để đưa canvas về trạng thái nó đã save trước đó.

Lưu ý. canvas.Restore() chỉ có thể gọi được nếu bạn đã call canvas.Save();. Nếu bạn cố tình gọi canvas.Restore() mà chưa gọi canvas.Save() ở trước thì Android sẽ ném ra ngoại lệ.

Kết luận

Qua hai bài viết tôi đã cùng các bạn tìm hiểu từ cơ bản cho đến nâng cao về canvas trong Android. Tôi tin rằng qua hai bài viết này các bạn có thể vẽ bất cứ thứ gì lên cavas giống như những View được Google xây dựng sẵn trong Android. Và việc bạn tạo View mới sử dụng cho dự án của bạn hoàn toàn dễ dàng. Nếu có bất cứ thắc mắc nào các bạn có thể để lại commnet để tối có thể giải đáp cho các bạn.

9 thoughts on “Canvas trong Android (Phần 2)”

  1. Bạn ơi, trong android có thể sử dụng repaint() ko vậy. Nếu ko thì có thể sử dụng phương thức nào thay thế?

    1. Ý của bạn là vẽ lại phải không ạ. Bạn có thể sử dụng phương thức invalidate(). Phương thức này sẽ call lại method onDraw() để thực hiện vẽ lại View nha bạn.

    2. Ngoài ra bạn cũng có thể sử dụng phương thức postInvalidateDelayed(long); để thực hiện vẽ lại View sau một khoảng thời gian nào đó tính bằng milisecond.

  2. Chào bạn,

    Mình đang muốn làm một chức năng như thế này: Mình sẽ tạo một con đường đi từ A đến B (đường đi này ngoằn ngoèo), user sẽ chạm tay vào từ điểm A và di chuyển đến điểm B. Vậy làm thế nào mình check được user đó có đi ra khỏi con đường đó không nhỉ?

    1. Nếu làm như vậy bạn đã lưu lại các điểm trên đoạn từ A tới B. Với việc check user có đi ra ngoài đoạn đường không thì trong View#onTouchEvent bạn lấy ra vị trí bạn đang chạm rồi kiểm tra với data các điểm của bạn.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.