iOS 8 UITableView分隔符插入0不起作用




objective-c swift (20)

Swift 2.0擴展

我只是想分享我從tableview單元格分隔符中刪除邊距的擴展。

extension UITableViewCell {
    func removeMargins() {

        if self.respondsToSelector("setSeparatorInset:") {
            self.separatorInset = UIEdgeInsetsZero
        }

        if self.respondsToSelector("setPreservesSuperviewLayoutMargins:") {
            self.preservesSuperviewLayoutMargins = false
        }

        if self.respondsToSelector("setLayoutMargins:") {
            self.layoutMargins = UIEdgeInsetsZero
        }
    }
}

在上下文中使用:

    let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! CustomCell

    cell.removeMargins()
    return cell

我有一個應用程序, UITableView的分隔符插入被設置為自定義值 - 右0 ,左0 。 這在iOS 7.x完美工作,但在iOS 8.0我發現分隔符插入在右側設置為默認值15 。 即使在xib文件中它設置為0 ,它仍然顯示不正確。

我如何刪除UITableViewCell分隔邊距?


Swift版本

iOS在單元格和表格視圖上引入了layoutMargins屬性。

該屬性在iOS 7.0中不可用,因此您需要確保在分配之前進行檢查!

但是,Apple已將一個名為preservesSuperviewLayoutMargins屬性添加到您的單元格,以防止它繼承您的表格視圖的邊距設置。 這樣,您的單元格可以獨立於表格視圖配置自己的邊距。 把它看作是一種重載。

該屬性名為preservesSuperviewLayoutMargins ,將其設置為NO可讓您使用自己的單元格的layoutMargin設置覆蓋Table View的layoutMargin設置。 它既節省時間( 您不必修改表視圖的設置 ),並且更簡潔。 詳細解釋請參考Mike Abdullah的答案。

注意:正如Mike Abdullah的回答所表達的那樣,這是適當的,不太混亂的實現; 設置你的單元格的蜜餞SuperViewLayoutMargins = NO將確保你的表視圖不會覆蓋單元格設置。

第一步 - 設置您的單元格邊距:

/*
    Tells the delegate that the table view is about to draw a cell for a particular row.
*/
override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell,
    forRowAtIndexPath indexPath: NSIndexPath)
{
    // Remove separator inset
    if cell.respondsToSelector("setSeparatorInset:") {
        cell.separatorInset = UIEdgeInsetsZero
    }

    // Prevent the cell from inheriting the Table View's margin settings
    if cell.respondsToSelector("setPreservesSuperviewLayoutMargins:") {
        cell.preservesSuperviewLayoutMargins = false
    }

    // Explictly set your cell's layout margins
    if cell.respondsToSelector("setLayoutMargins:") {
        cell.layoutMargins = UIEdgeInsetsZero
    }
}

將單元格上的保留SuperviewLayoutMargins屬性設置為NO 防止您的表視圖覆蓋您的單元格邊距。 在某些情況下,它似乎不能正常工作。

第二步 - 只有在全部失敗的情況下,您才可能暴力破解您的表格視圖邊距:

/*
    Called to notify the view controller that its view has just laid out its subviews.
*/
override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

    // Force your tableview margins (this may be a bad idea)
    if self.tableView.respondsToSelector("setSeparatorInset:") {
        self.tableView.separatorInset = UIEdgeInsetsZero
    }

    if self.tableView.respondsToSelector("setLayoutMargins:") {
        self.tableView.layoutMargins = UIEdgeInsetsZero
    }
}

...你去了! 這應該適用於iOS 8以及iOS 7。

注意:使用iOS 8.1和7.1進行測試,在我的情況下,我只需要使用此解釋的第一步。

只有在渲染單元格下方有未填充的單元格時,才需要執行第二步。 如果表格大於表格模型中的行數。 不做第二步會導致不同的分隔符偏移量。


Swift 3.0例子:

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    // removing seperator inset
    if cell.responds(to: #selector(setter: UITableViewCell.separatorInset)) {
        cell.separatorInset = .zero
    }
    // prevent the cell from inheriting the tableView's margin settings
    if cell.responds(to: #selector(setter: UIView.preservesSuperviewLayoutMargins)) {
        cell.preservesSuperviewLayoutMargins = false
    }
    // explicitly setting cell's layout margins
    if cell.responds(to: #selector(setter: UITableViewCell.layoutMargins)) {
        cell.layoutMargins = .zero
    }
}

Swift for iOS 8中的簡單解決方案,帶有自定義的UITableViewCell

override func awakeFromNib() {
    super.awakeFromNib()

    self.layoutMargins = UIEdgeInsetsZero
    self.separatorInset = UIEdgeInsetsZero
}

通過這種方式,您可以將layoutMarginseparatorInset設置為一次,而不是像以上大多數答案所建議的那樣針對每個willDisplayCell執行此操作。

如果你使用的是自定義的UITableViewCell這是正確的地方。 否則,你應該在tableView:cellForRowAtIndexPath做到這一點。

只是另一個提示:你不需要設置preservesSuperviewLayoutMargins = false因為默認值已經不是!


