IOS11旋转设备时UIToolbar左右间距

Posted

技术标签:

【中文标题】IOS11旋转设备时UIToolbar左右间距【英文标题】:UIToolbar left and right spacing when rotating device in IOS11 【发布时间】:2018-01-31 13:38:52 【问题描述】:

ios11 以来,UIToolbar 的填充有一个奇怪的问题。当设备旋转时,工具栏的左右填充变大(看下面的例子)。

设备在旋转之前是处于纵向还是横向模式并不重要。额外的间距仅在旋转后出现。我认为这是一个自动调整大小的问题。

旋转前查看调试器(间距正确): https://www.dropbox.com/s/1wigv1et88t1mvn/Schermafdruk%202018-01-31%2015.51.05.png?dl=0

旋转后查看调试器(间距错误): https://www.dropbox.com/s/9gnqi6hzv5czcnw/Schermafdruk%202018-01-31%2020.59.48.png?dl=0

示例:

https://www.dropbox.com/s/s7jbmbsuorump5e/spacing-toolbar.gif?dl=0

我正在使用工具栏类在工具栏中创建按钮。 在 xcode 界面中,选中了“Autoresize Subview”选项。

代码:

class ToolbarClass: UIToolbar 

    //Set height of toolbar
    override func sizeThatFits(_ size: CGSize) -> CGSize 
        var size = super.sizeThatFits(size)
        size.height = 60
        return size
    

    //Toolbar settings
    override func layoutSubviews() 
        super.layoutSubviews()

        //Default
        self.barStyle = UIBarStyle.default
        self.sizeToFit()

        //Buttons ios11+

        //Space
        let spaceButton = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
        let spaceBetween:UIBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.fixedSpace, target: nil, action: nil)
        spaceBetween.width = 1.0

        let nameSpace:UIBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.fixedSpace, target: nil, action: nil)
        nameSpace.width = 10

        //Logo
        let logoImage = UIImage(named: "MBS-Logo")
        let logoImageView = UIImageView(image: logoImage)
        logoImageView.frame = CGRect(x: -46, y: 0, width: 48, height: 54)
        logoImageView.contentMode = .scaleAspectFit
        let logoView = UIView(frame: CGRect(x: 0, y: 0, width: 48, height: 54))
        logoView.clipsToBounds = false
        logoView.layer.cornerRadius = logoView.frame.width / 2
        logoView.addSubview(logoImageView)
        let logoImg = UIBarButtonItem(customView: logoView)
        logoImg.customView = logoView

        //Profile
        let profileImage = UIImage(named: "No-Profile")
        let profileImageView = UIImageView(image: profileImage)
        profileImageView.frame = CGRect(x: 40, y: 0, width: 50, height: 50)
        profileImageView.contentMode = .scaleAspectFit
        profileImageView.clipsToBounds = true
        profileImageView.layer.cornerRadius = profileImageView.frame.width / 2
        let profileView = UIView(frame: CGRect(x: 0, y: 0, width: 50, height: 50))
        profileView.clipsToBounds = false
        profileView.addSubview(profileImageView)
        let profileImg = UIBarButtonItem(customView: profileView)
        profileImg.customView = profileView

        //NameLabel
        let nameLbl = UILabel()
        nameLbl.frame = CGRect(x: 0, y: 0, width: 200, height: 60)
        nameLbl.text = "Hi"
        nameLbl.font = UIFont(name: "Roboto", size: 22)
        nameLbl.textColor = UIColor.white
        let nameLabel = UIBarButtonItem()
        nameLabel.customView = nameLbl

        //Settings
        let settingsBtn = UIButton()
        settingsBtn.frame = CGRect(x: 0, y: 0, width: 64, height: 60)
        settingsBtn.setImage(UIImage(named: "Settings-Bar")?.withRenderingMode(.alwaysOriginal), for: .normal)
        settingsBtn.addTarget(self, action: #selector(self.settingsPressed), for: .touchUpInside)
        let settingsButton = UIBarButtonItem()
        settingsButton.customView = settingsBtn

        //Classes
        let classesBtn = UIButton()
        classesBtn.frame = CGRect(x: 0, y: 0, width: 64, height: 60)
        classesBtn.setImage(UIImage(named: "Classes-Bar")?.withRenderingMode(.alwaysOriginal), for: .normal)
        classesBtn.addTarget(self, action: #selector(self.classesPressed), for: .touchUpInside)
        let classesButton = UIBarButtonItem()
        classesButton.customView = classesBtn

        //Set buttons
        self.setItems([profileImg, logoImg, nameSpace, nameLabel, spaceButton, classesButton, spaceBetween, settingsButton], animated: false)

    


【问题讨论】:

“不是”???????? @matt 你是什么意思? 尝试使用视图调试器找出工具栏边缘和栏按钮项目及其自定义视图的真正位置。它们可能不是你认为的那样...... @matt 他们应该使用调试视图层次结构:dropbox.com/s/1wigv1et88t1mvn/… 因此,当您使用 View Debugger 对视图层次结构进行快照时,甚至不会出现问题????视图调试器向您显示 与您在运行的应用程序中实际看到的不同的布局????? 【参考方案1】:

首先layoutSubviews 不是添加所有项目的正确位置。例如,每次调用 device orientate layoutSubviews 时,都会再次创建所有项目。使用init?(coder:)init(frame:)

将代码移至init?(coder:)init(frame:) 后,您将看到左右边距(目前仅在您定向时才会出现)。这是UIToolBar 的实际行为,它会自动在两侧添加边距。

要删除该边距,只需在工具栏项的开头和结尾添加固定大小的负分隔符。

let negativeFizedSpace = UIBarButtonItem(barButtonSystemItem: .fixedSpace, target: nil, action: nil)
negativeFizedSpace.width = -20 // Spacing 20 for iPad and 16 for iPhone

class ToolbarClass: UIToolbar 

    override init(frame: CGRect) 
        super.init(frame: frame)
        commonInit()
    

    required init?(coder aDecoder: NSCoder) 
        super.init(coder: aDecoder)
        commonInit()
    

    private func commonInit() 

        //Space
        let spaceButton = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
        let spaceBetween:UIBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.fixedSpace, target: nil, action: nil)
        spaceBetween.width = 1.0

        let nameSpace:UIBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.fixedSpace, target: nil, action: nil)
        nameSpace.width = 10

        //Logo
        let logoImage = UIImage(named: "MBS-Logo")
        let logoImageView = UIImageView(image: logoImage)
        logoImageView.frame = CGRect(x: -46, y: 0, width: 48, height: 54)
        logoImageView.contentMode = .scaleAspectFit
        let logoView = UIView(frame: CGRect(x: 0, y: 0, width: 48, height: 54))
        logoView.clipsToBounds = false
        logoView.layer.cornerRadius = logoView.frame.width / 2
        logoView.addSubview(logoImageView)
        let logoImg = UIBarButtonItem(customView: logoView)
        logoImg.customView = logoView

        //Profile
        let profileImage = UIImage(named: "No-Profile")
        let profileImageView = UIImageView(image: profileImage)
        profileImageView.frame = CGRect(x: 40, y: 0, width: 50, height: 50)
        profileImageView.contentMode = .scaleAspectFit
        profileImageView.clipsToBounds = true
        profileImageView.layer.cornerRadius = profileImageView.frame.width / 2
        let profileView = UIView(frame: CGRect(x: 0, y: 0, width: 50, height: 50))
        profileView.clipsToBounds = false
        profileView.addSubview(profileImageView)
        let profileImg = UIBarButtonItem(customView: profileView)
        profileImg.customView = profileView

        //NameLabel
        let nameLbl = UILabel()
        nameLbl.frame = CGRect(x: 0, y: 0, width: 200, height: 60)
        nameLbl.text = "Hi"
        nameLbl.font = UIFont(name: "Roboto", size: 22)
        nameLbl.textColor = UIColor.white
        let nameLabel = UIBarButtonItem()
        nameLabel.customView = nameLbl

        //Settings
        let settingsBtn = UIButton()
        settingsBtn.frame = CGRect(x: 0, y: 0, width: 64, height: 60)
        settingsBtn.setImage(UIImage(named: "Settings-Bar")?.withRenderingMode(.alwaysOriginal), for: .normal)
        settingsBtn.addTarget(self, action: #selector(self.settingsPressed), for: .touchUpInside)
        let settingsButton = UIBarButtonItem()
        settingsButton.customView = settingsBtn

        //Classes
        let classesBtn = UIButton()
        classesBtn.frame = CGRect(x: 0, y: 0, width: 64, height: 60)
        classesBtn.setImage(UIImage(named: "Classes-Bar")?.withRenderingMode(.alwaysOriginal), for: .normal)
        classesBtn.addTarget(self, action: #selector(self.classesPressed), for: .touchUpInside)
        let classesButton = UIBarButtonItem()
        classesButton.customView = classesBtn


        let negativeFizedSpace = UIBarButtonItem(barButtonSystemItem: .fixedSpace, target: nil, action: nil)
        negativeFizedSpace.width = -20 // Spacing 20 for iPad and 16 for iPhone

        //Set buttons
        self.setItems([negativeFizedSpace, profileImg, logoImg, nameSpace, nameLabel, spaceButton, classesButton, spaceBetween, settingsButton, negativeFizedSpace], animated: false)
    

    //Set height of toolbar
    override func sizeThatFits(_ size: CGSize) -> CGSize 
        var size = super.sizeThatFits(size)
        size.height = 60
        return size
            


更新

如果使用导航控制器工具栏。另一种方法是创建一个UIViewController 扩展来添加通用工具栏项并在您的 ViewController 的 viewDidLoad 方法中调用它。

class ViewController: UIViewController 
    override func viewDidLoad() 
        super.viewDidLoad()
        addGeneralToolbarItems()
    


class ToolbarClass: UIToolbar 
    //Set height of toolbar
    override func sizeThatFits(_ size: CGSize) -> CGSize 
        var size = super.sizeThatFits(size)
        size.height = 60
        return size
    


extension UIViewController 
    func addGeneralToolbarItems()  
        //Space
        let spaceButton = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
        let spaceBetween:UIBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.fixedSpace, target: nil, action: nil)
        spaceBetween.width = 1.0

        let nameSpace:UIBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.fixedSpace, target: nil, action: nil)
        nameSpace.width = 10

        //Logo
        let logoImage = UIImage(named: "MBS-Logo")
        let logoImageView = UIImageView(image: logoImage)
        logoImageView.frame = CGRect(x: -46, y: 0, width: 48, height: 54)
        logoImageView.contentMode = .scaleAspectFit
        let logoView = UIView(frame: CGRect(x: 0, y: 0, width: 48, height: 54))
        logoView.clipsToBounds = false
        logoView.layer.cornerRadius = logoView.frame.width / 2
        logoView.addSubview(logoImageView)
        let logoImg = UIBarButtonItem(customView: logoView)
        logoImg.customView = logoView

        //Profile
        let profileImage = UIImage(named: "No-Profile")
        let profileImageView = UIImageView(image: profileImage)
        profileImageView.frame = CGRect(x: 40, y: 0, width: 50, height: 50)
        profileImageView.contentMode = .scaleAspectFit
        profileImageView.clipsToBounds = true
        profileImageView.layer.cornerRadius = profileImageView.frame.width / 2
        let profileView = UIView(frame: CGRect(x: 0, y: 0, width: 50, height: 50))
        profileView.clipsToBounds = false
        profileView.addSubview(profileImageView)
        let profileImg = UIBarButtonItem(customView: profileView)
        profileImg.customView = profileView

        //NameLabel
        let nameLbl = UILabel()
        nameLbl.frame = CGRect(x: 0, y: 0, width: 200, height: 60)
        nameLbl.text = "Hi"
        nameLbl.font = UIFont(name: "Roboto", size: 22)
        nameLbl.textColor = UIColor.white
        let nameLabel = UIBarButtonItem()
        nameLabel.customView = nameLbl

        //Settings
        let settingsBtn = UIButton()
        settingsBtn.frame = CGRect(x: 0, y: 0, width: 64, height: 60)
        settingsBtn.setImage(UIImage(named: "Settings-Bar")?.withRenderingMode(.alwaysOriginal), for: .normal)
        settingsBtn.addTarget(self, action: #selector(self.settingsPressed), for: .touchUpInside)
        let settingsButton = UIBarButtonItem()
        settingsButton.customView = settingsBtn

        //Classes
        let classesBtn = UIButton()
        classesBtn.frame = CGRect(x: 0, y: 0, width: 64, height: 60)
        classesBtn.setImage(UIImage(named: "Classes-Bar")?.withRenderingMode(.alwaysOriginal), for: .normal)
        classesBtn.addTarget(self, action: #selector(self.classesPressed), for: .touchUpInside)
        let classesButton = UIBarButtonItem()
        classesButton.customView = classesBtn


        let negativeFizedSpace = UIBarButtonItem(barButtonSystemItem: .fixedSpace, target: nil, action: nil)
        negativeFizedSpace.width = -20 // Spacing 20 for iPad and 16 for iPhone

        //Set buttons
        self.setToolbarItems([negativeFizedSpace, profileImg, logoImg, nameSpace, nameLabel, spaceButton, classesButton, spaceBetween, settingsButton, negativeFizedSpace], animated: false)

    

    @objc func settingsPressed() 

    

    @objc func classesPressed() 

    

【讨论】:

感谢您的回答,但是这样工具栏根本不显示任何内容。也没有错误。除此之外,您建议的负间隔从 iOS11 开始不起作用。链接:***.com/questions/45544961/… 我已经测试过了,它工作正常。您在故事板或笔尖中添加ToolbarClass?? 我正在故事板中添加课程:dropbox.com/s/t4mhixopcuw8x5k/… 是的,它正在被调用。还有标签和负间隔等。 您能以某种方式将您的 xcode 文件与示例一起发送给我吗?

以上是关于IOS11旋转设备时UIToolbar左右间距的主要内容,如果未能解决你的问题,请参考以下文章

UIToolbar 上的按钮间距

垂直 UIToolBar 及其 UIBarButtonItem

在较小的设备中覆盖填充 React Material UI

Xcode 6 Auto Layout - 所有设备的 UI 元素之间的恒定水平间距

UIToolbar 在屏幕顶部时无法正确旋转

旋转到横向时拉伸 UIToolbar 背景图像