- Cùng tìm hiểu Canvas trong Android (Phần 1)
- Custom attributes view trong Android (Phần 2)
- Thêm animation cho custom view Android (serie Canvas phần 3)
Thêm các thuộc tính (attributes) trong custom view Android
Chào mọi người, tiếp tục với serrie Canvas trong Android, mình cũng chẳng biết nên gọi là custom view hay là canvas nữa, vì canvas nó được sử dụng để tạo custom view.
Vào vấn đề chính của bài viết luôn, hôm nay mình sẽ giới thiệu cho bạn về các tạo các thuộc tính (atrributes) trong custom view. Ngoài các attribute mà android đã cung cấp sẵn thì bạn hoàn toàn có thể tạo thêm các thuộc tính mới mà mình tự định nghĩa giúp custom view linh hoạt hơn, tái sử dụng được trong nhiều trường hợp.
Mình sẽ tiếp tục với hình pacman ở bài trước, con pacman lần trước đang bị fix cứng màu sắc nên mình sẽ sử dụng các thuộc tính để nó có thể linh động thay đổi theo ý thích, do đó mình sẽ cần thêm 3 thuộc tính nữa đó là màu của pacman, màu của mắt, và sẽ thêm các dấu chấm to nữa để pacman có thể ăn.
Trong android, để định nghĩa các attribute thì bạn phải để nó trong file attrs.xml trong res.
<declare-styleable name="TestCanvas"> <attr name="numDot" format="integer" /> <attr name="pacmanColor" format="color"/> <attr name="eyeColor" format="color"/> </declare-styleable>
Chú ý name là tên class mà bạn định nghĩa custom view trong đó. Trong file layout của bạn, ví dụ mình đang dùng activity_main.xml thì bạn có thể dùng các thuộc tính đó một cách bình thường.
<com.fadbg.tuan.testcanvas.Canvas.TestCanvas android:layout_width="match_parent" android:layout_height="match_parent" app:numDot="4" app:pacmanColor="#c13f10" app:eyeColor="#00CED1" />
Các giá trị này sẽ được nhận trong class mà chúng ta đã định nghĩa custom view, mình đang dùng TestCanvas.
private void intAttrs(Context context, AttributeSet attrs) { TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.TestCanvas, 0, 0); try { numDot = a.getInteger(R.styleable.TestCanvas_numDot, numDot); colorPacman = a.getColor(R.styleable.TestCanvas_pacmanColor, getResources().getColor(R.color.colorAccent)); colorEye = a.getColor(R.styleable.TestCanvas_eyeColor, getResources().getColor(R.color.colorPrimary)); } finally { a.recycle(); } }
Bạn hãy chú ý trong các contructor thì có tham số AttributeSet attrs đây là nơi chứa các giá trị mà mình điền từ trong file layout.
Do đó bạn cần đưa hàm này vào trong constructor để xử lí dữ liệu.
public TestCanvas(Context context) { super(context); init(); } public TestCanvas(Context context, AttributeSet attrs) { super(context, attrs); intAttrs(context, attrs); init(); } public TestCanvas(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); intAttrs(context, attrs); init(); } public TestCanvas(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); intAttrs(context, attrs); init(); }
Trong init() thì bạn cũng cần sửa lại như sau, để điền mã màu vào cho con pacman sau khi đã lấy được từ layout
private void init() { pacmanPaint = new Paint(Paint.ANTI_ALIAS_FLAG); pacmanPaint.setColor(colorPacman); eyeOfPacmanPaint = new Paint(Paint.ANTI_ALIAS_FLAG); eyeOfPacmanPaint.setColor(colorEye); }
Chạy lại ứng dụng, thay đổi mã màu và màu của con pacman đã được thay đổi.
Bây giờ ta sẽ tạo thêm các dấu chấm cho con pacman chuẩn bị ăn, numDot chính là số lượng dấu chấm mà mình cần.
for (int i = 1; i <= numDot; i++) { canvas.drawCircle(cx + 200*i, 100 + 150, radiusDot, pacmanPaint); }
Chạy lại, bạn đã có kết quả như demo rồi, lưu ý bạn hãy sử dụng các hàm như getWidth() và getHeight() để có kích thước chính xác nhất, mình đang test nên fix cứng cho nhanh ấy mà.
Trong bài sau mình sẽ giới thiệu cho các bạn về các hiệu ứng (animation) để sự xuất hiện của con pacman được thực tế hơn.
Full code trong class TestCanvas:
public class TestCanvas extends View { Paint pacmanPaint; Paint eyeOfPacmanPaint; int numDot = 3; int colorPacman = getResources().getColor(R.color.colorAccent); int colorEye = getResources().getColor(R.color.colorPrimary); public TestCanvas(Context context) { super(context); init(); } public TestCanvas(Context context, AttributeSet attrs) { super(context, attrs); intAttrs(context, attrs); init(); } public TestCanvas(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); intAttrs(context, attrs); init(); } public TestCanvas(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); intAttrs(context, attrs); init(); } private void intAttrs(Context context, AttributeSet attrs) { TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.TestCanvas, 0, 0); try { numDot = a.getInteger(R.styleable.TestCanvas_numDot, numDot); colorPacman = a.getColor(R.styleable.TestCanvas_pacmanColor, getResources().getColor(R.color.colorAccent)); colorEye = a.getColor(R.styleable.TestCanvas_eyeColor, getResources().getColor(R.color.colorPrimary)); } finally { a.recycle(); } } private void init() { pacmanPaint = new Paint(Paint.ANTI_ALIAS_FLAG); pacmanPaint.setColor(colorPacman); eyeOfPacmanPaint = new Paint(Paint.ANTI_ALIAS_FLAG); eyeOfPacmanPaint.setColor(colorEye); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); int square = 300; float top = 100; float left = 100; float right = left + square; float bottom = top + square; canvas.drawArc(left, top, right, bottom, 30, 300, true, pacmanPaint); float cx = left + 180; float cy = top + 70; float radius = 25; canvas.drawCircle(cx, cy, radius, eyeOfPacmanPaint); for (int i = 1; i <= numDot; i++) { canvas.drawCircle(cx + 200*i, 100 + 150, radius + 10, pacmanPaint); } } }