代码之家  ›  专栏  ›  技术社区  ›  Kenny Winker

改变我的凯莱的锚定点移动视图

  •  124
  • Kenny Winker  · 技术社区  · 15 年前

    我想改变 anchorPoint ,但请将视图保留在同一位置。 我试过了 NSLog -ing self.layer.position self.center 无论锚定点如何变化,它们都保持不变。然而我的观点却在改变!

    有什么建议吗?

    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
    
    11 回复  |  直到 6 年前
        1
  •  133
  •   Brad Larson    9 年前

    这个 Layer Geometry and Transforms 核心动画编程指南的一节解释了Calayer的位置和锚定点属性之间的关系。基本上,层的位置是根据层的锚定点的位置来指定的。默认情况下,层的锚定点为(0.5,0.5),位于层的中心。设置图层位置时,将设置图层中心在其超级图层坐标系中的位置。

    因为位置相对于层的锚定点,所以在保持相同位置的同时更改该锚定点会移动层。为了防止这种移动,您需要调整层的位置来考虑新的锚定点。我这样做的一种方法是获取层的边界,将边界的宽度和高度乘以新旧锚定点的标准化值,取两个锚定点的差,并将该差应用于层的位置。

    您甚至可以通过使用 CGPointApplyAffineTransform() 使用uiview的cgaffinetTransform。

        2
  •  195
  •   dahiya_boy    6 年前

    我也有同样的问题。布拉德拉森的解决方案工作得很好,即使当视图旋转。这是他的解决方案翻译成代码。

    -(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;
    }
    

    以及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
    }
    

    斯威夫特4

    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
    }
    
        3
  •  43
  •   luk2302    6 年前

    解决这个问题的关键是使用frame属性,这是唯一一个奇怪的改变。

    斯威夫特2

    let oldFrame = self.frame
    self.layer.anchorPoint = CGPointMake(1, 1)
    self.frame = oldFrame
    

    斯威夫特3

    let oldFrame = self.frame
    self.layer.anchorPoint = CGPoint(x: 1, y: 1)
    self.frame = oldFrame
    

    然后我调整尺寸,从锚定点开始调整。 然后我必须恢复原来的锚定点;

    斯威夫特2

    let oldFrame = self.frame
    self.layer.anchorPoint = CGPointMake(0.5,0.5)
    self.frame = oldFrame
    

    斯威夫特3

    let oldFrame = self.frame
    self.layer.anchorPoint = CGPoint(x: 0.5, y: 0.5)
    self.frame = oldFrame
    

    编辑:如果视图旋转,则此值将变为薄片状,因为如果应用了CGaffinetTransform,则未定义“帧”属性。

        4
  •  26
  •   2cupsOfTech    10 年前

    对于我来说,当我开始将其与我对框架的理解进行比较时,理解 位置 锚定点 是最简单的。带有frame.origin=(20,30)的uiview意味着uiview从左起20点,从其父视图顶部起30点。此距离是从ui视图的哪个点计算的?它是从uiview的左上角计算的。

    在layer anchorpoint marks the point(in normalized form,即0 to 1)from where this distance is calculated so e.g.layer.position=(20,30)means that the layer anchorpoint is 20 points from left and 30 points from top of its parent layer.默认情况下,层锚定点为(0.5,0.5),因此距离计算点正好位于层的中心。下图将有助于澄清我的观点:

    anchorpoint also happens to be the point around which rotation will have in case you apply a transform to the layer.

    当我开始将它与我在uiview中对frame.origin的理解进行比较时最简单。带有frame.origin=(20,30)的uiview意味着uiview从左起20点,从其父视图顶部起30点。此距离是从ui视图的哪个点计算的?它是从uiview的左上角计算的。

    在层 锚点 标记计算此距离的点(标准化形式,即0到1),例如layer.position=(20,30)表示层 锚定点 是从左侧20点,从其父层顶部30点。默认情况下,层锚定点为(0.5,0.5),因此距离计算点正好位于层的中心。下图将有助于澄清我的观点:

    enter image description here

    锚定点 如果对图层应用变换,也会发生旋转。

        5
  •  15
  •   Fried Rice    6 年前

    有这么简单的解决办法。这是基于肯尼的回答。但是不要应用旧框架,而是使用它的原点和新的原点来计算过渡,然后将该过渡应用到中心。它也适用于旋转视图!这是代码,比其他解决方案简单得多:

    - (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 = CGPoint(x: newOrigin.x - oldOrigin.x, y: newOrigin.y - oldOrigin.y)
    
       view.center = CGPoint(x: view.center.x - transition.x, y: view.center.y - transition.y)
    }
    
        6
  •  9
  •   Corey Davis    10 年前

    对于那些需要它的人,这里是马格努斯在斯威夫特的解决方案:

    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
    }
    
        7
  •  5
  •   BigMountainStudio.com    8 年前

    在故事板上编辑并查看uiview的定位点(swift 3)

    这是一个备用解决方案,允许您通过属性检查器更改定位点,并具有另一个属性来查看定位点以进行确认。

    创建要包含在项目中的新文件

    导入uikit @可设计的 类uiViewAnchorPoint:uiView{ @IBinspectable var showanchorpoint:bool=false @IBinspectable var anchorpoint:cgpoint=cgpoint(x:0.5,y:0.5){ DIDSET { 设置锚定点(锚定点:锚定点) } } 覆盖func draw(rect:cgrect){ 如果Showanchorpoint{ 让anchorPointLayer=calayer()。 anchorPointLayer.backgroundcolor=uicolor.red.cgcolor anchorPointLayer.bounds=cgrct(x:0,y:0,width:6,height:6) 锚点层。转弯半径=3 let anchor=层.锚定点 让大小=layer.bounds.size anchorpointlayer.position=cgpoint(x:anchor.x*size.width,y:anchor.y*size.height) 层.添加子层(锚点层) } } func setanchorpoint(anchorpoint:cgpoint){ var newpoint=cgpoint(x:bounds.size.width*锚定点.x,y:bounds.size.height*锚定点.y) var oldpoint=cgpoint(x:bounds.size.width*layer.anchorpoint.x,y:bounds.size.height*layer.anchorpoint.y) newpoint=newpoint.applying(转换) oldpoint=oldpoint.applying(转换) var位置=层位置 位置.x-=oldpoint.x 位置.x+=新点.x 位置.Y-=旧点.Y 位置.Y+=新点.Y layer.position=位置 layer.anchorPoint=锚定点 } }

    将视图添加到情节提要并设置自定义类

    现在为uiview设置新的定位点

    打开“显示定位点”将显示一个红点,这样您可以更好地看到定位点的视觉位置。您可以稍后关闭它。

    当计划在uiview上转换时,这真的帮助了我。

    通过属性检查器更改定位点,并具有另一个属性来查看定位点以进行确认。

    创建要包含在项目中的新文件

    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
        }
    }
    

    将视图添加到情节提要并设置自定义类

    Custom Class

    现在为uiview设置新的定位点

    Demonstration

    打开“显示定位点”将显示一个红点,这样您可以更好地看到定位点的视觉位置。你可以以后再关掉它。

    这确实帮助了我在计划UIView上的转换。

        8
  •  5
  •   Shmidt    7 年前

    这里是 user945711's answer 已针对OS X上的nsview进行调整。此外,nsview没有 .center 属性,nsview的帧不会更改(可能是因为nsview在默认情况下不随calayer一起提供),但calayer帧的原点会在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)
    }
    
        9
  •  4
  •   Mahendra    8 年前

    如果改变锚定点,它的位置也会改变,除非原点是零点。 CGPointZero .

    position.x == origin.x + anchorPoint.x;
    position.y == origin.y + anchorPoint.y;
    
        10
  •  2
  •   AJ9    8 年前

    对于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
    }
    
        11
  •  0
  •   Charles Robertson    8 年前

    在马格努斯的伟大和彻底的答案的基础上,我创建了一个适用于子层的版本:

    -(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;
    }