UIView
và các lớp con của nó đều có các thuộc tính frame
và bounds
. Có gì khác biệt?
UIView
và các lớp con của nó đều có các thuộc tính frame
và bounds
. Có gì khác biệt?
Câu trả lời:
Giới hạn của một UIView là hình chữ nhật , được biểu thị dưới dạng vị trí (x, y) và kích thước (chiều rộng, chiều cao) so với hệ tọa độ của chính nó (0,0).
Các khung của một UIView là hình chữ nhật , thể hiện dưới dạng một vị trí (x, y) và kích thước (chiều rộng, chiều cao) so với SuperView nó được chứa bên trong.
Vì vậy, hãy tưởng tượng một khung nhìn có kích thước 100x100 (chiều rộng x chiều cao) được định vị ở mức 25,25 (x, y) của giám sát của nó. Đoạn mã sau in ra giới hạn và khung của khung nhìn này:
// This method is in the view controller of the superview
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"bounds.origin.x: %f", label.bounds.origin.x);
NSLog(@"bounds.origin.y: %f", label.bounds.origin.y);
NSLog(@"bounds.size.width: %f", label.bounds.size.width);
NSLog(@"bounds.size.height: %f", label.bounds.size.height);
NSLog(@"frame.origin.x: %f", label.frame.origin.x);
NSLog(@"frame.origin.y: %f", label.frame.origin.y);
NSLog(@"frame.size.width: %f", label.frame.size.width);
NSLog(@"frame.size.height: %f", label.frame.size.height);
}
Và đầu ra của mã này là:
bounds.origin.x: 0
bounds.origin.y: 0
bounds.size.width: 100
bounds.size.height: 100
frame.origin.x: 25
frame.origin.y: 25
frame.size.width: 100
frame.size.height: 100
Vì vậy, chúng ta có thể thấy rằng trong cả hai trường hợp, chiều rộng và chiều cao của chế độ xem là như nhau bất kể chúng ta đang nhìn vào giới hạn hay khung. Điều khác biệt là định vị x, y của chế độ xem. Trong trường hợp giới hạn, tọa độ x và y là 0,0 vì các tọa độ này có liên quan đến chính khung nhìn. Tuy nhiên, tọa độ khung x và y có liên quan đến vị trí của chế độ xem trong chế độ xem chính (mà trước đó chúng tôi đã nói là ở 25,25).
Ngoài ra còn có một bài thuyết trình tuyệt vời bao gồm UIViews. Xem các slide 1-20 không chỉ giải thích sự khác biệt giữa các khung và giới hạn mà còn hiển thị các ví dụ trực quan.
frame = vị trí và kích thước của khung nhìn bằng hệ tọa độ của khung nhìn cha
Bound = vị trí và kích thước của chế độ xem bằng hệ thống tọa độ của chính nó
Để giúp tôi nhớ khung hình , tôi nghĩ về một khung hình trên tường . Khung hình giống như đường viền của khung nhìn. Tôi có thể treo bức tranh bất cứ nơi nào tôi muốn trên tường. Theo cách tương tự, tôi có thể đặt chế độ xem ở bất cứ đâu tôi muốn trong chế độ xem chính (còn được gọi là giám sát). Quan điểm của phụ huynh giống như bức tường. Nguồn gốc của hệ thống tọa độ trong iOS là trên cùng bên trái. Chúng ta có thể đặt chế độ xem của mình tại điểm gốc của giám sát bằng cách đặt tọa độ xy của khung nhìn thành (0, 0), giống như treo ảnh của chúng ta ở góc trên cùng bên trái của bức tường. Để di chuyển nó đúng, tăng x, để di chuyển xuống tăng y.
Để giúp tôi nhớ giới hạn , tôi nghĩ về một sân bóng rổ , nơi đôi khi bóng rổ bị đánh bật ra khỏi giới hạn . Bạn đang rê bóng khắp sân bóng rổ, nhưng bạn không thực sự quan tâm đến chính sân đó. Nó có thể là trong một phòng tập thể dục, hoặc bên ngoài tại một trường trung học, hoặc trước nhà của bạn. Nó không thành vấn đề. Bạn chỉ muốn chơi bóng rổ. Theo cùng một cách, hệ thống tọa độ cho giới hạn của chế độ xem chỉ quan tâm đến chính chế độ xem. Nó không biết bất cứ điều gì về vị trí của khung nhìn trong khung nhìn cha. Nguồn gốc của giới hạn (điểm (0, 0) theo mặc định) là góc trên cùng bên trái của chế độ xem. Bất kỳ cuộc phỏng vấn nào mà quan điểm này đã được đặt ra liên quan đến điểm này. Nó giống như đưa bóng rổ đến góc trước bên trái của tòa án.
Bây giờ sự nhầm lẫn đến khi bạn cố gắng so sánh khung và giới hạn. Nó thực sự không tệ như lúc đầu. Hãy sử dụng một số hình ảnh để giúp chúng tôi hiểu.
Trong bức ảnh đầu tiên bên trái, chúng ta có một khung nhìn nằm ở phía trên bên trái của khung nhìn chính của nó. Hình chữ nhật màu vàng đại diện cho khung nhìn. Ở bên phải chúng ta thấy khung nhìn một lần nữa nhưng lần này khung nhìn cha không được hiển thị. Đó là bởi vì giới hạn không biết về quan điểm của phụ huynh. Hình chữ nhật màu xanh lá cây đại diện cho giới hạn của khung nhìn. Các chấm đỏ ở cả hai hình ảnh đại diện cho nguồn gốc của khung hoặc giới hạn.
Frame
origin = (0, 0)
width = 80
height = 130
Bounds
origin = (0, 0)
width = 80
height = 130
Vì vậy, khung và giới hạn giống hệt nhau trong bức tranh đó. Hãy xem xét một ví dụ nơi chúng khác nhau.
Frame
origin = (40, 60) // That is, x=40 and y=60
width = 80
height = 130
Bounds
origin = (0, 0)
width = 80
height = 130
Vì vậy, bạn có thể thấy rằng việc thay đổi tọa độ xy của khung sẽ di chuyển nó trong chế độ xem chính. Nhưng nội dung của chế độ xem vẫn trông giống hệt nhau. Các giới hạn không có ý tưởng rằng bất cứ điều gì là khác nhau.
Cho đến nay, chiều rộng và chiều cao của cả khung và giới hạn đều giống hệt nhau. Điều đó không phải lúc nào cũng đúng. Hãy nhìn xem điều gì sẽ xảy ra nếu chúng ta xoay góc nhìn 20 độ theo chiều kim đồng hồ. (Xoay được thực hiện bằng cách sử dụng các phép biến đổi. Xem tài liệu và các ví dụ về khung nhìn và lớp này để biết thêm thông tin.)
Frame
origin = (20, 52) // These are just rough estimates.
width = 118
height = 187
Bounds
origin = (0, 0)
width = 80
height = 130
Bạn có thể thấy rằng giới hạn vẫn giống nhau. Họ vẫn không biết chuyện gì đã xảy ra! Các giá trị khung đã thay đổi, mặc dù.
Bây giờ dễ dàng hơn một chút để thấy sự khác biệt giữa khung và giới hạn, phải không? Bài viết Bạn có thể không hiểu khung và giới hạn xác định khung xem là
... Hộp giới hạn nhỏ nhất của chế độ xem đó đối với hệ tọa độ cha mẹ của nó, bao gồm mọi biến đổi được áp dụng cho chế độ xem đó.
Điều quan trọng cần lưu ý là nếu bạn chuyển đổi chế độ xem, thì khung sẽ không được xác định. Vì vậy, thực sự, khung màu vàng mà tôi đã vẽ xung quanh các giới hạn màu xanh lá cây xoay trong hình trên không bao giờ thực sự tồn tại. Điều đó có nghĩa là nếu bạn xoay, chia tỷ lệ hoặc thực hiện một số chuyển đổi khác thì bạn không nên sử dụng các giá trị khung nữa. Bạn vẫn có thể sử dụng các giá trị giới hạn, mặc dù. Các tài liệu của Apple cảnh báo:
Quan trọng: Nếu thuộc
transform
tính của chế độ xem không chứa biến đổi nhận dạng, khung của chế độ xem đó không được xác định và kết quả của các hành vi tự động hóa của nó là không xác định.
Khá đáng tiếc về việc tự động hóa .... Mặc dù vậy, có một số điều bạn có thể làm.
Khi sửa đổi thuộc
transform
tính của chế độ xem của bạn, tất cả các phép biến đổi được thực hiện tương ứng với điểm chính giữa của chế độ xem.
Vì vậy, nếu bạn cần di chuyển một khung nhìn xung quanh cha mẹ sau khi thực hiện chuyển đổi, bạn có thể thực hiện bằng cách thay đổi view.center
tọa độ. Giống như frame
, center
sử dụng hệ tọa độ của khung nhìn cha.
Ok, chúng ta hãy thoát khỏi vòng quay của chúng tôi và tập trung vào giới hạn. Cho đến nay, nguồn gốc giới hạn luôn ở mức (0, 0). Nó không phải, mặc dù. Điều gì xảy ra nếu chế độ xem của chúng tôi có một khung nhìn lớn quá lớn để hiển thị tất cả cùng một lúc? Chúng tôi sẽ làm cho nó một UIImageView
hình ảnh lớn. Đây là hình ảnh thứ hai của chúng tôi từ trên cao một lần nữa, nhưng lần này chúng ta có thể thấy toàn bộ nội dung của quan điểm của chúng ta sẽ như thế nào.
Frame
origin = (40, 60)
width = 80
height = 130
Bounds
origin = (0, 0)
width = 80
height = 130
Chỉ góc trên cùng bên trái của hình ảnh có thể nằm gọn trong giới hạn của chế độ xem. Bây giờ hãy xem điều gì xảy ra nếu chúng ta thay đổi tọa độ gốc của giới hạn.
Frame
origin = (40, 60)
width = 80
height = 130
Bounds
origin = (280, 70)
width = 80
height = 130
Khung không được di chuyển trong giám sát nhưng nội dung bên trong khung đã thay đổi do nguồn gốc của hình chữ nhật giới hạn bắt đầu ở một phần khác của chế độ xem. Đây là toàn bộ ý tưởng đằng sau một UIScrollView
và các lớp con của nó (ví dụ: a UITableView
). Xem Hiểu UIScrollView để được giải thích thêm.
Vì frame
liên quan đến vị trí của chế độ xem trong chế độ xem chính của nó, bạn sử dụng nó khi bạn thực hiện các thay đổi bên ngoài , như thay đổi độ rộng của nó hoặc tìm khoảng cách giữa chế độ xem và đầu của chế độ xem chính.
Sử dụng bounds
khi bạn đang thực hiện các thay đổi bên trong , như vẽ mọi thứ hoặc sắp xếp các cuộc phỏng vấn trong chế độ xem. Đồng thời sử dụng giới hạn để có được kích thước của chế độ xem nếu bạn đã thực hiện một số biến đổi trên nó.
Tài liệu của Apple
Các câu hỏi liên quan đến StackOverflow
Các nguồn lực khác
Ngoài việc đọc các bài viết trên, nó giúp tôi rất nhiều để làm một ứng dụng thử nghiệm. Bạn có thể muốn thử làm một cái gì đó tương tự. (Tôi có ý tưởng từ khóa học video này nhưng tiếc là nó không miễn phí.)
Đây là mã để bạn tham khảo:
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var myView: UIView!
// Labels
@IBOutlet weak var frameX: UILabel!
@IBOutlet weak var frameY: UILabel!
@IBOutlet weak var frameWidth: UILabel!
@IBOutlet weak var frameHeight: UILabel!
@IBOutlet weak var boundsX: UILabel!
@IBOutlet weak var boundsY: UILabel!
@IBOutlet weak var boundsWidth: UILabel!
@IBOutlet weak var boundsHeight: UILabel!
@IBOutlet weak var centerX: UILabel!
@IBOutlet weak var centerY: UILabel!
@IBOutlet weak var rotation: UILabel!
// Sliders
@IBOutlet weak var frameXSlider: UISlider!
@IBOutlet weak var frameYSlider: UISlider!
@IBOutlet weak var frameWidthSlider: UISlider!
@IBOutlet weak var frameHeightSlider: UISlider!
@IBOutlet weak var boundsXSlider: UISlider!
@IBOutlet weak var boundsYSlider: UISlider!
@IBOutlet weak var boundsWidthSlider: UISlider!
@IBOutlet weak var boundsHeightSlider: UISlider!
@IBOutlet weak var centerXSlider: UISlider!
@IBOutlet weak var centerYSlider: UISlider!
@IBOutlet weak var rotationSlider: UISlider!
// Slider actions
@IBAction func frameXSliderChanged(sender: AnyObject) {
myView.frame.origin.x = CGFloat(frameXSlider.value)
updateLabels()
}
@IBAction func frameYSliderChanged(sender: AnyObject) {
myView.frame.origin.y = CGFloat(frameYSlider.value)
updateLabels()
}
@IBAction func frameWidthSliderChanged(sender: AnyObject) {
myView.frame.size.width = CGFloat(frameWidthSlider.value)
updateLabels()
}
@IBAction func frameHeightSliderChanged(sender: AnyObject) {
myView.frame.size.height = CGFloat(frameHeightSlider.value)
updateLabels()
}
@IBAction func boundsXSliderChanged(sender: AnyObject) {
myView.bounds.origin.x = CGFloat(boundsXSlider.value)
updateLabels()
}
@IBAction func boundsYSliderChanged(sender: AnyObject) {
myView.bounds.origin.y = CGFloat(boundsYSlider.value)
updateLabels()
}
@IBAction func boundsWidthSliderChanged(sender: AnyObject) {
myView.bounds.size.width = CGFloat(boundsWidthSlider.value)
updateLabels()
}
@IBAction func boundsHeightSliderChanged(sender: AnyObject) {
myView.bounds.size.height = CGFloat(boundsHeightSlider.value)
updateLabels()
}
@IBAction func centerXSliderChanged(sender: AnyObject) {
myView.center.x = CGFloat(centerXSlider.value)
updateLabels()
}
@IBAction func centerYSliderChanged(sender: AnyObject) {
myView.center.y = CGFloat(centerYSlider.value)
updateLabels()
}
@IBAction func rotationSliderChanged(sender: AnyObject) {
let rotation = CGAffineTransform(rotationAngle: CGFloat(rotationSlider.value))
myView.transform = rotation
updateLabels()
}
private func updateLabels() {
frameX.text = "frame x = \(Int(myView.frame.origin.x))"
frameY.text = "frame y = \(Int(myView.frame.origin.y))"
frameWidth.text = "frame width = \(Int(myView.frame.width))"
frameHeight.text = "frame height = \(Int(myView.frame.height))"
boundsX.text = "bounds x = \(Int(myView.bounds.origin.x))"
boundsY.text = "bounds y = \(Int(myView.bounds.origin.y))"
boundsWidth.text = "bounds width = \(Int(myView.bounds.width))"
boundsHeight.text = "bounds height = \(Int(myView.bounds.height))"
centerX.text = "center x = \(Int(myView.center.x))"
centerY.text = "center y = \(Int(myView.center.y))"
rotation.text = "rotation = \((rotationSlider.value))"
}
}
bounds
so với frame
quan điểm.
cố gắng chạy mã dưới đây
- (void)viewDidLoad {
[super viewDidLoad];
UIWindow *w = [[UIApplication sharedApplication] keyWindow];
UIView *v = [w.subviews objectAtIndex:0];
NSLog(@"%@", NSStringFromCGRect(v.frame));
NSLog(@"%@", NSStringFromCGRect(v.bounds));
}
đầu ra của mã này là:
trường hợp thiết bị định hướng là Portrait
{{0, 0}, {768, 1024}}
{{0, 0}, {768, 1024}}
trường hợp thiết bị định hướng là Cảnh
{{0, 0}, {768, 1024}}
{{0, 0}, {1024, 768}}
rõ ràng, bạn có thể thấy sự khác biệt giữa khung và giới hạn
khung là nguồn gốc (góc trên bên trái) và kích thước của khung nhìn trong hệ tọa độ siêu quan điểm của mình, các phương tiện này mà bạn dịch các quan điểm theo quan điểm siêu của nó bằng cách thay đổi nguồn gốc khung, vọt mặt khác là kích thước và nguồn gốc trong của nó hệ tọa độ riêng, do đó, theo mặc định, giới hạn gốc là (0,0).
hầu hết thời gian khung và giới hạn đồng nhất, nhưng nếu bạn có chế độ xem khung ((140,65), (200,250)) và giới hạn ((0,0), (200,250)) chẳng hạn và chế độ xem bị nghiêng sao cho nó đứng ở góc dưới cùng bên phải của nó, khi đó giới hạn sẽ vẫn là ((0,0), (200,250)), nhưng khung thì không.
khung sẽ là hình chữ nhật nhỏ nhất đóng gói / bao quanh khung nhìn, vì vậy khung (như trong ảnh) sẽ là ((140,65), (320.320)).
một sự khác biệt khác là ví dụ nếu bạn có superView có giới hạn là ((0,0), (200,200)) và superView này có một SubView có khung là ((20,20), (100,100)) và bạn đã thay đổi giới hạn superView đến (20,20), (200,200)), sau đó khung SubView sẽ vẫn ((20,20), (100,100)) nhưng được bù bởi (20,20) vì hệ tọa độ giám sát của nó được bù bởi (20, 20).
tôi hi vọng nó sẽ giúp ích cho mọi người.
subView
khung có liên quan đến nó superView
. thay đổi superView
giới hạn thành bất cứ điều gì sẽ không làm cho subView
nguồn gốc trùng khớp với nó superView
.
Hãy để tôi thêm 5 xu của tôi.
Khung được sử dụng bởi chế độ xem chính của chế độ xem để đặt khung bên trong chế độ xem chính.
Giới hạn được sử dụng bởi chính chế độ xem để đặt nội dung của chính nó (giống như chế độ xem cuộn trong khi cuộn). Xem thêm clipToBound . Giới hạn cũng có thể được sử dụng để phóng to / thu nhỏ nội dung của chế độ xem.
Tương tự:
Khung ~ Khung màn hình TV Giới hạn
~ Camera (thu phóng, di chuyển, xoay)
Các câu trả lời ở trên đã giải thích rất rõ sự khác biệt giữa Giới hạn và Khung.
Giới hạn: Chế độ xem và Vị trí theo hệ tọa độ của chính nó.
Khung: Kích thước khung nhìn và Vị trí so với SuperView của nó.
Sau đó, có sự nhầm lẫn rằng trong trường hợp Bound the X, Y sẽ luôn là "0". Điều này không đúng . Điều này có thể được hiểu trong UIScrollView và UICollectionView.
Khi giới hạn 'x, y không bằng 0.
Giả sử chúng ta có UIScrollView. Chúng tôi đã thực hiện phân trang. UIScrollView có 3 trang và chiều rộng của ContentSize gấp ba lần Chiều rộng màn hình (giả sử ScreenWidth là 320). Chiều cao không đổi (giả sử 200).
scrollView.contentSize = CGSize(x:320*3, y : 200)
Thêm ba UIImageView dưới dạng subViews và xem xét kỹ giá trị x của khung
let imageView0 = UIImageView.init(frame: CGRect(x:0, y: 0 , width : scrollView.frame.size.width, height : scrollView.frame.size.height))
let imageView1 : UIImageView.init( frame: CGRect(x:320, y: 0 , width : scrollView.frame.size.width, height : scrollView.frame.size.height))
let imageView2 : UIImageView.init(frame: CGRect(x:640, y: 0 , width : scrollView.frame.size.width, height : scrollView.frame.size.height))
scrollView.addSubview(imageView0)
scrollView.addSubview(imageView0)
scrollView.addSubview(imageView0)
Trang 0: Khi ScrollView ở 0 Trang, giới hạn sẽ là (x: 0, y: 0, width: 320, height: 200)
Trang 1: Di chuyển và di chuyển đến Trang 1.
Bây giờ giới hạn sẽ là (x: 320, y: 0, width: 320, height: 200)
Hãy nhớ rằng chúng tôi đã nói về hệ tọa độ của chính nó. Vì vậy, bây giờ "Phần hiển thị" của ScrollView của chúng tôi có "x" là 320. Nhìn vào khung của imageView1.
Tương tự cho trường hợp của UICollectionView. Cách dễ nhất để xem bộ sưu tập là cuộn nó và in / ghi các giới hạn của nó và bạn sẽ có được ý tưởng.
Tất cả các câu trả lời ở trên là chính xác và đây là ý kiến của tôi về điều này:
Để phân biệt giữa khung và giới hạn, nhà phát triển CONCEPTS nên đọc:
- liên quan đến giám sát (một chế độ xem cha), nó được chứa trong = FRAME
- liên quan đến hệ tọa độ của chính nó, xác định vị trí xem phụ của nó = BOUNDS
"Giới hạn" gây nhầm lẫn bởi vì nó mang lại ấn tượng rằng tọa độ là vị trí của chế độ xem được đặt. Nhưng đây là trong quan hệ và điều chỉnh theo hằng số khung.
Khung vs ràng buộc
frame = vị trí và kích thước của khung nhìn bằng hệ tọa độ của khung nhìn cha
Bound = vị trí và kích thước của chế độ xem bằng hệ thống tọa độ của chính nó
Một khung nhìn theo dõi kích thước và vị trí của nó bằng hai hình chữ nhật: hình chữ nhật khung và hình chữ nhật giới hạn. Hình chữ nhật khung xác định vị trí và kích thước của khung nhìn trong giám sát bằng hệ thống tọa độ của giám sát. Hình chữ nhật giới hạn xác định hệ tọa độ bên trong được sử dụng khi vẽ nội dung của khung nhìn, bao gồm cả gốc và tỷ lệ. Hình 2-1 cho thấy mối quan hệ giữa hình chữ nhật khung, bên trái và hình chữ nhật giới hạn, bên phải.
Nói tóm lại, khung là ý tưởng của giám sát về góc nhìn và giới hạn là ý tưởng riêng của khung nhìn. Có nhiều hệ tọa độ, một cho mỗi khung nhìn, là một phần của hệ thống phân cấp khung nhìn.