programing

iOS 11에서 UI 검색 막대가 탐색 막대 높이를 높입니다.

yellowcard 2023. 8. 8. 21:26
반응형

iOS 11에서 UI 검색 막대가 탐색 막대 높이를 높입니다.

는 나의 는나의를 있습니다.UISearchBar다음과 같은 탐색 모음에 속합니다.

 let searchBar = UISearchBar()
 //some more configuration to the search bar
 .....
 navigationItem.titleView = searchBar

로 한 후iOS 11내 앱의 검색창에 이상한 일이 생겼습니다.iOS 10그리고 전에 다음과 같은 네비게이션 바를 가지고 있었습니다.

enter image description here

자이제와 함께iOS 11가 가진 것:

enter image description here

보시다시피 두 검색창의 반올림에 차이가 있어서 신경이 쓰이지 않습니다.문제는 검색창이 탐색창의 높이를 높인다는 점입니다.그래서 다른 컨트롤러로 이동할 때도 이상하게 보입니다.

enter image description here

사실 이상한 검은색 선의 높이에 현재 탐색 막대의 높이를 더한 값이 두 번째 사진에 표시된 탐색 막대의 높이와 같습니다.

검은색 선을 제거하고 모든 뷰 컨트롤러에서 일관된 탐색 막대 높이를 유지하는 방법이 있습니까?

iOS 11에서 검색바와 함께 탐색바 아래에 검은색 줄이 두 가지 경우에 있습니다.

  • UIS 검색 표시줄을 사용하여 ViewController에서 다른 ViewController를 푸시한 경우

  • 내가 "해임권 끌어오기"로 UI 검색바와 함께 ViewController를 해임했을 때.

제 해결책은 다음과 같습니다. UI 검색바를 사용하여 이 코드를 View 컨트롤러에 추가하는 것입니다.

-(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
}

스위프트 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
}

iOS 11의 검색창에 높이 44의 제약 조건을 추가할 수 있습니다.

스위프트

if #available(iOS 11.0, *) {
    searchBar.heightAnchor.constraint(equalToConstant: 44).isActive = true
}

목표-C

if (@available(iOS 11.0, *)) {
    [searchBar.heightAnchor constraintEqualToConstant:44].active = YES;
}

iOS 11 UIS Search Bar는 이제 56과 같은 높이를 가지고 있으며, UINavigation Bar는 하위 뷰에 맞게 자동 레이아웃을 사용하여 높이를 높입니다.만약 당신이 여전히 iOS 11 이전과 같은 제목 뷰로 UI 검색바를 가지고 싶다면, 나는 그것을 하는 가장 좋은 방법이 UIS 검색바를 사용자 정의 뷰에 내장하고, 이 뷰의 높이를 44로 설정하여 navigationItem에 할당하는 것이라는 것을 알게 되었습니다.제목 보기

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  
    }  
} 

viewDidLoad의 "확인" 뷰 컨트롤러에서 이 코드를 시도합니다.

self.extendedLayoutIncludesOpaqueBars = true

여러분 감사합니다.저는 마침내 해결책을 찾았습니다.

다음 코드를 UI 검색 표시줄을 사용하여 View 컨트롤러에 추가합니다.

  1. 번째 단계: 첫번째단계::viewDidLoad
-(void)viewDidLoad
{
    [super viewDidLoad];
    self.extendedLayoutIncludesOpaqueBars = YES;
    ...
}
override func viewDidLoad() {
    super.viewDidLoad()
    self.extendedLayoutIncludesOpaqueBars = true
}
  1. 번째 단계 번째단계두: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
    }

In Objective-C

if (@available(iOS 11.0, *)) {
        [self.searchBar.heightAnchor constraintLessThanOrEqualToConstant: 44].active = YES;
}              

iOS 12.4에서 모두 잘 실행되고 위의 13에서 이상해지는 저에게도 이런 일이 발생합니다.iOS 13에서 검색바를 구현하는 UIViewController에서 점프 후 내비게이션 바 높이가 88에서 100으로 증가하는 것이 문제입니다.

검색바를 구현하는 UIView 컨트롤러에서 이 기능을 사용해 보십시오.

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    navigationController?.view.setNeedsLayout()
    navigationController?.view.layoutIfNeeded()
}

수정 후 미리 보기:

enter image description here enter image description here

수정하기 전에 미리 보기

enter image description here enter image description here

편집: @zgjie 답변이 이 문제에 대한 더 나은 해결책입니다. https://stackoverflow.com/a/46356265/1713123

iOS 11에서는 SearchBar의 기본 높이 값이 이전 iOS 버전에서는 44가 아닌 56으로 변경되었기 때문에 이러한 현상이 발생한 것으로 보입니다.

지금은 이 해결 방법을 적용하여 searchBar 높이를 44로 다시 설정했습니다.

let barFrame = searchController.searchBar.frame
searchController.searchBar.frame = CGRect(x: 0, y: 0, width: barFrame.width, height: 44)    

다른 솔루션은 탐색 시 새 searchController 속성을 사용할 수 있습니다.iOS 11의 항목:

navigationItem.searchController = searchController

그러나 이렇게 하면 탐색 제목 아래에 검색 표시줄이 나타납니다.

모든 솔루션이 제대로 작동하지 않았기 때문에 보기 컨트롤러를 누르기 전에 다음과 같이 했습니다.

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)

    self.navigationItem.titleView = UIView()
}

돌아갈 때 검색 줄을 표시하려면 다음을 수행합니다.

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    self.navigationItem.titleView = UISearchBar()
}

나는 navBar를 44로 유지하는 솔루션을 사용할 수 없었습니다.그래서 하루가 걸렸지만 결국 바 높이를 바꾸지 않고 바 중앙에 버튼을 위치시키는 해결책을 찾았습니다.문제는 버튼이 Horizontal stack view로 구성된 스택 뷰에 배치되어 있기 때문에 높이 변경에 따라 조정되지 않는다는 것입니다.

이 작업은 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)];
}

onviewWillApear(또는 보기가 탐색 스택에 추가된 후 언제든지)

   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];
        }
    }

SubviewOfClass는 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;
}

UIS 검색 막대를 하위 분류하고 "내장 콘텐츠 크기"를 재정의하기만 하면 됩니다.

@implementation CJSearchBar
-(CGSize)intrinsicContentSize{
    CGSize s = [super intrinsicContentSize];
    s.height = 44;
    return s;
}
@end

enter image description here

의견을 말할 수는 없지만, 다른 솔루션 중 하나를 사용한 후에도 이 문제의 진상을 파악하는 데 많은 시간을 소비하면서 마주친 몇 가지 추가 문제를 공유하고 싶습니다.

저에게 가장 좋은 해결책은 앤드류의 대답이었던 것 같습니다.

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    navigationController?.view.setNeedsLayout() // force update layout
    navigationController?.view.layoutIfNeeded() // to fix height of the navigation bar
}

하지만, 적어도 iOS 12.1에서는, 만약 당신이UINavigationBar:

  • 가지다isTranslucent로 설정한.false대화형으로 해제할 때 검색 막대가 있는 View Controller는 뷰 레이아웃을 다시 조정하지 않는 것으로 나타납니다(뒤로 단추를 사용한 일반 해제가 작동하는 것으로 나타납니다).
  • 다음을 사용하여 배경 이미지가 설정되어 있습니까?setBackgroundImage(UIImage(), for: .default)전환 애니메이션이 제대로 작동하지 않고 종료 후 다시 제자리로 점프합니다.

그러나 이러한 특정 속성은 탐색 모음이 특정한 방식으로 나타나도록 설정되었기 때문에 이를 되돌리거나 이상한 동작을 참기 위해 조정을 해야 합니다.다른 OS 버전에서 다른 문제가 발생하거나 다른 솔루션 또는 차이점이 발견되면 상기 내용을 업데이트하도록 노력할 것입니다.

저의 경우, UIN 내비게이션 바의 키가 큰 것은 문제가 되지 않았습니다.나는 단지 왼쪽과 오른쪽 막대 단추 항목을 다시 정렬하기만 하면 되었습니다.이것이 제가 생각해 낸 해결책입니다.

- (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;
            }
        }
    }
}

기본적으로 막대 단추 항목을 포함하는 스택 뷰를 검색한 다음 해당 항목의 상단 및 하단 제약 조건 값을 변경합니다.네, 이것은 더티 해킹이며, 다른 방법으로 문제를 해결할 수 있다면 사용하는 것을 권장하지 않을 것입니다.

//
//  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
            }
        }
    }
}

저는 Mai Mai의 솔루션이 실제로 사용할 수 있는 유일한 솔루션이라는 것을 알게 되었습니다.
하지만 여전히 완벽하지는 않습니다.
장치를 회전할 때 검색 표시줄의 크기가 제대로 조정되지 않고 더 작은 크기로 유지됩니다.

저는 그것에 대한 해결책을 찾았습니다.다음은 목표 C의 코드와 관련 부품에 주석이 달린 내용입니다.

// 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

이제 제가 아직 파악하지 못한 사건이 하나 남아 있습니다.재생하려면 다음을 수행합니다.

활성화
방향으로
크기가되지 않음: 막대크조정지되않음가기

검색 표시줄이 포함된 지도 보기 컨트롤러에 viewDidAppear 제약 조건을 추가하여 이 문제를 해결했습니다.

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
    }
}

요▁people를 사용하는 에게 안녕하세요.UISearchController그리고 그것을 부착합니다.UISearchBar에▁navigationItem.titleView저는 이 문제를 해결하기 위해 하루 중 4-5시간을 미친 듯이 보냈습니다.iOS 11+ 권장 접근 방식을 따르며, 이는 다음과 같습니다.searchController에▁navigation.searchController제 경우에만 적합한 것은 아닙니다.이 검색 컨트롤러/검색 막대가 있는 화면에는 사용자 지정 단추인 백버튼이 있습니다.

저는 이것을 iOS 10, iOS 11, 그리고 12에서 테스트했습니다.다른 장치에서.어쩔 수 없었어요이 악마를 해결하지 않고는 집에 갈 수 없습니다.마감시한이 촉박한 상황에서 제가 오늘 할 수 있는 가장 완벽한 일은 이것입니다.

그래서 저는 제가 했던 이 힘든 일을 공유하고 싶습니다. 여러분이 원하는 곳에 모든 것을 투입하는 것은 여러분에게 달려 있습니다(예: 모델 보기의 변수).자, 시작합니다.

의 첫 화면: 홈이 컨트롤러가 없습니다)에서 있습니다.viewDidLoad().

self.extendedLayoutIncludesOpaqueBars = true

두 번째에서, 저는 을 제 두번째화면서검컨있화가서는면에나이, 에 가지고 있습니다.viewDidAppear.

funcviewDidAppear(_ 애니메이션:Bool) {super.viewDidAppear(애니메이션)

    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.
}

다음은 제 검색 컨트롤러의 선언입니다.

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
}()

그래서 저는 이것이 언젠가 누군가에게 도움이 되길 바랍니다.

저는 사이즈를 원래의 44로 되돌리기 위해 다양한 방법을 시도했지만, 검색바는 항상 이상하게 보이고 행동합니다 - 너무 늘어나거나, Y-오프셋과 유사합니다.

(다른 스택 오버플로 게시물을 통해) 여기서 좋은 솔루션을 찾았습니다.https://github.com/DreamTravelingLight/searchBarDemo

SearchViewController에서 뷰 컨트롤러를 파생하고 SearchViewController 및 WM Searchbar 클래스를 프로젝트에 포함하기만 하면 됩니다.만약 (iOS11)이 아니라면 추한 일 없이 저를 위해 즉시 작업했습니다.추악한 짓

저의 경우 textField의 높이를 36pt -> 28pt로 줄여야 합니다.

enter image description here

그래서 프레임의 높이, 레이어의 높이를 변경하려고 했습니다.하지만 그 방법들은 효과가 없었습니다.

마침내, 저는 마스크라는 해결책을 찾았습니다.좋은 방법은 아니지만 효과가 있다고 생각합니다.

    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
    }

textField의 프레임을 변경하려는 경우 삽입값을 변경할 수 있습니다.

언급URL : https://stackoverflow.com/questions/46318022/uisearchbar-increases-navigation-bar-height-in-ios-11

반응형