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




objective-c swift (24)

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

我如何刪除UITableViewCell分隔邊距?


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

使用下面的代碼片段,避免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];
    }
}

大多數答案顯示分隔符插入和佈局邊距是通過各種方法(例如, 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];

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

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

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


至於什麼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];
        }
}

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

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

2。

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

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


經過多次調查......

這是完全控制這些東西的唯一方法(我可以找到)

要完全控制每個單元格上的分隔符插頁和佈局頁邊距。 在willDisplayCell方法中執行此UITableviewDelegate

func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
    cell.layoutMargins = UIEdgeInsetsZero
    cell.contentView.layoutMargins = UIEdgeInsetsMake(0, 10, 0, 10)
    cell.separatorInset = UIEdgeInsetsMake(0, 0, 0, 0)
}

單元對象控制分​​隔符, contentView控制其他所有內容。 如果您的分隔符插入空格顯示為意想不到的顏色,則應解決此問題:

cell.backgroundColor = cell.contentView.backgroundColor

我這樣做是為了工作:

tableView.separatorInset = UIEdgeInsetsZero;
tableView.layoutMargins = UIEdgeInsetsZero;
cell.layoutMargins = UIEdgeInsetsZero;

在iOS8中:

將此添加到我的UITableViewCell子類:

- (UIEdgeInsets)layoutMargins {
    return UIEdgeInsetsZero;
}

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

[editCell setSeparatorInset:UIEdgeInsetsZero];

為我工作。


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

override func awakeFromNib() {
    super.awakeFromNib()

    self.layoutMargins = UIEdgeInsetsZero
    self.separatorInset = UIEdgeInsetsZero
}

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

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

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


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

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

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

該屬性名為preservesSuperviewLayoutMargins ,將其設置為NO將允許單元格的layoutMargin設置覆蓋TableView上設置的任何layoutMargin 。 它既節省時間( 您不必修改表視圖的設置 ),並且更簡潔。 詳細解釋請參考Mike Abdullah的答案。

注意:接下來是一個乾淨的實施細胞級別的保證金設置 ,如邁克阿卜杜拉的答案中所表達的。 設置你的單元格的蜜餞SuperviewLayoutMargins = NO將確保你的表格視圖不會覆蓋單元格設置。 如果您確實希望整個表格視圖具有一致的邊距,請相應地調整您的代碼。

設置您的單元格邊距:

-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Remove seperator inset
    if ([cell respondsToSelector:@selector(setSeparatorInset:)]) {
           [cell setSeparatorInset:UIEdgeInsetsZero];
    }

    // Prevent the cell from inheriting the Table View's margin settings
    if ([cell respondsToSelector:@selector(setPreservesSuperviewLayoutMargins:)]) {
        [cell setPreservesSuperviewLayoutMargins:NO];
    }

    // Explictly set your cell's layout margins
    if ([cell respondsToSelector:@selector(setLayoutMargins:)]) {
        [cell setLayoutMargins:UIEdgeInsetsZero];
    }
}

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

如果全部失敗,您可能會蠻力強制您的表視圖頁邊距:

