How to position UITableViewCell at bottom of screen?

前端 未结 14 586
旧时难觅i
旧时难觅i 2020-12-08 03:25

There are one to three UITableViewCells in a UITableViewView. Is there a way to always position the cell(s) at the bottom of screen after rel

相关标签:
14条回答
  • 2020-12-08 03:34

    You can set a header in your table view and make it tall enough to push the first cell down. Then set the contentOffset of your tableView accordingly. I don't think there is a quick built in way to do this though.

    0 讨论(0)
  • 2020-12-08 03:34
    if(indexPath.row!=CategoriesArray.count-1)  
    {    
        cell.hidden = YES;
    }
    
    return cell;
    
    0 讨论(0)
  • 2020-12-08 03:35

    Here is the Swift 3 version of the @Brennan accepted solution, tested and approved :)

    func updateContentInsetForTableView( tableView:UITableView,animated:Bool) {
    
        let lastRow = tableView.numberOfRows(inSection: 0)
        let lastIndex = lastRow > 0 ? lastRow - 1 : 0;
    
        let lastIndexPath = IndexPath(row: lastIndex, section: 9)
    
    
        let lastCellFrame = tableView.rectForRow(at: lastIndexPath)
        let topInset = max(tableView.frame.height - lastCellFrame.origin.y - lastCellFrame.height, 0)
    
        var contentInset = tableView.contentInset;
        contentInset.top = topInset;
    
        _ = UIViewAnimationOptions.beginFromCurrentState;
            UIView.animate(withDuration: 0.1, animations: { () -> Void in
    
        tableView.contentInset = contentInset;
       })
    
       } 
    
    0 讨论(0)
  • 2020-12-08 03:37
    func updateContentInsetForTableView( tableView:UITableView,animated:Bool) {
    
        let lastRow = tableView.numberOfRows(inSection: 0)
        let lastIndex = lastRow > 0 ? lastRow - 1 : 0;
    
        let lastIndexPath = IndexPath(row: lastIndex, section: 9)
    
        let lastCellFrame = tableView.rectForRow(at: lastIndexPath)
        let topInset = max(tableView.frame.height - lastCellFrame.origin.y - lastCellFrame.height, 0)
    
        var contentInset = tableView.contentInset;
        contentInset.top = topInset;
    
        _ = UIViewAnimationOptions.beginFromCurrentState;
        UIView.animate(withDuration: 0.1, animations: { () -> Void in
    
            tableView.contentInset = contentInset;
        })
    
    
        if self.commesnts.count > 0 {
            tableView.scrollToRow(at: IndexPath(item:self.commesnts.count-1, section: 0), at: .bottom, animated: true)
        }
    
    }
    

    I used @bkokot solution with little addition. It does two things

    1. Start showing cells from bottom of UITableView
    2. Scroll cells to bottom so that last inserted row become visible
    (just like chat)
    
    0 讨论(0)
  • 2020-12-08 03:43

    I didn't like empty-cell, contentInset or transform based solutions, instead I came up with other solution:

    UITableView's layout is private and subject to change if Apple desires, it's better to have full control thus making your code future-proof and more flexible. I switched to UICollectionView and implemented special layout based on UICollectionViewFlowLayout for that (Swift 3):

    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        // Do we need to stick cells to the bottom or not
        var shiftDownNeeded = false
    
        // Size of all cells without modifications
        let allContentSize = super.collectionViewContentSize()
    
        // If there are not enough cells to fill collection view vertically we shift them down
        let diff = self.collectionView!.bounds.size.height - allContentSize.height
        if Double(diff) > DBL_EPSILON {
            shiftDownNeeded = true
        }
    
        // Ask for common attributes
        let attributes = super.layoutAttributesForElements(in: rect)
    
        if let attributes = attributes {
            if shiftDownNeeded {
                for element in attributes {
                    let frame = element.frame;
                    // shift all the cells down by the difference of heights
                    element.frame = frame.offsetBy(dx: 0, dy: diff);
                }
            }
        }
    
        return attributes;
    }
    

    It works pretty well for my cases and, obviously, may be optimized by somehow caching content size height. Also, I'm not sure how will that perform without optimizations on big datasets, I didn't test that. I've put together sample project with demo: MDBottomSnappingCells.

    Here is Objective-C version:

    - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect;
    {
        // Do we need to stick cells to the bottom or not
        BOOL shiftDownNeeded = NO;
    
        // Size of all cells without modifications
        CGSize allContentSize = [super collectionViewContentSize];
    
        // If there are not enough cells to fill collection view vertically we shift them down
        CGFloat diff = self.collectionView.bounds.size.height - allContentSize.height;
        if(diff > DBL_EPSILON)
        {
            shiftDownNeeded = YES;
        }
    
        // Ask for common attributes
        NSArray *attributes = [super layoutAttributesForElementsInRect:rect];
        if(shiftDownNeeded)
        {
            for(UICollectionViewLayoutAttributes *element in attributes)
            {
                CGRect frame = element.frame;
                // shift all the cells down by the difference of heights
                element.frame = CGRectOffset(frame, 0, diff);
            }
        }
    
        return attributes;
    }
    
    0 讨论(0)
  • 2020-12-08 03:45

    The best way of doing this I found is to observe the content size of the tableview and adjust the inset if necessary. For example:

    static char kvoTableContentSizeContext = 0;
    
    - (void) viewWillAppear:(BOOL)animated
    {
        [_tableView addObserver:self forKeyPath:@"contentSize" options:0 context:&kvoTableContentSizeContext];
    }
    
    - (void) viewWillDisappear:(BOOL)animated
    {
        [_tableView removeObserver:self forKeyPath:@"contentSize"];
    }
    
    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
    {
        if (context == &kvoTableContentSizeContext) {
    
            CGFloat contentHeight = _tableView.contentSize.height;
            CGFloat tableHeight = _tableView.frame.size.height;
    
            if (contentHeight < tableHeight) {
    
                UIEdgeInsets insets = _tableView.contentInset;
    
                insets.top = tableHeight - contentHeight;
                _tableView.contentInset = insets;
    
            } else {
                _tableView.contentInset = UIEdgeInsetsZero;
            }
    
        } else {
            [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
        }
    }
    
    0 讨论(0)
提交回复
热议问题