我正在使用iOS 11的大标题导航栏,但是当我添加一个条形按钮项时,它看起来很奇怪,位于与原始标题导航栏相同的位置。我想在标题很大时向下移动条形按钮项目,并在导航栏不再大时将其移回原始位置。这样做的最佳方式是什么?
这是显示条形按钮项目的奇怪位置的图像
我可以使用viewWillLayoutSubviews()动态获取导航栏高度,但我无法使用setTitlePositionAdjustment
更改小节按钮项的位置override func viewWillLayoutSubviews() {
guard let navbarHeight = self.navigationController?.navigationBar.frame.height else{ return }
}
答案 0 :(得分:5)
为了解决我自己的问题,我只添加了一个按钮作为导航栏的子视图,并将右侧和底部约束设置为导航栏。现在,当导航栏改变大小时,该按钮将上下移动。但是,这需要在您从此视图控制器显示segue的任何视图控制器中删除该按钮。因此,我在按钮上添加了1的标记,并将其从其他视图控制器的superview中删除。这是解决它的最简单方法,我发现它是最简单的方法。
设置右键:
func setupNavBar() {
self.title = "Home"
self.navigationController?.navigationBar.prefersLargeTitles = true
self.navigationController?.navigationBar.isTranslucent = false
let searchController = UISearchController(searchResultsController: nil)
self.navigationItem.searchController = searchController
let rightButton = UIButton()
rightButton.setTitle("Right Button", for: .normal)
rightButton.setTitleColor(.purple, for: .normal)
rightButton.addTarget(self, action: #selector(rightButtonTapped(_:)), for: .touchUpInside)
navigationController?.navigationBar.addSubview(rightButton)
rightButton.tag = 1
rightButton.frame = CGRect(x: self.view.frame.width, y: 0, width: 120, height: 20)
let targetView = self.navigationController?.navigationBar
let trailingContraint = NSLayoutConstraint(item: rightButton, attribute:
.trailingMargin, relatedBy: .equal, toItem: targetView,
attribute: .trailingMargin, multiplier: 1.0, constant: -16)
let bottomConstraint = NSLayoutConstraint(item: rightButton, attribute: .bottom, relatedBy: .equal,
toItem: targetView, attribute: .bottom, multiplier: 1.0, constant: -6)
rightButton.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([trailingContraint, bottomConstraint])
}
要从任何show segued视图控制器中删除它:
func removeRightButton(){
guard let subviews = self.navigationController?.navigationBar.subviews else{return}
for view in subviews{
if view.tag != 0{
view.removeFromSuperview()
}
}
}
在viewWillAppear函数
中调用这两个函数答案 1 :(得分:3)
您要做的是设置BarButtonItem
的标题位置调整。将以下行添加到viewWillAppear
func。使用vertical
和horizontal
值进行游戏,以获得您喜欢的layout
。
navigationItem.rightBarButtonItem?.setTitlePositionAdjustment(.init(horizontal: 10, vertical: 20), for: UIBarMetrics.default)
https://developer.apple.com/documentation/uikit/uibarbuttonitem/1617149-settitlepositionadjustment
答案 2 :(得分:1)
好的方法是你可以调整导航标题,如果它的大,那么你的酒吧 按钮将自动调整。这是代码。还有iOS邮件 应用程序做同样的事情供你参考。
func adjustsTitle() {
guard let font = UIFont(name: "Helvetica-Medium", size: 16) else { return }
let label = UILabel(frame: CGRect(x: 0, y: 0, width: 100, height: 20))
label.textColor = UIColor.black
label.textAlignment = .center
label.text = navigationItem.title
label.adjustsFontSizeToFitWidth = true
navigationItem.titleView = label
}
更新了答案 如果要调整标题下方的按钮(如果它增长),那么在这种情况下,您需要在导航栏上加载自定义视图。
//Hide back button. Since you are going to have custom button
navigationItem.hidesBackButton = true
//Increase the height based on your view intrinsic content size
navigationController?.navigationBar.frame.size.height = 100
guard let yourCustomView = UINib(nibName: "yourCustomXib", bundle: nil).instantiate(withOwner: nil, options: nil).first as? YourCustomView else {
fatalError("Missing yourCustomXib")
}
navigationController?.navigationBar.addSubview(yourCustomView)
答案 3 :(得分:0)
我进行了一些挖掘,最终想到了与Messages应用程序中相同的行为(这意味着该按钮位于navigationBar下方,而不是上方)。
唯一缺少的部分是当UIBarButtonItem
出现时发生的动画/模糊效果。
警告:我当前的解决方案是使用私有类(名为_UINavigationBarLargeTitleView
),因此,Apple可能会拒绝您的应用……
// Make sure you have a `navigationBar`
guard let navigationBar = navigationController?.navigationBar else {
return
}
// Make sure you get the correct class from the string, the class itself is not exposed…
guard let UINavigationBarLargeTitleView = NSClassFromString("_UINavigationBarLargeTitleView") else {
return
}
// Then, you need to find the subview of type `_UINavigationBarLargeTitleView` :
navigationBar.subviews.forEach { subview in
if subview.isKind(of: UINavigationBarLargeTitleView.self) {
// If you have it, add whatever button you want (some example below)
subview.addSubview(largeTitleViewRightBarButton)
// Constrain it as you want
NSLayoutConstraint.activate([
largeTitleViewRightBarButton.bottomAnchor.constraint(equalTo: subview.bottomAnchor, constant: -10),
largeTitleViewRightBarButton.trailingAnchor.constraint(
equalTo: subview.trailingAnchor,
constant: -view.directionalLayoutMargins.trailing
)
])
}
}
// Finally, the magic happens with one scrollView delegate method :
override func scrollViewDidScroll(_ scrollView: UIScrollView) {
if scrollView.contentOffset.y >= -103 { // Moving up
navigationItem.rightBarButtonItem = rightBarButtonItem
} else { // Moving down
navigationItem.rightBarButtonItem = nil
}
}
这是我制作按钮的方式:
private(set) lazy var image: UIImage? = {
let config = UIImage.SymbolConfiguration(pointSize: 28, weight: .semibold, scale: .default)
let image = UIImage(systemName: "magnifyingglass.circle.fill", withConfiguration: config)
return image
}()
private(set) lazy var largeTitleViewRightBarButton: UIButton = {
let button = UIButton(type: .custom)
button.translatesAutoresizingMaskIntoConstraints = false
button.imageView?.tintColor = R.color.appDodgerBlue()
button.setImage(image, for: .normal)
button.addTarget(presenter, action: #selector(presenter.onSearchRequested), for: .touchUpInside)
return button
}()
private(set) lazy var rightBarButtonItem: UIBarButtonItem = {
let barButtonItem = UIBarButtonItem(
image: image,
style: .plain,
target: presenter,
action: #selector(presenter.onSearchRequested)
)
return barButtonItem
}()
答案 4 :(得分:0)
如果有人仍在寻找如何在SwiftUI中执行此操作。我做了一个package named NavigationBarLargeTitleItems来解决这个问题。它模仿您在AppStore和Messages-app中看到的行为。
在此示例中,您将看到一个配置文件图标,但您也可以使用诸如“创建配方”按钮之类的文本。如果您希望在滚动时将其显示为标准导航栏项目,则需要使用GeometryReader。如果您想举个例子,请告诉我。
请注意,要实现此行为,我们需要添加到“ _UINavigationBarLargeTitleView”(这是一个私有类),因此在提交到App Store时可能会拒绝您的应用。
对于那些不喜欢链接或只想复制/粘贴的人,我还将在此处包括完整的相关源代码。
@app.route('/', methods=['POST', 'GET'])
def calc():
if request.method == 'POST':
if request.form['btn'] == 'calculate':
t = int(request.form.get('t'))
v = int(request.form.get('v'))
calc = t*v
else:
calc = ''
return render_template('wind.html', title='Chill Calc', calc=calc)
return render_template('wind.html', title='Chill Calc')
// Copyright © 2020 Mark van Wijnen
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the “Software”), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
import SwiftUI
public extension View {
func navigationBarLargeTitleItems<L>(trailing: L) -> some View where L : View {
overlay(NavigationBarLargeTitleItems(trailing: trailing).frame(width: 0, height: 0))
}
}
fileprivate struct NavigationBarLargeTitleItems<L : View>: UIViewControllerRepresentable {
typealias UIViewControllerType = Wrapper
private let trailingItems: L
init(trailing: L) {
self.trailingItems = trailing
}
func makeUIViewController(context: Context) -> Wrapper {
Wrapper(representable: self)
}
func updateUIViewController(_ uiViewController: Wrapper, context: Context) {
}
class Wrapper: UIViewController {
private let representable: NavigationBarLargeTitleItems?
init(representable: NavigationBarLargeTitleItems) {
self.representable = representable
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
self.representable = nil
super.init(coder: coder)
}
override func viewWillAppear(_ animated: Bool) {
guard let representable = self.representable else { return }
guard let navigationBar = self.navigationController?.navigationBar else { return }
guard let UINavigationBarLargeTitleView = NSClassFromString("_UINavigationBarLargeTitleView") else { return }
navigationBar.subviews.forEach { subview in
if subview.isKind(of: UINavigationBarLargeTitleView.self) {
let controller = UIHostingController(rootView: representable.trailingItems)
controller.view.translatesAutoresizingMaskIntoConstraints = false
subview.addSubview(controller.view)
NSLayoutConstraint.activate([
controller.view.bottomAnchor.constraint(
equalTo: subview.bottomAnchor,
constant: -15
),
controller.view.trailingAnchor.constraint(
equalTo: subview.trailingAnchor,
constant: -view.directionalLayoutMargins.trailing
)
])
}
}
}
}
}