-(void)viewDidLayoutSubviews
{
    [super viewDidLayoutSubviews];

    // Force your tableview margins (this may be a bad idea)
    if ([self.tableView respondsToSelector:@selector(setSeparatorInset:)]) {
        [self.tableView setSeparatorInset:UIEdgeInsetsZero];
    }

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

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

編輯: Mohamed Saleh讓我注意到iOS 9中可能發生的變化。如果您想自定義cellLayoutMarginsFollowReadableWidth或頁邊距,您可能需要將Table View的cellLayoutMarginsFollowReadableWidthNO 。 你的里程可能會有所不同,這是沒有記錄得很好。

此屬性僅存在於iOS 9中,因此請務必在設置前進行檢查。

if([myTableView respondsToSelector:@selector(setCellLayoutMarginsFollowReadableWidth:)])
{
    myTableView.cellLayoutMarginsFollowReadableWidth = NO;
} 

(上面的代碼從iOS 8 UITableView分隔符插入0不工作

編輯:這是一個純粹的界面生成器方法:

注意:iOS 11更改並簡化了大部分此類行為,即將進行更新...


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中為我工作的代碼:

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

我相信這是我在這裡問的同一個問題: 在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是否先存在。


讓我們花點時間在盲目充電之前了解問題,然後嘗試解決問題。

在調試器中快速瀏覽會告訴你分隔線是UITableViewCell子視圖。 看起來單元本身對這些線路的佈局承擔了相當大的責任。

iOS 8引入了佈局邊距的概念。 默認情況下,視圖的佈局邊距在所有方面都是8pt ,並且從祖先視圖繼承

最好的情況是,在佈局分隔線時, UITableViewCell選擇尊重左側佈局邊距,使用它來限制左側插入邊界。

把所有這些放在一起,為了達到真正為零的理想插圖,我們需要:

  • 將左側佈局邊距設置為0
  • 停止任何繼承的邊界覆蓋

像這樣,這是一個非常簡單的任務:

cell.layoutMargins = UIEdgeInsetsZero;
cell.preservesSuperviewLayoutMargins = NO;

注意事項:

  • 這個代碼只需要在每個單元格中運行一次(畢竟你只是配置單元格的屬性),並且當你選擇執行它時沒有什麼特別之處。 做什麼似乎對你最清潔。
  • 可悲的是,這兩個屬性都無法在Interface Builder中進行配置,但如果需要,您可以指定用戶定義的運行時屬性,用於preservesSuperviewLayoutMargins SupersviewLayoutMargins。
  • 很顯然,如果你的應用程序定位到早期的操作系統版本,你需要避免執行上面的代碼,直到運行在iOS 8或更高版本上。
  • 可以配置祖先視圖(如表格)以使其具有0左邊距,而不是設置preservesSuperviewLayoutMargins視圖邊距邊界,但由於您無法控制整個層次結構,因此這看起來更具錯誤傾向。
  • 將左邊距設置為0並保留其他值可能會稍微更清晰。
  • 如果你想在UITableView在普通樣式表底部繪製的“額外”分隔符上有一個0插入,我猜這需要在表級別指定相同的設置(還沒有嘗試過這個!)

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

- (UIEdgeInsets)layoutMargins
{
    return UIEdgeInsetsZero;
}

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


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

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

這在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;
    }

迅速:

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
}

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
        // ... Get the cell
        cell.separatorInset = UIEdgeInsetsMake(0.f, 20.f, 0.f, [UIScreen mainScreen].bounds.size.width - 20);
        // others
        return cell;
}

對於任何想要隱藏分隔符的特定單元格。


這是一個簡單的方法來全局刪除插入。

UITableViewCell+Extensions.swift

import UIKit

extension UITableViewCell {

  override public var layoutMargins: UIEdgeInsets {
    get { return UIEdgeInsetsZero }
    set { }
  }

}

AppDelegate application:didFinishLaunchingWithOptions: ::

  UITableViewCell.appearance().separatorInset = UIEdgeInsetsZero

您可能認為a)也只是在擴展中重寫separatorInset ,或者b)設置layoutMargins的外觀代理。 兩者都不會起作用。 即使separatorInset被指示為屬性,但試圖將其作為屬性(或方法)覆蓋時會生成編譯器錯誤。 並且為UITableViewCelllayoutMargins設置外觀代理(或者為此,也為UITableViewlayoutMarginsseparatorInset設置外觀代理)不起作用。


盧卡斯斯在斯威夫特的回答:

    // iOS 7:
    UITableView.appearance().separatorStyle = .SingleLine
    UITableView.appearance().separatorInset = UIEdgeInsetsZero
    UITableViewCell.appearance().separatorInset = UIEdgeInsetsZero

    // iOS 8:
    if UITableView.instancesRespondToSelector("setLayoutMargins:") {
        UITableView.appearance().layoutMargins = UIEdgeInsetsZero
        UITableViewCell.appearance().layoutMargins = UIEdgeInsetsZero
        UITableViewCell.appearance().preservesSuperviewLayoutMargins = false
    }

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

cell.layoutMargins = UIEdgeInsetsZero

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




ios8