Подтвердить что ты не робот

Как скрыть нижнюю строку UINavigationBar 1px

У меня есть приложение, для которого иногда требуется панель навигации, чтобы вписаться в контент.

Кто-нибудь знает, как избавиться или изменить цвет этого раздражающего бара?

На изображении ниже ситуации у меня есть - я говорю об этой строке высоты 1px ниже "Root View Controller"

enter image description here

4b9b3361

Ответ 1

Для iOS 13:

Используйте свойство .shadowColor property

Если это свойство равно нулю или содержит чистый цвет, на панели не отображается тень

Для iOS 12 и ниже:

Для этого вам нужно установить собственное теневое изображение. Но для отображения теневого изображения вам также необходимо установить собственное фоновое изображение, цитата из документации Apple:

Для отображения пользовательского теневого изображения пользовательское фоновое изображение должно также устанавливается с помощью метода setBackgroundImage (_: for :). Если по умолчанию используется фоновое изображение, затем будет использоваться теневое изображение по умолчанию независимо от стоимости этого свойства.

Итак:

let navigationBar = navigationController!.navigationBar
navigationBar.setBackgroundImage(#imageLiteral(resourceName: "BarBackground"),
                                                        for: .default)
navigationBar.shadowImage = UIImage()

Выше - единственный "официальный" способ скрыть это. К сожалению, это устраняет прозрачность полосы.

Я не хочу фоновое изображение, просто цвет

У вас есть эти варианты:

  1. Сплошной цвет, нет прозрачности:

    navigationBar.barTintColor = UIColor.redColor()
    navigationBar.isTranslucent = false
    navigationBar.setBackgroundImage(UIImage(), for: .default)
    navigationBar.shadowImage = UIImage()
    
  2. Создайте небольшое фоновое изображение, заполненное цветом, и используйте его.

  3. Используйте "хакерский" метод, описанный ниже. Это также будет держать бар прозрачным.

Как сохранить бар прозрачным?

Чтобы сохранить прозрачность, вам нужен другой подход, он выглядит как хак, но работает хорошо. Тень, которую мы пытаемся удалить, это линия волос UIImageView где-то под UINavigationBar. Мы можем его найти и спрятать/показать при необходимости.

В приведенных ниже инструкциях предполагается, что линия волос скрыта только в одном контроллере иерархии UINavigationController.

  1. Объявите переменную экземпляра:

    private var shadowImageView: UIImageView?
    
  2. Добавить метод, который находит эту тень (волосяная линия) UIImageView:

    private func findShadowImage(under view: UIView) -> UIImageView? {
        if view is UIImageView && view.bounds.size.height <= 1 {
            return (view as! UIImageView)
        }
    
        for subview in view.subviews {
            if let imageView = findShadowImage(under: subview) {
                return imageView
            }
        }
        return nil
    }
    
  3. Добавить/изменить viewWillAppear/viewWillDisappear методы:

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
    
        if shadowImageView == nil {
            shadowImageView = findShadowImage(under: navigationController!.navigationBar)
        }
        shadowImageView?.isHidden = true
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
    
        shadowImageView?.isHidden = false
    }
    

Тот же метод должен также работать для волосяного покрова UISearchBar, и (почти) все, что вам нужно скрыть :)

Большое спасибо @Leo Natan за оригинальную идею!

Ответ 2

Ниже может помочь просто!

Swift:

self.navigationController?.navigationBar.setValue(true, forKey: "hidesShadow")

Цель C:

[self.navigationController.navigationBar setValue:@(YES) forKeyPath:@"hidesShadow"];

Ответ 3

Если вы просто хотите использовать сплошной цвет панели навигации и настроили это в своем раскадровке, используйте этот код в своем классе AppDelegate, чтобы удалить границу с 1 пикселем через прокси-сервер вида:

[[UINavigationBar appearance] setBackgroundImage:[[UIImage alloc] init]
                                  forBarPosition:UIBarPositionAny
                                      barMetrics:UIBarMetricsDefault];

