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 overridesizeThatFitsto set the toolbar height, callingsizeToFitinsidelayoutSubviewstriggers unintended layout adjustments that mess with edge padding. - Hardcoded frames for custom views: Fixed
CGRectvalues 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
safeAreaInsetsinlayoutSubviewsif 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
相关产品推荐
相关产品推荐

