class ProfileNavigationBar: UINavigationBar { var titleLabel: UILabel var backButton: UIBarButtonItem var friendsButton: FriendsButton? required init?(coder: NSCoder) { titleLabel = UILabel(frame: CGRect(x: 0, y: 40, width: 320, height: 40)) backButton = UIBarButtonItem.backButton(nil, action: nil) friendsButton = FriendsButton(frame: CGRect(x: 0, y: 0, width: 24, height: 24)) super.init(coder: coder) } override func awakeFromNib() { super.awakeFromNib() let item = UINavigationItem() item.titleView = titleLabel item.leftBarButtonItem = backButton item.hidesBackButton = true let friendsItem = UIBarButtonItem(customView: friendsButton!) item.rightBarButtonItems = [friendsItem] pushItem(item, animated: false) } }
FriendsButton在更改状态属性时自行调整大小的位置.
问题是当第一次加载视图时,它看起来像这样,后退按钮和FriendsButton就在导航栏的边缘:( .loading state)
但是,当我将FriendsButton状态更改为.add时,通常会显示如下:
我怎样才能解决这个问题?
这是FriendsButton的实现:
class FriendsButton: UIView { var state: FriendsButtonState { didSet { style(selected: state) } } var title: String = "" { didSet { set(title: title) } } var font = UIFont.boldSystemFont(ofSize: 11) private var imageView: UIImageView! private var button: UIButton! var loading: UIActivityIndicatorView! init(frame: CGRect, state: FriendsButtonState = .loading) { self.state = state super.init(frame: frame) backgroundColor = .yellow let plusSize = frame.size.height/2 let plusYValue = (frame.size.height-plusSize)/2 imageView = UIImageView(frame: CGRect(x: plusYValue*2, y: plusYValue, width: plusSize, height: plusSize)) imageView.contentMode = .scaleAspectFit addSubview(imageView) let titleSize = (title as NSString).size(attributes: [NSFontAttributeName : font]) button = UIButton(frame: CGRect(x: plusYValue*3.5 + plusSize, y: 0, width: titleSize.width, height: frame.size.height)) addSubview(button) loading = UIActivityIndicatorView(activityIndicatorStyle: .gray) loading.center = center addSubview(loading) style(selected: state) updateSize() } func addTarget(object: Any, selector: Selector) { button.addTarget(object, action: selector, for: .touchUpInside) } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } private func style(selected: FriendsButtonState) { configureBorder(state: selected) loading.startAnimating() loading.isHidden = state != .loading isHidden = false switch state { case .friends: backgroundColor = .black button.setTitleColor(.white, for: .normal) imageView.image = #imageLiteral(resourceName: "friends-tick") title = "Friends" // ... + all other cases } self.updateSize() } private func configureBorder(state: FriendsButtonState) { layer.borderColor = UIColor.black.cgColor layer.borderWidth = state == .loading ? 0 : 1 layer.cornerRadius = 5 } private func set(title: String) { let plusSize = frame.size.height/2 let plusYValue = (frame.size.height-plusSize)/2 let titleSize = (title as NSString).size(attributes: [NSFontAttributeName : font]) button.titleLabel?.font = font button.setTitle(title, for: .normal) button.frame = CGRect(x: plusYValue*3.5 + plusSize, y: 0, width: titleSize.width, height: frame.size.height) self.updateSize() } private func updateSize() { if state == .loading { frame.size.width = frame.size.width loading.center = CGPoint(x: frame.size.width/2, y: frame.size.height/2) loading.startAnimating() return } let plusSize = frame.size.height/2 let plusYValue = (frame.size.height-plusSize)/2 let titleSize = (title as NSString).size(attributes: [NSFontAttributeName : font]) let totalWidth = plusYValue*5.5 + plusSize + titleSize.width frame.size.width = totalWidth }
编辑:我已经尝试将按钮设置为最初的.add状态,但它仍然会出现在导航栏的最右侧,直到它被更改为其他状态.似乎按钮的第一个状态总是使导航栏将其所有子项移动到帧的边缘,直到它被更新.
编辑:我无法通过复制相关代码在另一个项目上重现问题,但这是我遇到的具体问题(如下图所示).首次导航到视图时,导航栏边缘和后退按钮之间的间隙不会保持(我设法在导航推送动画的中途获得屏幕截图).我现在的问题是,是什么导致这种情况?
你必须停止活动指示器,否则它不会隐藏自己:private func style(selected: FriendsButtonState) { configureBorder(state: selected) if (state == .loading) { loading.startAnimating() } else { loading.stopAnimating() } loading.isHidden = state != .loading
顺便说一句:你也可以跳过loading.isHidden = state!= .loading如果你将UIActivityIndicatorView配置成在它停止时隐藏自己:
init(frame: CGRect, state: FriendsButtonState = .loading) { // ... loading = UIActivityIndicatorView(activityIndicatorStyle: .gray) loading.center = center loading.hidesWhenStopped = true addSubview(loading) // ... }
要正确布置右侧导航栏按钮,您必须修改FriendsButton.updateSize:当处于状态.loading时 – 至少是第一次 – 您还必须更新框架.
private func updateSize() { if state == .loading { frame.size.width = frame.size.width loading.center = CGPoint(x: frame.size.width/2, y: frame.size.height/2) loading.startAnimating() // do not return here } let plusSize = frame.size.height/2 let plusYValue = (frame.size.height-plusSize)/2 let titleSize = (title as NSString).size(attributes: [NSFontAttributeName : font]) let totalWidth = plusYValue*5.5 + plusSize + titleSize.width frame.size.width = totalWidth }
我假设左侧按钮相同,但不幸的是你的代码不能在这里编译(在调用backButton = UIBarButtonItem.backButton(nil,action:nil)时在init?方法中得到一个错误,因为没有静态成员backButton on的UIBarButtonItem
现在,it works on my machine:
在应用程序启动后:
状态改为.friends后
国家又改回了.loading
一切都很好,没有变化等.如果这不适合您的项目,那么您可能还有其他方面没有与您的代码一起发布.