iOS Swift中为Tab添加底部边框不显示的问题求助
问题原因
你在viewDidLoad中调用addBorder时,segmentedControl的frame还没通过AutoLayout计算出正确值——此时它的frame是初始空值或默认尺寸,导致底部边框被放在错误位置(比如超出屏幕可见区域),所以看不到红色边框。
解决方案
下面提供两种可靠的修复方式:
方式一:在布局完成后添加边框
将添加边框的逻辑移到viewDidLayoutSubviews中,这个方法会在AutoLayout完成布局、view的frame确定后调用。同时要避免重复添加边框:
修改ViewController代码
import UIKit class ViewController: UIViewController { // 将segmentedControl改为类属性,方便在viewDidLayoutSubviews中访问 private let segmentedControl = UIStackView() override func viewDidLoad() { super.viewDidLoad() self.view.backgroundColor = .systemBackground self.navigationItem.titleView = UIImageView( image: UIImage(named: "Twitter")!.resize(25, 25) ) let leftBarImage = UIImageView( image: UIImage(named: "Profile")!.resize(35, 35) ) leftBarImage.layer.borderWidth = 1 leftBarImage.layer.borderColor = UIColor.systemGray4.cgColor leftBarImage.layer.cornerRadius = leftBarImage.frame.width / 2 leftBarImage.clipsToBounds = true self.navigationItem.leftBarButtonItem = UIBarButtonItem( customView: leftBarImage ) segmentedControl.translatesAutoresizingMaskIntoConstraints = false segmentedControl.axis = .horizontal segmentedControl.alignment = .center segmentedControl.distribution = .fillEqually segmentedControl.backgroundColor = .green for menuLabelText in ["For you", "Following"] { let menuLabel = UILabel() menuLabel.text = menuLabelText menuLabel.textAlignment = .center menuLabel.font = UIFont.boldSystemFont(ofSize: 16) segmentedControl.addArrangedSubview(menuLabel) } self.view.addSubview(segmentedControl) NSLayoutConstraint.activate([ segmentedControl.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor), segmentedControl.widthAnchor.constraint(equalTo: view.safeAreaLayoutGuide.widthAnchor) ]) } override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() // 先移除已存在的底部边框,避免重复添加 segmentedControl.layer.sublayers?.forEach { layer in if layer.name == "BottomBorder" { layer.removeFromSuperlayer() } } // 添加底部边框 segmentedControl.addBorder(for: .Bottom, color: UIColor.red.cgColor, thickness: 20) } }
修改UIView扩展(给边框加标识)
import UIKit extension UIView { enum BorderSide { case Left, Right, Top, Bottom } func addBorder(for side: BorderSide, color: CGColor, thickness: CGFloat) { let border = CALayer() border.backgroundColor = color border.name = "BottomBorder" // 添加标识,方便后续移除 switch side { case .Left: border.frame = CGRect( x: frame.minX, y: frame.minY, width: thickness, height: frame.height ) case .Right: border.frame = CGRect( x: frame.maxX, y: frame.minY, width: thickness, height: frame.height ) case .Top: border.frame = CGRect( x: frame.minX, y: frame.minY, width: frame.width, height: thickness ) case .Bottom: border.frame = CGRect( x: frame.minX, y: frame.maxY, width: frame.width, height: thickness ) } layer.addSublayer(border) } }
方式二:用AutoLayout创建边框(更推荐)
放弃依赖frame的CALayer方式,改用UIView+AutoLayout实现边框,这样边框会自动跟随view的布局变化,无需担心frame问题:
重写UIView扩展
import UIKit extension UIView { enum BorderSide { case left, right, top, bottom } func addBorder(for side: BorderSide, color: UIColor, thickness: CGFloat) { let borderView = UIView() borderView.backgroundColor = color borderView.translatesAutoresizingMaskIntoConstraints = false addSubview(borderView) let constraints: [NSLayoutConstraint] switch side { case .left: constraints = [ borderView.leadingAnchor.constraint(equalTo: leadingAnchor), borderView.topAnchor.constraint(equalTo: topAnchor), borderView.bottomAnchor.constraint(equalTo: bottomAnchor), borderView.widthAnchor.constraint(equalToConstant: thickness) ] case .right: constraints = [ borderView.trailingAnchor.constraint(equalTo: trailingAnchor), borderView.topAnchor.constraint(equalTo: topAnchor), borderView.bottomAnchor.constraint(equalTo: bottomAnchor), borderView.widthAnchor.constraint(equalToConstant: thickness) ] case .top: constraints = [ borderView.leadingAnchor.constraint(equalTo: leadingAnchor), borderView.trailingAnchor.constraint(equalTo: trailingAnchor), borderView.topAnchor.constraint(equalTo: topAnchor), borderView.heightAnchor.constraint(equalToConstant: thickness) ] case .bottom: constraints = [ borderView.leadingAnchor.constraint(equalTo: leadingAnchor), borderView.trailingAnchor.constraint(equalTo: trailingAnchor), borderView.bottomAnchor.constraint(equalTo: bottomAnchor), borderView.heightAnchor.constraint(equalToConstant: thickness) ] } NSLayoutConstraint.activate(constraints) } }
修改ViewController中的调用
在viewDidLoad中直接调用即可,无需移到viewDidLayoutSubviews:
segmentedControl.addBorder(for: .bottom, color: .red, thickness: 20)
补充说明
AutoLayout的布局计算流程是:viewDidLoad → viewWillAppear → 布局计算 → viewDidLayoutSubviews。所以在viewDidLoad阶段,所有用AutoLayout约束的view的frame都还未确定,此时基于frame的操作都会出错。
内容的提问来源于stack exchange,提问作者Axel
相关产品推荐
相关产品推荐

