it-swarm.com.ru

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

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

Кто-нибудь знает, как избавиться или изменить цвет этой надоедливой маленькой планки?

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

enter image description here

397
Szymon Kuczur

Для этого вам нужно установить собственное теневое изображение. Но для отображения теневого изображения вам также необходимо установить собственное фоновое изображение, цитата из документации 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. Добавьте метод, который находит эту тень (hairline) 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 за оригинальную идею!

648
Serhii Yakovenko

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

Swift:

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

Цель C:

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

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

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

[[UINavigationBar appearance] setShadowImage:[[UIImage alloc] init]];
142
Rick Pastoor

Хотел добавить Swift версию ответа Сергея. Я создал 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
    }
}
60
pxpgraphics

Способ Swift сделать это:

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

UINavigationBar.appearance().shadowImage = UIImage()
58
OscarVGG

Простое решение в Swift

   let navigationBar = self.navigationController?.navigationBar
    navigationBar?.setBackgroundImage(UIImage(), forBarPosition: UIBarPosition.Any, barMetrics: UIBarMetrics.Default)
    navigationBar?.shadowImage = UIImage()
18
Jakub Průša

Изучив ответ от Serhil, я создал pod INavigationBar + Addition , который может легко скрыть линию волос.

#import "UINavigationBar+Addition.h"

- (void)viewDidLoad {
    [super viewDidLoad];

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

В 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)
13
smohn

решение 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
tf.alves

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

navigationController?.navigationBar.shadowImage = UIImage()
10
Faris Muhammed

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

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

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

Navigation Bar Storyboard

10
Alvivi

Swift 4 протестирован ОДНО ЛИНЕЙНОЕ РЕШЕНИЕ

В Viewdidload() Установить значение userdefault контроллера Navigation true для ключа "hidesShadow"

override func viewDidLoad() {
    super.viewDidLoad()

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

}
9
Sachin Rasane

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

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

enter image description here

7
Gagandeep Gambhir

Другой вариант, если вы хотите сохранить прозрачность и не хотите создавать подклассы для каждого 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
7
jhurliman

Свифт поставь это

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

в

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

Решение в Swift 4.2:

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

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

5
Mattk90
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()

}
5
James

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

В Свифте:

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

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

self.navigationController.navigationBar.clipsToBounds = YES;
3
user3344977

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

2
Leo Natan

Вы должны добавить представление в нижней части 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)
2
Socheat

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

UINavigationBar.appearance().shadowImage = UIImage()
1
Mariano Pardo

В 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% людей

1
David West

ответ 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
  }
}
1
Reza Shirazian

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

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

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

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

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

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

  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
    }


}
1
Ricardo LR

Вот способ сделать это без использования изображений, это единственный способ, который работал для меня:

self.navigationController.navigationBar.layer.shadowOpacity = 0;

К сожалению, вы должны сделать это для каждого файла, где вы хотите, чтобы строка не появлялась. Нет способа сделать это таким образом в appDelegate.

Edit:

Установка shadowColor в nil не требуется, это единственная строка, которая вам понадобится.

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

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

Цель 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]];
1
Vaibhav Gaikwad

В Swift мы делаем это так

Для любого контроллера представления:

navigationBar.shadowImage = UIImage()
setBackgroundImage(UIImage(), for: .default)

для всего приложения:

UINavigationBar.appearance().setBackgroundImage(UIImage(),barMetrics: .Default)
UINavigationBar.appearance().shadowImage = UIImage()
1
Karthik damodara

Привет, это работает для Swift 4.

    override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    self.navigationController?.navigationBar.shadowImage = UIImage()
    self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
    self.navigationController?.navigationBar.isTranslucent = false
}

вам нужно поместить это в viewDidLayoutSubviews вместо viewDidLoad

0
Kelvin Fok

Вот еще один вариант - я думаю, что это работает, только если вам не требуется прозрачность на панели навигации (я не сделал). Я просто добавил UIView высотой 1 пиксель в нижнюю часть панели навигации (1 пиксель под панелью навигации) того же цвета, что и моя панель навигации:

UIView *view = [[UIView alloc] init];
[view setBackgroundColor:self.navigationController.navigationBar.barTintColor];
[self.navigationController.navigationBar addSubview:view];
[view mas_makeConstraints:^(MASConstraintMaker *make) {
    make.height.equalTo(@(1.0f));
    make.leading.trailing.equalTo(self.navigationController.navigationBar);
    make.bottom.equalTo(self.navigationController.navigationBar).offset(1.0f);
}];

Я добавляю ограничения, используя масонство.

0
jwswart
[tabviewController.view setBackgroundColor:[UIColor blackColor]];

Сделал это для меня [UIColor blackColor] может быть вашим цветом фона, а tabviewController - вашим UITabBarController, если вы используете его!

0
Jeffrey Snijder

Бар в стиле черный сделал это для меня.

[[UINavigationBar appearance] setBarStyle:UIBarStyleBlack];

Все свойства, которые у меня есть (на всякий случай):

    [[UINavigationBar appearance] setBarTintColor:color];
    [[UINavigationBar appearance] setTranslucent:NO];
    [[UINavigationBar appearance] setShadowImage:[UIImage new]];
    [[UINavigationBar appearance] setBarStyle:UIBarStyleBlack];
0
user1122069

Хорошая короткая функция Swift для нахождения волосяного покрова в подпредставлениях:

 func findHairLineInImageViewUnder(view view: UIView) -> UIImageView? {
    if let hairLineView = view as? UIImageView where hairLineView.bounds.size.height <= 1.0 {
        return hairLineView
    }

    if let hairLineView = view.subviews.flatMap({self.findHairLineInImageViewUnder(view: $0)}).first {
      return hairLineView
    }

    return nil
}
0
Marijn

То, что сработало для меня и было самым простым, - это создать png (он должен быть размером один пиксель на один пиксель) с требуемым цветом, а затем установить для него backgroundImage и shadowImage:

let greenPixel = UIImage(named: "TheNameOfYourPng")
navigationBar.setBackgroundImage(greenPixel, forBarMetrics: UIBarMetrics.Default)
navigationBar.shadowImage = greenPixel
0
Gruntcakes

Мой подход:

UINavigationBar.appearance().setBackgroundImage(
            UIImage(),
            forBarPosition: .Any,
            barMetrics: .Default)
    var _width:CGFloat! = self.navigationController?.navigationBar.layer.frame.width
            var _height:CGFloat! = self.navigationController?.navigationBar.layer.frame.height
            var navBarBg = UIView(frame:CGRectMake(0, 0, _width, _height))
            //solid color for bg
            navBarBg.backgroundColor = UIColor.orangeColor()
            view.addSubview(navBarBg)
0
Maysam

В Xamarin Forms это сработало для меня. Просто добавьте это в AppDelegate.cs:

UINavigationBar.Appearance.ShadowImage = new UIImage();
0
Kelson Pereira

Я столкнулся с той же проблемой, и ни один из ответов не был действительно удовлетворительным. Вот мой взгляд на Swift3:

func hideNavigationBarLine() {
    navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
    navigationController?.navigationBar.shadowImage = UIImage()
}

Просто вызовите это изнутри viewDidLoad ().

0
easytarget

Это может звучать глупо, но эта линия роста появляется только тогда, когда цвет фона для представления viewController установлен на любой цвет, кроме белого. Я был шокирован, узнав этот факт.

Поэтому, если вы хотите, чтобы он исчез без особых проблем, просто установите цвет фона представления контроллера на WHITE COLOR.

0
Pavel Gurov