设备方向后的子视图中心

Center of subview after device orientation

我在这里发过类似的问题UIView Position After Device Orientation

我正在设计一个具有单个 ViewController 和主视图子视图的应用程序。这个子视图是一张地图。最初它的中心等于主视图的中心(并且等于设备的中心)。这个子视图的位置可以使用手势改变,所以它没有任何布局约束。当设备的方向改变时,默认行为是子视图的中心以其与设备左上角的水平和垂直距离保持不变的方式移动。我试图改变这一点,以便保持不变的距离将是子视图中心和主视图中心之间的水平和垂直距离(在定向之后,它仍然等于设备的中心)。我尝试了以下方法:

第一种方法(它适用于 iphone,但不适用于 ipad,因为它具有针对两个方向的垂直和水平 class 的常规特征集合。)

var distanceOfCenters: CGPoint?
override func willTransition(to newCollection: UITraitCollection, with coordinator: UIViewControllerTransitionCoordinator)
{
    super.willTransition(to: newCollection, with: coordinator)
    distanceOfCenters = CGPoint(x: view.subviews[0].center.x-view.center.x, y: view.subviews[0].center.y-view.center.y)
}
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?)
{
    super.traitCollectionDidChange(previousTraitCollection)
    if let x = distanceOfCenters?.x, let y = distanceOfCenters?.y
    {
        view.subviews[0].center = CGPoint(x: view.center.x+x, y: view.center.y+y)
    }
}

第二个方法(它适用于 iphone 和 ipad,但在设备从左横向立即旋转到右横向的情况下失败,即没有首先从 protrait 传递。也运行不流畅)

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator)
{
    super.viewWillTransition(to: size, with: coordinator)
    view.subviews[0].center.x += view.center.y - view.center.x
    view.subviews[0].center.y += view.center.x - view.center.y
}

有什么实现方法吗?我觉得很奇怪,在应用程序中添加这么简单的功能是如此困难。

这是一些截图。黑点是主视图的中心。当设备旋转到横向时,它应该像屏幕截图 3 中那样,其中子视图中心和主视图中心之间的距离在旋转到横向后保持不变。默认情况如截图 2,旋转到横向后,子视图的中心与主视图左上角之间的距离保持不变。

要定位您的子视图,请尝试使用 viewWillLayoutSubviewsviewDidLayoutSubviews 例如:

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
        
    view.subviews[0].center.x += view.center.y - view.center.x
    view.subviews[0].center.y += view.center.x - view.center.y
}

这是一个使用约束并让自动布局在设备旋转时处理定位的基本示例。

它会在视图中心创建一个蓝色的小圆点,并在周围拖动一个 100x100 的红色方形视图 - 它是半透明的,因此我们可以透过它看到该点。

viewDidAppear() 上,我们将红色“dragView”的左上角设置在视图的中心(如果是蓝色“dotView”,也是中心:

class DragTestViewController: UIViewController {
    
    let dotView: UIView = {
        let v = UIView()
        v.translatesAutoresizingMaskIntoConstraints = false
        v.backgroundColor = .systemBlue
        return v
    }()
    
    let dragView: UIView = {
        let v = UIView()
        v.translatesAutoresizingMaskIntoConstraints = false
        v.backgroundColor = UIColor.systemRed.withAlphaComponent(0.75)
        return v
    }()
    
    // drag view's center constraints - created in viewDidLoad()
    var centerX: NSLayoutConstraint!
    var centerY: NSLayoutConstraint!

    // these are used by the pan gesture handler
    var currentCenterX: CGFloat = 0
    var currentCenterY: CGFloat = 0

    override func viewDidLoad() {
        super.viewDidLoad()

        view.addSubview(dotView)
        view.addSubview(dragView)
        
        // respect safe area
        let g = view.safeAreaLayoutGuide
        
        // create centerX and centerY constraints for dragView
        centerX = dragView.centerXAnchor.constraint(equalTo: g.centerXAnchor)
        centerY = dragView.centerYAnchor.constraint(equalTo: g.centerYAnchor)
        
        NSLayoutConstraint.activate([
            
            // put 8x8 dotView in center
            dotView.widthAnchor.constraint(equalToConstant: 8.0),
            dotView.heightAnchor.constraint(equalTo: dotView.widthAnchor),
            dotView.centerXAnchor.constraint(equalTo: g.centerXAnchor),
            dotView.centerYAnchor.constraint(equalTo: g.centerYAnchor),
            
            // dragView width & height 100x100
            dragView.widthAnchor.constraint(equalToConstant: 100.0),
            dragView.heightAnchor.constraint(equalTo: dragView.widthAnchor),
            
            // activate dragView's center anchors
            centerX,
            centerY
        ])
        
        let pan = UIPanGestureRecognizer(target: self, action: #selector(self.panGestureHandler(_:)))
        dragView.addGestureRecognizer(pan)

    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        
        // make dotView round
        dotView.layer.cornerRadius = dotView.bounds.width * 0.5
        
        // start with dragView's top-left corner at center of view
        centerX.constant = dragView.bounds.midX
        centerY.constant = dragView.bounds.midY
    }

    @objc func panGestureHandler(_ recognizer: UIPanGestureRecognizer){
        
        switch recognizer.state {
        case .began:
            // save the current center x and y constant value
            currentCenterX = centerX.constant
            currentCenterY = centerY.constant
            break
            
        case .changed:
            // update dragView's center x & y, based on pan motion
            let translation = recognizer.translation(in: self.view)
            centerX.constant = currentCenterX + translation.x
            centerY.constant = currentCenterY + translation.y
            break
            
        case .ended, .cancelled:
            // if you want to do something when pan ends
            break
            
        default:
            break
        }
        
    }

}

发布时:

将红色视图向上和向左拖动一点:

旋转设备: