transparente quitar puedo por inicio home flotante desactivar control como centro boton barra activar abajo ios uinavigationbar ios11

quitar - Personalización de la altura de la barra de navegación de iOS 11



dock transparente en ios 11 (11)

Actualizado 07 ene 2018

Este código es compatible con XCode 9.2, iOS 11.2

Yo tuve el mismo problema. A continuación está mi solución. Supongo que el tamaño de la altura es 66.

Elige mi respuesta si te ayuda.

Crear CINavgationBar.swift

import UIKit @IBDesignable class CINavigationBar: UINavigationBar { //set NavigationBar''s height @IBInspectable var customHeight : CGFloat = 66 override func sizeThatFits(_ size: CGSize) -> CGSize { return CGSize(width: UIScreen.main.bounds.width, height: customHeight) } override func layoutSubviews() { super.layoutSubviews() print("It called") self.tintColor = .black self.backgroundColor = .red for subview in self.subviews { var stringFromClass = NSStringFromClass(subview.classForCoder) if stringFromClass.contains("UIBarBackground") { subview.frame = CGRect(x: 0, y: 0, width: self.frame.width, height: customHeight) subview.backgroundColor = .green subview.sizeToFit() } stringFromClass = NSStringFromClass(subview.classForCoder) //Can''t set height of the UINavigationBarContentView if stringFromClass.contains("UINavigationBarContentView") { //Set Center Y let centerY = (customHeight - subview.frame.height) / 2.0 subview.frame = CGRect(x: 0, y: centerY, width: self.frame.width, height: subview.frame.height) subview.backgroundColor = .yellow subview.sizeToFit() } } } }

Establecer guión gráfico

Establecer clase de barra de navegación personalizada

Agregar TestView + Establecer SafeArea

ViewController.swift

import UIKit class ViewController: UIViewController { var navbar : UINavigationBar! @IBOutlet weak var testView: UIView! override func viewDidLoad() { super.viewDidLoad() //update NavigationBar''s frame self.navigationController?.navigationBar.sizeToFit() print("NavigationBar Frame : /(String(describing: self.navigationController!.navigationBar.frame))") } //Hide Statusbar override var prefersStatusBarHidden: Bool { return true } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(false) //Important! if #available(iOS 11.0, *) { //Default NavigationBar Height is 44. Custom NavigationBar Height is 66. So We should set additionalSafeAreaInsets to 66-44 = 22 self.additionalSafeAreaInsets.top = 22 } } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } }

SecondViewController.swift

import UIKit class SecondViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. // Create BackButton var backButton: UIBarButtonItem! let backImage = imageFromText("Back", font: UIFont.systemFont(ofSize: 16), maxWidth: 1000, color:UIColor.white) backButton = UIBarButtonItem(image: backImage, style: UIBarButtonItemStyle.plain, target: self, action: #selector(SecondViewController.back(_:))) self.navigationItem.leftBarButtonItem = backButton self.navigationItem.leftBarButtonItem?.setBackgroundVerticalPositionAdjustment(-10, for: UIBarMetrics.default) } override var prefersStatusBarHidden: Bool { return true } @objc func back(_ sender: UITabBarItem){ self.navigationController?.popViewController(animated: true) } //Helper Function : Get String CGSize func sizeOfAttributeString(_ str: NSAttributedString, maxWidth: CGFloat) -> CGSize { let size = str.boundingRect(with: CGSize(width: maxWidth, height: 1000), options:(NSStringDrawingOptions.usesLineFragmentOrigin), context:nil).size return size } //Helper Function : Convert String to UIImage func imageFromText(_ text:NSString, font:UIFont, maxWidth:CGFloat, color:UIColor) -> UIImage { let paragraph = NSMutableParagraphStyle() paragraph.lineBreakMode = NSLineBreakMode.byWordWrapping paragraph.alignment = .center // potentially this can be an input param too, but i guess in most use cases we want center align let attributedString = NSAttributedString(string: text as String, attributes: [NSAttributedStringKey.font: font, NSAttributedStringKey.foregroundColor: color, NSAttributedStringKey.paragraphStyle:paragraph]) let size = sizeOfAttributeString(attributedString, maxWidth: maxWidth) UIGraphicsBeginImageContextWithOptions(size, false , 0.0) attributedString.draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height)) let image = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return image! } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } }

El amarillo es barbackgroundView. La opacidad negra es BarContentView.

Y eliminé el backgroundColor de BarContentView.

Eso es.

Ahora en iOS 11, el método sizeThatFits no se llama desde UINavigationBar subclases UINavigationBar . Cambiar el marco de UINavigationBar provoca fallas e inserciones incorrectas. Entonces, ¿alguna idea de cómo personalizar la altura de la barra de navegación ahora?


Agregado: el problema se resuelve en iOS 11 beta 6, por lo que el siguiente código no sirve de nada ^ _ ^

Respuesta original:

Resuelto con el siguiente código:

(Siempre quiero el navigationBar.height + statusBar.height == 64 si lo oculto de statusBar es verdadero o no)

@implementation P1AlwaysBigNavigationBar - (CGSize)sizeThatFits:(CGSize)size { CGSize sizeThatFit = [super sizeThatFits:size]; if ([UIApplication sharedApplication].isStatusBarHidden) { if (sizeThatFit.height < 64.f) { sizeThatFit.height = 64.f; } } return sizeThatFit; } - (void)setFrame:(CGRect)frame { if ([UIApplication sharedApplication].isStatusBarHidden) { frame.size.height = 64; } [super setFrame:frame]; } - (void)layoutSubviews { [super layoutSubviews]; if (![UIApplication sharedApplication].isStatusBarHidden) { return; } for (UIView *subview in self.subviews) { NSString* subViewClassName = NSStringFromClass([subview class]); if ([subViewClassName containsString:@"UIBarBackground"]) { subview.frame = self.bounds; }else if ([subViewClassName containsString:@"UINavigationBarContentView"]) { if (subview.height < 64) { subview.y = 64 - subview.height; }else { subview.y = 0; } } } } @end


Aunque está corregido en beta 4, parece que la imagen de fondo de la barra de navegación no se escala con la vista real (puede verificar esto mirando en el visor de jerarquía de vistas). Una solución alternativa por ahora es anular layoutSubviews en su UINavigationBar personalizada y luego usar este código:

- (void)layoutSubviews { [super layoutSubviews]; for (UIView *subview in self.subviews) { if ([NSStringFromClass([subview class]) containsString:@"BarBackground"]) { CGRect subViewFrame = subview.frame; subViewFrame.origin.y = -20; subViewFrame.size.height = CUSTOM_FIXED_HEIGHT+20; [subview setFrame: subViewFrame]; } } }

Si observa, el fondo de la barra, de hecho, tiene un desplazamiento de -20 para que aparezca detrás de la barra de estado, por lo que el cálculo anterior agrega eso.


Estaba duplicando la altura de mi barra de navegación para poder agregar una fila de iconos de estado sobre los controles de navegación predeterminados, subclasificando UINavigationBar y usando sizeThatFits para anular la altura. Afortunadamente, esto tiene el mismo efecto y es más simple, con menos efectos secundarios. Lo probé con iOS 8 a 11. Ponga esto en su controlador de vista:

- (void)viewDidLoad { [super viewDidLoad]; if (self.navigationController) { self.navigationItem.prompt = @" "; // this adds empty space on top } }


Esto es lo que yo uso. Funciona para contenido normal (44.0 px) si usa UISearchBar como título u otras vistas que modifican el tamaño del contenido de la barra, debe actualizar los valores en consecuencia. Use esto bajo su propio riesgo, ya que podría frenar en algún momento.

Esta es la barra de navegación con 90.0px de altura codificada, que funciona tanto en iOS 11 como en versiones anteriores. Es posible que UIBarButtonItem agregar algunas inserciones al UIBarButtonItem para que iOS 11 anterior UIBarButtonItem el mismo aspecto.

class NavBar: UINavigationBar { override init(frame: CGRect) { super.init(frame: frame) if #available(iOS 11, *) { translatesAutoresizingMaskIntoConstraints = false } } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func sizeThatFits(_ size: CGSize) -> CGSize { return CGSize(width: UIScreen.main.bounds.width, height: 70.0) } override func layoutSubviews() { super.layoutSubviews() guard #available(iOS 11, *) else { return } frame = CGRect(x: frame.origin.x, y: 0, width: frame.size.width, height: 90) if let parent = superview { parent.layoutIfNeeded() for view in parent.subviews { let stringFromClass = NSStringFromClass(view.classForCoder) if stringFromClass.contains("NavigationTransition") { view.frame = CGRect(x: view.frame.origin.x, y: frame.size.height - 64, width: view.frame.size.width, height: parent.bounds.size.height - frame.size.height + 4) } } } for subview in self.subviews { var stringFromClass = NSStringFromClass(subview.classForCoder) if stringFromClass.contains("BarBackground") { subview.frame = CGRect(x: 0, y: 0, width: self.frame.width, height: 90) subview.backgroundColor = .yellow } stringFromClass = NSStringFromClass(subview.classForCoder) if stringFromClass.contains("BarContent") { subview.frame = CGRect(x: subview.frame.origin.x, y: 40, width: subview.frame.width, height: subview.frame.height) } } } }

Y lo agrega a una subclase UINavigationController como esta:

class CustomBarNavigationViewController: UINavigationController { init() { super.init(navigationBarClass: NavBar.self, toolbarClass: nil) } override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) } override init(rootViewController: UIViewController) { super.init(navigationBarClass: NavBar.self, toolbarClass: nil) self.viewControllers = [rootViewController] } required public init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } }


Esto funciona bien para la barra de navegación normal. Si está utilizando LargeTitle, esto no funcionará bien porque el tamaño titleView no tendrá una altura fija de 44 puntos. Pero para la vista regular esto debería ser suficiente.

Como @frangulyan apple sugirió agregar una vista debajo de la barra de navegación y ocultar la línea delgada (imagen de sombra). Esto es lo que se me ocurrió a continuación. Agregué una uiview a titleView del elemento de navegación y luego agregué una imageView dentro de esa uiview. Eliminé la línea delgada (imagen de sombra). La uiview que agregué es del mismo color exacto que la barra de navegación . Agregué un uiLabel dentro de esa vista y eso es todo.

Aquí está la imagen en 3D. La vista extendida se encuentra detrás de usernameLabel debajo de navBar. Es gris y tiene una delgada línea debajo. Simplemente ancle su collectionView o lo que sea debajo de la delgada línea de separación.

Los 9 pasos se explican arriba de cada línea de código:

class ExtendedNavController: UIViewController { fileprivate let extendedView: UIView = { let view = UIView() view.translatesAutoresizingMaskIntoConstraints = false view.backgroundColor = .white return view }() fileprivate let separatorLine: UIView = { let view = UIView() view.translatesAutoresizingMaskIntoConstraints = false view.backgroundColor = .gray return view }() fileprivate let usernameLabel: UILabel = { let label = UILabel() label.translatesAutoresizingMaskIntoConstraints = false label.font = UIFont.systemFont(ofSize: 14) label.text = "username goes here" label.textAlignment = .center label.lineBreakMode = .byTruncatingTail label.numberOfLines = 1 return label }() fileprivate let myTitleView: UIView = { let view = UIView() view.backgroundColor = .white return view }() fileprivate let profileImageView: UIImageView = { let imageView = UIImageView() imageView.translatesAutoresizingMaskIntoConstraints = false imageView.clipsToBounds = true imageView.backgroundColor = .darkGray return imageView }() override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .white // 1. the navBar''s titleView has a height of 44, set myTitleView height and width both to 44 myTitleView.frame = CGRect(x: 0, y: 0, width: 44, height: 44) // 2. set myTitleView to the nav bar''s titleView navigationItem.titleView = myTitleView // 3. get rid of the thin line (shadow Image) underneath the navigationBar navigationController?.navigationBar.setValue(true, forKey: "hidesShadow") navigationController?.navigationBar.layoutIfNeeded() // 4. set the navigationBar''s tint color to the color you want navigationController?.navigationBar.barTintColor = UIColor(red: 249.0/255.0, green: 249.0/255.0, blue: 249.0/255.0, alpha: 1.0) // 5. set extendedView''s background color to the same exact color as the navBar''s background color extendedView.backgroundColor = UIColor(red: 249.0/255.0, green: 249.0/255.0, blue: 249.0/255.0, alpha: 1.0) // 6. set your imageView to get pinned inside the titleView setProfileImageViewAnchorsInsideMyTitleView() // 7. set the extendedView''s anchors directly underneath the navigation bar setExtendedViewAndSeparatorLineAnchors() // 8. set the usernameLabel''s anchors inside the extendedView setNameLabelAnchorsInsideTheExtendedView() } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(true) // 9. **Optional** If you want the shadow image to show on other view controllers when popping or pushing navigationController?.navigationBar.setBackgroundImage(nil, for: .default) navigationController?.navigationBar.setValue(false, forKey: "hidesShadow") navigationController?.navigationBar.layoutIfNeeded() } func setExtendedViewAndSeparatorLineAnchors() { view.addSubview(extendedView) view.addSubview(separatorLine) extendedView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true extendedView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true extendedView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true extendedView.heightAnchor.constraint(equalToConstant: 29.5).isActive = true separatorLine.topAnchor.constraint(equalTo: extendedView.bottomAnchor).isActive = true separatorLine.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true separatorLine.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true separatorLine.heightAnchor.constraint(equalToConstant: 0.5).isActive = true } func setProfileImageViewAnchorsInsideMyTitleView() { myTitleView.addSubview(profileImageView) profileImageView.topAnchor.constraint(equalTo: myTitleView.topAnchor).isActive = true profileImageView.centerXAnchor.constraint(equalTo: myTitleView.centerXAnchor).isActive = true profileImageView.widthAnchor.constraint(equalToConstant: 44).isActive = true profileImageView.heightAnchor.constraint(equalToConstant: 44).isActive = true // round the profileImageView profileImageView.layoutIfNeeded() profileImageView.layer.cornerRadius = profileImageView.frame.width / 2 } func setNameLabelAnchorsInsideTheExtendedView() { extendedView.addSubview(usernameLabel) usernameLabel.topAnchor.constraint(equalTo: extendedView.topAnchor).isActive = true usernameLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true usernameLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true } }


Junto con la anulación de -layoutSubviews y -setFrame: debe verificar la propiedad additionalSafereaInsets adicional SafereaInsets de UIViewController ( Documentación de Apple ) si no desea que la barra de navegación redimensionada oculte su contenido.


Según los desarrolladores de Apple (mira here , here y here ), no se admite cambiar la altura de la barra de navegación en iOS 11. Here sugieren hacer soluciones alternativas como tener una vista debajo de la barra de navegación (pero fuera de ella) y luego eliminar el borde de la barra de navegación. Como resultado, tendrá esto en el guión gráfico:

se ve así en el dispositivo:

Ahora puede hacer una solución alternativa que se sugirió en las otras respuestas: cree una subclase personalizada de UINavigationBar , agregue su subvista grande personalizada, anule sizeThatFits y layoutSubviews , luego establezca additionalSafeAreaInsets.top para el controlador superior de la navegación a la diferencia customHeight - 44px , pero la vista de barra seguirá siendo la predeterminada de 44 píxeles, aunque visualmente todo se verá perfecto. No intenté anular setFrame , tal vez funcione, sin embargo, como escribió el desarrollador de Apple en uno de los enlaces anteriores: "... y ninguno está [soportado] cambiando el marco de una barra de navegación que es propiedad de un UINavigationController (el el controlador de navegación pisoteará felizmente los cambios en el marco cada vez que lo considere conveniente ".

En mi caso, la solución anterior hizo que las vistas se vean así (vista de depuración para mostrar bordes):

Como puede ver, la apariencia visual es bastante buena, los additionalSafeAreaInsets SafeAreaInsets empujaron correctamente el contenido hacia abajo, la gran barra de navegación es visible, sin embargo, tengo un botón personalizado en esta barra y solo el área que se encuentra debajo de la barra de navegación estándar de 44 píxeles clicable (área verde en la imagen). Los toques por debajo de la altura de la barra de navegación estándar no alcanzan mi subvista personalizada, por lo que necesito cambiar el tamaño de la barra de navegación, lo que los desarrolladores de Apple dicen que no es compatible.


Simplificado con Swift 4.

class CustomNavigationBar : UINavigationBar { private let hiddenStatusBar: Bool // MARK: Init init(hiddenStatusBar: Bool = false) { self.hiddenStatusBar = hiddenStatusBar super.init(frame: .zero) } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } // MARK: Overrides override func layoutSubviews() { super.layoutSubviews() if #available(iOS 11.0, *) { for subview in self.subviews { let stringFromClass = NSStringFromClass(subview.classForCoder) if stringFromClass.contains("BarBackground") { subview.frame = self.bounds } else if stringFromClass.contains("BarContentView") { let statusBarHeight = self.hiddenStatusBar ? 0 : UIApplication.shared.statusBarFrame.height subview.frame.origin.y = statusBarHeight subview.frame.size.height = self.bounds.height - statusBarHeight } } } } }


en Xcode 9 Beta 6 todavía tengo el problema. La barra siempre tiene una altura de 44 píxeles y se coloca debajo de la barra de estado.

Para resolver eso, hice una subclase con el código @strangetimes (en Swift)

class NavigationBar: UINavigationBar { override func layoutSubviews() { super.layoutSubviews() for subview in self.subviews { var stringFromClass = NSStringFromClass(subview.classForCoder) print("--------- /(stringFromClass)") if stringFromClass.contains("BarBackground") { subview.frame.origin.y = -20 subview.frame.size.height = 64 } } } }

y coloco la barra más baja que la barra de estado

let newNavigationBar = NavigationBar(frame: CGRect(origin: CGPoint(x: 0, y: 20), size: CGSize(width: view.frame.width, height: 64) ) )


esto funciona para mi:

- (CGSize)sizeThatFits:(CGSize)size { CGSize sizeThatFit = [super sizeThatFits:size]; if ([UIApplication sharedApplication].isStatusBarHidden) { if (sizeThatFit.height < 64.f) { sizeThatFit.height = 64.f; } } return sizeThatFit; } - (void)setFrame:(CGRect)frame { if ([UIApplication sharedApplication].isStatusBarHidden) { frame.size.height = 64; } [super setFrame:frame]; } - (void)layoutSubviews { [super layoutSubviews]; for (UIView *subview in self.subviews) { if ([NSStringFromClass([subview class]) containsString:@"BarBackground"]) { CGRect subViewFrame = subview.frame; subViewFrame.origin.y = 0; subViewFrame.size.height = 64; [subview setFrame: subViewFrame]; } if ([NSStringFromClass([subview class]) containsString:@"BarContentView"]) { CGRect subViewFrame = subview.frame; subViewFrame.origin.y = 20; subViewFrame.size.height = 44; [subview setFrame: subViewFrame]; } } }