改变我的CALayer的anchorPoint移动视图
我想改变anchorPoint
,但保持视图在同一个地方。 我已经试过NSLog
-ing self.layer.position
和self.center
,他们都保持不变的anchorPoint不变。 然而,我的观点在动!
有关如何做到这一点的任何提示?
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);
输出是:
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
核心animation编程指南中的Layer Geometry和Transforms部分解释了CALayer的位置和anchorPoint属性之间的关系。 基本上,图层的位置是根据图层的anchorPoint的位置来指定的。 默认情况下,图层的anchorPoint是(0.5,0.5),位于图层的中心。 当你设置图层的位置时,你就可以在图层的中心坐标系中设置图层的中心位置。
由于位置相对于图层的anchorPoint,所以在保持相同位置的同时更改该anchorPoint会移动该图层。 为了防止这种移动,你需要调整图层的位置来考虑新的anchorPoint。 我这样做的一种方法是抓住图层的边界,将边界的宽度和高度乘以新的和新的anchorPoint的规格化值,取两个anchorPoint的差异,并将该差异应用于图层的位置。
你甚至可以通过在你的UIView的CGAffineTransform中使用CGPointApplyAffineTransform()
来CGPointApplyAffineTransform()
这个问题。
我有同样的问题。 即使旋转视图,Brad Larson的解决scheme也很有效。 这是他的解决scheme翻译成代码。
-(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; }
和快速的等值:
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 2
CGRect oldFrame = self.frame self.layer.anchorPoint = CGPointMake(1, 1) self.frame = oldFrame
Swift 3
CGRect oldFrame = self.frame self.layer.anchorPoint = CGPoint(x: 1, y: 1) self.frame = oldFrame
然后我做我的resize,从anchorPoint扩大。 然后我必须恢复旧的anchorPoint;
Swift 2
oldFrame = self.frame self.layer.anchorPoint = CGPointMake(0.5,0.5) self.frame = oldFrame
Swift 3
oldFrame = self.frame self.layer.anchorPoint = CGPoint(x: 0.5, y: 0.5) self.frame = oldFrame
编辑:这如果视图旋转,如果框架属性是未定义的,如果CGAffineTransform已被应用,剥落。
对于我来说,理解position
和anchorPoint
是最容易的,当我开始比较它和我在UIView中对frame.origin的理解。 使用frame.origin =(20,30)的UIView意味着UIView从左边20个点到其父视点顶部30个点。 这个距离是从一个UIView的哪个点计算出来的? 它从UIView的左上angular计算。
在图层中, anchorPoint
标记从距离计算所在的点(标准化forms,即0到1),例如layer.position =(20,30)意味着图层anchorPoint
从左边20个点到顶部30个点层。 默认情况下,一个图层anchorPoint是(0.5,0.5),所以距离计算点在图层的中心。 下图将有助于澄清我的观点:
如果您将转换应用于图层,则anchorPoint
也恰好是旋转将发生的点。
有这样一个简单的解决scheme。 这是基于肯尼的答案。 但不是应用旧的框架,而是使用它的原点和新的框架来计算转换,然后将该转换应用到中心。 它也适用于旋转视图! 这是代码,比其他解决scheme简单得多:
- (void) setAnchorPoint:(CGPoint)anchorPoint forView:(UIView *)view{ CGPoint oldOrigin = view.frame.origin; view.layer.anchorPoint = anchorPoint; CGPoint newOrigin = view.frame.origin; CGPoint transition; transition.x = newOrigin.x - oldOrigin.x; transition.y = newOrigin.y - oldOrigin.y; view.center = CGPointMake (view.center.x - transition.x, view.center.y - transition.y); }
而Swift版本:
func setAnchorPoint(anchorPoint: CGPoint, view: UIView){ let oldOrigin = view.frame.origin view.layer.anchorPoint = anchorPoint let newOrigin = view.frame.origin let transition = CGPointMake (newOrigin.x - oldOrigin.x, newOrigin.y - oldOrigin.y) view.center = CGPointMake (view.center.x - transition.x, view.center.y - transition.y) }
对于那些需要它的人来说,这里是Magnus在Swift中的解决scheme:
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 }
这里是user945711的答案在OS X上为NSView进行了调整。除了没有.center
属性的NSView,NSView的框架不会改变(可能是因为默认情况下NSView没有带有CALayer),但是当anchorPoint是改变。
func setAnchorPoint(anchorPoint: NSPoint, view: NSView) { if view.layer == nil { return } let layer = view.layer! var 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) }
如果你改变了anchorPoint,它的位置也会改变,除非你的原点是零点CGPointZero
。
position.x == origin.x + anchorPoint.x; position.y == origin.y + anchorPoint.y;
编辑并查看故事板上的UIView的锚点(Swift 3)
这是一个备用解决scheme,允许您通过属性检查器更改锚点,并有另一个属性来查看锚点以进行确认。
创build新文件以包含在您的项目中
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 } }
添加视图到故事板并设置自定义类
现在为UIView设置新的锚点
打开“显示锚点”将显示一个红点,以便您可以更好地查看锚点的可视位置。 您可以随时closures它。
当在UIViews上规划转换时,这真的帮了我很大的忙。
对于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 }
为了扩大Magnus的伟大和彻底的答案,我创build了一个在子图层上工作的版本:
-(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; }