Próbuję zrozumieć funkcjonalności tych metod. Czy mógłbyś podać mi prosty przypadek użycia, aby zrozumieć ich semantykę?
Z dokumentacji, na przykład, metoda convertPoint: fromView: jest opisana w następujący sposób:
Konwertuje punkt z układu współrzędnych danego widoku na punkt w odbiorniku.
Co oznacza układ współrzędnych ? A co z odbiornikiem ?
Na przykład, czy ma sens używanie convertPoint: fromView: jak poniżej?
CGPoint p = [view1 convertPoint:view1.center fromView:view1];
Używając narzędzia NSLog, zweryfikowałem, że wartość p pokrywa się ze środkiem view1.
Z góry dziękuję.
EDYCJA: dla zainteresowanych stworzyłem prosty fragment kodu, aby zrozumieć te metody.
UIView* view1 = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 150, 200)];
view1.backgroundColor = [UIColor redColor];
NSLog(@"view1 frame: %@", NSStringFromCGRect(view1.frame));
NSLog(@"view1 center: %@", NSStringFromCGPoint(view1.center));
CGPoint originInWindowCoordinates = [self.window convertPoint:view1.bounds.origin fromView:view1];
NSLog(@"convertPoint:fromView: %@", NSStringFromCGPoint(originInWindowCoordinates));
CGPoint originInView1Coordinates = [self.window convertPoint:view1.frame.origin toView:view1];
NSLog(@"convertPoint:toView: %@", NSStringFromCGPoint(originInView1Coordinates));
W obu przypadkach self.window jest odbiornikiem. Ale jest różnica. W pierwszym przypadku parametr convertPoint jest wyrażony we współrzędnych view1. Wynik jest następujący:
convertPoint: fromView: {100, 100}
W drugim natomiast convertPoint jest wyrażony we współrzędnych superview (self.window). Wynik jest następujący:
convertPoint: toView: {0, 0}
convertPoint
iconvertRect
różnią się typem zwracania.CGPoint
lubCGRect
. Ale co zfrom
ito
? Czy jest jakaś praktyczna zasada, której mógłbym użyć? Dziękuję Ci.Zawsze uważam to za zagmatwane, więc stworzyłem plac zabaw, na którym możesz wizualnie zbadać, co
convert
robi ta funkcja. Odbywa się to w Swift 3 i Xcode 8.1b:import UIKit import PlaygroundSupport class MyViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // Main view view.backgroundColor = .black view.frame = CGRect(x: 0, y: 0, width: 500, height: 500) // Red view let redView = UIView(frame: CGRect(x: 20, y: 20, width: 460, height: 460)) redView.backgroundColor = .red view.addSubview(redView) // Blue view let blueView = UIView(frame: CGRect(x: 20, y: 20, width: 420, height: 420)) blueView.backgroundColor = .blue redView.addSubview(blueView) // Orange view let orangeView = UIView(frame: CGRect(x: 20, y: 20, width: 380, height: 380)) orangeView.backgroundColor = .orange blueView.addSubview(orangeView) // Yellow view let yellowView = UIView(frame: CGRect(x: 20, y: 20, width: 340, height: 100)) yellowView.backgroundColor = .yellow orangeView.addSubview(yellowView) // Let's try to convert now var resultFrame = CGRect.zero let randomRect: CGRect = CGRect(x: 0, y: 0, width: 100, height: 50) /* func convert(CGRect, from: UIView?) Converts a rectangle from the coordinate system of another view to that of the receiver. */ // The following line converts a rectangle (randomRect) from the coordinate system of yellowView to that of self.view: resultFrame = view.convert(randomRect, from: yellowView) // Try also one of the following to get a feeling of how it works: // resultFrame = view.convert(randomRect, from: orangeView) // resultFrame = view.convert(randomRect, from: redView) // resultFrame = view.convert(randomRect, from: nil) /* func convert(CGRect, to: UIView?) Converts a rectangle from the receiver’s coordinate system to that of another view. */ // The following line converts a rectangle (randomRect) from the coordinate system of yellowView to that of self.view resultFrame = yellowView.convert(randomRect, to: view) // Same as what we did above, using "from:" // resultFrame = view.convert(randomRect, from: yellowView) // Also try: // resultFrame = orangeView.convert(randomRect, to: view) // resultFrame = redView.convert(randomRect, to: view) // resultFrame = orangeView.convert(randomRect, to: nil) // Add an overlay with the calculated frame to self.view let overlay = UIView(frame: resultFrame) overlay.backgroundColor = UIColor(white: 1.0, alpha: 0.9) overlay.layer.borderColor = UIColor.black.cgColor overlay.layer.borderWidth = 1.0 view.addSubview(overlay) } } var ctrl = MyViewController() PlaygroundPage.current.liveView = ctrl.view
Pamiętaj, aby pokazać Asystenta Edytora ( ⎇⌘⏎), aby zobaczyć widoki, powinien on wyglądać tak:
Zapraszam do dodania więcej przykładów tutaj lub w tym streszczeniu .
źródło
self.view
są one zbędne, proste w użyciu,view
jeśliself
nie są potrzebne.self
Oto wyjaśnienie w prostym języku angielskim.
Gdy chcesz przekonwertować prostokąt widoku podrzędnego (
aView
jest to widok podrzędny[aView superview]
) na przestrzeń współrzędnych innego widoku (self
).// So here I want to take some subview and put it in my view's coordinate space _originalFrame = [[aView superview] convertRect: aView.frame toView: self];
źródło
Każdy widok w iOS ma układ współrzędnych. Układ współrzędnych jest podobny do wykresu, który ma oś X (linia pozioma) i oś Y (linia pionowa). Punkt, w którym przecinają się linie, nazywany jest początkiem. Punkt jest reprezentowany przez (x, y). Na przykład (2, 1) oznacza, że punkt ma 2 piksele na lewo i 1 piksel w dół.
Możesz przeczytać więcej o układach współrzędnych tutaj - http://en.wikipedia.org/wiki/Coordinate_system
Ale musisz wiedzieć, że w iOS każdy widok ma swój WŁASNY układ współrzędnych, w którym lewy górny róg jest początkiem. Oś X rośnie w prawo, a oś Y rośnie w dół.
W przypadku pytania dotyczącego punktów konwersji weź ten przykład.
Jest widok zwany V1, który ma 100 pikseli szerokości i 100 pikseli wysokości. Teraz w środku jest inny widok, zwany V2, w (10, 10, 50, 50), co oznacza, że (10, 10) jest punktem w układzie współrzędnych V1, w którym powinien znajdować się lewy górny róg V2, oraz ( 50, 50) to szerokość i wysokość V2. Teraz weź punkt WEWNĄTRZ układu współrzędnych V2, powiedzmy (20, 20). Jaki byłby ten punkt wewnątrz układu współrzędnych V1? Do tego służą metody (oczywiście możesz obliczyć same, ale oszczędzają one dodatkowej pracy). Dla przypomnienia, punktem w V1 byłoby (30, 30).
Mam nadzieję że to pomoże.
źródło
Dziękuję wszystkim za opublikowanie pytania i odpowiedzi: pomogło mi to załatwić.
Mój kontroler widoku ma normalny widok.
Wewnątrz tego widoku znajduje się wiele widoków grupujących, które robią niewiele więcej niż zapewniają ich widokom podrzędnym czystą interakcję z ograniczeniami automatycznego układu.
W jednym z tych widoków grupujących mam przycisk Dodaj, który przedstawia kontroler widoku popover, w którym użytkownik wprowadza pewne informacje.
view --groupingView ----addButton
Podczas obracania urządzenia kontroler widoku jest ostrzegany za pośrednictwem wywołania UIPopoverViewControllerDelegate popoverController: willRepositionPopoverToRect: inView:
- (void)popoverController:(UIPopoverController *)popoverController willRepositionPopoverToRect:(inout CGRect *)rect inView:(inout UIView *__autoreleasing *)view { *rect = [self.addButton convertRect:self.addbutton.bounds toView:*view]; }
Zasadniczą częścią, która pochodzi z wyjaśnienia podanego w pierwszych dwóch odpowiedziach powyżej, było to, że prostą, z której musiałem dokonać konwersji, były granice przycisku dodawania, a nie jego ramka.
Nie próbowałem tego z bardziej złożoną hierarchią widoków, ale podejrzewam, że używając widoku dostarczonego w wywołaniu metody (inView :) omijamy komplikacje wielopoziomowego widoku liści.
źródło
Użyłem tego posta, aby złożyć wniosek w moim przypadku. Mam nadzieję, że w przyszłości pomoże to innemu czytelnikowi.
Widok może zobaczyć tylko swoje bezpośrednie widoki podrzędne i nadrzędne. Nie widzi poglądów swoich dziadków ani wnuków.
Tak więc, w moim przypadku, mam wielki Zobacz główne nazwie
self.view
, w tymself.view
Dodałem subviews zwaneself.child1OfView
,self.child2OfView
. Wself.child1OfView
dodałem subviews zwaneself.child1OfView1
,self.child2OfView1
.Teraz, jeśli fizycznie przeniosę się
self.child1OfView1
do obszaru znajdującego się poza granicami innegoself.child1OfView
miejscaself.view
, to do obliczenia nowej pozycjiself.child1OfView1
wewnątrzself.view:
CGPoint newPoint = [self.view convertPoint:self.child1OfView1.center fromView:self.child1OfView];
źródło
Możesz zobaczyć poniższy kod, aby zrozumieć, jak to naprawdę działa.
let scrollViewTemp = UIScrollView.init(frame: CGRect.init(x: 10, y: 10, width: deviceWidth - 20, height: deviceHeight - 20)) override func viewDidLoad() { super.viewDidLoad() scrollViewTemp.backgroundColor = UIColor.lightGray scrollViewTemp.contentSize = CGSize.init(width: 2000, height: 2000) self.view.addSubview(scrollViewTemp) let viewTemp = UIView.init(frame: CGRect.init(x: 100, y: 100, width: 150, height: 150)) viewTemp.backgroundColor = UIColor.green self.view.addSubview(viewTemp) let viewSecond = UIView.init(frame: CGRect.init(x: 100, y: 700, width: 300, height: 300)) viewSecond.backgroundColor = UIColor.red self.view.addSubview(viewSecond) self.view.convert(viewTemp.frame, from: scrollViewTemp) print(viewTemp.frame) /* First take one point CGPoint(x: 10, y: 10) of viewTemp frame,then give distance from viewSecond frame to this point. */ let point = viewSecond.convert(CGPoint(x: 10, y: 10), from: viewTemp) //output: (10.0, -190.0) print(point) /* First take one point CGPoint(x: 10, y: 10) of viewSecond frame,then give distance from viewTemp frame to this point. */ let point1 = viewSecond.convert(CGPoint(x: 10, y: 10), to: viewTemp) //output: (10.0, 210.0) print(point1) /* First take one rect CGRect(x: 10, y: 10, width: 20, height: 20) of viewSecond frame,then give distance from viewTemp frame to this rect. */ let rect1 = viewSecond.convert(CGRect(x: 10, y: 10, width: 20, height: 20), to: viewTemp) //output: (10.0, 210.0, 20.0, 20.0) print(rect1) /* First take one rect CGRect(x: 10, y: 10, width: 20, height: 20) of viewTemp frame,then give distance from viewSecond frame to this rect. */ let rect = viewSecond.convert(CGRect(x: 10, y: 10, width: 20, height: 20), from: viewTemp) //output: (10.0, -190.0, 20.0, 20.0) print(rect) }
źródło
Przeczytałem odpowiedź i rozumiem mechanikę, ale myślę, że ostatni przykład nie jest poprawny. Zgodnie z dokumentem API, właściwość center widoku zawiera znany punkt środkowy widoku w układzie współrzędnych superviewu.
Jeśli tak jest, to myślę, że nie ma sensu prosić superwidoku o konwersję środka widoku podrzędnego Z układu współrzędnych widoku podrzędnego, ponieważ wartość nie znajduje się w układzie współrzędnych widoku podrzędnego. Sensowne byłoby zrobienie czegoś odwrotnego, tj. Konwersja z układu współrzędnych superwizji na widok podrzędny ...
Możesz to zrobić na dwa sposoby (oba powinny dać tę samą wartość):
CGPoint centerInSubview = [subview convertPoint:subview.center fromView:subview.superview];
lub
CGPoint centerInSubview = [subview.superview convertPoint:subview.center toView:subview];
Czy daleko mi do zrozumienia, jak to powinno działać?
źródło
Jeszcze jeden ważny punkt dotyczący korzystania z tych interfejsów API. Upewnij się, że łańcuch widoku macierzystego jest kompletny między konwertowanym prostokątem a widokiem do / z widoku. Na przykład - aView, bView i cView -
Jeśli spróbujemy wykonać metodę przed dodaniem bView jako podwidoku cView, otrzymamy odpowiedź bunk. Niestety w metodach w tym przypadku nie ma wbudowanej ochrony. Może się to wydawać oczywiste, ale należy o tym pamiętać w przypadkach, gdy nawrócenie przebiega przez długi łańcuch rodziców.
źródło