You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS11中设备旋转导致UIToolbar左右间距变大问题求助

Fix for UIToolbar Extra Padding After Rotation on iOS 11+

I’ve run into this exact padding glitch with UIToolbar on iOS 11 and later, and it almost always boils down to conflicting layout logic during rotation—especially combined with iOS 11’s updated safe area handling. Let’s break down the fixes for your implementation:

Key Issues in Your Current Code

  • Re-building toolbar items in layoutSubviews: This method fires constantly (including every rotation), so re-creating all bar button items each time disrupts the toolbar’s internal layout calculations. When the safe area shifts after rotation, this leads to unexpected padding.
  • Redundant sizeToFit() call: Since you already override sizeThatFits to set the toolbar height, calling sizeToFit inside layoutSubviews triggers unintended layout adjustments that mess with edge padding.
  • Hardcoded frames for custom views: Fixed CGRect values don’t adapt to safe area changes or dynamic device sizes, which amplifies padding issues during rotation.

Modified Code with Fixes

Here’s an updated version of ToolbarClass that resolves these problems:

class ToolbarClass: UIToolbar { 
    // Pre-create bar button items once (avoids re-building on every layout pass)
    private lazy var profileImg: UIBarButtonItem = createProfileButton()
    private lazy var logoImg: UIBarButtonItem = createLogoButton()
    private lazy var nameLabel: UIBarButtonItem = createNameLabel()
    private lazy var classesButton: UIBarButtonItem = createClassesButton()
    private lazy var settingsButton: UIBarButtonItem = createSettingsButton()
    
    // Custom toolbar height
    override func sizeThatFits(_ size: CGSize) -> CGSize { 
        var size = super.sizeThatFits(size) 
        size.height = 60 
        return size 
    } 
    
    // Initialize toolbar setup once
    override init(frame: CGRect) {
        super.init(frame: frame)
        configureToolbar()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        configureToolbar()
    }
    
    private func configureToolbar() {
        self.barStyle = .default
        
        // Spacers
        let flexibleSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil) 
        let smallFixedSpace: UIBarButtonItem = UIBarButtonItem(barButtonSystemItem: .fixedSpace, target: nil, action: nil) 
        smallFixedSpace.width = 1.0 
        let nameFixedSpace: UIBarButtonItem = UIBarButtonItem(barButtonSystemItem: .fixedSpace, target: nil, action: nil) 
        nameFixedSpace.width = 10 
        