[[UINavigationBar appearance] setShadowImage:[[UIImage alloc] init]];

Ответ 4

Попробуйте следующее:

[[UINavigationBar appearance] setBackgroundImage: [UIImage new]  
                                   forBarMetrics: UIBarMetricsDefault];

[UINavigationBar appearance].shadowImage = [UIImage new];

Ниже приведено объяснение (iOS7 NavigationBar):

enter image description here

И проверьте этот вопрос: iOS7 - Изменить цвет границы UINavigationBar

Ответ 5

Хотел добавить версию ответа Сергея Свифта. Я создал UIBarExtension.swift со следующим:

import Foundation
import UIKit

extension UINavigationBar {
    func hideBottomHairline() {
        self.hairlineImageView?.isHidden = true
    }

    func showBottomHairline() {
        self.hairlineImageView?.isHidden = false
    }
}

extension UIToolbar {
    func hideBottomHairline() {
        self.hairlineImageView?.isHidden = true
    }

    func showBottomHairline() {
        self.hairlineImageView?.isHidden = false
    }
}

extension UIView {
    fileprivate var hairlineImageView: UIImageView? {
        return hairlineImageView(in: self)
    }

    fileprivate func hairlineImageView(in view: UIView) -> UIImageView? {
        if let imageView = view as? UIImageView, imageView.bounds.height <= 1.0 {
            return imageView
        }

        for subview in view.subviews {
            if let imageView = self.hairlineImageView(in: subview) { return imageView }
        }

        return nil
    }
}

Ответ 6

Быстрый способ сделать это:

UINavigationBar.appearance().setBackgroundImage(
    UIImage(),
    forBarPosition: .Any,
    barMetrics: .Default)

UINavigationBar.appearance().shadowImage = UIImage()

Ответ 7

Простое решение в быстрой

   let navigationBar = self.navigationController?.navigationBar
    navigationBar?.setBackgroundImage(UIImage(), forBarPosition: UIBarPosition.Any, barMetrics: UIBarMetrics.Default)
    navigationBar?.shadowImage = UIImage()

Ответ 8

После изучения ответа от Serhil я создал pod UINavigationBar + дополнение, который может скрыть прямую линию волос.

#import "UINavigationBar+Addition.h"

- (void)viewDidLoad {
    [super viewDidLoad];

    UINavigationBar *navigationBar = self.navigationController.navigationBar;
    [navigationBar hideBottomHairline];
}

Ответ 9

В Swift 3.0

Отредактируйте ваш AppDelegate.swift, добавив следующий код в функцию вашего приложения:

// Override point for customization after application launch.

// Remove border in navigationBar
UINavigationBar.appearance().shadowImage = UIImage()
UINavigationBar.appearance().setBackgroundImage(UIImage(), for: .default)

Ответ 10

pxpgraphics' решение обновлено для Swift 2.0

extension UINavigationBar {

    func hideBottomHairline()
    {
        hairlineImageViewInNavigationBar(self)?.hidden = true
    }

    func showBottomHairline()
    {
        hairlineImageViewInNavigationBar(self)?.hidden = false
    }

    private func hairlineImageViewInNavigationBar(view: UIView) -> UIImageView?
    {
        if let imageView = view as? UIImageView where imageView.bounds.height <= 1
        {
            return imageView
        }

        for subview: UIView in view.subviews
        {
            if let imageView = hairlineImageViewInNavigationBar(subview)
            {
                return imageView
            }
        }

        return nil
    }

}

extension UIToolbar
{

    func hideHairline()
    {
        let navigationBarImageView = hairlineImageViewInToolbar(self)?.hidden = true
    }

    func showHairline()
    {
        let navigationBarImageView = hairlineImageViewInToolbar(self)?.hidden = false
    }

