UIView
і його підкласи мають усі властивості frame
і bounds
. Яка різниця?
UIView
і його підкласи мають усі властивості frame
і bounds
. Яка різниця?
Відповіді:
У межах А. Н. UIView є прямокутником , вираженим як місце розташування (х, у) і розмір (ширина, висота) по відношенню до своєї власної системи координат (0,0).
Кадр з UIView є прямокутник , виражений як місце розташування (х, у) і розмір (ширина, висота) по відношенню до надтабліце він міститься всередині.
Отже, уявіть вигляд, який має розмір 100x100 (ширина х висота), розміщений на рівні 25,25 (x, 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);
}
І вихід цього коду:
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
Отже, ми можемо бачити, що в обох випадках ширина і висота виду однакові незалежно від того, дивимось ми межі чи рамку. Різне - це розташування подання x, y. У випадку меж координати x і y знаходяться на рівні 0,0, оскільки ці координати відносно самого виду. Однак координати кадру x і y відносно положення виду в батьківському поданні (що раніше ми говорили, що було 25,25).
Також є чудова презентація, яка охоплює UIViews. Дивіться слайди 1-20, які не тільки пояснюють різницю між кадрами та межею, але й показують наочні приклади.
frame = розташування та розмір подання за допомогою системи координат батьківського перегляду
межі = розташування та розмір подання, використовуючи власну систему координат
Щоб мені запам'ятати кадр , я думаю про рамку для картин на стіні . Рамка для малюнка схожа на межу перегляду. Я можу повісити малюнок де завгодно на стіну. Таким же чином я можу поставити представлення будь-де, де я хочу всередині батьківського подання (його також називають наглядом). Батьківський погляд - як стіна. Походження системи координат в iOS - зліва вгорі. Ми можемо поставити наш погляд на початок цього огляду, встановивши координати xy кадру огляду на (0, 0), що ніби висить наше зображення в самому верхньому лівому куті стіни. Щоб перемістити його праворуч, збільшити x, для переміщення вниз збільшити y.
Щоб допомогти мені запам'ятати межі , я думаю про баскетбольний майданчик, де іноді баскетбол вибивається за межі . Ви ведете м'яч по всьому баскетбольному майданчику, але вам зовсім не байдуже, де знаходиться сам корт. Це може бути у спортзалі, або на вулиці в середній школі, або перед вашим будинком. Це не має значення. Ви просто хочете пограти в баскетбол. Таким же чином система координат для меж перегляду піклується лише про сам вид. Він нічого не знає про те, де перегляд знаходиться у батьківському поданні. Походження меж (за замовчуванням точка (0, 0)) - лівий верхній кут подання. Будь-які підзаголовки, які є в цій точці зору, викладені стосовно цього моменту. Це як би взяти баскетбол до лівого переднього кута корта.
Тепер плутанина настає, коли ви намагаєтеся порівняти рамку та межі. Насправді це не так погано, як здається спочатку, хоча. Давайте скористаємося деякими малюнками, щоб допомогти нам зрозуміти.
На першому малюнку зліва ми маємо вид, розташований у верхньому лівому куті його батьківського виду. Жовтий прямокутник являє собою кадр подання. Праворуч ми знову бачимо подання, але цього разу батьківський погляд не відображається. Це тому, що межі не знають про батьківський вигляд. Зелений прямокутник відображає межі виду. Червона точка на обох зображеннях є початок кадру або рамки.
Frame
origin = (0, 0)
width = 80
height = 130
Bounds
origin = (0, 0)
width = 80
height = 130
Тож рамка та межі були точно однаковими на цій фотографії. Давайте розглянемо приклад, де вони різні.
Frame
origin = (40, 60) // That is, x=40 and y=60
width = 80
height = 130
Bounds
origin = (0, 0)
width = 80
height = 130
Таким чином, ви можете бачити, що зміна координат xy кадру переміщує його в батьківський вигляд. Але зміст самого погляду все одно виглядає точно так само. Межі поняття не мають, що щось інакше.
Досі ширина та висота рами та бортів були абсолютно однаковими. Однак це не завжди так. Подивіться, що станеться, якщо повернути погляд на 20 градусів за годинниковою стрілкою. (Обертання здійснюється за допомогою перетворень. Докладнішу інформацію див. У документації та цих прикладах перегляду та шарів .)
Frame
origin = (20, 52) // These are just rough estimates.
width = 118
height = 187
Bounds
origin = (0, 0)
width = 80
height = 130
Видно, що межі все одно однакові. Вони досі не знають, що щось сталося! Хоча значення кадру все змінилися.
Тепер трохи простіше помітити різницю між рамкою та межею, чи не так? Стаття, яку ви, ймовірно, не розумієте, кадрів і меж визначає кадр перегляду як
... найменше обмежувальне поле цього погляду стосовно системи координат батьків, включаючи будь-які перетворення, застосовані до цього виду.
Важливо зазначити, що якщо ви перетворите перегляд, то кадр стає невизначеним. Так що насправді жовтої рамки, яку я намалював навколо обертових зелених меж на зображенні вище, насправді ніколи не існує. Це означає, що якщо ви обертаєте, масштабуєте чи робите якусь іншу трансформацію, то більше не слід використовувати значення кадру. Однак ви все ще можете використовувати значення меж. Документи Apple попереджають:
Важливо: Якщо
transform
властивість представлення не містить перетворення ідентичності, рамка цього виду не визначена, як і результати її автоматизованої поведінки.
Швидше прикро щодо автореалізації .... Хоча щось можна зробити.
Під час зміни
transform
властивості вашого зору всі перетворення виконуються відносно центральної точки зору.
Отже, якщо вам потрібно перенести погляд у батьківській програмі після перетворення, ви можете це зробити, змінивши view.center
координати. Мовляв frame
, center
використовує систему координат батьківського подання.
Гаразд, давайте позбудемося обертання і зосередимось на межах. Поки межа походження завжди залишалася на рівні (0, 0). Однак це не обов'язково. Що робити, якщо наш погляд має великий підвид, який занадто великий, щоб відображати всіх відразу? Ми зробимо це UIImageView
з великим зображенням. Ось наша друга картинка зверху ще раз, але цього разу ми можемо побачити, як виглядатиме весь зміст підпогляду нашого погляду.
Frame
origin = (40, 60)
width = 80
height = 130
Bounds
origin = (0, 0)
width = 80
height = 130
Лише верхній лівий кут зображення може вміщуватися в межах виду. Тепер подивіться, що станеться, якщо ми змінимо координати початку меж.
Frame
origin = (40, 60)
width = 80
height = 130
Bounds
origin = (280, 70)
width = 80
height = 130
Кадр не перемістився в огляді, але вміст всередині кадру змінився, оскільки початок прямокутника меж починається з іншої частини подання. Це вся ідея a UIScrollView
і це підкласи (наприклад, a UITableView
). Докладніші відомості див. У розділі Розуміння UIScrollView .
Оскільки frame
пов’язує розташування подання у своєму батьківському поданні, ви використовуєте його, коли вносите зовнішні зміни , наприклад, змінюючи його ширину або знаходячи відстань між поданням та вершиною його батьківського подання.
Використовуйте те, bounds
коли ви вносите зміни всередину , як-от малювання речей або впорядкування підпоказів у межах подання. Також використовуйте межі, щоб отримати розмір перегляду, якщо ви зробили деяке зображення.
Документи Apple
Пов'язані питання щодо StackOverflow
Інші ресурси
Окрім читання вищезазначених статей, мені дуже допомагає зробити тестовий додаток. Можливо, ви захочете спробувати зробити щось подібне. (Я отримав ідею з цього відеокурсу, але, на жаль, це не безкоштовно.)
Ось код для вашої довідки:
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
проти frame
перегляду.
спробуйте запустити код нижче
- (void)viewDidLoad {
[super viewDidLoad];
UIWindow *w = [[UIApplication sharedApplication] keyWindow];
UIView *v = [w.subviews objectAtIndex:0];
NSLog(@"%@", NSStringFromCGRect(v.frame));
NSLog(@"%@", NSStringFromCGRect(v.bounds));
}
вихід цього коду:
корпус орієнтації пристрою - портрет
{{0, 0}, {768, 1024}}
{{0, 0}, {768, 1024}}
Випадок орієнтації пристрою - Пейзаж
{{0, 0}, {768, 1024}}
{{0, 0}, {1024, 768}}
очевидно, ви можете побачити різницю між рамкою та межею
кадр - це початок (верхній лівий кут) і розмір подання в системі координат суперпогляду, це означає, що ви переводите подання у його суперпогляд, змінюючи походження кадру, межі , з іншого боку, розмір і походження в його власна система координат, тому за замовчуванням початок меж дорівнює (0,0).
більшу частину часу кадри та межі є конгруентними, але якщо у вас є вид кадру ((140,65), (200,250)) та меж ((0,0), (200,250)), наприклад, і вигляд був нахилений так що він стоїть у нижньому правому куті, то рамки все одно будуть ((0,0), (200,250)), але рамка - ні.
кадр буде найменшим прямокутником, який інкапсулює / оточує вигляд, тому кадр (як на фото) буде ((140,65), (320,320)).
інша відмінність, наприклад, якщо у вас є SuperView, межі якого ((0,0), (200,200)), і цей superView має підпогляд, фрейм якого ((20,20), (100,100)), і ви змінили межі SuperView до ((20,20), (200,200)), тоді кадр subView буде все ще ((20,20), (100,100)), але зміщений на (20,20), оскільки його система координат нагляду була змінена на (20, 20).
Я сподіваюся, що це комусь допоможе.
subView
кадр відносно нього superView
. зміна superView
меж нічого не призведе до того, що subView
походження збігається з цим superView
.
Дозвольте додати свої 5 центів.
Кадр використовується батьківським поданням подання, щоб розмістити його всередині батьківського подання.
Межі використовується самим представленням для розміщення власного вмісту (як це робить перегляд прокрутки під час прокрутки). Дивіться також кліпиToBounds . Межі також можна використовувати для збільшення / зменшення вмісту перегляду.
Аналогія:
Кадр ~
Зв'язок екрану телевізора ~ Камера (збільшення, переміщення, обертання)
Наведені вище відповіді дуже добре пояснили різницю між Рамками та Рамками.
Межі: Розмір і розташування перегляду відповідно до власної системи координат.
Кадр: розмір перегляду та розташування щодо його SuperView.
Тоді виникає плутанина, що у випадку Bounds X, Y завжди буде "0". Це неправда . Це можна зрозуміти також у UIScrollView та UICollectionView.
Коли межі 'x, y не дорівнюють 0.
Припустимо, у нас є UIScrollView. Ми реалізували пагинацію. UIScrollView має 3 сторінки, а його ширина ContentSize втричі перевищує ширину екрана (припустимо, ширина екрану становить 320). Висота постійна (припустимо, 200).
scrollView.contentSize = CGSize(x:320*3, y : 200)
Додайте три UIImageView як підпогляди та пильно подивіться на значення x кадру
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)
Сторінка 0: Якщо ScrollView знаходиться на 0 сторінці, то коржі будуть (x: 0, y: 0, ширина: 320, висота: 200)
Сторінка 1: Прокрутіть і перейдіть до сторінки 1.
Тепер межі будуть (х: 320, у: 0, ширина: 320, висота: 200).
Пам'ятайте, що ми говорили стосовно власної системи координат. Отже, "Видима частина" нашого ScrollView має "x" на 320. Подивіться на кадр imageView1.
Те саме для випадку UICollectionView. Найпростіший спосіб поглянути на collectionView - прокрутити його та надрукувати / записати його межі, і ви отримаєте ідею.
Усі відповіді, наведені вище, є правильними, і я вважаю, що це:
Для розмежування кадру та меж CONCEPTS розробник повинен прочитати:
- по відношенню до огляду (один батьківський погляд) він міститься в межах = FRAME
- відносно власної системи координат визначає його місце підпогляду = BOUNDS
"межі" є заплутаними, оскільки створюється враження, що координати - це положення виду, для якого воно встановлено. Але вони співвідносяться і регулюються відповідно до констант кадру.
Кадр проти зв'язаного
frame = розташування та розмір подання за допомогою системи координат батьківського перегляду
межі = розташування та розмір подання, використовуючи власну систему координат
Перегляд відстежує його розміри та розташування за допомогою двох прямокутників: прямокутника кадру та прямокутника за межею. Прямокутник кадру визначає розташування та розмір подання в нагляді за допомогою системи координат нагляду. Прямокутник прямокутних ліній визначає систему координат інтер'єру, яка використовується при малюванні вмісту зображення, включаючи походження та масштабування. На рисунку 2-1 показано співвідношення між прямокутником кадру зліва та прямокутником рамки праворуч. "
Коротше кажучи, кадр - це ідея перегляду виду, а межі - це власна ідея перегляду. Наявність декількох систем координат, по одній для кожного перегляду, є частиною ієрархії подання.