【问题标题】:UITableView goes under translucent Navigation BarUITableView 在半透明的导航栏下
【发布时间】:2014-08-19 13:37:26
【问题描述】:

我正在尝试在 IOS 7 应用程序中使用透明导航栏。我的应用程序中有一个全屏图像。我在该图像上也有一个 UITableView 。当我使用下面的代码时,图像适合我想要的屏幕,但 UITableView 位于导航栏下方。

viewDidLoad

我用

self.navigationController.navigationBar.shadowImage = [UIImage new];
self.navigationController.navigationBar.translucent = YES;
self.navigationController.view.backgroundColor = [UIColor clearColor];

当我更改为 self.navigationController.navigationBar.translucent = NO; 时没问题,但我在导航栏上失去了透明度。

【问题讨论】:

    标签: ios objective-c uitableview uinavigationbar


    【解决方案1】:

    您可以设置 tableView 的 contentInsets,使其最初位于导航栏下方,但会在其后面滚动(内容会重叠)

    self.tableView.contentInset = UIEdgeInsetsMake(44,0,0,0);
    

    或者你可以偏移表格视图的框架。然后滚动的内容会在导航栏下方被截断(也不太好看)

    【讨论】:

    • 这在第一次 viewdidload 时很有帮助,但是当我按下表格单元格并转到下一个视图然后返回此视图时,tableview 再次下降,超出预期。我的意思是它下降了 88 像素..
    • 这不应该发生。您是否正在调整 viewWill(Did)Appear 中可能导致该行为的任何内容?如果没有,我想您使用了框架解决方案,并且由于某种原因,第二次正确设置了 contentInsets。因此,将它们再次覆盖为 UIEdgeInsetsZero 可能会有所帮助。
    • 我只在 viewDidLoad 中设置您的设置。我还没有实现任何其他出现或加载方法。我的下一个视图是不透明的,不是半透明的。当我去它并回来时,viewDidLoad 和你的代码没有被调用,但它仍然下降然后正常。
    • 尝试在 viewDidAppear 中记录 contentInsets 和 frame 以了解那里发生了什么。然后,您应该更深入地了解需要调整的内容。
    • 一定要设置scrollIndicatorInsets!
    【解决方案2】:

    我的案例对此有所帮助(Bill Chan 代码的修改版):

    Objective C 版本:

    - (void)viewDidLayoutSubviews
    {
        [super viewDidLayoutSubviews];   
        CGRect rect = self.navigationController.navigationBar.frame;
        float y = rect.size.height + rect.origin.y;
        self.tableView.contentInset = UIEdgeInsetsMake(y, 0, 0, 0);
    }
    

    关键是必须将表格向下推到导航栏的高度(rect.size.height)加上状态栏的高度(rect.origin.y);

    Swift 版本(也兼容 Swift 2):

    override func viewDidLayoutSubviews() {
        if let rect = self.navigationController?.navigationBar.frame {
            let y = rect.size.height + rect.origin.y
            self.tableView.contentInset = UIEdgeInsetsMake( y, 0, 0, 0)
        }
    }
    

    【讨论】:

    • 我刚刚实现了一个完全相同的解决方案。看我的回答
    • y 应该用 "let" 定义,因为它不会被变异
    • 您还应该考虑添加 self.tableView.scrollIndicatorInsets = UIEdgeInsetsMake(y, 0, 0, 0) 以使滚动不会显示在导航栏下方
    【解决方案3】:

    我在 iOS 9 上遇到了类似的问题。当我第一次打开 viewController 时,tableView 位于顶部栏下方。然后滚动 tableView 后一切正常。

    1. 选择您的视图控制器
    2. 点击“属性检查器”标签
    3. 取消选中“在顶部栏下”

    【讨论】:

    • 我已添加 [self.view setNeedsLayout]; [self.view layoutIfNeeded];在 viewWillAppear() 中并按上述方式禁用。这对我有用。
    • 我已经做了和你一样的事情,但对我来说,如果你有任何其他解决方案,请告诉我,因为我已经花了几个小时。谢谢
    • 你拯救了我的一天)
    • 这就是我想要的。谢谢!
    【解决方案4】:

    将tableview的y位置设置为导航栏的高度加上状态栏的高度(设为height

      height = 64; // height of navigation bar = 44(In portait), height of status bar = 20
      tableView.frame = CGRectMake(tableView.frame.origin.x, height , tableView.frame.size.width, tableView.frame.size.height);
    

    如果您使用自动布局,只需更改更新 tableView 顶部约束而不是更改框架。

    并且还自动将 viewControllerAdjustsScrollViewInsets 更改为 NO

    self.automaticallyAdjustsScrollViewInsets =  NO;
    

    如果您支持不同的方向更新 frame 和 contentInset 为 (52),因为横向模式下的导航栏高度为 32。

    检查这个Sample

    【讨论】:

    • 我这样做了,但是当我从另一个视图呈现 ViewController 时。导航栏闪烁为白色。截图:j.airkrft.com/XBOA
    • @JordanBrown 我没有得到截图,链接无效。
    【解决方案5】:

    这在 iOS8 中同时适用于横向模式和纵向模式:

    - (void)viewDidLayoutSubviews
    {
      [super viewDidLayoutSubviews];
    
      CGRect rect = self.navigationController.navigationBar.frame;
    
      float y = -rect.origin.y;
    
      self.tableView.contentInset = UIEdgeInsetsMake(y ,0,0,0);
    }
    

    【讨论】:

      【解决方案6】:

      最好不要硬编码 Inset 值,因为它可能基于设备的方向。

      代码:

      func setTableViewContentInset() {
      
          let contentInsetHeight = topLayoutGuide.length
          let contentInset = UIEdgeInsetsMake(contentInsetHeight, 0, 0, 0)
      
          tableView.contentInset = contentInset
          tableView.scrollIndicatorInsets = contentInset
      }
      
      func scrollToTop() {
      
          if tableView.indexPathsForVisibleRows?.count > 0 {
      
              let topIndexPath = NSIndexPath(forRow: 0, inSection: 0)
      
              tableView.scrollToRowAtIndexPath(topIndexPath, atScrollPosition: .Top, animated: false)
          }
      }
      
      func scrollToTopOfVisibleCells() {
      
          if let visibleIndexPaths = tableView.indexPathsForVisibleRows where tableView.indexPathsForVisibleRows?.count > 0 {
      
              let topMostVisibleIndexPath = visibleIndexPaths[0]
      
              tableView.scrollToRowAtIndexPath(topMostVisibleIndexPath, atScrollPosition: .Top, animated: false)
      
          }        
      }
      
      //MARK: Load Views
      override func viewDidLoad() {
          super.viewDidLoad()
      
          setTableViewContentInset()
      }
      
      override func viewDidAppear(animated: Bool) {
          super.viewDidAppear(animated)
      
          scrollToTop()
      }
      
      //MARK: Trait collection change
      override func traitCollectionDidChange(previousTraitCollection: UITraitCollection?) {
          super.traitCollectionDidChange(previousTraitCollection)
      
          setTableViewContentInset()
          scrollToTopOfVisibleCells()
      }
      

      【讨论】:

      • 赞成,因为您是唯一提到 scrollIndicatorInsets 的答案,这是必须的
      【解决方案7】:

      引入魔法常数的解决方案在大多数情况下都无法扩展。例如,如果下一代 iPhone 引入了不同的导航栏高度,我们将不得不更新我们的代码。

      幸运的是,Apple 为我们提供了解决此问题的更简洁的方法,例如 topLayoutGuide

      topLayoutGuide 属性在视图控制器启动时发挥作用 最前面的屏幕。它表示最高垂直范围 您不希望出现在半透明或 透明的 UIKit 栏(例如状态栏或导航栏)

      您可以通过以下代码 sn-p 以编程方式实现(同样可以通过 IB 实现):

      override func viewDidLoad() {
        super.viewDidLoad()
      
        automaticallyAdjustsScrollViewInsets = false
        tableView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
          tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
          tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
          tableView.topAnchor.constraint(equalTo: 
             topLayoutGuide.bottomAnchor),
          tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
        ])
      }
      

      注意: topLayoutGuide 在 iOS 11 中已弃用,我们应该改用 UIView 的 safeAreaLayoutGuide 属性。

      【讨论】:

        【解决方案8】:

        简介

        我是 iOS 开发和 Stack Overflow 的新手,如果我的帖子不完美,请见谅。

        我也遇到了这个问题,当我为我的 UITableView 使用内容插图时,它运行良好在第一次加载时,或者从我的其他标签访问它时;但是,如果我导航回视图,它将具有额外的“填充”。我想出了一个解决方法,这样我的 UITableView 每次都会正确放置。

        问题

        当您第一次加载 UITableView 或选项卡时,它需要插图才能正确启动导航栏下方的表格,但是当您向后导航时,它不需要插图,因为出于某种原因,它会正确计算UITableView 的位置。这就是为什么您可以获得额外的填充。

        解决方案

        解决方案涉及使用布尔值来确定您是否已导航离开,以便它可以正确确定是否需要插入内容。

        -(void)viewDidLoad 中,我设置了hasNavigatedFurther = NO。那么:

        -(void)viewWillAppear:(BOOL)animated {
            [super viewWillAppear:animated];
            if (!hasNavigatedFurther) {
                self.tableView.contentInset = UIEdgeInsetsMake(64, 0, 0, 0);
            } else {
                self.tableView.contentInset = UIEdgeInsetsZero;
                //In order to allow visiting between tabs and retaining desired look
                hasNavigatedFurther = NO;
            }
        }
        

        为了完成这项工作,您需要在将另一个视图推送到导航堆栈的代码之前设置hasNavigatedFurther = YES

        -(void)btnTouched:(id)sender {
            hasNavigatedFurther = YES;
            NextViewController* nvc = [NextViewController new];
            [self.navigationController pushViewController:nvc animated:YES];
        }
        

        【讨论】:

        • 你可以用这个解决方案代替你介绍的,在你的viewDidLoad中添加:edgesForExtendedLayout = [.bottom, .left, .right]
        【解决方案9】:

        我想出了以下解决方案,它在第一次导航到视图控制器时,将表格视图的contentInset 调整为导航栏的高度,同时考虑到顶部单元格可能具有的任何填充。在将另一个视图控制器推入堆栈后返回此视图控制器时,我将contentInset重新调整为UIEdgeInsetsZero

        - (void)viewWillAppear:(BOOL)animated {
            [super viewWillAppear:animated];
            [self adjustEdgeInsetsForTableView];
        }
        
        - (void)adjustEdgeInsetsForTableView {
            if(self.isMovingToParentViewController) {
                self.tableViewForm.contentInset = UIEdgeInsetsMake(self.navigationController.navigationBar.frame.size.height + padding, 0, 0, 0);
            } else {
                self.tableViewForm.contentInset = UIEdgeInsetsZero;
            }
        }
        

        【讨论】:

          【解决方案10】:

          我结合了@Adam Farrell 和@Tash Pemhiwa 的解决方案,最后下面的代码对我有用:

          - (void)viewWillAppear:(BOOL)animated
          {
              [super viewWillAppear:animated];
          
              [self adjustEdgeInsetsForTableView];
          }
          
          
          
          - (void)adjustEdgeInsetsForTableView
          {
              if(self.isMovingToParentViewController) {
                  self.tableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0);
              } else {
                  self.tableView.contentInset = UIEdgeInsetsMake(64, 0, 0, 0);
              }
          }
          

          希望这能帮助那些在这种奇怪的 UI 行为上浪费几个小时的人。

          【讨论】:

            【解决方案11】:

            将表格视图限制在导航栏的底部。表格视图会自动偏移 44,但是在代码中我们可以这样做:

            tableView.contentInset = UIEdgeInsets(top: -44, left: 0, bottom: 0, right: 0)
            

            栏是透明的,没有颜色,但表格视图根本不重叠。请注意,尽管导航栏是透明的,但“Hook”一词还是被截断了。这只对您将表格视图顶部边缘从导航栏中限制为 0 有效。从顶视图看不是 0。

            【讨论】:

              【解决方案12】:

              你只需要这个:

              assert(tableView.contentInsetAdjustmentBehavior == .automatic)
              

              从 iOS 11 开始,不需要做丑陋的魔法常数胡子

              我什至不需要将 contentInsetAdjustmentBehavior 设置为 .none 修复导航栏重叠。

              .automatic
              

              自动工作

              【讨论】:

              • 根据文档automatic默认值。
              【解决方案13】:

              尝试使用 layoutguide 修复

              var constraints = [NSLayoutConstraint]()   
              let guide = view.safeAreaLayoutGuide
                          constraints.append(self.tableView.leadingAnchor.constraint(equalTo: guide.leadingAnchor))
                          constraints.append(self.tableView.trailingAnchor.constraint(equalTo: guide.trailingAnchor))
                          constraints.append(self.tableView.topAnchor.constraint(equalTo: guide.topAnchor))
                          constraints.append(self.tableView.bottomAnchor.constraint(equalTo: guide.bottomAnchor))
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2017-07-16
                相关资源
                最近更新 更多