        // Set toolbar items once
        self.setItems([profileImg, logoImg, nameFixedSpace, nameLabel, flexibleSpace, classesButton, smallFixedSpace, settingsButton], animated: false)
    }
    
    // Only handle layout updates here (no re-building items)
    override func layoutSubviews() { 
        super.layoutSubviews() 
        // Add dynamic layout adjustments here if needed (e.g., safe area tweaks)
    }
    
    // MARK: - Helper Methods for Custom Views
    private func createProfileButton() -> UIBarButtonItem {
        let profileImage = UIImage(named: "No-Profile") 
        let profileImageView = UIImageView(image: profileImage) 
        profileImageView.contentMode = .scaleAspectFit 
        profileImageView.clipsToBounds = true 
        profileImageView.layer.cornerRadius = 25 // Half of 50
        
        // Use AutoLayout instead of fixed frames
        profileImageView.translatesAutoresizingMaskIntoConstraints = false
        let profileView = UIView()
        profileView.addSubview(profileImageView)
        NSLayoutConstraint.activate([
            profileImageView.widthAnchor.constraint(equalToConstant: 50),
            profileImageView.heightAnchor.constraint(equalToConstant: 50),
            profileImageView.centerXAnchor.constraint(equalTo: profileView.centerXAnchor),
            profileImageView.centerYAnchor.constraint(equalTo: profileView.centerYAnchor)
        ])
        
        return UIBarButtonItem(customView: profileView)
    }
    
    private func createLogoButton() -> UIBarButtonItem {
        let logoImage = UIImage(named: "MBS-Logo") 
        let logoImageView = UIImageView(image: logoImage) 
        logoImageView.contentMode = .scaleAspectFit 
        
        logoImageView.translatesAutoresizingMaskIntoConstraints = false
        let logoView = UIView()
        logoView.clipsToBounds = false 
        logoView.layer.cornerRadius = 24 // Half of 48
        logoView.addSubview(logoImageView)
        
        NSLayoutConstraint.activate([
            logoImageView.widthAnchor.constraint(equalToConstant: 48),
            logoImageView.heightAnchor.constraint(equalToConstant: 54),
            logoImageView.centerYAnchor.constraint(equalTo: logoView.centerYAnchor),
            logoImageView.leadingAnchor.constraint(equalTo: logoView.leadingAnchor, constant: -46)
        ])
        
        return UIBarButtonItem(customView: logoView)
    }
    
    private func createNameLabel() -> UIBarButtonItem {
        let nameLbl = UILabel() 
        nameLbl.text = "Hi" 
        nameLbl.font = UIFont(name: "Roboto", size: 22) 
        nameLbl.textColor = .white 
        
        nameLbl.translatesAutoresizingMaskIntoConstraints = false
        let nameView = UIView()
        nameView.addSubview(nameLbl)
        
        NSLayoutConstraint.activate([
            nameLbl.widthAnchor.constraint(equalToConstant: 200),
            nameLbl.heightAnchor.constraint(equalToConstant: 60),
            nameLbl.centerXAnchor.constraint(equalTo: nameView.centerXAnchor),
            nameLbl.centerYAnchor.constraint(equalTo: nameView.centerYAnchor)
        ])
        
        return UIBarButtonItem(customView: nameView)
    }
    
    private func createClassesButton() -> UIBarButtonItem {
        let classesBtn = UIButton(type: .custom)
        classesBtn.setImage(UIImage(named: "Classes-Bar")?.withRenderingMode(.alwaysOriginal), for: .normal) 
        classesBtn.addTarget(self, action: #selector(classesPressed), for: .touchUpInside) 
        
        classesBtn.translatesAutoresizingMaskIntoConstraints = false
        let classesView = UIView()
        classesView.addSubview(classesBtn)
        
        NSLayoutConstraint.activate([
            classesBtn.widthAnchor.constraint(equalToConstant: 64),
            classesBtn.heightAnchor.constraint(equalToConstant: 60),
            classesBtn.centerXAnchor.constraint(equalTo: classesView.centerXAnchor),
            classesBtn.centerYAnchor.constraint(equalTo: classesView.centerYAnchor)
        ])
        
        return UIBarButtonItem(customView: classesView)
    }
    
    private func createSettingsButton() -> UIBarButtonItem {
        let settingsBtn = UIButton(type: .custom)
        settingsBtn.setImage(UIImage(named: "Settings-Bar")?.withRenderingMode(.alwaysOriginal), for: .normal) 
        settingsBtn.addTarget(self, action: #selector(settingsPressed), for: .touchUpInside) 
        
        settingsBtn.translatesAutoresizingMaskIntoConstraints = false
        let settingsView = UIView()
        settingsView.addSubview(settingsBtn)
        
        NSLayoutConstraint.activate([
            settingsBtn.widthAnchor.constraint(equalToConstant: 64),
            settingsBtn.heightAnchor.constraint(equalToConstant: 60),
            settingsBtn.centerXAnchor.constraint(equalTo: settingsView.centerXAnchor),
            settingsBtn.centerYAnchor.constraint(equalTo: settingsView.centerYAnchor)
        ])
        
        return UIBarButtonItem(customView: settingsView)
    }
    
    // MARK: - Button Actions
    @objc private func settingsPressed() {
        // Add your action logic here
    }
    
    @objc private func classesPressed() {
        // Add your action logic here
    }
}

Additional Tips

  • Safe Area Adaptation: For iPhone X and later, check safeAreaInsets in layoutSubviews if you need to adjust padding dynamically to avoid content being cut off.
  • Avoid Hardcoded Offsets: The negative X offset for the logo might cause issues on different devices. Consider replacing it with adaptive constraints based on device size or safe area.
  • Keep Autoresize Enabled: Leave the 'Autoresize Subview' option checked, but rely on AutoLayout for custom views to ensure consistent layout across rotations and devices.

内容的提问来源于stack exchange,提问作者ElBrm

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 06:49:26