Tengo mi UISearchBar
ser parte de la barra de navegación como:
let searchBar = UISearchBar()
//some more configuration to the search bar
.....
navigationItem.titleView = searchBar
Después de actualizar a iOS 11
algo extraño sucedió en la barra de búsqueda en mi aplicación. Una iOS 10
y otra vez, mi barra de navegación se veía así:
Ahora con iOS 11
tengo:
Como puede ver, hay una diferencia en el redondeo de las dos barras de búsqueda, lo que no me molesta. El problema es que la barra de búsqueda aumenta la altura de la barra de navegación. Entonces, cuando voy a otro controlador, también se ve extraño:
De hecho, la altura de la extraña línea negra más la altura de la barra de navegación actual es igual a la altura de la barra de navegación que se muestra en la segunda imagen ...
¿Alguna idea de cómo deshacerse de la línea negra y tener una altura de barra de navegación constante en todos los controladores de vista?
fuente
Respuestas:
Obtuve una línea negra debajo de NavigationBar con SearchBar en iOS 11 en dos casos:
cuando empujé otro ViewControllers de ViewController con UISearchBar
cuando descarté ViewController con UISearchBar con "arrastrar a la derecha para descartar"
Mi solución fue: agregar este código a mi ViewController con UISearchBar:
-(void)viewWillDisappear:(BOOL)animated{ [super viewWillDisappear:animated]; [self.navigationController.view setNeedsLayout]; // force update layout [self.navigationController.view layoutIfNeeded]; // to fix height of the navigation bar }
Actualización de Swift 4
override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) navigationController?.view.setNeedsLayout() // force update layout navigationController?.view.layoutIfNeeded() // to fix height of the navigation bar }
fuente
Puede agregar una restricción de altura 44 a la barra de búsqueda para iOS 11.
// Rápido
if #available(iOS 11.0, *) { searchBar.heightAnchor.constraint(equalToConstant: 44).isActive = true }
// C objetivo
if (@available(iOS 11.0, *)) { [searchBar.heightAnchor constraintEqualToConstant:44].active = YES; }
fuente
Creo que en iOS 11, UISearchBar ahora tiene la altura igual a 56, y UINavigationBar usa el diseño automático para adaptarse a sus subvistas, por lo que aumenta la altura. Si aún desea tener UISearchBar como titleView como en versiones anteriores de iOS 11, descubrí que la mejor manera de hacerlo es incrustar UISearchBar en una vista personalizada, establecer la altura de esta vista en 44 y asignarla a navigationItem.titleView
class SearchBarContainerView: UIView { let searchBar: UISearchBar init(customSearchBar: UISearchBar) { searchBar = customSearchBar super.init(frame: CGRect.zero) addSubview(searchBar) } override convenience init(frame: CGRect) { self.init(customSearchBar: UISearchBar()) self.frame = frame } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func layoutSubviews() { super.layoutSubviews() searchBar.frame = bounds } } class MyViewController: UIViewController { func setupNavigationBar() { let searchBar = UISearchBar() let searchBarContainer = SearchBarContainerView(customSearchBar: searchBar) searchBarContainer.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: 44) navigationItem.titleView = searchBarContainer } }
fuente
prueba este código en el controlador de vista "ACKNOWLEDGMENTS" en viewDidLoad
self.extendedLayoutIncludesOpaqueBars = true
fuente
extendedLayoutIncludesOpaqueBars
hace la propiedad.¡Gracias a todos! Finalmente encontré una solución.
Agregar el siguiente código a ViewController con UISearchBar.
viewDidLoad
-(void)viewDidLoad { [super viewDidLoad]; self.extendedLayoutIncludesOpaqueBars = YES; ... }
override func viewDidLoad() { super.viewDidLoad() self.extendedLayoutIncludesOpaqueBars = true }
viewWillDisappear
-(void)viewWillDisappear:(BOOL)animated{ [super viewWillDisappear:animated]; // force update layout [self.navigationController.view setNeedsLayout]; // to fix height of the navigation bar [self.navigationController.view layoutIfNeeded]; }
override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) navigationController?.view.setNeedsLayout() // force update layout navigationController?.view.layoutIfNeeded() // to fix height of the navigation bar }
fuente
En Objective-C
if (@available(iOS 11.0, *)) { [self.searchBar.heightAnchor constraintLessThanOrEqualToConstant: 44].active = YES; }
fuente
Esto también me pasó a mí, todo funciona bien en iOS 12.4 y se vuelve extraño en el 13 anterior. El problema está en el aumento de altura de la barra de navegación de iOS 13 de 88 a 100 después de saltar desde UIViewController que implementa searchBar.
Pruebe esto en su UIViewController que implementa searchBar.
override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) navigationController?.view.setNeedsLayout() navigationController?.view.layoutIfNeeded() }
Vista previa después de corregir:
Vista previa antes de corregir:
fuente
EDITAR: La respuesta @zgjie es una mejor solución para este problema: https://stackoverflow.com/a/46356265/1713123
Parece que esto sucede porque en iOS 11 el valor de altura predeterminado de SearchBar se cambió a 56, en lugar de 44 en las versiones anteriores de iOS.
Por ahora, he aplicado esta solución, estableciendo la altura de la barra de búsqueda de nuevo en 44:
let barFrame = searchController.searchBar.frame searchController.searchBar.frame = CGRect(x: 0, y: 0, width: barFrame.width, height: 44)
Otra solución podría ser usar la nueva propiedad searchController en navigationItem en iOS 11 :
Pero de esta manera, la barra de búsqueda aparece debajo del título de navegación.
fuente
CGRect().insetBy(dx:dy:)
yCGRect().offsetBy(dx:dy:)
, en este caso -searchController.searchBar.frame = searchController.searchBar.frame.insetBy(dx: 0, dy: -12)
Toda la solución no funcionó para mí, así que antes de presionar el controlador de vista, lo hice:
override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) self.navigationItem.titleView = UIView() }
Y para hacer que la barra de búsqueda esté presente al regresar:
override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) self.navigationItem.titleView = UISearchBar() }
fuente
No pude usar la solución de mantener la barra de navegación en 44. Así que me tomó un día, pero finalmente encontré una solución que no cambia la altura de la barra y coloca el botón en el medio de la barra. El problema es que los botones se colocan en una vista de pila que está configurada como vista de pila horizontal y, por lo tanto, no se ajusta al cambio de altura.
Esto se hace en init:
UIBarButtonItem *cancelButton; if (@available(iOS 11.0, *)) { // For iOS11 creating custom button to accomadate the change of navbar + search bar being 56 points self.navBarCustomButton = [UIButton buttonWithType:UIButtonTypeCustom]; [self.navBarCustomButton setTitle:@"Cancel"]; [self.navBarCustomButton addTarget:self action:@selector(cancelButtonTapped) forControlEvents:UIControlEventTouchUpInside]; cancelButton = [[UIBarButtonItem alloc] initWithCustomView:self.navBarCustomButton]; } else { cancelButton = [[UIBarButtonItem alloc] initWithTitle:MagicLocalizedString(@"button.cancel", @"Cancel") style:UIBarButtonItemStylePlain target:self action:@selector(cancelButtonTapped)]; }
en viewWillApear (o en cualquier momento después de que se agregó la vista a la pila de navegación)
if (@available(iOS 11.0, *)) { UIView *buttonsStackView = [navigationController.navigationBar subviewOfClass:[UIStackView class]]; if (buttonsStackView ) { [buttonsStackView.centerYAnchor constraintEqualToAnchor:navigationController.navigationBar.centerYAnchor].active = YES; [self.navBarCustomButton.heightAnchor constraintEqualToAnchor:buttonsStackView.heightAnchor]; } }
Y subviewOfClass es una categoría en UIView:
- (__kindof UIView *)subviewOfClass:(Class)targetClass { // base case if ([self isKindOfClass:targetClass]) { return self; } // recursive for (UIView *subview in self.subviews) { UIView *dfsResult = [subview subviewOfClass:targetClass]; if (dfsResult) { return dfsResult; } } return nil; }
fuente
Todo lo que tiene que hacer es subclase UISearchBar y anular "intrinsicContentSize":
@implementation CJSearchBar -(CGSize)intrinsicContentSize{ CGSize s = [super intrinsicContentSize]; s.height = 44; return s; } @end
fuente
No puedo comentar, pero quería compartir algunos problemas adicionales que encontré mientras pasaba muchas horas tratando de llegar al fondo de este problema, incluso después de usar una de las otras soluciones.
Parece que la mejor solución para mí fue la respuesta de Andrew :
override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) navigationController?.view.setNeedsLayout() // force update layout navigationController?.view.layoutIfNeeded() // to fix height of the navigation bar }
Sin embargo, al menos en iOS 12.1 , si su
UINavigationBar
:isTranslucent
configurado enfalse
, el controlador de vista con la barra de búsqueda parece no ajustar el diseño de la vista cuando se cierra de forma interactiva (el cierre normal a través del botón Atrás parece funcionar).setBackgroundImage(UIImage(), for: .default)
, la animación de transición no funciona correctamente y volverá a su posición después de terminar.Sin embargo, estas propiedades particulares se configuraron para que la barra de navegación aparezca de cierta manera, por lo que debo hacer algunos ajustes para recuperarla o soportar el comportamiento extraño. Intentaré recordar actualizar lo anterior si me encuentro con algo más o encuentro otras soluciones o diferencias en otras versiones del sistema operativo.
fuente
En mi caso, la altura de UINavigationBar más grande no fue un problema para mí. Solo necesitaba realinear los elementos de los botones de la barra izquierda y derecha. Esa es la solución que se me ocurrió:
- (void)iOS11FixNavigationItemsVerticalAlignment { [self.navigationController.navigationBar layoutIfNeeded]; NSString * currSysVer = [[UIDevice currentDevice] systemVersion]; if ([currSysVer compare:@"11" options:NSNumericSearch] != NSOrderedAscending) { UIView * navigationBarContentView; for (UIView * subview in [self.navigationController.navigationBar subviews]) { if ([subview isKindOfClass:NSClassFromString(@"_UINavigationBarContentView")]) { navigationBarContentView = subview; break; } } if (navigationBarContentView) { for (UIView * subview in [navigationBarContentView subviews]) { if (![subview isKindOfClass:NSClassFromString(@"_UIButtonBarStackView")]) continue; NSLayoutConstraint * topSpaceConstraint; NSLayoutConstraint * bottomSpaceConstraint; CGFloat topConstraintMultiplier = 1.0f; CGFloat bottomConstraintMultiplier = 1.0f; for (NSLayoutConstraint * constraint in navigationBarContentView.constraints) { if (constraint.firstItem == subview && constraint.firstAttribute == NSLayoutAttributeTop) { topSpaceConstraint = constraint; break; } if (constraint.secondItem == subview && constraint.secondAttribute == NSLayoutAttributeTop) { topConstraintMultiplier = -1.0f; topSpaceConstraint = constraint; break; } } for (NSLayoutConstraint * constraint in navigationBarContentView.constraints) { if (constraint.firstItem == subview && constraint.firstAttribute == NSLayoutAttributeBottom) { bottomSpaceConstraint = constraint; break; } if (constraint.secondItem == subview && constraint.secondAttribute == NSLayoutAttributeBottom) { bottomConstraintMultiplier = -1.0f; bottomSpaceConstraint = constraint; break; } } CGFloat contentViewHeight = navigationBarContentView.frame.size.height; CGFloat subviewHeight = subview.frame.size.height; topSpaceConstraint.constant = topConstraintMultiplier * (contentViewHeight - subviewHeight) / 2.0f; bottomSpaceConstraint.constant = bottomConstraintMultiplier * (contentViewHeight - subviewHeight) / 2.0f; } } } }
Básicamente, buscamos vistas de pila que contengan elementos de botones de barra y luego cambiamos sus valores de restricciones superiores e inferiores. Sí, es un truco sucio y no recomendaré usarlo si puede solucionar su problema de otra manera.
fuente
// // Created by Sang Nguyen on 10/23/17. // Copyright © 2017 Sang. All rights reserved. // import Foundation import UIKit class CustomSearchBarView: UISearchBar { final let SearchBarHeight: CGFloat = 44 final let SearchBarPaddingTop: CGFloat = 8 override open func awakeFromNib() { super.awakeFromNib() self.setupUI() } override init(frame: CGRect) { super.init(frame: frame) self.setupUI() } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) // fatalError("init(coder:) has not been implemented") } func findTextfield()-> UITextField?{ for view in self.subviews { if view is UITextField { return view as? UITextField } else { for textfield in view.subviews { if textfield is UITextField { return textfield as? UITextField } } } } return nil; } func setupUI(){ if #available(iOS 11.0, *) { self.translatesAutoresizingMaskIntoConstraints = false self.heightAnchor.constraint(equalToConstant: SearchBarHeight).isActive = true } } override func layoutSubviews() { super.layoutSubviews() if #available(iOS 11.0, *) { if let textfield = self.findTextfield() { textfield.frame = CGRect(x: textfield.frame.origin.x, y: SearchBarPaddingTop, width: textfield.frame.width, height: SearchBarHeight - SearchBarPaddingTop * 2)`enter code here` return } } } }
fuente
Descubrí que la solución de Mai Mai es la única realmente utilizable.
Sin embargo, todavía no es perfecto:
al girar el dispositivo, la barra de búsqueda no cambia de tamaño correctamente y permanece en la dimensión más pequeña.
He encontrado una solución para eso. Aquí está mi código en Objective C con las partes relevantes anotadas:
// improvements in the search bar wrapper @interface SearchBarWrapper : UIView @property (nonatomic, strong) UISearchBar *searchBar; - (instancetype)initWithSearchBar:(UISearchBar *)searchBar; @end @implementation SearchBarWrapper - (instancetype)initWithSearchBar:(UISearchBar *)searchBar { // setting width to a large value fixes stretch-on-rotation self = [super initWithFrame:CGRectMake(0, 0, 4000, 44)]; if (self) { self.searchBar = searchBar; [self addSubview:searchBar]; } return self; } - (void)layoutSubviews { [super layoutSubviews]; self.searchBar.frame = self.bounds; } // fixes width some cases of resizing while search is active - (CGSize)sizeThatFits:(CGSize)size { return size; } @end // then use it in your VC @implementation MyViewController - (void)viewDidLoad { [super viewDidLoad]; self.navigationItem.titleView = [[SearchBarWrapper alloc] initWithSearchBar:self.searchController.searchBar]; } @end
Ahora todavía queda un caso que aún no he descubierto. Para reproducir, haga lo siguiente:
- comience en vertical
- active el campo de búsqueda
- gire a horizontal
- error: la barra no cambia de tamaño
fuente
Arreglé esto agregando la restricción a viewDidAppear en el controlador de vista de mapa donde está incrustada la barra de búsqueda
public override func viewDidAppear(_ animated: Bool) { if #available(iOS 11.0, *) { resultSearchController?.searchBar.heightAnchor.constraint(equalToConstant: 44).isActive = true // searchBar.heightAnchor.constraint(equalToConstant: 44).isActive = true } }
fuente
Hola a la gente que usa
UISearchController
y luego adjunta suUISearchBar
alnavigationItem.titleView
. He gastado 4-5 horas locas de mi día para resolver esto. Siguiendo el enfoque recomendado por iOS 11+, que está poniendo elsearchController
anavigation.searchController
no es lo correcto para mi caso. La pantalla que tiene este searchController / searchBar tiene un backButton, uno personalizado.He probado esto en iOS 10, iOS 11 y 12. En diferentes dispositivos. Solo tenía que hacerlo. No puedo volver a casa sin resolver este demonio. Esto es lo más perfecto que pude hacer hoy, dada mi fecha límite ajustada.
Así que solo quiero compartir este arduo trabajo que hice, depende de ti poner todo donde quieras (por ejemplo, variables en tu viewModel). Aquí va:
En mi primera pantalla (digamos la pantalla de inicio, que no tiene este controlador de búsqueda), tengo esto en mi
viewDidLoad()
.self.extendedLayoutIncludesOpaqueBars = true
En mi segunda pantalla, la que tiene el searchController, tengo esto en mi
viewDidAppear
.anular func viewDidAppear (_ animado: Bool) {super.viewDidAppear (animado)
let systemMajorVersion = ProcessInfo.processInfo.operatingSystemVersion.majorVersion if systemMajorVersion < 12 { // Place the search bar in the navigation item's title view. self.navigationItem.titleView = self.searchController.searchBar } if systemMajorVersion >= 11 { self.extendedLayoutIncludesOpaqueBars = true UIView.animate(withDuration: 0.3) { self.navigationController?.navigationBar.setNeedsLayout() self.navigationController?.navigationBar.layoutIfNeeded() } self.tableView.contentInset = UIEdgeInsets(top: -40, left: 0, bottom: 0, right: 0) if self.viewHadAppeared { self.tableView.contentInset = .zero } } self.viewHadAppeared = true // this is set to false by default. }
y aquí está la declaración de mi searchController:
lazy var searchController: UISearchController = { let searchController = UISearchController(searchResultsController: nil) searchController.hidesNavigationBarDuringPresentation = false searchController.dimsBackgroundDuringPresentation = false searchController.searchBar.textField?.backgroundColor = .lalaDarkWhiteColor searchController.searchBar.textField?.tintColor = .lalaDarkGray searchController.searchBar.backgroundColor = .white return searchController }()
Así que espero que esto ayude a alguien algún día.
fuente
Intenté varias cosas para que el tamaño volviera al 44 original, pero luego la barra de búsqueda siempre se ve y se comporta de manera extraña, como estar demasiado estirada, con desplazamiento y y similares.
Encontré una buena solución aquí (a través de otra publicación de stackoverflow): https://github.com/DreamTravelingLight/searchBarDemo
Simplemente derive su viewcontroller del SearchViewController e incluya en su proyecto las clases SearchViewController y WMSearchbar. Funcionó de la caja para mí sin ningún feo if (iOS11) más ... fealdad.
fuente
En mi caso, tengo que disminuir la altura del campo de texto 36pt -> 28pt.
Así que intenté cambiar la altura del marco, la altura de la capa. Pero las formas no funcionaron.
Finalmente, encontré una solución que es la máscara. Creo que no es una buena forma, pero funciona.
let textField = searchBar.value(forKey: "searchField") as? UITextField textField?.font = UIFont.systemFont(ofSize: 14.0, weight: .regular) textField?.textColor = #colorLiteral(red: 0.1960784314, green: 0.1960784314, blue: 0.1960784314, alpha: 1) textField?.textAlignment = .left if #available(iOS 11, *) { let radius: CGFloat = 5.0 let magnifyIconWidth: CGFloat = 16.0 let inset = UIEdgeInsets(top: 4.0, left: 0, bottom: 4.0, right: 0) let path = CGMutablePath() path.addArc(center: CGPoint(x: searchBar.bounds.size.width - radius - inset.right - magnifyIconWidth, y: inset.top + radius), radius: radius, startAngle: .pi * 3.0/2.0, endAngle: .pi*2.0, clockwise: false) // Right top path.addArc(center: CGPoint(x: searchBar.bounds.size.width - radius - inset.right - magnifyIconWidth, y: searchBar.bounds.size.height - radius - inset.bottom), radius: radius, startAngle: 0, endAngle: .pi/2.0, clockwise: false) // Right Bottom path.addArc(center: CGPoint(x: inset.left + radius, y: searchBar.bounds.size.height - radius - inset.bottom), radius: radius, startAngle: .pi/2.0, endAngle: .pi, clockwise: false) // Left Bottom path.addArc(center: CGPoint(x: inset.left + radius, y: inset.top + radius), radius: radius, startAngle: .pi, endAngle: .pi * 3.0/2.0, clockwise: false) // Left top let maskLayer = CAShapeLayer() maskLayer.path = path maskLayer.fillRule = kCAFillRuleEvenOdd textField?.layer.mask = maskLayer }
Puede cambiar las inserciones, si desea cambiar el marco del campo de texto.
fuente