Chcę zmienić anchorPoint
, ale zachować widok w tym samym miejscu. Próbowałem NSLog
-ing self.layer.position
i self.center
i obaj pozostają takie same, niezależnie od zmian w Anchorpoint. Jednak mój pogląd się porusza!
Jakieś wskazówki, jak to zrobić?
self.layer.anchorPoint = CGPointMake(0.5, 0.5);
NSLog(@"center point: %f %f", self.layer.position.x, self.layer.position.y);
self.layer.anchorPoint = CGPointMake(1, 1);
NSLog(@"center point: %f %f", self.layer.position.x, self.layer.position.y);
Wynik to:
2009-12-27 20:43:24.161 Type[11289:207] center point: 272.500000 242.500000
2009-12-27 20:43:24.162 Type[11289:207] center point: 272.500000 242.500000
źródło
anchorPoint
iposition
są ze sobą powiązane?Miałem ten sam problem. Rozwiązanie Brada Larsona działało świetnie, nawet gdy widok jest obrócony. Oto jego rozwiązanie przetłumaczone na kod.
-(void)setAnchorPoint:(CGPoint)anchorPoint forView:(UIView *)view { CGPoint newPoint = CGPointMake(view.bounds.size.width * anchorPoint.x, view.bounds.size.height * anchorPoint.y); CGPoint oldPoint = CGPointMake(view.bounds.size.width * view.layer.anchorPoint.x, view.bounds.size.height * view.layer.anchorPoint.y); newPoint = CGPointApplyAffineTransform(newPoint, view.transform); oldPoint = CGPointApplyAffineTransform(oldPoint, view.transform); CGPoint position = view.layer.position; position.x -= oldPoint.x; position.x += newPoint.x; position.y -= oldPoint.y; position.y += newPoint.y; view.layer.position = position; view.layer.anchorPoint = anchorPoint; }
I szybki odpowiednik:
func setAnchorPoint(anchorPoint: CGPoint, forView view: UIView) { var newPoint = CGPointMake(view.bounds.size.width * anchorPoint.x, view.bounds.size.height * anchorPoint.y) var oldPoint = CGPointMake(view.bounds.size.width * view.layer.anchorPoint.x, view.bounds.size.height * view.layer.anchorPoint.y) newPoint = CGPointApplyAffineTransform(newPoint, view.transform) oldPoint = CGPointApplyAffineTransform(oldPoint, view.transform) var position = view.layer.position position.x -= oldPoint.x position.x += newPoint.x position.y -= oldPoint.y position.y += newPoint.y view.layer.position = position view.layer.anchorPoint = anchorPoint }
func setAnchorPoint(anchorPoint: CGPoint, forView view: UIView) { var newPoint = CGPoint(x: view.bounds.size.width * anchorPoint.x, y: view.bounds.size.height * anchorPoint.y) var oldPoint = CGPoint(x: view.bounds.size.width * view.layer.anchorPoint.x, y: view.bounds.size.height * view.layer.anchorPoint.y) newPoint = newPoint.applying(view.transform) oldPoint = oldPoint.applying(view.transform) var position = view.layer.position position.x -= oldPoint.x position.x += newPoint.x position.y -= oldPoint.y position.y += newPoint.y view.layer.position = position view.layer.anchorPoint = anchorPoint }
źródło
Kluczem do rozwiązania tego problemu było użycie właściwości frame, która jest dziwną jedyną rzeczą, która się zmienia.
Szybki 2
let oldFrame = self.frame self.layer.anchorPoint = CGPointMake(1, 1) self.frame = oldFrame
Szybki 3
let oldFrame = self.frame self.layer.anchorPoint = CGPoint(x: 1, y: 1) self.frame = oldFrame
Następnie zmieniam rozmiar, w którym skaluje się od punktu kotwiczenia. Następnie muszę przywrócić stary anchorPoint;
Szybki 2
let oldFrame = self.frame self.layer.anchorPoint = CGPointMake(0.5,0.5) self.frame = oldFrame
Szybki 3
let oldFrame = self.frame self.layer.anchorPoint = CGPoint(x: 0.5, y: 0.5) self.frame = oldFrame
EDYTUJ: ta opcja znika, jeśli widok jest obrócony, ponieważ właściwość ramki jest niezdefiniowana, jeśli zastosowano CGAffineTransform.
źródło
Dla mnie zrozumienie
position
ianchorPoint
było to najłatwiejsze, gdy zacząłem porównywać to z moim rozumieniem frame.origin w UIView. UIView z frame.origin = (20,30) oznacza, że UIView ma 20 punktów od lewej i 30 punktów od góry widoku nadrzędnego. Ta odległość jest obliczana z którego punktu UIView? Jest obliczany z lewego górnego rogu UIView.W warstwie
anchorPoint
zaznacza się punkt (w znormalizowanej formie tj. Od 0 do 1), od którego obliczana jest ta odległość, więc np. Layer.position = (20, 30) oznacza, że warstwaanchorPoint
znajduje się 20 punktów od lewej i 30 punktów od góry jej warstwy macierzystej. Domyślnie punkt zakotwiczenia warstwy to (0,5, 0,5), więc punkt obliczania odległości znajduje się dokładnie w środku warstwy. Poniższy rysunek pomoże wyjaśnić mój punkt widzenia:anchorPoint
zdarza się również, że jest to punkt, wokół którego nastąpi obrót w przypadku zastosowania transformacji do warstwy.źródło
Jest takie proste rozwiązanie. To jest oparte na odpowiedzi Kenny'ego. Ale zamiast stosować starą ramkę, użyj jej początku i nowej do obliczenia tłumaczenia, a następnie zastosuj to tłumaczenie do środka. Działa również z widokiem obróconym! Oto kod, dużo prostszy niż inne rozwiązania:
func setAnchorPoint(anchorPoint: CGPoint, view: UIView) { let oldOrigin = view.frame.origin view.layer.anchorPoint = anchorPoint let newOrigin = view.frame.origin let translation = CGPoint(x: newOrigin.x - oldOrigin.x, y: newOrigin.y - oldOrigin.y) view.center = CGPoint(x: view.center.x - translation.x, y: view.center.y - translation.y) }
źródło
Dla tych, którzy tego potrzebują, oto rozwiązanie Magnusa w Swift:
func setAnchorPoint(anchorPoint: CGPoint, view: UIView) { var newPoint: CGPoint = CGPointMake(view.bounds.size.width * anchorPoint.x, view.bounds.size.height * anchorPoint.y) var oldPoint: CGPoint = CGPointMake(view.bounds.size.width * view.layer.anchorPoint.x, view.bounds.size.height * view.layer.anchorPoint.y) newPoint = CGPointApplyAffineTransform(newPoint, view.transform) oldPoint = CGPointApplyAffineTransform(oldPoint, view.transform) var position: CGPoint = view.layer.position position.x -= oldPoint.x position.x += newPoint.x position.y -= oldPoint.y position.y += newPoint.y view.setTranslatesAutoresizingMaskIntoConstraints(true) // Added to deal with auto layout constraints view.layer.anchorPoint = anchorPoint view.layer.position = position }
źródło
view.setTranslatesAutoresizingMaskIntoConstraints(true)
. dzięki człowiekowiview.setTranslatesAutoresizingMaskIntoConstraints(true)
jest konieczne, gdy używane są ograniczenia automatycznego układu.translatesAutoresizingMaskIntoConstraints
jest właśnie to, czego mi brakowało, do tej pory mogłem się nauczyćOto odpowiedź użytkownika945711 dostosowana do NSView na OS X. Poza tym, że NSView nie ma
.center
właściwości, ramka NSView nie zmienia się (prawdopodobnie dlatego, że NSViews domyślnie nie są dostarczane z CALayer), ale początek ramki CALayer zmienia się, gdy zmienia się punkt anchorPoint.func setAnchorPoint(anchorPoint: NSPoint, view: NSView) { guard let layer = view.layer else { return } let oldOrigin = layer.frame.origin layer.anchorPoint = anchorPoint let newOrigin = layer.frame.origin let transition = NSMakePoint(newOrigin.x - oldOrigin.x, newOrigin.y - oldOrigin.y) layer.frame.origin = NSMakePoint(layer.frame.origin.x - transition.x, layer.frame.origin.y - transition.y) }
źródło
Jeśli zmienisz anchorPoint, jego pozycja również się zmieni, chyba że twój początek jest punktem zerowym
CGPointZero
.źródło
Edytuj i zobacz punkt zakotwiczenia UIView bezpośrednio na Storyboard (Swift 3)
Jest to alternatywne rozwiązanie, które umożliwia zmianę punktu zakotwiczenia za pomocą Inspektora atrybutów i ma inną właściwość do wyświetlania punktu zakotwiczenia w celu potwierdzenia.
Utwórz nowy plik, który zostanie dołączony do projektu
import UIKit @IBDesignable class UIViewAnchorPoint: UIView { @IBInspectable var showAnchorPoint: Bool = false @IBInspectable var anchorPoint: CGPoint = CGPoint(x: 0.5, y: 0.5) { didSet { setAnchorPoint(anchorPoint: anchorPoint) } } override func draw(_ rect: CGRect) { if showAnchorPoint { let anchorPointlayer = CALayer() anchorPointlayer.backgroundColor = UIColor.red.cgColor anchorPointlayer.bounds = CGRect(x: 0, y: 0, width: 6, height: 6) anchorPointlayer.cornerRadius = 3 let anchor = layer.anchorPoint let size = layer.bounds.size anchorPointlayer.position = CGPoint(x: anchor.x * size.width, y: anchor.y * size.height) layer.addSublayer(anchorPointlayer) } } func setAnchorPoint(anchorPoint: CGPoint) { var newPoint = CGPoint(x: bounds.size.width * anchorPoint.x, y: bounds.size.height * anchorPoint.y) var oldPoint = CGPoint(x: bounds.size.width * layer.anchorPoint.x, y: bounds.size.height * layer.anchorPoint.y) newPoint = newPoint.applying(transform) oldPoint = oldPoint.applying(transform) var position = layer.position position.x -= oldPoint.x position.x += newPoint.x position.y -= oldPoint.y position.y += newPoint.y layer.position = position layer.anchorPoint = anchorPoint } }
Dodaj widok do scenorysu i ustaw klasę niestandardową
Teraz ustaw nowy punkt kotwiczenia dla UIView
Włączenie punktu kontrolnego Pokaż punkt zakotwiczenia spowoduje wyświetlenie czerwonej kropki, dzięki czemu będzie można lepiej zobaczyć, gdzie będzie punkt kontrolny. Zawsze możesz to wyłączyć później.
To naprawdę pomogło mi przy planowaniu zmian w UIViews.
źródło
Dla Swift 3:
func setAnchorPoint(_ anchorPoint: CGPoint, forView view: UIView) { var newPoint = CGPoint(x: view.bounds.size.width * anchorPoint.x, y: view.bounds.size.height * anchorPoint.y) var oldPoint = CGPoint(x: view.bounds.size.width * view.layer.anchorPoint.x, y: view.bounds.size.height * view.layer.anchorPoint.y) newPoint = newPoint.applying(view.transform) oldPoint = oldPoint.applying(view.transform) var position = view.layer.position position.x -= oldPoint.x position.x += newPoint.x position.y -= oldPoint.y position.y += newPoint.y view.layer.position = position view.layer.anchorPoint = anchorPoint }
źródło
Rozwijając świetną i dokładną odpowiedź Magnusa, stworzyłem wersję, która działa na warstwach podrzędnych:
-(void)setAnchorPoint:(CGPoint)anchorPoint forLayer:(CALayer *)layer { CGPoint newPoint = CGPointMake(layer.bounds.size.width * anchorPoint.x, layer.bounds.size.height * anchorPoint.y); CGPoint oldPoint = CGPointMake(layer.bounds.size.width * layer.anchorPoint.x, layer.bounds.size.height * layer.anchorPoint.y); CGPoint position = layer.position; position.x -= oldPoint.x; position.x += newPoint.x; position.y -= oldPoint.y; position.y += newPoint.y; layer.position = position; layer.anchorPoint = anchorPoint; }
źródło