以比最投票答案更緊湊的方式...

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {

    if ([cell respondsToSelector:@selector(setSeparatorInset:)] && [cell respondsToSelector:@selector(setPreservesSuperviewLayoutMargins:)] && [cell respondsToSelector:@selector(setLayoutMargins:)]) {
         [cell setSeparatorInset:UIEdgeInsetsZero];
         [cell setPreservesSuperviewLayoutMargins:NO];
         [cell setLayoutMargins:UIEdgeInsetsZero];
    }

}


使用下面的代碼片段,避免IOS 8和7中的UITableView出現不必要的填充問題。

-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath{

    if ([tableView respondsToSelector:@selector(setSeparatorInset:)])
    {
        [tableView setSeparatorInset:UIEdgeInsetsZero];
    }

    if ([tableView respondsToSelector:@selector(setLayoutMargins:)])
    {
        [tableView setLayoutMargins:UIEdgeInsetsZero];
    }

    if ([cell respondsToSelector:@selector(setLayoutMargins:)])
    {
        [cell setLayoutMargins:UIEdgeInsetsZero];
    }
}

在Swift中它比較麻煩,因為layoutMargins是一個屬性,所以你必須重寫getter setter。

override var layoutMargins: UIEdgeInsets {
  get { return UIEdgeInsetsZero }
  set(newVal) {}
}

這將有效地使layoutMargins只讀,這在我的情況是好的。


在iOS8中:

將此添加到我的UITableViewCell子類:

- (UIEdgeInsets)layoutMargins {
    return UIEdgeInsetsZero;
}

這和“tableView:cellForRowAtIndexPath”或“tableView:willDisplayCell”:

[editCell setSeparatorInset:UIEdgeInsetsZero];

為我工作。


大多數答案顯示分隔符插入和佈局邊距是通過各種方法(例如, viewDidLayoutSubviewswillDisplayCell等)為單元格和表格設置的,但我發現只要將這些放置在cellForRowAtIndexPath效果很好。 看起來像最乾淨的方式。

// kill insets for iOS 8
if ([[UIDevice currentDevice].systemVersion floatValue] >= 8) {
    cell.preservesSuperviewLayoutMargins = NO;
    [cell setLayoutMargins:UIEdgeInsetsZero];
}
// iOS 7 and later
if ([cell respondsToSelector:@selector(setSeparatorInset:)])
    [cell setSeparatorInset:UIEdgeInsetsZero];

對我來說,簡單的線路完成了這項工作

cell.layoutMargins = UIEdgeInsetsZero

您可以在應用程序啟動時(在UI加載之前)使用UIAppearance一次,將其設置為默認的全局設置:

// iOS 7:
[[UITableView appearance] setSeparatorStyle:UITableViewCellSeparatorStyleSingleLine];
[[UITableView appearance] setSeparatorInset:UIEdgeInsetsZero];

[[UITableViewCell appearance] setSeparatorInset:UIEdgeInsetsZero];

// iOS 8:
if ([UITableView instancesRespondToSelector:@selector(setLayoutMargins:)]) {

    [[UITableView appearance] setLayoutMargins:UIEdgeInsetsZero];
    [[UITableViewCell appearance] setLayoutMargins:UIEdgeInsetsZero];
    [[UITableViewCell appearance] setPreservesSuperviewLayoutMargins:NO];

}

這樣,您可以保持UIViewController的代碼清潔,並且可以隨時覆蓋它。


我相信這是我在這裡問的同一個問題: 在iOS 8上移除SeparatorInset UITableView for XCode 6 iPhone模擬器

iOS 8中 ,所有從UIView繼承的對像都有一個新屬性。 因此,在iOS 7.x中設置SeparatorInset的解決方案將無法刪除您在iOS 8中的UITableView上看到的空白區域。

新的屬性被稱為“ layoutMargins ”。

@property(nonatomic) UIEdgeInsets layoutMargins
Description   The default spacing to use when laying out content in the view.
Availability  iOS (8.0 and later)
Declared In   UIView.h
Reference UIView Class Reference

解決方案:-

-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath{

    if ([tableView respondsToSelector:@selector(setSeparatorInset:)]) {
        [tableView setSeparatorInset:UIEdgeInsetsZero];
    }

    if ([tableView respondsToSelector:@selector(setLayoutMargins:)]) {
        [tableView setLayoutMargins:UIEdgeInsetsZero];
    }

   if ([cell respondsToSelector:@selector(setLayoutMargins:)]) {
        [cell setLayoutMargins:UIEdgeInsetsZero];
   }
}

如果你設置cell.layoutMargins = UIEdgeInsetsZero; 如果不檢查layoutMargins存在,應用程序將在iOS 7.x上崩潰。 所以,最好的方法是在setLayoutMargins:UIEdgeInsetsZero之前檢查layoutMargins是否先存在。


每當單元格滾動時(使用willDisplayCell ),我都會建議在cellForRowAtIndexPath:執行一次,而不是更新preservesSuperviewLayoutMarginslayoutMargins

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

    let cell = super.tableView(tableView, cellForRowAtIndexPath: indexPath)

    cell.preservesSuperviewLayoutMargins = false
    cell.layoutMargins = UIEdgeInsetsZero

    return cell

}

