Thước kẻ là ứng dụng không dễ
cũng không khó, đòi hỏi kỹ năng tính toán, xử lý một chút.
Hãy tạo một class mới là
subclass của UIView.
Đây là chỗ ta vẽ các đường kẻ
lên màn hình iphone để giả lập các vạch của cái thước kẻ. Khi người dùng chạm
tay vào màn hình, sẽ có cái vạch di chuyển theo tay chạm và dòng chữ ghi tọa độ
vị trí cả bằng cm và inch.
Khai báo các biến
và thêm các hàm để bắt chạm tay vào màn hình.
Copy lên trên
dòng overridefunc drawRect
var x=0.0//so inch
var den=0
var diem=0
var dem=0
let r = UIScreen.mainScreen().bounds.size.width
let c = UIScreen.mainScreen().bounds.size.height
var l = CGPointZero
var f = CGPointZero
overridefunc touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
iflet touch = touches.first {
f = touch.locationInView(self)
l = f
setNeedsDisplay()
}
}
overridefunc touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
iflet touch = touches.first {
l = touch.locationInView(self)
setNeedsDisplay()
}
}
overridefunc touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
iflet touch = touches.first {
l = touch.locationInView(self)
setNeedsDisplay()
}
}
Ta khai báo các
biến đếm để phân biệt người dùng chọn cm hay inch, lấy chiều dài rộng màn hình.
Biến l để lấy toạ độ
tay chạm người dùng.
Ba hàm override
touch là thủ tục để lấy toạ độ tay người dùng chạm màn hình.
Bây giờ có một
vấn đề là làm sao để vẽ 1cm thì dài đúng 1cm.
Ta sẽ cần biết
kích thước thực tế đường chéo màn hình tức số inch, sau đó tính để xem 1cm
tương đương bao nhiêu pixel, từ đó vẽ đúng tỷ lệ tính được.
Biến x là số
inch, ta sẽ lấy nó sau này bên class chính, bây giờ cứ dùng để tính tỷ lệ.
Copy các dòng
sau vào trong hàm drawRect
let tcanh=r*r+c*c
var so=x*25.4
so=so*so;
let socann=Double(tcanh)/so;
let socan = sqrt(socann)
let context = UIGraphicsGetCurrentContext()
CGContextSetLineWidth(context, 0.5)
var socanb=socan
ifden%2==1{
socanb=socan/2.54
}
Đây ta tính đường
chéo theo pixel rồi chia với kích thước thật được socan là tỷ lệ cần có.
Lệnh if tức là khi người dùng chọn là inch thì phải chia cho 2.54 mới
ra tỷ lệ cần dùng.
Copy hàm sau
lên trên ngoặc đóng cuối cùng.
func round2(a:Double)->Double{
let mu = pow(10.0,2.0)
let r=round(a*mu)/mu
return r
}
Hàm round2() để
làm tròn số mm, inch tọa độ của cái gạch đỏ ta sẽ vẽ.
Bây giờ hãy vẽ
các gạch và chữ để cho nó giống một cái thước kẻ.
Copy vào trong
hàm drawRect tiếp xuống dưới.
for i in0..<250 {
if(i%5==0){
let kl=i/5;
if(kl%2==0){
CGContextMoveToPoint(context, r-CGFloat(socanb*Double(7)),CGFloat(socan*Double(i)))
/* And end it at this
point */
CGContextAddLineToPoint(context, r,CGFloat(socan*Double(i)))
}
else{
CGContextMoveToPoint(context, r-CGFloat(socanb*Double(5)),CGFloat(socan*Double(i)))
/* And end it at this
point */
CGContextAddLineToPoint(context, r,CGFloat(socan*Double(i)))
}
}
else{
CGContextMoveToPoint(context, r-CGFloat(socanb*Double(3)),CGFloat(socan*Double(i)))
/* And end it at this
point */
CGContextAddLineToPoint(context, r,CGFloat(socan*Double(i)))
}
}
for i in1..<25 {
let string = String(i)
string.drawAtPoint(CGPointMake(r-70, CGFloat(10*socan*Double(i))-10),
withAttributes:
[NSFontAttributeName : UIFont(name: "Arial", size: 24.0)!])
}
UIColor.blackColor().set()
CGContextStrokePath(context)
Để cho tiện ta
sẽ làm xong luôn bên class vẽ này, sau sẽ sang class chính mới chạy nó.
Trong lệnh for i in 0..<250 ta vẽ ra 3 loại đường kẻ dài ngắn khác
nhau tuỳ thứ tự của chúng. Ta chia cho 5 để biết đường nào là được nửa phân, đủ
1 phân thì vẽ dài ra, còn lại vẽ ngắn là các kẻ ly thường.
Khoảng cách tuỳ
socan của cm hay socanb của inch mà khác nhau.
Lệnh for i in1..<25 {
vẽ ra các số từ 1-25, thực ra ta có thể để 30,40 nhưng không có thiết bị
nào dài đến thế kể cả ipad pro nên cứ để 25 là được rồi.
Giờ ta muốn có
cái gạch ngang màu đỏ khi vừa vào màn hình. Copy đoạn sau tiếp xuống dưới lệnh for.
ifl.y == 0 {
let conn = UIGraphicsGetCurrentContext()
UIColor.redColor().set()
CGContextSetLineWidth(conn, 0.5)
CGContextMoveToPoint(conn, 0, c/2)
//vẽ line khi chưa có
chạm
CGContextAddLineToPoint(conn, r, c/2)
UIColor.redColor().set()
CGContextStrokePath(conn)
}
l.y == 0 tức toạ độ điểm
chạm chưa có gì, là lúc ban đầu mở vào.
Bây giờ, khi
người dùng chạm tay vào màn hình, ta phải vẽ kẻ gạch di chuyển theo chạm và số
cm của kẻ gạch đó trên màn hình.
Copy tiếp xuống
dưới, vẫn trong hàm drawRect.
ifl.y>0{
let con = UIGraphicsGetCurrentContext()
UIColor.redColor().set()
/* Set the color that
we want to use to draw the line */
CGContextMoveToPoint(con, 0, l.y)
/* And end it at this
point */
CGContextAddLineToPoint(con, r, l.y)
CGContextStrokePath(con)
let pa=CGPathCreateMutable()
CGContextAddPath(context, pa)
CGContextDrawPath(context, CGPathDrawingMode(rawValue: 1)!)
ifden%2==0{
//let cmm =
Double(r-l.x)/socan
let cm = Double(l.y)/socan
let cc=round2(cm)
let tring = String(cc) + "
mm"
tring.drawAtPoint(CGPointMake(r/6, l.y ), withAttributes: [NSForegroundColorAttributeName: UIColor.redColor(), NSFontAttributeName: UIFont(name: "HelveticaNeue", size: 27.0)!])
}
else{
//đây là inch
// let cmm =
Double(r-l.x)/socan
let cm = Double(l.y)/socan
let cc=round2(cm/10)
let tring = String(cc) + "
inch"
tring.drawAtPoint(CGPointMake(r/6, l.y ), withAttributes: [NSForegroundColorAttributeName: UIColor.redColor(), NSFontAttributeName: UIFont(name: "HelveticaNeue", size: 27.0)!])
}
}
l.y>0 tức là có chạm
tay rồi, ta vẽ cái gạch theo toạ độ l.y, vì tay di chuyển nên y cũng di chuyển
dọc màn hình, tức là cái gạch nó di chuyển theo vị trí tay chạm.
Trong lệnh if khi biến đếm chẵn tức đang chọn cm thì vẽ độ dài theo mm,
còn lẻ là chọn inch thì vẽ theo inch.
Vậy là xong
class vẽ, nếu muốn vẽ gạch cả vào chiều ngang màn hình, bạn sẽ dùng l.x để vẽ.
Bây giờ sang
class chính để hiển thị những gì vẽ ra, thêm các nút bấm vào.
Copy một loạt
biến sau lên trên viewDidLoad
var bu: UIButton!
var bu2: UIButton!
var denn=0
var diem=0
var x=0.0
var ik=0.0
var gv=0
var scale:CGFloat?
let c = UIScreen.mainScreen().bounds.size.height
let ruler = five()
Ta tạo ra đối
tượng ruler để truy xuất class có hàm drawRect vẽ kia.
Copy xuống dưới
viewDidLoad
scale = UIScreen.mainScreen().scale;
ifc<500{
x = 3.5
}
elseifc<600&&c>500{
x = 4
}
elseifc<700&&c>600{
x = 4.7
}
elseifc<800&&c>700{
x = 5.5
}
elseifc<1030&&c>800{
ifscale==1.0{
x = 7.9
}
else{
x = 9.7
}
}
else{
x = 12.9
}
ik=x
Ta dùng biến c
là chiều cao màn hình và chỉ số scale để biết số inch. Các thiết bị khác nhau
có chiều dài tương ứng số inch đường chéo khác nhau. Ta lấy được số inch để
dùng. Bạn có thể cập nhật thêm nếu các đời iphone sau có thay đổi.
Copy tiếp xuống
dưới dòng ik=x
bu = UIButton(frame: CGRect(x: -20, y: 50, width: 80, height: 40))
let a=NSMutableAttributedString(string: "Cm->Inch", attributes: [NSForegroundColorAttributeName: UIColor.blueColor(), NSFontAttributeName: UIFont(name: "Georgia", size: 16.0)!])
bu.setAttributedTitle(a, forState: .Normal)
bu2 = UIButton(frame: CGRect(x: 3, y: Int(c-34), width: 50, height: 42))
bu2.setTitle("Quit",forState: .Normal)
bu2.setTitleColor(UIColor.grayColor(), forState: .Normal)
Đây là ta vẽ
cái nút chuyển cm->inch và nút Quit, tô màu chữ cho chúng.
Copy tiếp xuống
dưới
ruler.frame = CGRect(x: 0, y: 0, width: view.frame.size.width, height: c)
ruler.backgroundColor = UIColor.whiteColor()
ifgv%2==1{
diem=2
denn=1
ik=x/2.54
}
else{
ik=x
}
ruler.den=denn
ruler.x=ik
UIView.animateWithDuration(0.0, animations: {
self.bu.transform = CGAffineTransformMakeRotation(CGFloat(90) * CGFloat(M_PI)/180)
})
view.addSubview(ruler)
view.addSubview(bu)
view.addSubview(bu2)
bu.addTarget(self, action: #selector(seven.cmin(_:)), forControlEvents: UIControlEvents.TouchUpInside)
bu2.addTarget(self, action: #selector(seven.bun(_:)), forControlEvents: UIControlEvents.TouchUpInside)
Ta chèn view
kín màn hình, đổ nền trắng, truyền giá trị biến đếm khi người dùng kích nút bấm
cm->inch và chỉ số kích thước theo inch vào class vẽ qua đối tượng ruler đã
tạo.
Tiếp theo là
quay cái nút cm->inch đi 90 độ cho nó dọc màn hình.
Cuối cùng nhét
tất cả vào view và set hàm cho bút bấm.
Copy các hàm cần
dùng xuống ngoài viewDidLoad.
func cmin(sender: UIButton){
denn=denn+1
ifdenn%2==1{
diem=2
ik=ik/2.54
}
else{
diem=1
ik=ik*2.54
}
ruler.den=denn
ruler.x=ik
ruler.setNeedsDisplay()
}
func bun(sender: UIButton){
rite2("","danhsach.txt")
rite(String(denn),fileName: "danhsach.txt")
exit(0)
}
Hàm cmin() của
nút cm->inch là để điều chỉnh biến đếm xem là chọn cm hay inch thì hiển thị
tương ứng.
Bây giờ có một
vấn đề là ta muốn nếu khi thoát người dùng để là cm hay inch thì lúc mở ra nó vẫn
phải y như thế.
Để biết ta dùng
biến đếm, nếu nó lẻ tức đang là inch, chẵn là cm. Khi thoát ta xoá trắng file
danhsach và ghi vào số denn của biến đếm.
Copy các hàm đọc
ghi xuống trên ngoặc đóng cuối cùng.
func rite(content: String, fileName: String) {
let contentToAppend = content
let filePath = NSHomeDirectory() + "/Documents/" + fileName
//Check if file exists
iflet fileHandle = NSFileHandle(forWritingAtPath: filePath) {
//Append to file
fileHandle.seekToEndOfFile() fileHandle.writeData(contentToAppend.dataUsingEncoding(NSUTF8StringEncoding)!)
}
else {
//Create new file
do {
try contentToAppend.writeToFile(filePath, atomically: true, encoding: NSUTF8StringEncoding)
} catch {
print("Error
creating \(filePath)")
}
}
}
func rite2(content: String,_ fileName: String) {
let contentToAppend = content
let filePath = NSHomeDirectory() + "/Documents/" + fileName
//Check if file exists
iflet fileHandle = NSFileHandle(forWritingAtPath: filePath) {
//Append to file
// fileHandle.seekToEndOfFile()
//
fileHandle.writeData(contentToAppend.dataUsingEncoding(NSUTF8StringEncoding)!)
do {
try content.writeToFile(filePath, atomically: false, encoding: NSUTF8StringEncoding)
} catch {
print("Error
creating \(filePath)")
}
}
else {
//Create new file
do {
try contentToAppend.writeToFile(filePath, atomically: true, encoding: NSUTF8StringEncoding)
} catch {
print("Error
creating \(filePath)")
}
}
}
func doc()->Int{
let documentsPath2 = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] asNSString
let path2 = documentsPath2.stringByAppendingPathComponent("danhsach.txt")
var rea2 : String = ""
var t2="g"
var t3=10
do {
try rea2 = NSString(contentsOfFile: path2, encoding: NSUTF8StringEncoding) asString
var ar = rea2.componentsSeparatedByString("\n")
t2=ar[0]
t3=Int(t2)!
}
catchlet error asNSError {
// print("ERROR :
reading from file \(fileName) : \(error.localizedDescription)")
}
return t3
}
Copy dòng sau
vào dưới dòng định vị các nút trong viewDidLoad
gv = doc()
Ta đọc file danhsach.txt để lấy số ghi
vào biết chẵn lẻ mà set giá trị tương ứng cho biến đếm và đơn vị đo kích thước
màn hình. Nếu lần đầu mở số đọc ra là 0 tức sẽ luôn là vẽ theo cm.
Chạy chương
trình để có kết quả, nháy thử nút cm->inch để xem thay đổi.
Để hiểu cách làm ứng dụng này, bạn
nên thực hành vẽ các đường thẳng, chữ trong class là subclass của UIView trước,
sẽ thấy nó rất cơ bản. Code chưa dài lắm, chỉ hơn trăm dòng, đều là những thứ
quen thuộc.
No comments:
Post a Comment