屏幕方向变化后,UIView的尺寸没有更新

12

如何使用Swift 3检测方向变化后的情况?

我需要在变化后检测以计算框架大小。

编辑

我问这个问题是因为我需要在方向改变时重新绘制视图,就像这个问题中所示:无法让背景渐变填充整个屏幕

我不知道如何实现被标记为正确答案的回答。

我尝试了另一个答案。

self.backgroundImageView.layer.sublayers?.first?.frame = self.view.bounds

但它没有起作用。

viewDidLoad() 中我有

let color1 =  UIColor(red: 225.0/255.0, green: 210.0/255.0, blue: 0.0/255.0, alpha: 1.0).cgColor
let color2 = UIColor(red: 255.0/255.0, green: 125.0/255.0, blue: 77.0/255.0, alpha: 1.0).cgColor

let gradientLayer = CAGradientLayer()
gradientLayer.colors = [color1, color2]
gradientLayer.locations = [ 0.0, 1.0]
gradientLayer.frame = self.view.bounds

self.view.layer.insertSublayer(gradientLayer, at: 0)

A. 你可以确保创建正确的视图层次结构,并尽量不破坏由iOS自动支持的通知链;或者 B. 你可以订阅 UIDeviceOrientationDidChangeNotification 并监听方向变化,在必要时更新你的自定义视图。 - holex
7个回答

33

上述被接受的答案返回过渡前的帧大小,因此您的视图没有更新。您需要在过渡完成后获取帧大小。

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {

        coordinator.animate(alongsideTransition: { (UIViewControllerTransitionCoordinatorContext) -> Void in

            let orient = UIApplication.shared.statusBarOrientation

            switch orient {

            case .portrait:

                print("Portrait")

            case .landscapeLeft,.landscapeRight :

                print("Landscape")

            default:

                print("Anything But Portrait")
            }

            }, completion: { (UIViewControllerTransitionCoordinatorContext) -> Void in
                //refresh view once rotation is completed not in will transition as it returns incorrect frame size.Refresh here           

        })
        super.viewWillTransition(to: size, with: coordinator)

    }

2
我尝试了很多方法,但是我找不到一个可以更新视图框架的解决方案。完成处理程序在视图框架之后执行的事实解决了这个问题,你的答案真的很有帮助。 - harmeet07
1
这是一个很棒的解决方案,如果你需要新的(旋转后)帧大小!非常感谢。我注意到的唯一一件事是,这个委托方法有时会被调用两次。因此,为了防止不必要地刷新视图两次,我存储旧的方向,只有在新的方向不同时才刷新视图。谢谢! - guido

7

添加此功能,即可检测方向变化:

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    if UIDevice.current.orientation.isLandscape {
        print("Landscape")
    } else if UIDevice.current.orientation.isPortrait {
        print("Portrait")
    }
}

谢谢!它可以工作,但我有另一个问题,这也是我首先提出这个问题的原因。我更新了我的问题。你能看一下吗? - user3847113
尝试在您的viewDidLoad方法结束时调用self.view.setNeedsLayout() - Rashwan L

6
为了获取屏幕方向变化的回调,您需要添加以下通知:

notification

NotificationCenter.default.addObserver(self, selector: #selector(ViewController.rotated), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil)

你需要实现这个方法。
func rotated() {
    if(UIDeviceOrientationIsLandscape(UIDevice.current.orientation))
    {
        print("landscape")
    }

    if(UIDeviceOrientationIsPortrait(UIDevice.current.orientation))
    {
        print("Portrait")
    }
}

1
太棒了!比起 viewWillTransition 要好得多,就像 viewDidTransition(但是它并不存在)。 - user924

3

这是我的解决方案,基于以下要求:

(1) 我的布局需要根据高度或宽度哪个更大来进行变化。 (基本上是竖屏或横屏,但今后呢?)

(2) 我的应用程序是通用的,因此我不能考虑与其相关的大小类或任何覆盖。

(3) 我的应用程序还具有照片编辑扩展功能,因此UIApplication不可用。(而且在这种类型的扩展中,像landscapeLeft和landscapeRight这样的方向是不起作用的)

注意:为了完整性,我添加了AutoLayout的结构。

UIViewController:

var p = [NSLayoutConstraint]()
var l = [NSLayoutConstraint]()
var initialOrientation = true
var isInPortrait = false

override func viewDidLoad() {
    super.viewDidLoad()
    // set up all constraints, including common, portrait and landscape
    setUpConstraints()  
}

override func viewWillLayoutSubviews() {
    super.viewWillLayoutSubviews()
    if initialOrientation {
        initialOrientation = false
        if view.frame.width > view.frame.height {
            isInPortrait = false
        } else {
            isInPortrait = true
        }
        orientationChanged()
    } else {
        if view.orientationHasChanged(&isInPortrait) {
            orientationChanged()
        }
    }
}

func orientationChanged() {
    // this was split out because of other app-specific logic
    view.setOrientation(p, l)
}

UIView:

extension UIView {

    public func orientationHasChanged(_ isInPortrait:inout Bool) -> Bool {
        // always check against isInPortrait to reduce unnecessary AutoLayout changes!
        if self.frame.width > self.frame.height {
            if isInPortrait {
                isInPortrait = false
                return true
            }
        } else {
            if !isInPortrait {
                isInPortrait = true
                return true
            }
        }
        return false
    }
    public func setOrientation(_ p:[NSLayoutConstraint], _ l:[NSLayoutConstraint]) {
        NSLayoutConstraint.deactivate(l)
        NSLayoutConstraint.deactivate(p)
        if self.bounds.width > self.bounds.height {
            NSLayoutConstraint.activate(l)
        } else {
            NSLayoutConstraint.activate(p)
        }
    }
}

0

试试这个

override func viewWillLayoutSubviews() {
    super.viewWillLayoutSubviews()
    if UIInterfaceOrientationIsLandscape(UIApplication.sharedApplication().statusBarOrientation) {

        print("Landscape mode called")

        if UI_USER_INTERFACE_IDIOM() == .Pad {
            print("Landscape mode in ipad");

        }
        else
        {
            print("Landscape mode in Iphone ")

        }
    } else {
        print("Portrait mode called")
        if UI_USER_INTERFACE_IDIOM() == .Pad {

            print("Portrait mode called in ipad")
        }
        else
        {
            print("Portrait mode called in iphone")
        }
    }
}
override func willRotateToInterfaceOrientation(toInterfaceOrientation:UIInterfaceOrientation, duration: NSTimeInterval) {
    print("willRotateToInterfaceOrientation method called");
    //Here you can invalidateLayout()
}

1
这不正确...请使用viewWillTransition。 - LC 웃
@Anish웃 这对我来说是有效的..你可以尝试一下这段代码 - Sanjeet Verma
2
它可以工作,但 viewWillTransition 只会在设备旋转时被调用,而 viewWillLayoutSubviews 可能会被调用多次。 - LC 웃
@Anish웃 你是对的,但你也可以使布局无效,谢谢你纠正我。 - Sanjeet Verma

0
override func willRotate(to toInterfaceOrientation: UIInterfaceOrientation, duration: TimeInterval) {

    self.sliding.setNeedsDisplay()

}

0

如果您正在使用此方法来获取 traitCollection 的更新值,请改用以下方法

override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
    print("Trait collection changes")

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接