Saya telah UISearchBar
menjadi bagian dari bilah navigasi seperti:
let searchBar = UISearchBar()
//some more configuration to the search bar
.....
navigationItem.titleView = searchBar
Setelah memperbarui ke iOS 11
sesuatu yang aneh terjadi pada bilah pencarian di aplikasi saya. Pada iOS 10
dan sebelumnya saya memiliki bilah navigasi seperti:
Sekarang dengan iOS 11
saya punya:
Seperti yang Anda lihat, ada perbedaan dalam pembulatan dua bilah pencarian yang tidak mengganggu saya. Masalahnya adalah bilah pencarian meningkatkan ketinggian bilah navigasi. Jadi ketika saya pergi ke pengontrol lain, itu juga terlihat aneh:
Faktanya bahwa tinggi garis hitam aneh ditambah tinggi bilah navigasi saat ini sama dengan tinggi bilah navigasi yang ditunjukkan pada gambar kedua ...
Adakah ide bagaimana cara menghilangkan garis hitam dan memiliki tinggi bilah navigasi yang konsisten di semua pengontrol tampilan?
sumber
Jawaban:
Saya mendapat garis hitam di bawah NavigationBar dengan SearchBar di iOS 11 dalam dua kasus:
ketika saya mendorong ViewControllers lain dari ViewController dengan UISearchBar
ketika saya menutup ViewController dengan UISearchBar dengan "seret ke kanan untuk menutup"
Solusi saya adalah: menambahkan kode ini ke ViewController saya dengan 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 }
Pembaruan 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 }
sumber
Anda dapat menambahkan batasan ketinggian 44 ke bilah pencarian untuk iOS 11.
// Swift
if #available(iOS 11.0, *) { searchBar.heightAnchor.constraint(equalToConstant: 44).isActive = true }
// Objective-C
if (@available(iOS 11.0, *)) { [searchBar.heightAnchor constraintEqualToConstant:44].active = YES; }
sumber
Saya percaya di iOS 11 UISearchBar sekarang memiliki tinggi yang sama dengan 56, dan UINavigationBar menggunakan autolayout agar sesuai dengan subview sehingga meningkatkan tinggi. Jika Anda masih ingin memiliki UISearchBar sebagai titleView seperti sebelum iOS 11, saya menemukan cara terbaik untuk melakukannya adalah dengan menyematkan UISearchBar dalam tampilan kustom, dan mengatur tinggi tampilan ini ke 44, dan menetapkannya ke 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 } }
sumber
coba kode ini pada pengontrol tampilan "ACKNOWLEDGMENTS" di viewDidLoad
self.extendedLayoutIncludesOpaqueBars = true
sumber
extendedLayoutIncludesOpaqueBars
dilakukan properti.Terima kasih semua! Saya akhirnya menemukan solusi.
Menambahkan kode berikut ke ViewController dengan 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 }
sumber
Di Objective-C
if (@available(iOS 11.0, *)) { [self.searchBar.heightAnchor constraintLessThanOrEqualToConstant: 44].active = YES; }
sumber
Ini juga terjadi pada saya, semuanya berjalan dengan baik di iOS 12.4 dan menjadi aneh di 13 di atas. Masalahnya ada di tinggi bilah navigasi iOS 13 meningkat dari 88 menjadi 100 setelah melompat dari UIViewController yang mengimplementasikan searchBar.
Coba ini di UIViewController Anda yang mengimplementasikan searchBar.
override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) navigationController?.view.setNeedsLayout() navigationController?.view.layoutIfNeeded() }
Pratinjau setelah memperbaiki:
Pratinjau sebelum memperbaiki:
sumber
EDIT: Jawaban @zgjie adalah solusi yang lebih baik untuk masalah ini: https://stackoverflow.com/a/46356265/1713123
Sepertinya ini terjadi karena di iOS 11 nilai tinggi default SearchBar diubah menjadi 56, bukan 44 pada versi iOS sebelumnya.
Untuk saat ini, saya telah menerapkan solusi ini, menyetel tinggi searchBar kembali ke 44:
let barFrame = searchController.searchBar.frame searchController.searchBar.frame = CGRect(x: 0, y: 0, width: barFrame.width, height: 44)
Solusi lain dapat menggunakan properti searchController baru di navigationItem di iOS 11 :
Tapi cara ini da searchBar muncul di bawah judul navigasi.
sumber
CGRect().insetBy(dx:dy:)
danCGRect().offsetBy(dx:dy:)
, dalam hal ini -searchController.searchBar.frame = searchController.searchBar.frame.insetBy(dx: 0, dy: -12)
Semua solusi tidak berfungsi untuk saya, jadi sebelum saya mendorong pengontrol tampilan, saya melakukannya:
override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) self.navigationItem.titleView = UIView() }
Dan untuk menampilkan bilah pencarian saat kembali:
override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) self.navigationItem.titleView = UISearchBar() }
sumber
Saya tidak bisa menggunakan solusi untuk menjaga navBar di 44. Jadi saya butuh waktu satu hari tapi akhirnya, saya menemukan solusi yang tidak mengubah tinggi bar dan posisi tombol di tengah bar. Masalahnya adalah bahwa tombol ditempatkan dalam tampilan tumpukan yang dikonfigurasi sebagai tampilan tumpukan horizontal dan oleh karena itu tidak menyesuaikan dengan perubahan ketinggian.
Ini dilakukan di 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)]; }
di viewWillApear (atau kapan saja setelah tampilan ditambahkan ke tumpukan navigasi)
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]; } }
Dan subviewOfClass adalah kategori di 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; }
sumber
Yang harus Anda lakukan adalah membuat subkelas UISearchBar dan mengganti "intrinsicContentSize":
@implementation CJSearchBar -(CGSize)intrinsicContentSize{ CGSize s = [super intrinsicContentSize]; s.height = 44; return s; } @end
sumber
Tidak dapat berkomentar, tetapi ingin berbagi beberapa masalah tambahan yang saya hadapi saat menghabiskan berjam-jam mencoba memahami dasar masalah ini bahkan setelah menggunakan salah satu solusi lain.
Tampaknya perbaikan terbaik bagi saya adalah jawaban 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 }
Namun, setidaknya di iOS 12.1 , jika Anda
UINavigationBar
:isTranslucent
diatur kefalse
, Pengontrol Tampilan dengan bilah pencarian tampaknya tidak mendapatkan tata letak tampilan yang disesuaikan kembali ketika menutup secara interaktif (penutupan normal melalui tombol kembali tampaknya berfungsi).setBackgroundImage(UIImage(), for: .default)
, animasi transisi tidak berfungsi dengan baik dan akan melompat kembali ke posisinya setelah selesai.Properti khusus ini diatur agar Bilah Navigasi muncul dengan cara tertentu, jadi saya perlu melakukan beberapa penyesuaian untuk mendapatkannya kembali, atau tahan dengan perilaku aneh. Akan mencoba mengingat untuk memperbarui di atas jika saya mengalami hal lain atau menemukan solusi atau perbedaan lain dalam versi OS lain.
sumber
Dalam kasus saya, tinggi UINavigationBar yang lebih besar bukanlah masalah bagi saya. Saya hanya perlu menyetel kembali item tombol bar kiri dan kanan. Itulah solusi yang saya dapatkan:
- (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; } } } }
Pada dasarnya, kami mencari tampilan tumpukan yang berisi item tombol batang dan kemudian mengubah nilai batasan atas dan bawahnya. Ya, ini adalah peretasan kotoran, dan tidak akan merekomendasikan untuk menggunakannya jika Anda dapat memperbaiki masalah Anda dengan cara lain.
sumber
// // 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 } } } }
sumber
Saya menemukan solusi Mai Mai menjadi satu-satunya solusi yang benar-benar berguna.
Namun itu masih belum sempurna:
Saat memutar perangkat, bilah pencarian tidak diubah ukurannya dengan benar dan tetap dalam dimensi yang lebih kecil.
Saya telah menemukan cara untuk memperbaikinya. Ini kode saya di Objective C dengan bagian-bagian yang relevan dijelaskan:
// 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
Sekarang masih ada satu kasus tersisa yang belum saya temukan. Untuk mereproduksi lakukan hal berikut:
- mulai dalam potret
- aktifkan bidang pencarian
- putar ke lanskap
- kesalahan: bilah tidak berubah ukuran
sumber
Saya memperbaikinya dengan menambahkan batasan ke viewDidAppear pada pengontrol tampilan peta tempat bilah pencarian disematkan
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 } }
sumber
Hai orang-orang yang menggunakan
UISearchController
dan kemudian melampirkan nyaUISearchBar
kenavigationItem.titleView
. Saya telah menghabiskan 4-5 jam hari saya yang gila untuk menyelesaikan ini. Mengikuti pendekatan yang direkomendasikan iOS 11+, yang menempatkansearchController
kenavigation.searchController
tidak tepat untuk kasus saya. Layar yang memiliki searchController / searchBar ini memiliki backButton, kustom.Saya telah menguji ini di iOS 10, iOS 11, dan 12. Di perangkat yang berbeda. Saya hanya harus. Saya tidak bisa pulang tanpa memecahkan iblis ini. Ini adalah yang paling sempurna yang bisa saya lakukan untuk hari ini, mengingat tenggat waktu saya yang ketat.
Jadi saya hanya ingin berbagi kerja keras yang saya lakukan ini, terserah Anda untuk meletakkan semuanya di mana pun Anda inginkan (mis. Variabel di viewModel Anda). Ini dia:
Di layar pertama saya (katakanlah layar beranda, yang tidak memiliki pengontrol pencarian ini), saya memiliki ini di
viewDidLoad()
.self.extendedLayoutIncludesOpaqueBars = true
Di layar kedua saya, yang memiliki searchController, saya memiliki ini di
viewDidAppear
.override func viewDidAppear (_ animated: Bool) {super.viewDidAppear (animated)
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. }
dan inilah deklarasi searchController saya:
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 }()
Jadi saya harap ini membantu seseorang suatu hari nanti.
sumber
Saya mencoba berbagai hal untuk mendapatkan ukuran kembali ke 44 asli, tetapi kemudian bilah pencarian selalu terlihat dan berperilaku aneh - seperti terlalu jauh, y-offset dan serupa.
Saya menemukan solusi yang bagus di sini (melalui beberapa pos stackoverflow lainnya): https://github.com/DreamTravelingLight/searchBarDemo
Dapatkan saja viewcontroller Anda dari SearchViewController dan sertakan dalam proyek Anda kelas SearchViewController dan WMSearchbar. Bekerja di luar kotak untuk saya tanpa jelek jika (iOS11) lain ... kejelekan.
sumber
Dalam kasus saya, saya harus menurunkan ketinggian textField 36pt -> 28pt.
Jadi saya mencoba mengubah tinggi bingkai, tinggi lapisan. Tetapi cara-cara itu tidak berhasil.
Akhirnya, saya menemukan solusi yaitu topeng. Saya pikir, Ini bukan cara yang baik tetapi berhasil.
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 }
Anda dapat mengubah insets, jika Anda ingin mengubah frame textField.
sumber