Các đối tượng trên Android như TextView
, EditText
, ImageView
đều được vẽ trên Canvas
của hệ thống Android, vậy vẽ các đối tượng này như thế nào?
Canvas là gì ?
Canvas
được xem là 1 bề mặt (giấy, bảng) có thể vẽ lên, ví dụ như vẽ điểm, đường thằng, hình chữ nhật, đường tròn, elip, văn bản, 1 hình ảnh và các hình học phức tạp khác.
Canvas có thể làm những gì ?
Trong Android, nếu muốn tạo 1 View
và tự vẽ lại tất cả các thành phần của View
đó, có thể sử dụng canvas.
Canvas trong Android cung cấp các phương thức để vẽ tất cả các đối tượng như sau:
- Các đối tượng hình học cơ bản (point, line, oval, rectangle, ...).
- Vẽ hình ảnh (bitmap, drawable).
- Vẽ đường - Path (tập hợp các điểm).
- Vẽ văn bản - Text.
Những thành phần vẽ đều được xử lý trong phương thức onDraw(Canvas canvas)
của class View
. Để vẽ những đối tượng thành phần lên Canvas
phải sử dụng 1 đối tượng Paint
để định dạng style
, color
, size
cho nét vẽ.
Khởi tạo project làm việc với Canvas
Chọn nền tảng và target API (có thể chọn API mới nhất).
Sau đó nhấn Next để Android Studio tiến hành tạo project.
Tiến hành tạo class GraphicView
kế thừa từ class View
để vẽ các thành phần.
package comcanvasdemo.example.nguyennghia.canvasdemo; import android.content.Context; import android.graphics.Canvas; import android.util.AttributeSet; import android.view.View; /** * Created by nguyennghia on 7/22/16. */ public class GraphicView extends View { public GraphicView(Context context) { this(context, null); } public GraphicView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public GraphicView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); // Draw component in here } }
Trong file activity_main.xml, thêm GraphicView
với độ rộng và độ cao match_parent
để có không gian rộng hiển thị các hình học:
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="comcanvasdemo.example.nguyennghia.canvasdemo.MainActivity"> <comcanvasdemo.example.nguyennghia.canvasdemo.GraphicView android:layout_width="match_parent" android:layout_height="match_parent" /> </FrameLayout>
Đối tượng Paint
Đối tượng Paint
trong Android dùng để định nghĩa size
, color
, kiểu nét vẽ sẽ sử dụng để vẽ bởi Canvas, truyền vào phương thức canvas.draw...
trong phương thức onDraw()
của View
.
Các phương thức của class Paint
Có 2 cách khởi tạo Paint
:
- Contructor không có đối số
Paint mPaint = new Paint();
- Contructor có 2 đối số
Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
Cờ Paint.ANTI_ALIAS_FLAG
truyền vào ở trên chỉ định cho Paint
rằng vẽ mượt cho các biên của các đối tượng (khử răng cưa). Ví dụ như vẽ hình tròn sẽ loại bỏ những răng cưa bao quanh hình tròn, từ đó có cảm giác hình vẽ lên mượt mà hơn.
Các phương thức được sử dụng phổ biến
setColor(int color)
: đặt màu cho nét vẽ.setAlpha(int a)
đặt giá trị alpha (từ 0 đến 255) cho nét vẽ, thường áp dụng để tạo hiệu ứng làm mờ.setStrokeWidth(float width)
: đặt giá trị độ rộng của nét vẽ.setStyle(Style style)
đặt kiểu cho nét vẽ, có 3 giá trị như sau:Paint.Style.FILL
: dùng để tô đối tượng, ví dụ như tô hình tròn, elip, oval.Paint.Style.STROKE
: dùng để vẽ đường (viền), ví dụ như vẽ đường tròn mà không có tô.Paint.Style.FILL_AND_STROKE
: vừa vẽ vừa tô.
setStrokeCap(Cap cap)
: đặt kiểu vẽ ở những điểm kết thúc của hai đường thẳng và có những giá trị sau:Cap.ROUND
: bo tròn nét vẽ ở hai đầu mút của đoạn thẳng.Cap.SQUARE
: vẽ nét vẽ bình thường, nét vẽ sẽ sắc cạnh ở 2 đầu mút của đoạn thẳng.
setTypeface(Typeface typeface)
: tùy chỉnh phông chữ vẽ text.setTextSize(float textSize)
: đặt kích thước phông chữ.
Vẽ các đối tượng cơ bản bằng Canvas
Canvas cung cấp rất nhiều các phương thức để vẽ các đối tượng hình học bắt đầu bởi phương thức cavas.draw…
:
DrawPoint
DrawLine
DrawRect
DrawCircle
DrawOvals
DrawArc
- ...
Tạo 1 đối tượng Paint
và đặt các thuộc tính phục vụ cho mục đích vẽ:
private void initPaint() { mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPaint.setColor(Color.BLUE); mPaint.setStrokeWidth(30); }
Màu sử dụng để vẽ là màu xanh BLUE
, độ rộng nét vẽ là 30 và đặt vào trong constructor thứ ba của GraphicView
.
public GraphicView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initPaint(); }
DrawPoint
Vẽ điểm tại toạ độ x, y sử dụng đối tượng paint
để vẽ:
drawPoint(float x, float y, @NonNull Paint paint)
Vẽ danh sách các điểm trong mảng pts
2 vị trí kề này là x và y, sử dụng đối tượng paint
để vẽ:
drawPoints(@NonNull float[] pts, @NonNull Paint paint)
Vẽ danh sách các điểm trong mảng pts và có giới hạn vẽ từ khoảng nào và độ dài là bao nhiêu?
drawPoints(float[] pts, int offset, int count, @NonNull Paint paint)
Ví dụ muốn vẽ 1 điểm ở vị trí x = 100, y = 100:
// Draw Point int x = 100; int y = 200; canvas.drawPoint(x, y, mPaint);
DrawLine
Vẽ đoạn thẳng với 4 tham số là điểm startX
, startY
và kết thúc là điểm stopX
, stopY
:
drawLine(float startX, float startY, float stopX, float stopY, Paint paint)
Vẽ đoạn thẳng trong mảng pts
với 4 phần tử liên tiếp sẽ là startX
, startY
, stopX
, stopY
với độ dời offset
trong mảng và số phần tử để vẽ:
drawLines(float[] pts, int offset, int count, Paint paint)
Vẽ đoạn thẳng trong mảng pts
, sử dụng paint
để vẽ:
drawLines(float[] pts, Paint paint)
Ví dụ vẽ đường chéo từ góc trái màn hình qua góc phải màn hình sẽ làm như sau:
// Draw Line float startX = 0; float startY = 0; float stopX = getWidth(); float stopY = getHeight(); canvas.drawLine(startX, startY, stopX, stopY, mPaint);
DrawRect
Vẽ hình chữ nhật với dữ liệu rect
là cấu trúc kiểu số thực:
drawRect(@NonNull RectF rect, @NonNull Paint paint)
Vẽ hình chữ nhật với rect
là cấu trúc kiểu số nguyên:
drawRect(@NonNull Rect rect, @NonNull Paint paint)
Với các thông số cơ bản left
, top
, right
, bottom
:
drawRect(float left, float top, float right, float bottom, @NonNull Paint paint)
Ví dụ muốn vẽ hình chữ nhật có độ rộng 100, độ cao 200 và nằm chính giữa màn hình như sau:
// Draw Rect float width = 100; float height = 200; float left = (getWidth() - width) / 2.0f; float top = (getHeight() - height) / 2.0f; canvas.drawRect(left, top, left + width, top + height, mPaint);
mPaint.setStyle(Paint.Style.STROKE);
DrawCircle
Với 4 tham số lần lượt là tọa độ tâm cx
, cy
, bán kính radius
và cuối cùng là paint
để vẽ:
drawCircle(float cx, float cy, float radius, @NonNull Paint paint)
Ví dụ vẽ hình tròn có bán kính là 50 ở góc trái trên:
// Draw Circle float radius = 50.0f; float cx = radius; float cy = radius; canvas.drawCircle(cx, cy, radius, mPaint);
DrawOval
Vẽ hình oval có các yếu tố là left
, top
, right
, bottom
, sử dụng paint
để vẽ:
drawOval(float left, float top, float right, float bottom, @NonNull Paint paint)
Vẽ hình oval trong giới hạn của cấu trúc rect
là số thực, sử dụng paint
để vẽ;
drawOval(@NonNull RectF rect, @NonNull Paint paint)
* Phương thức này chỉ gọi được trên Android API 21
Ví dụ vẽ hình oval chính giữa màn hình:
// Draw Oval float width = 300; float height = 100; float left = (getWidth() - width) / 2.0f; float top = (getHeight() - height) / 2.0f; canvas.drawOval(new RectF(left, top, left + width, top + height), mPaint);
DrawArc
Đây là hình học cuối cùng có các phương thức đễ vẽ cung tròn Arc lên Canvas.
Vẽ cung tròn với hình chữ nhật bao quanh rect
, góc bắt đầu vẽ startAngle
, cung vẽ sweepAngle
, sử dụng tâm vẽ useCenter
và paint
để có thể vẽ lên Canvas:
drawArc(@NonNull RectF rect, float startAngle, float sweepAngle, boolean useCenter, @NonNull Paint paint)
Vẽ cung tròn với các đối số left
, top
, right
, bottom
đại diện cho hình chữ nhật bao quanh, góc bắt đầu vẽ startAngle
, cung vẽ sweepAngle
, sử dụng tâm vẽ useCenter
và paint
để có thể vẽ lên Canvas:
drawArc(float left, float top, float right, float bottom, float startAngle, float sweepAngle, boolean useCenter, @NonNull Paint paint)
Ví dụ vẽ cung tròn ở giữa màn hình thiết bị với các thông số là góc bắt đầu vẽ có giá trị 45 và chiều dài cung vẽ là 270:
// Draw Arc float width = 400; float height = 400; float left = (getWidth() - width) / 2.0f; float top = (getHeight() - height) / 2.0f; canvas.drawArc(new RectF(left, top, left + width, top + height),45, 270, false, mPaint);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeCap(Paint.Cap.ROUND);
Có 2 đầu mút được bo tròn là tác dụng của Paint.Cap.Round
.
Hình ảnh cuối bài viết này là tiếp tục chỉnh lại phương thức drawArc()
đổi false
thành true
và xem kết quả.
// Draw Arc float width = 400; float height = 400; float left = (getWidth() - width) / 2.0f; float top = (getHeight() - height) / 2.0f; canvas.drawArc(new RectF(left, top, left + width, top + height),45, 270, true, mPaint);