Zmiana punktu kotwiczenia mojego Calayera przesuwa widok
Chcę zmienić anchorPoint
, ale zachować widok w tym samym miejscu.
Próbowałem NSLog
- ing self.layer.position
i self.center
i oba pozostają takie same, niezależnie od zmian w punkcie kontrolnym. A jednak mój Widok 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);
Wyjście 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
11 answers
Sekcja Geometria warstwy i transformacje podręcznika programowania animacji rdzenia wyjaśnia związek między pozycją Caleyera a właściwościami punktu kotwiczenia. Zasadniczo, położenie warstwy jest określone w kategoriach położenia punktu kotwiczenia warstwy. Domyślnie punktem kontrolnym warstwy jest (0.5, 0.5), który znajduje się na środku warstwy. Po ustawieniu położenia warstwy ustawia się położenie środka warstwy w jej superlayer ' s układ współrzędnych.
Ponieważ pozycja jest względem punktu kontrolnego warstwy, zmiana tego punktu kontrolnego przy zachowaniu tej samej pozycji przesuwa warstwę. Aby zapobiec temu ruchowi, należy dostosować położenie warstwy, aby uwzględnić nowy punkt kontrolny. Jednym ze sposobów, w jaki to zrobiłem, jest pobranie obramowań warstwy, pomnożenie szerokości i wysokości obramowań przez znormalizowane wartości Starego i nowego punktu kotwiczenia, wzięcie różnicy dwóch punktów kotwiczenia i zastosowanie tego różnica w stosunku do położenia warstwy.
Możesz nawet być w stanie rozliczyć rotację w ten sposób, używając CGPointApplyAffineTransform()
z CGAffineTransform UIView.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-11 16:14:41
Miałem ten sam problem. Rozwiązanie Brada Larsona działało świetnie, nawet gdy widok jest obracany. 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 odpowiednik swift:
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
}
SWIFT 4.x
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
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-22 12:34:39
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.
Swift 2
let oldFrame = self.frame
self.layer.anchorPoint = CGPointMake(1, 1)
self.frame = oldFrame
Swift 3
let oldFrame = self.frame
self.layer.anchorPoint = CGPoint(x: 1, y: 1)
self.frame = oldFrame
Potem zmieniam Rozmiar, gdzie skaluje się od punktu kontrolnego. W takim razie muszę przywrócić stary punkt kontrolny;
Swift 2
let oldFrame = self.frame
self.layer.anchorPoint = CGPointMake(0.5,0.5)
self.frame = oldFrame
Swift 3
let oldFrame = self.frame
self.layer.anchorPoint = CGPoint(x: 0.5, y: 0.5)
self.frame = oldFrame
EDIT: ta opcja jest wyłączona, jeśli widok jest obrócony, ponieważ właściwość frame jest niezdefiniowana, jeśli CGAffineTransform został zastosowany.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-03 15:13:27
Dla mnie zrozumienie position
i anchorPoint
było najłatwiejsze, kiedy zacząłem porównywać je z moim zrozumieniem kadru.pochodzenie w UIView. UIView z ramką.origin = (20,30) oznacza, że UIView ma 20 punktów od lewej i 30 punktów od góry widoku nadrzędnego. Odległość ta jest obliczana z którego punktu UIView? Jego obliczona od lewego górnego rogu Ujazdu.
W warstwie anchorPoint
oznacza punkt (w postaci znormalizowanej tj. 0 do 1), od którego odległość ta jest obliczana tak np. warstwa.position = (20, 30) oznacza, że warstwa anchorPoint
znajduje się 20 punktów od lewej i 30 punktów od góry jej warstwy nadrzędnej. Domyślnie punktem kontrolnym warstwy jest (0.5, 0.5), więc punkt obliczania odległości znajduje się na środku warstwy. Poniższy rysunek pomoże wyjaśnić mój punkt:
anchorPoint
zdarza się również, że punkt, wokół którego nastąpi obrót, jeśli zastosujesz transformację do warstwy.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-05 04:18:07
Jest takie proste rozwiązanie. Opiera się to na odpowiedzi Kenny ' ego. Ale zamiast nakładać starą ramkę, użyj jej pochodzenia i Nowej, aby obliczyć tłumaczenie, a następnie zastosuj to tłumaczenie do środka. Działa również z obracanym widokiem! Oto kod, dużo prostszy od innych rozwiązań:
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)
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-10-21 01:12:37
Dla tych, którzy tego potrzebują, oto rozwiązanie Magnusa w języku 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
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-27 22:55:02
Oto odpowiedź user945711 dostosowana dla NSView na OS X. poza tym, że nsview nie ma właściwości .center
, ramka NSView nie zmienia się (prawdopodobnie dlatego, że nsview nie jest domyślnie wyposażona w funkcję Kalayer), Ale pochodzenie Ramki kalayer zmienia się po zmianie punktu kotwiczenia.
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)
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-20 18:50:49
Jeśli zmienisz punkt kontrolny, jego pozycja również się zmieni, chyba że masz punkt zerowy CGPointZero
.
position.x == origin.x + anchorPoint.x;
position.y == origin.y + anchorPoint.y;
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-24 06:00:17
Edytuj i zobacz punkt kontrolny UIView tuż na Storyboardzie (Swift 3)
Jest to alternatywne rozwiązanie, które pozwala zmienić punkt kontrolny za pomocą Inspektora atrybutów i ma inną właściwość, aby wyświetlić punkt kontrolny w celu potwierdzenia.
Utwórz nowy plik do umieszczenia w projekcie
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 Storyboard i ustaw klasę niestandardową
Teraz ustaw nowy punkt kontrolny dla UIView
Włączenie Pokaż punkt kontrolny pokaże czerwoną kropkę, dzięki czemu można lepiej zobaczyć, gdzie punkt kontrolny będzie wizualnie. Zawsze możesz go wyłączyć później.
To naprawdę pomogło mi podczas planowania przekształceń w UIViews.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-16 12:19:15
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
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-26 15:43:15
Rozbudowując świetną i dokładną odpowiedź Magnusa, stworzyłem wersję, która działa na podwarstwach:
-(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;
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-23 17:56:48