    private func hairlineImageViewInToolbar(view: UIView) -> UIImageView?
    {
        if let imageView = view as? UIImageView where imageView.bounds.height <= 1
        {
            return imageView
        }

        for subview: UIView in view.subviews
        {
            if let imageView = hairlineImageViewInToolbar(subview)
            {
                return imageView
            }
        }

        return nil
    }

}

Ответ 11

Swift 4//для скрытия навигационной панели тени линии

navigationController?.navigationBar.shadowImage = UIImage()

Ответ 12

Я использую расширение UINavigationBar, которое позволяет мне скрывать/показывать эту тень с помощью API UIAppearance или выбирать, какая панель навигации должна скрывать/показывать эту тень с помощью раскадровки (или исходного кода). Вот расширение:

import UIKit

private var flatAssociatedObjectKey: UInt8 = 0

/*
  An extension that adds a "flat" field to UINavigationBar. This flag, when
  enabled, removes the shadow under the navigation bar.
 */
@IBDesignable extension UINavigationBar {
    @IBInspectable var flat: Bool {
        get {
            guard let obj = objc_getAssociatedObject(self, &flatAssociatedObjectKey) as? NSNumber else {
                return false
            }
            return obj.boolValue;
        }

        set {
            if (newValue) {
                let void = UIImage()
                setBackgroundImage(void, forBarPosition: .Any, barMetrics: .Default)
                shadowImage = void
            } else {
                setBackgroundImage(nil, forBarPosition: .Any, barMetrics: .Default)
                shadowImage = nil
            }
            objc_setAssociatedObject(self, &flatAssociatedObjectKey, NSNumber(bool: newValue),
                    objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
}

Теперь, чтобы отключить тень на всех навигационных панелях, вы должны использовать:

UINavigationBar.appearance().flat = true

Или вы можете включить/отключить это поведение с помощью раскадровки:

Раскрутка панели навигации

Ответ 13

Может также быть скрыт от раскадровки (работает на Xcode 10.1)

Добавив атрибут времени выполнения: hidesShadow - Boolean - True

enter image description here

Ответ 14

Swift 4 проверено решение одной линии

В Viewdidload() задайте значение по умолчанию для пользовательского контроллера Navigation для ключа "hidesShadow"

override func viewDidLoad() {
    super.viewDidLoad()

    self.navigationController?.navigationBar.setValue(true, forKey: "hidesShadow")

}

Ответ 15

Начиная с iOS 13 есть системный API для установки или удаления тени.

UIKit использует shadowImage и свойство shadowColor для определения внешнего вида тени. Если shadowImage равно nil, на панели отображается тень по умолчанию, окрашенная в соответствии со значением в свойстве shadowColor. Если shadowColor равен нулю или содержит цвет clearColor, на панели не отображается тень.

    let appearance = UINavigationBarAppearance()
    appearance.shadowImage = nil
    appearance.shadowColor = nil
    navigationController.navigationBar.standardAppearance = appearance

Ответ 16

Другой вариант, если вы хотите сохранить прозрачность и не хотите создавать подклассы для каждого UINavigationController в вашем приложении:

#import <objc/runtime.h>

@implementation UINavigationController (NoShadow)

+ (void)load {
    Method original = class_getInstanceMethod(self, @selector(viewWillAppear:));
    Method swizzled = class_getInstanceMethod(self, @selector(swizzled_viewWillAppear:));
    method_exchangeImplementations(original, swizzled);
}

+ (UIImageView *)findHairlineImageViewUnder:(UIView *)view {
    if ([view isKindOfClass:UIImageView.class] && view.bounds.size.height <= 1.0) {
        return (UIImageView *)view;
    }

    for (UIView *subview in view.subviews) {
        UIImageView *imageView = [self findHairlineImageViewUnder:subview];
        if (imageView) {
            return imageView;
        }
    }

    return nil;
}

- (void)swizzled_viewWillAppear:(BOOL)animated {
    UIImageView *shadow = [UINavigationController findHairlineImageViewUnder:self.navigationBar];
    shadow.hidden = YES;

    [self swizzled_viewWillAppear:animated];
}

@end

Ответ 17

Swift положил это

UINavigationBar.appearance().setBackgroundImage(UIImage(), forBarPosition: .Any, barMetrics: .Default)
UINavigationBar.appearance().shadowImage = UIImage()

в

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool

Ответ 18

Slightly Swift Solution 
func setGlobalAppearanceCharacteristics () {
    let navigationBarAppearace = UINavigationBar.appearance()
    navigationBarAppearace.tintColor = UIColor.white
    navigationBarAppearace.barTintColor = UIColor.blue
    navigationBarAppearace.setBackgroundImage(UIImage(), for: UIBarMetrics.default)
    navigationBarAppearace.shadowImage = UIImage()

}

Ответ 19

Решение в Swift 4.2:

private func removeHairlineFromNavbar() {
    UINavigationBar.appearance().setBackgroundImage(
        UIImage(),
        for: .any,
        barMetrics: .default)
    UINavigationBar.appearance().shadowImage = UIImage()
}

Просто поместите эту функцию в первый Viewcontroller и вызовите ее в viewdidload

Ответ 20

В iOS8, если вы установите UINavigationBar.barStyle на .Black, вы можете установить фоновый фон в виде обычного цвета без рамки.

В Swift:

UINavigationBar.appearance().translucent = false
UINavigationBar.appearance().barStyle = UIBarStyle.Black
UINavigationBar.appearance().barTintColor = UIColor.redColor()

Ответ 21

Здесь очень простое решение:

self.navigationController.navigationBar.clipsToBounds = YES;

Ответ 22

Проблема с установкой фонового изображения заключается в удалении размытия. Вы можете удалить его, не устанавливая фоновое изображение. См. Мой ответ здесь.

Ответ 23

Вы должны добавить представление к нижней части UISearchBar

let rect = searchController.searchBar.frame;
let lineView : UIView = UIView.init(frame: CGRect.init(x: 0, y: rect.size.height-1, width: rect.size.width, height: 1))
lineView.backgroundColor = UIColor.init(hexString: "8CC73E")
searchController.searchBar.addSubview(lineView)

Ответ 24

Я знаю, что это старый поток, но я нашел решение, которое работает очень хорошо:

Подкласс UINavigationBar. В вашем подклассе UINavigationBar переопределение didAddSubview со следующим кодом:

- (void)didAddSubview:(UIView *)subview
{
    [super didAddSubview:subview];

    if ([subview isKindOfClass:[UIImageView class]]) {
        [subview setClipsToBounds:YES];
    }
}

Ответ 25

Я только что создал расширение для этого... Извините за форматирование (это мой первый ответ).

Использование:

  override func viewDidLoad() {
    super.viewDidLoad()
    self.navigationController?.hideShadow = true
}

Расширение:

 UINavigationController.swift
//  Created by Ricardo López Rey on 16/7/15.

import Foundation


struct UINavigationControllerExtension {
    static var hideShadowKey : String = "HideShadow"
static let backColor = UIColor(red: 247/255, green: 247/255, blue: 248/255, alpha: 1.0)
}

extension UINavigationController {

    var hideShadow : Bool {
        get {
            if let ret =  objc_getAssociatedObject(self, &UINavigationControllerExtension.hideShadowKey) as? Bool {
                return ret
            } else {
                return false
            }


        }
        set {
            objc_setAssociatedObject(self,&UINavigationControllerExtension.hideShadowKey,newValue, objc_AssociationPolicy(OBJC_ASSOCIATION_RETAIN_NONATOMIC))

            if newValue {


            self.navigationBar.setBackgroundImage(solidImage(UINavigationControllerExtension.backColor), forBarMetrics: UIBarMetrics.Default)

                self.navigationBar.shadowImage = solidImage(UIColor.clearColor())
            } else {
                self.navigationBar.setBackgroundImage(nil, forBarMetrics: UIBarMetrics.Default)
            }
        }
    }

    private func solidImage(color: UIColor, size: CGSize = CGSize(width: 1,height: 1)) -> UIImage {
        var rect = CGRectMake(0, 0, size.width, size.height)
        UIGraphicsBeginImageContextWithOptions(size, false, 0)
        color.setFill()
        UIRectFill(rect)
        var image: UIImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return image
    }


}

Ответ 26

-(void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];

    UIImage *emptyImage = [UIImage new];
    self.navigationController.navigationBar.shadowImage = emptyImage;
    [self.navigationController.navigationBar setBackgroundImage:emptyImage forBarMetrics:UIBarMetricsDefault];
}

Ответ 27

Внутри AppDelegate это глобально изменило формат NavBar:

 func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {

    UINavigationBar.appearance().setBackgroundImage(UIImage(), forBarPosition: UIBarPosition.Any, barMetrics: UIBarMetrics.Default)
    UINavigationBar.appearance().shadowImage = UIImage()
    UINavigationBar.appearance().tintColor = UIColor.whiteColor()
    UINavigationBar.appearance().barTintColor = UIColor.redColor()
    UINavigationBar.appearance().translucent = false
    UINavigationBar.appearance().clipsToBounds = false
    UINavigationBar.appearance().backgroundColor = UIColor.redColor()
    UINavigationBar.appearance().titleTextAttributes = [NSFontAttributeName : (UIFont(name: "FONT NAME", size: 18))!, NSForegroundColorAttributeName: UIColor.whiteColor()] }

Не удалось реализовать что-то другое на конкретном VC, но это поможет 90% людей

Ответ 28

Для пользователей iOS 9 это сработало для меня. просто добавьте это:

UINavigationBar.appearance().shadowImage = UIImage()

Ответ 29

Цель C Ответ на вопрос выше

//удаление строки навигации 1px

[[UINavigationBar appearance] setBackgroundImage:[[UIImage alloc]init] forBarMetrics:UIBarMetricsDefault];
[[UINavigationBar appearance] setShadowImage:[[UIImage alloc] init]];
[[UINavigationBar appearance] setTranslucent:NO];
[[UINavigationBar appearance] setTintColor:[UIColor yourColor]];

Ответ 30

pxpgraphics для Swift 3.0.

import Foundation
import UIKit

extension UINavigationBar {

  func hideBottomHairline() {
    let navigationBarImageView = hairlineImageViewInNavigationBar(view: self)
    navigationBarImageView!.isHidden = true
  }

  func showBottomHairline() {
    let navigationBarImageView = hairlineImageViewInNavigationBar(view: self)
    navigationBarImageView!.isHidden = false
  }

  private func hairlineImageViewInNavigationBar(view: UIView) -> UIImageView? {
    if view is UIImageView && view.bounds.height <= 1.0 {
      return (view as! UIImageView)
    }

    let subviews = (view.subviews as [UIView])
    for subview: UIView in subviews {
      if let imageView: UIImageView = hairlineImageViewInNavigationBar(view: subview) {
        return imageView
      }
    }
    return nil
  }
}

extension UIToolbar {

  func hideHairline() {
    let navigationBarImageView = hairlineImageViewInToolbar(view: self)
    navigationBarImageView!.isHidden = true
  }

  func showHairline() {
    let navigationBarImageView = hairlineImageViewInToolbar(view: self)
    navigationBarImageView!.isHidden = false
  }

  private func hairlineImageViewInToolbar(view: UIView) -> UIImageView? {
    if view is UIImageView && view.bounds.height <= 1.0 {
      return (view as! UIImageView)
    }

    let subviews = (view.subviews as [UIView])
    for subview: UIView in subviews {
      if let imageView: UIImageView = hairlineImageViewInToolbar(view: subview) {
        return imageView
      }
    }
    return nil
  }
}