添加這個代碼片段,Swift中的簡單優雅適用於iOS8中的我:)

    // tableview single line
func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
    cell.preservesSuperviewLayoutMargins = false
    cell.layoutMargins = UIEdgeInsetsZero
}

精氨酸! 在你的Cell子類中進行這些操作後,

- (UIEdgeInsets)layoutMargins
{
    return UIEdgeInsetsZero;
}

或者設置cell.layoutMargins = UIEdgeInsetsZero; 為我修好了。


至於什麼cdstamper建議,而不是表視圖,在單元格的layoutSubview方法中添加下面幾行適用於我。

- (void)layoutSubviews 
{
    [super layoutSubviews];

    if ([self respondsToSelector:@selector(setSeparatorInset:)])
                [self setSeparatorInset:UIEdgeInsetsZero];

        if ([self respondsToSelector:@selector(setPreservesSuperviewLayoutMargins:)])
        {
            [self setPreservesSuperviewLayoutMargins:NO];;
        }

        if ([self respondsToSelector:@selector(setLayoutMargins:)]) 
        {
            [self setLayoutMargins:UIEdgeInsetsZero];
        }
}

迅速:

override func viewDidLoad() {
    super.viewDidLoad()

    if self.tableView.respondsToSelector("setSeparatorInset:") {
        self.tableView.separatorInset = UIEdgeInsetsZero
    }
    if self.tableView.respondsToSelector("setLayoutMargins:") {
        self.tableView.layoutMargins = UIEdgeInsetsZero
    }

    self.tableView.layoutIfNeeded()            // <--- this do the magic
}

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
     ...

    if cell.respondsToSelector("setSeparatorInset:") {
        cell.separatorInset = UIEdgeInsetsZero
    }
    if cell.respondsToSelector("setLayoutMargins:") {
        cell.layoutMargins = UIEdgeInsetsZero
    }

    return cell
}

這在iOS 8和iOS 9中完美適用於我。

對於OBJ-C

 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath  { 
        if ([tableView respondsToSelector:@selector(setSeparatorInset:)])
        {
            [tableView setSeparatorInset:UIEdgeInsetsZero];
        }

        if ([tableView respondsToSelector:@selector(setLayoutMargins:)])
        {
            [tableView setLayoutMargins:UIEdgeInsetsZero];
        }

        if ([cell respondsToSelector:@selector(setLayoutMargins:)])
        {
            [cell setLayoutMargins:UIEdgeInsetsZero];
        }
         return cell;
    }

這是在Swift中為我工作的代碼:

override func viewDidLoad() 
{
    super.viewDidLoad()
    ...
    if tableView.respondsToSelector("setSeparatorInset:") {
        tableView.separatorInset = UIEdgeInsetsZero
    }
}

func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell,forRowAtIndexPath indexPath: NSIndexPath)
{
    if cell.respondsToSelector("setSeparatorInset:") {
        cell.separatorInset.left = CGFloat(0.0)
    }
    if tableView.respondsToSelector("setLayoutMargins:") {
        tableView.layoutMargins = UIEdgeInsetsZero
    }
    if cell.respondsToSelector("setLayoutMargins:") {
        cell.layoutMargins.left = CGFloat(0.0)
    }
}

這對我來說是最清潔的(現在),因為所有單元格/ tableView邊緣/邊距調整都是在tableView:willDisplayCell:forRowAtIndexPath:方法中完成的,不需要在tableView:cellForRowAtIndexPath: tableView:willDisplayCell:forRowAtIndexPath:不必要的代碼。

順便說一句,我只是設置單元格的左邊的separatorInset / layoutMargins,因為在這種情況下,我不想搞亂我在單元格中設置的約束條件。

代碼更新到Swift 2.2:

 override func viewDidLoad() {
   super.viewDidLoad()       

    if tableView.respondsToSelector(Selector("setSeparatorInset:")) {
      tableView.separatorInset = UIEdgeInsetsZero
        }
    }

 override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell,forRowAtIndexPath indexPath: NSIndexPath) {
        if cell.respondsToSelector(Selector("setSeparatorInset:")) {
            cell.separatorInset.left = CGFloat(0.0)
        }
        if tableView.respondsToSelector(Selector("setLayoutMargins:")) {
            tableView.layoutMargins = UIEdgeInsetsZero
        }
        if cell.respondsToSelector(Selector("setLayoutMargins:")) {
            cell.layoutMargins.left = CGFloat(0.0)
        }
    }

這是我的解決方案。 這適用於自定義單元格子類,只需將它們添加到子類。

  1. - (UIEdgeInsets)layoutMargins {    
        return UIEdgeInsetsMake(0, 10, 0, 10);
    }
    

2。

self.separatorInset = UIEdgeInsetsMake(0, 10, 0, 10);

而且,您可以自定義分隔符的位置,而不要求設計師為您繪製一個便捷的方式..........





ios8