【问题标题】:How to make the uiview not move after setting its layer's anchorPoint under Autolayout自动布局下设置图层的锚点后如何使uiview不动
【发布时间】:2021-05-07 06:36:03
【问题描述】:

我有一个需求,需要更改 UIView 图层的锚点,但是更改锚点后视图无法移动。 我知道当视图由 frame(CGRect:...) 定义时是可能的。像这样:

let width = SCREEN_WIDTH - 40
let view2 = UIView(frame: CGRect(x: 20, y: 300, width: width, height: 200))
view2.backgroundColor = .blue
self.view.addSubview(view2)
let oldFrame2 = view2.frame
view2.layer.anchorPoint = CGPoint(x: 0, y: 0.5)
view2.frame = oldFrame2

这行得通。

但是我的视图是由 Autolayout 定义的,我尝试了上面代码的解决方案,但它不起作用。代码:

let view1 = UIView()
view1.backgroundColor = .orange
self.view.addSubview(view1)
view1.snp.makeConstraints { (maker) in
     maker.top.equalToSuperview().offset(50)
     maker.leading.equalToSuperview().offset(20)
     maker.trailing.equalToSuperview().offset(-20)
     maker.height.equalTo(200)
}
let oldFrame1 = view1.frame
view1.layer.anchorPoint = CGPoint(x: 0, y: 0.5)
view1.frame = oldFrame1

结果是:橙色view1被移动了,改变anchorPoint后应该和蓝色view2一样。

那么谁能给我一些建议?

------------------更新答案--------------- --------------

正如@DonMag 的回答,我们可以通过在使用自动布局时更新视图而非框架的约束来实现此要求。这是 SnapKit 的代码:

let view1 = UIView()
view1.backgroundColor = .orange
view1.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(view1)
view1.snp.makeConstraints { (maker) in
    maker.top.equalToSuperview().offset(100)
    maker.leading.equalToSuperview().offset(20)
    maker.trailing.equalToSuperview().offset(-20)
    maker.height.equalTo(200)
}
        
// important!!!
view1.layoutIfNeeded()

let oldFrame1 = view1.frame
view1.layer.anchorPoint = CGPoint(x: 0, y: 0.5)

// update constraints by updateConstraints function
// if you use @IBOutlet NSLayoutConstraint from xib,
// you can also just set xxx.constant = yyy to update the constraints.
view1.snp.updateConstraints { (maker) in
    let subOffset = oldFrame1.width * 0.5
    maker.leading.equalToSuperview().offset(20 - subOffset)
    maker.trailing.equalToSuperview().offset(-20 - subOffset)
}

let width = SCREEN_WIDTH - 40
let view2 = UIView(frame: CGRect(x: 20, y: 300, width: width, height: 200))
view2.backgroundColor = .blue
self.view.addSubview(view2)
let oldFrame2 = view2.frame
view2.layer.anchorPoint = CGPoint(x: 0, y: 0.5)
view2.frame = oldFrame2

另一种解决方案是通过设置translatesAutoresizingMaskIntoConstraints = true 将自动布局视图更改为框架,如下所示:

let width = SCREEN_WIDTH - 40
let view1 = UIView()
view1.backgroundColor = .orange

self.view.addSubview(view1)
// Autolayout
view1.snp.makeConstraints { (maker) in
    maker.top.equalToSuperview().offset(100)
    maker.leading.equalToSuperview().offset(20)
    maker.trailing.equalToSuperview().offset(-20)
    maker.height.equalTo(200)
}

// change autolayout to frame
view1.translatesAutoresizingMaskIntoConstraints = true
view1.frame = CGRect(x: 20, y: 100, width: width, height: 200)
let oldFrame1 = view1.frame
view1.layer.anchorPoint = CGPoint(x: 0, y: 0.5)
view1.frame = oldFrame1

let view2 = UIView(frame: CGRect(x: 20, y: 300, width: width, height: 200))
view2.backgroundColor = .blue
self.view.addSubview(view2)
let oldFrame2 = view2.frame
view2.layer.anchorPoint = CGPoint(x: 0, y: 0.5)
view2.frame = oldFrame2

【问题讨论】:

  • 评论此行并检查view1.layer.anchorPoint = CGPoint(x: 0, y: 0.5)
  • 这一行是我需要更改anchorPoint of view...所以我不能评论它...我只想更改anchorPoint 并且视图保持原点位置。你有什么解决办法吗?
  • 你也设置了这样的锚点view1.layer.anchorPoint = CGPoint(x: 0, y: self.view.frame.width/2)
  • @RB's 不,anchorPoint 的值是从 0 到 1,它是边界大小的比率...我这里需要 0.5。不过还是谢谢你们。

标签: swift autolayout frame anchorpoint


【解决方案1】:

首先,当使用自动布局/约束时,直接设置视图的.frame 不会得到想要的结果。一旦自动布局更新 UI,就会重新应用约束。

当您更改.anchorPoint 时,您会更改视图的几何形状。因此,您最好使用.frame 而不是自动布局。

如果您确实需要/想要使用自动布局,则需要更新约束的 .constant 值以考虑几何变化。

我不知道如何使用 SnapKit 做到这一点,但这里有一个使用“标准”约束语法的示例。

  • 声明前导和尾随约束变量
  • 分配和激活约束
  • 告诉自动布局计算框架
  • 更改锚点
  • 更新前导和尾随约束常量以反映几何变化

注意:这只是示例代码!:

class ViewController: UIViewController {
    
    // these will have their .constant values changed
    //  to account for layer.anchorPoint change
    var leadingConstraint: NSLayoutConstraint!
    var trailingConstraint: NSLayoutConstraint!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // NOT using auto-layout constraints
        let width = view.frame.width - 40
        let view2 = UIView(frame: CGRect(x: 20, y: 300, width: width, height: 200))
        view2.backgroundColor = .blue
        self.view.addSubview(view2)
        let oldFrame2 = view2.frame
        view2.layer.anchorPoint = CGPoint(x: 0, y: 0.5)
        view2.frame = oldFrame2
        
        // USING auto-layout constraints
        let view1 = UIView()
        view1.backgroundColor = .orange
        view1.translatesAutoresizingMaskIntoConstraints = false
        self.view.addSubview(view1)

        // create leading and trailing constraints
        leadingConstraint = view1.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20.0)
        trailingConstraint = view1.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20.0)
        
        // activate constraints
        NSLayoutConstraint.activate([
            view1.topAnchor.constraint(equalTo: view.topAnchor, constant: 80.0),
            view1.heightAnchor.constraint(equalToConstant: 200.0),
            leadingConstraint,
            trailingConstraint,
        ])

        // auto-layout has not run yet, so force it to layout
        //  the view frame
        view1.layoutIfNeeded()
        
        // get the auto-layout generated frame
        let oldFrame1 = view1.frame
        
        // change the anchorPoint
        view1.layer.anchorPoint = CGPoint(x: 0, y: 0.5)
        
        // we've move the X anchorPoint from 0.5 to 0.0, so
        //  we need to adjust the leading and trailing constants
        //  by 0.5 * the frame width
        leadingConstraint.constant -= oldFrame1.width * 0.5
        trailingConstraint.constant -= oldFrame1.width * 0.5

    }
    
}

结果:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-06-16
    • 2019-06-05
    • 1970-01-01
    • 2013-04-15
    • 1970-01-01
    • 2012-10-08
    • 2015-11-15
    • 2018-01-02
    相关资源
    最近更新 更多