UITableView goes under translucent Navigation Bar

前端 未结 14 987
一整个雨季
一整个雨季 2020-12-22 23:51

I am trying to have a transparent navigation bar in IOS 7 app. There is a full screen image in my application. I am also having a UITableView over that image. When I use the

相关标签:
14条回答
  • 2020-12-23 00:03

    Introduction

    I am new to both iOS development and Stack Overflow, so forgive me if my post isn't perfect.

    I also had this issue, and when I used the content insets for my UITableView it worked perfectly upon loading first, or when visiting it from my other tabs; however, if I navigated back to the view, it would have the extra "padding". I figured out a work around, so that my UITableView will be correctly placed every time.

    The Issue

    When you first load the UITableView, or tab to it, it needs the insets to correctly start the table below the navigation bar, but when you navigate back it does not need the insets, because for some reason, it correctly calculates for the placement of the UITableView. This is why you can get the extra padding.

    The Solution

    The solution involves using a boolean to determine whether you have navigated away, so that it can correctly determine whether it needs the content insets or not.

    In -(void)viewDidLoad I set hasNavigatedFurther = NO. Then:

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

    In order to make this work, you need to set hasNavigatedFurther = YES just before your code that pushes another view onto the navigation stack.

    -(void)btnTouched:(id)sender {
        hasNavigatedFurther = YES;
        NextViewController* nvc = [NextViewController new];
        [self.navigationController pushViewController:nvc animated:YES];
    }
    
    0 讨论(0)
  • 2020-12-23 00:07

    All you need is love this:

    assert(tableView.contentInsetAdjustmentBehavior == .automatic)
    

    there is zero need to do ugly magic constants beardance from iOS 11 onwards

    I did not even need to set contentInsetAdjustmentBehavior to .none to fix navbar underlapping.

    .automatic
    

    worked automagically

    0 讨论(0)
  • 2020-12-23 00:10

    This is working in both landscape mode and portrait mode in iOS8:

    - (void)viewDidLayoutSubviews
    {
      [super viewDidLayoutSubviews];
    
      CGRect rect = self.navigationController.navigationBar.frame;
    
      float y = -rect.origin.y;
    
      self.tableView.contentInset = UIEdgeInsetsMake(y ,0,0,0);
    }
    
    0 讨论(0)
  • 2020-12-23 00:14

    Set the y-position of tableview to height of the navigation bar plus height of the status bar (let it be height)

    i.e,

      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);
    

    If you are using autolayout just change the update the tableView top constraint instead of changing frame.

    and also change viewController automaticallyAdjustsScrollViewInsets to NO

    self.automaticallyAdjustsScrollViewInsets =  NO;
    

    If you are supporting different orientation update frame and contentInset to (52) because navigation bar height in landscape mode is 32.

    check this Sample

    0 讨论(0)
  • 2020-12-23 00:16

    You could set the contentInsets of your tableView so it is initially below the navigation bar, but would scroll behind it (content would be overlapping)

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

    Or you could offset the frame of the tableview. Then the scrolling content would be cut off below the navigation bar (which wouldn't look good, too)

    0 讨论(0)
  • 2020-12-23 00:16

    Better not to hardcode the Inset values as it might based on the orientation of the device.

    Code:

    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()
    }
    
    0 讨论(0)
提交回复
热议问题