【问题标题】:Center of subview after device orientation设备定向后子视图的中心
【发布时间】:2021-04-30 06:05:00
【问题描述】:

我在这里UIView Position After Device Orientation发布了一个类似的问题

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

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

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,但在设备立即从左侧横向旋转到右侧横向的情况下失败,即没有先从纵向经过。它也不能顺利运行)

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 一样,子视图中心和主视图左上角之间的距离在旋转到横向后保持不变。

【问题讨论】:

  • 您不使用自动布局/约束是否有原因?大小/特征更改无需计算或代码。
  • @DonMag 我尝试了以下方法,但无法正常工作: let margins = view.layoutMarginsGuide view.subviews[0].centerYAnchor.constraint(equalTo: margins.centerYAnchor).isActive = true view .subviews[0].leadingAnchor.constraint(equalTo: margins.leadingAnchor).isActive = true
  • 此外,我不确定将约束置于用户使用手势移动的子视图是否正确。
  • 有点混乱... 设备处于纵向,并以 100x100 居中视图开始。用户将视图拖到右下角。用户旋转设备。视图应该在哪里?在视图底部下方(即屏幕外)?
  • 还有...你是如何移动视图的?使用约束并更新其.constant 值以移动它们并保持自动布局的所有优点并不少见。

标签: ios swift uiview uiviewcontroller autolayout


【解决方案1】:

要定位您的子视图,请尝试使用 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
}

【讨论】:

    【解决方案2】:

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

    它会在视图的中心创建一个小的圆形蓝色“点”,以及一个 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
            }
            
        }
    
    }
    

    发布时:

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

    旋转设备:

    【讨论】:

    • DonMag 感谢您的回答。它完美地工作。你帮了我很多,我很感激。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-24
    • 1970-01-01
    相关资源
    最近更新 更多