Contents
Chào bạn, khi người ta nhắc tới vẽ thì đó đúng làm ác mộng của giới lập trình viên. Trong một thời đại mà cái gì cũng có sẵn và nhanh. Thì việc tạo giao diện bằng kéo thả luôn luôn là ưu tiên số 1. Tuy nhiên, sẽ có những UI rất phức tạp và chỉ còn cách duy nhất là vẽ mà thôi. Và
Vẽ cũng là 1 trong các phương pháp custom view.
Bài viết này sẽ vén bức màn bí mật về vẽ trong iOS với Swift. Nếu bạn chưa tìm hiểu về Custom View thì có thể tham khảo bài trước:
Chuẩn bị
- MacOS 10.14.4
- Xcode 11.0
- Swift 5.1
1. Khái niệm
1.1. Drawing là gì?
Configure your app’s drawing environment using colors, renderers, draw paths, strings, and shadows.
Theo Apple Documents
- Có rất nhiều thư viện liên quan tới đồ hoạ
- Có rất nhiều cách vẽ khác nhau
- Có rất nhiều phương pháp vẽ khác nhau
Lập trình viên iOS sẽ rơi vào ma trận của Vẽ và 1 điều rất quan trọng cần chú ý đó là hiệu năng của ứng dụng.
- Trong bài này thì mình sẽ giới thiệu và hướng dẫn về `UIBezier
Path` để custom view bằng phương pháp vẽ.
1.2. UIBezierPath
- Hiểu đơn giản thì nó là path
- Dùng để vẽ 1 hình (shape)
- Các hình cơ bản
- Các hình phức tạp
- Đường thẳng
- Đường cong
- …
- Vẽ lên
- CAShapeLayer
- Trực tiếp lên View
- Vì là path nên sẽ chứa các toạ độ điểm theo
vector
, dẫn tới tăng cường hiệu năng của ứng dụng khirender
- Vẽ
stroke
: vẽ các đường viền theo pathfill
: tô màu cho path
- Cần xét các thuộc tính
color
vàwidth
cho từng việc stroke hay fill
2. Drawing
- Việc vẽ sẽ tuân thủ theo các bước sau:
- Bước 1: Tạo Path
- Bước 2: Tạo Layer
- Bước 3: add Path vào Layer
- Bước 4: add Layer vào View
2.1. Create Path
- Bắt đầu với path cho việc vẽ 1 đường thẳng đơn giản, có
start point
vàend point
let path = UIBezierPath() path.move(to: start) path.addLine(to: end) path.close()
- Giải thích:
- Tạo 1 path
- Di chuyển về toạ độ điểm bắt đầu
- Add 1 line từ điểm hiện tại (đang là
start
) tới điểm mới (đang làend
) - Close path
2.2. Drawing trong ViewController
- Viết 1 function để vẽ cho nó pro hơn xí
func drawLine(start: CGPoint, end: CGPoint) { // PATH let path = UIBezierPath() path.move(to: start) path.addLine(to: end) path.close() //LAYER let shapeLayer = CAShapeLayer() shapeLayer.strokeColor = UIColor.blue.cgColor shapeLayer.lineWidth = 1.0 shapeLayer.path = path.cgPath //ADD LAYER self.view.layer.addSublayer(shapeLayer) }
- Trong đó:
- Layer
- Tạo 1 layer mới
- Xét thuộc tính màu và độ dày line
- Xét path cho layer
- Add Layer vào view của ViewController
- Layer
- Tiếp tục thực thi trong file
ViewController.swift
- Gọi hàm trong
viewDidLoad
- Truyền 2 đối số 2 toạ độ điểm vào
- Gọi hàm trong
import UIKit class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() drawLine(start: CGPoint(x: 50, y: 100), end: CGPoint(x: 350, y: 600)) } func drawLine(start: CGPoint, end: CGPoint) { // PATH let path = UIBezierPath() path.move(to: start) path.addLine(to: end) path.close() //LAYER let shapeLayer = CAShapeLayer() shapeLayer.strokeColor = UIColor.blue.cgColor shapeLayer.lineWidth = 1.0 shapeLayer.path = path.cgPath //ADD LAYER self.view.layer.addSublayer(shapeLayer) } }
- Kết quả
2.3. Drawing với custom view
- Tạo 1 sub-class UIView mới để custom view. Tạm thời đặt tên là
FxLineView
import UIKit class FxLineView: UIView { //init override init(frame: CGRect) { super.init(frame: frame) } required init?(coder: NSCoder) { super.init(coder: coder) fatalError("init(coder:) has not been implemented") } }
- Chúng ta sử dụng 2 phương pháp vẽ
2.3.1 Draw path in a layer
- Sử dụng lại function vẽ ở trên cho custom view
- Thay đổi màu sắc thành màu đỏ
import UIKit class FxLineView: UIView { //init override init(frame: CGRect) { super.init(frame: frame) } required init?(coder: NSCoder) { super.init(coder: coder) fatalError("init(coder:) has not been implemented") } //draw func drawLine(start: CGPoint, end: CGPoint) { // PATH let path = UIBezierPath() path.move(to: start) path.addLine(to: end) path.close() //LAYER let shapeLayer = CAShapeLayer() shapeLayer.strokeColor = UIColor.red.cgColor shapeLayer.lineWidth = 1.0 shapeLayer.path = path.cgPath //ADD LAYER self.layer.addSublayer(shapeLayer) } }
- Sử dụng trong ViewController
let lineView = FxLineView(frame: view.bounds) lineView.drawLine(start: CGPoint(x: 50, y: 100), end: CGPoint(x: 300, y: 600)) view.addSubview(lineView)
- Giải thích
- Tạo đối tượng custom view
- Add custom view vào view
- Trong ví dụ, mình sử dụng frame của custom view bằng chính view của ViewController
- Với bài toán thực tế thì bạn cần phải tính toán cẩn thận hơn.
- Kết quả
2.3.2. Draw path in drawRect
- Sử dụng chính function của UIView khi custom là
drawRect
để vẽ - Tạo 1 sub-class UIView mới, tạm lấy tên là
FxRectangularView
- Tạm thời setup như dưới
createPath
tạo ra 1 pathdrawRect
- new path
- xét thuộc tính và màu
- fill (vì bài này ko cần vẽ đường thẳng mà sử dụng fill)
import UIKit class FxRectangularView: UIView { override func draw(_ rect: CGRect) { // create path let path = createPath() // fill let fillColor = UIColor.orange fillColor.setFill() path.fill() } func createPath() -> UIBezierPath { return UIBezierPath() } }
- Tiến hành tạo path, trong ví dụ thì chúng ta tạo 1 hình chữ nhật đơn giản bằng chính
bounds
import UIKit class FxRectangularView: UIView { override func draw(_ rect: CGRect) { // create path let path = createPath() // fill let fillColor = UIColor.orange fillColor.setFill() path.fill() } func createPath() -> UIBezierPath { let path = UIBezierPath(rect: self.bounds) return path } }
- Sử dụng trong ViewController
let rectView = FxRectangularView(frame: CGRect(x: 30, y: 300, width: 350, height: 150)) view.addSubview(rectView)
- Kết quả
- Chú ý
stroke
dùng để vẽ các đường thẳng, đường cong. Đi đối với nó set color phải phù hợp theo ( `strokeColor`)fill
dùng để tô màu 1 hình hay 1 path mà các điểm nối liền mạch với nhau. Đi đôi với nó làfillColor
- Tuý bị bạn sử dụng, tốt nhất là có cả 2 trong custom view của bạn. Ví dụ:
override func draw(_ rect: CGRect) { // create path // Specify the fill color and apply it to the path. UIColor.orange.setFill() path.fill() // Specify a border (stroke) color. UIColor.purple.setStroke() path.stroke() }
Tới đây thì bạn đã nắm được cơ bản các cách vẽ và các phương pháp vẽ khác nhau. Cách sử dụng
UIBezierPath
. Và sử dụng chúng vào mục đích custom view. Các phần sau thì bạn tự tìm hiểu thêm về các hình vẽ cơ bản củaUIBezierPath
.
3. Một số hình vẽ cơ bản
Rectangular
func createRectangle() { // Initialize the path. path = UIBezierPath() // Specify the point that the path should start get drawn. path.move(to: CGPoint(x: 0.0, y: 0.0)) // Create a line between the starting point and the bottom-left side of the view. path.addLine(to: CGPoint(x: 0.0, y: self.frame.size.height)) // Create the bottom line (bottom-left to bottom-right). path.addLine(to: CGPoint(x: self.frame.size.width, y: self.frame.size.height)) // Create the vertical line from the bottom-right to the top-right side. path.addLine(to: CGPoint(x: self.frame.size.width, y: 0.0)) // Close the path. This will create the last line automatically. path.close() }
Triangles
func createTriangle() { path = UIBezierPath() path.move(to: CGPoint(x: self.frame.width/2, y: 0.0)) path.addLine(to: CGPoint(x: 0.0, y: self.frame.size.height)) path.addLine(to: CGPoint(x: self.frame.size.width, y: self.frame.size.height)) path.close() }
Ovals and Circles
override func draw(_ rect: CGRect) { // self.createRectangle() // self.createTriangle() // Create an oval shape path. self.path = UIBezierPath(ovalIn: self.bounds) ... }
override func draw(_ rect: CGRect) { self.path = UIBezierPath(ovalIn: CGRect(x: self.frame.size.width/2 - self.frame.size.height/2, y: 0.0, width: self.frame.size.height, height: self.frame.size.height)) ... }
Rectangles with Rounded Corners
override func draw(_ rect: CGRect) { ... path = UIBezierPath(roundedRect: self.bounds, cornerRadius: 15.0) ... }
override func draw(_ rect: CGRect) { ... path = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: [.topLeft, .bottomRight], cornerRadii: CGSize(width: 15.0, height: 0.0)) ... }
Creating Arcs
override func draw(_ rect: CGRect) { ... path = UIBezierPath(arcCenter: CGPoint(x: self.frame.size.width/2, y: self.frame.size.height/2), radius: self.frame.size.height/2, startAngle: CGFloat(180.0).toRadians(), endAngle: CGFloat(0.0).toRadians(), clockwise: true) ... }
Bảng phân độ như sau
Tạm kết
- Biết được cách custom view bằng vẽ
- Sử dụng UIBezierPath và 2 phương pháp vẽ
- add layer
- drawRect
- Một số hình cơ bản
Related Posts:
Written by chuotfx
Hãy ngồi xuống, uống miếng bánh và ăn miếng trà. Chúng ta cùng nhau đàm đạo về đời, về code nhóe!
3 comments
Leave a Reply Cancel reply
Fan page
Tags
Recent Posts
- Prompt Engineering trong 10 phút
- Một số ví dụ sử dụng Prompt cơ bản khi làm việc với AI
- Prompt trong 10 phút
- Charles Proxy – Phần 1 : Giới thiệu, cài đặt và cấu hình
- Complete Concurrency với Swift 6
- 300 Bài code thiếu nhi bằng Python – Ebook
- Builder Pattern trong 10 phút
- Observer Pattern trong 10 phút
- Memento Pattern trong 10 phút
- Strategy Pattern trong 10 phút
You may also like:
Archives
- December 2024 (3)
- September 2024 (1)
- July 2024 (1)
- June 2024 (1)
- May 2024 (4)
- April 2024 (2)
- March 2024 (5)
- January 2024 (4)
- February 2023 (1)
- January 2023 (2)
- November 2022 (2)
- October 2022 (1)
- September 2022 (5)
- August 2022 (6)
- July 2022 (7)
- June 2022 (8)
- May 2022 (5)
- April 2022 (1)
- March 2022 (3)
- February 2022 (5)
- January 2022 (4)
- December 2021 (6)
- November 2021 (8)
- October 2021 (8)
- September 2021 (8)
- August 2021 (8)
- July 2021 (9)
- June 2021 (8)
- May 2021 (7)
- April 2021 (11)
- March 2021 (12)
- February 2021 (3)
- January 2021 (3)
- December 2020 (3)
- November 2020 (9)
- October 2020 (7)
- September 2020 (17)
- August 2020 (1)
- July 2020 (3)
- June 2020 (1)
- May 2020 (2)
- April 2020 (3)
- March 2020 (20)
- February 2020 (5)
- January 2020 (2)
- December 2019 (12)
- November 2019 (12)
- October 2019 (19)
- September 2019 (17)
- August 2019 (10)
Mấy bài viết của bạn khá là hay, cám ơn bạn.
Giao lưu nhé.
Thanks bạn! Okay, có gì thì mail cho mình. 😀
teamlead co khac 😀 😀