Wstawka separatora UITableView iOS 8 nie działa

662

Mam aplikację, w której UITableViewwstawka separatora jest ustawiona na niestandardowe wartości - prawo 0, lewo 0. Działa to doskonale w iOS 7.x, ale iOS 8.0widzę, że wstawka separatora jest ustawiona na domyślną wartość 15po prawej stronie. Mimo że w plikach xib ustawiono na0 nadal wyświetla się niepoprawnie.

Jak usunąć UITableViewCellmarginesy separatora?

użytkownik3570727
źródło
Czy próbowałeś ustawić wstawkę na 0,001 zamiast 0? Pamiętam, że mam podobny problem, w którym wstawka krawędzi nie reaguje na 0, ale reaguje na 0,001 (lub coś podobnego małego).
freshking
Próbowałem tego i to też nie działało ..
user3570727,
4
Następnie sugeruję ustawienie koloru separatorów na [UIColor clearColor]i narysowanie własnych separatorów. W ten sposób jesteś znacznie bardziej elastyczny.
freshking
1
Nadal nie mogę uwierzyć, że nadal nie jest to jedna z UITableViewCellSeparatorStyledomyślnych wartości. Nawet zaakceptowana odpowiedź to naprawdę brudny hack.
Enrico Susatyo,

Odpowiedzi:

1071

iOS 8.0 wprowadza właściwość layoutMargins do komórek ORAZ widoków tabeli.

Ta właściwość nie jest dostępna w systemie iOS 7.0, dlatego musisz ją sprawdzić przed przypisaniem!

Łatwym rozwiązaniem jest podklasowanie komórki i zastąpienie właściwości marginesów układu, zgodnie z sugestią @ user3570727. Utracisz jednak zachowanie systemu, takie jak dziedziczenie marginesów z obszaru bezpiecznego, więc nie polecam poniższego rozwiązania:

(Cel C)

-(UIEdgeInsets)layoutMargins { 
     return UIEdgeInsetsZero // override any margins inc. safe area
}

(szybkie 4.2):

override var layoutMargins: UIEdgeInsets { get { return .zero } set { } }

Jeśli nie chcesz przesłonić właściwości lub musisz ustawić ją warunkowo, czytaj dalej.


Oprócz tej layoutMarginswłaściwości firma Apple dodała do komórki właściwość , która uniemożliwi dziedziczenie ustawień marginesów widoku tabeli. Po ustawieniu tej właściwości komórki mogą konfigurować własne marginesy niezależnie od widoku tabeli. Potraktuj to jako nadpisanie.

Ta właściwość jest wywoływana preservesSuperviewLayoutMargins, a jej ustawienie NOpozwoli na layoutMarginzastąpienie ustawienia komórki tym, co layoutMarginjest ustawione na TableView. Oba oszczędzają czas ( nie musisz modyfikować ustawień Widoku tabeli ) i są bardziej zwięzłe. Szczegółowe wyjaśnienie znajduje się w odpowiedzi Mike'a Abdullaha.

UWAGA: poniżej znajduje się czysta implementacja ustawienia marginesu na poziomie komórki , wyrażona w odpowiedzi Mike'a Abdullaha. Ustawienie komórki preservesSuperviewLayoutMargins=NOzapewni, że widok tabeli nie zastąpi ustawień komórki. Jeśli chcesz, aby cały widok tabeli miał spójne marginesy, odpowiednio dostosuj kod.

Skonfiguruj marginesy komórkowe:

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

Swift 4:

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    // Remove seperator inset
    if cell.responds(to: #selector(setter: UITableViewCell.separatorInset)) {
        cell.separatorInset = .zero
    }
    // Prevent the cell from inheriting the Table View's margin settings
    if cell.responds(to: #selector(setter: UITableViewCell.preservesSuperviewLayoutMargins)) {
        cell.preservesSuperviewLayoutMargins = false
    }
    // Explictly set your cell's layout margins
    if cell.responds(to: #selector(setter: UITableViewCell.layoutMargins)) {
        cell.layoutMargins = .zero
    }
}

Ustawienie preservesSuperviewLayoutMarginswłaściwości w komórce na NIE powinno uniemożliwić widok tabeli nadpisujący marginesy komórki. W niektórych przypadkach wydaje się, że nie działa poprawnie.

Jeśli wszystko zawiedzie, możesz brutalnie wymusić marginesy widoku tabeli:

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

Swift 4:

func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    // Force your tableview margins (this may be a bad idea)
    if tableView.responds(to: #selector(setter: UITableView.separatorInset)) {
        tableView.separatorInset = .zero
    }
    if tableView.responds(to: #selector(setter: UITableView.layoutMargins)) {
        tableView.layoutMargins = .zero
    }
}

... i proszę bardzo! To powinno działać na iOS 7 i 8.


EDIT: Mohamed Saleh zwrócił moją uwagę ewentualne zmiany w iOS 9. Być może trzeba ustawić Table View na cellLayoutMarginsFollowReadableWidthceluNO , jeśli chcesz dostosować wypustki lub marże. Twój przebieg może się różnić, nie jest to dobrze udokumentowane.

Ta właściwość istnieje tylko w iOS 9, więc sprawdź ją przed ustawieniem.

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

Swift 4:

if myTableView.responds(to: #selector(setter: self.cellLayoutMarginsFollowReadableWidth)) {
    myTableView.cellLayoutMarginsFollowReadableWidth = false
}

(powyższy kod z wstawki 0 separatora UITableView dla systemu iOS 8 nie działa )

EDYCJA: Oto czysta metoda Konstruktora interfejsów:

TableViewAttributesInspector TableViewCellSizeInspector

UWAGA: iOS 11 zmienia i upraszcza wiele z tego zachowania, nadchodzi aktualizacja ...

cdstamper
źródło
2
W przypadku widoków tabeli w UIPopoverController musiałem wykonać oba te elementy, jak pokazano powyżej, zamiast tylko w willDisplayCell.
Zhang
44
Odkryłem również, że pomimo całego powyższego kodu, który wciąż musiałem dodać cell.preservesSuperviewLayoutMargins = NOwedług sugestii @ bffmike lub po przewinięciu sposobu wyświetlania wstawek. (wtf ??)
nieorganiczny
Co jeśli chcemy ustawić margines tylko dla jednego rodzaju komórek w zgrupowanym tableView?
SAHM
Możesz spróbować ustawić go w willDisplayCell i sprawdzić, czy to faktycznie działa (masz uchwyt na komórce, więc powinno być trywialne). Jeśli nie, musimy zgłosić błąd. Marginesy układu specyficzne dla komórki powinny być możliwe, IMO.
cdstamper
2
Działa to dla mnie z dodaniem cell.preservesSuperviewLayoutMarginsw mojej metodzie źródła danych:- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
mts
257

Arg !!! Po rozegraniu jednej z tych czynności w Cellpodklasie:

- (UIEdgeInsets)layoutMargins
{
    return UIEdgeInsetsZero;
}

lub ustawienie cell.layoutMargins = UIEdgeInsetsZero;naprawione dla mnie.

użytkownik3570727
źródło
13
pierwsze rozwiązanie w tej odpowiedzi zadziałało dla mnie, drugie nie zadziałało.
spybart
5
Nie używaj po prostu cell.layoutMargins = UIEdgeInsetsZero; ponieważ nastąpi awaria w systemie iOS 7.x. Przed użyciem należy lepiej sprawdzić, czy selektor istnieje. Zobacz moje rozwiązanie poniżej.
Ricky,
3
Nie ustawia cell.layoutMargins ... To rozwiązanie działa świetnie, gdy masz już niestandardowe komórki.
Sjoerd Perfors
11
Będzie to działać dobrze w iOS 7, ponieważ metoda nie zostanie wywołana! Musisz także ustawić układ widoku tabeli Marginesy, bo inaczej to nie zadziała.
cdstamper
2
nadpisanie akcesorium działało dla mnie. ale wszystkie inne rozwiązania tego nie zrobiły. nawet konfiguracja separatorInsetw IB nie działała. występuje również problem z kolorami tła widoku tabeli. to jest naprawdę chore.
glasz
178

Poświęć chwilę na zrozumienie problemu, zanim zaczniesz ślepo ładować, aby spróbować go naprawić.

Szybkie przeczesywanie w debuggerze powie ci, że linie separatora są widokami podrzędnymi UITableViewCell . Wygląda na to, że sama komórka bierze znaczną odpowiedzialność za układ tych linii.

iOS 8 wprowadza pojęcie marginesów układu . Domyślnie marginesy układu widoku są 8ptze wszystkich stron i są dziedziczone z widoków przodka.

Jak najlepiej możemy powiedzieć, układając linię separatora, UITableViewCell decyduje się przestrzegać marginesu układu po lewej stronie, używając go do ograniczenia lewej wstawki.

Łącząc to wszystko, aby osiągnąć pożądany przedział naprawdę zerowy, musimy:

  • Ustaw lewy margines układu na 0
  • Zatrzymaj wszelkie odziedziczone marginesy zastępujące to

Mówiąc tak, jest to dość proste zadanie do osiągnięcia:

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

Ważne uwagi:

  • Ten kod wymaga tylko być uruchamiany tylko raz na komórkę (w końcu konfigurujesz właściwości komórki) i nie ma nic specjalnego, kiedy zdecydujesz się go wykonać. Rób to, co wydaje ci się najczystsze.
  • Niestety żadna właściwość nie jest dostępna do skonfigurowania w Konstruktorze interfejsów, ale w preservesSuperviewLayoutMarginsrazie potrzeby można określić zdefiniowany przez użytkownika atrybut środowiska wykonawczego .
  • Oczywiście, jeśli aplikacja jest kierowana również na wcześniejsze wersje systemu operacyjnego, musisz unikać wykonywania powyższego kodu, dopóki nie uruchomisz go w systemie iOS 8 i nowszych.
  • Zamiast ustawienia preservesSuperviewLayoutMargins, to można skonfigurować przodek widoki (takie jak w tabeli), aby 0lewy margines też, ale to wydaje się z natury bardziej podatne na błędy, jak nie kontrolują tego całą hierarchię.
  • Prawdopodobnie byłoby nieco czystsze ustawienie tylko lewego marginesu 0i pozostawienie pozostałych.
  • Jeśli chcesz mieć wstawkę 0 na „dodatkowych” separatorach, które UITableViewrysują na dole zwykłych tabel, zgaduję, że będzie to wymagało określenia tych samych ustawień również na poziomie tabeli (nie próbowałem tego!)
Mike Abdullah
źródło
3
Dziękuję Ci! To naprawdę jest bardziej zwięzła odpowiedź. O wiele lepsze niż przesłanianie dwóch metod i brutalne wymuszanie.
LunaCodeGirl
16
W iOS 8 to dla mnie nie działałoby[self.tableView setSeparatorInset:UIEdgeInsetsMake(0, 0, 0, 0)];
davetw12
1
Masz mój głos, dziękuję za jasne wyjaśnienie. Wspomnę tylko, że sam TableView ma także layoutMargins, które w niektórych przypadkach mogą wymagać ustawienia oprócz separatorInset.
cdstamper,
@ davetw12 i @cdstamper Czy możesz to przedstawić? Wszystkie moje dotychczasowe eksploracje mówią, że ustawienie zarówno na komórce, jak layoutMarginsi preservesSuperviewLayoutMarginsna komórce jest wszystkim, czego potrzeba. Wszystko inne przypomina zaufanie do voodoo.
Mike Abdullah
3
Nie, to nie jest forma voodoo @MikeAbdullah. W celu, aby uniknąć domyślnie separatorInsetod a UITableViewCellw iOS 8, trzeba ustawić Ustaw UIEdgeInsetsna zero zarówno na UITableViewi UITableViewCell. Jeśli nie zrobisz obu, nadal będziesz mieć lewą wstawkę, która jest większa od zera. Potwierdziłem to wiele razy.
davetw12
58

Sądzę, że to to samo pytanie, które tutaj zadałem: Usuń SeparatorInset na iOS 8 UITableView dla XCode 6 iPhone Simulator

W iOS 8 istnieje jedna nowa właściwość dla wszystkich dziedziczonych obiektów UIView. Tak więc rozwiązanie, aby ustawićSeparatorInset w iOS 7.x nie będzie w stanie usunąć białych znaków widocznych na UITableView w iOS 8.

Nowa właściwość nosi nazwę „ 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

iOS 8 UITableView setSeparatorInset: UIEdgeInsetsZero setLayoutMargins: UIEdgeInsetsZero

Rozwiązanie:-

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

Jeśli ustawisz cell.layoutMargins = UIEdgeInsetsZero;bez sprawdzania, czy layoutMarginsistnieje, aplikacja ulegnie awarii w systemie iOS 7.x. Najlepszym sposobem byłoby sprawdzenie, czy layoutMarginsistnieje wcześniej setLayoutMargins:UIEdgeInsetsZero.

Ricky
źródło
Jak można zastosować to podejście, jeśli celem wdrożenia jest iOS 7?
Petar
Umieszczam kod tableView w viewDidLoad i działają dobrze. Myślę, że nie trzeba wywoływać ich za każdym razem w willDisplayCell ().
Abdullah Umer
46

Możesz użyć UIAppearance raz, podczas uruchamiania aplikacji (przed załadowaniem interfejsu użytkownika), aby ustawić go jako domyślne ustawienia globalne:

// 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];

}

W ten sposób utrzymujesz kod UIViewController w czystości i zawsze możesz go zastąpić, jeśli chcesz.

Łukasz
źródło
41

iOS wprowadza właściwość layoutMargins do komórek ORAZ widoków tabeli.

Ta właściwość nie jest dostępna w iOS 7.0, więc musisz ją sprawdzić przed przypisaniem!

Apple dodał jednak do komórki właściwość o nazwieservesSuperviewLayoutMargins , która uniemożliwi dziedziczenie ustawień marginesów w widoku tabeli. W ten sposób komórki mogą konfigurować własne marginesy niezależnie od widoku tabeli. Potraktuj to jako nadpisanie.

Ta właściwość jest nazywany preservesSuperviewLayoutMargins i ustawienie go na NO może zezwolić, aby zastąpić ustawienia layoutMargin stole widok jest z ustawieniem layoutMargin swojej własnej komórki. Oba oszczędzają czas ( nie musisz modyfikować ustawień Widoku tabeli ) i są bardziej zwięzłe. Szczegółowe wyjaśnienie znajduje się w odpowiedzi Mike'a Abdullaha.

UWAGA: jest to właściwa, mniej niechlujna implementacja, wyrażona w odpowiedzi Mike'a Abdullaha; ustawienie zachowań komórki w komórceSuperviewLayoutMargins = NIE zapewni, że widok tabeli nie zastąpi ustawień komórki.

Pierwszy krok - skonfiguruj marginesy komórkowe:

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

Ustawienie właściwościserveesSuperviewLayoutMargins w komórce na NIE powinno uniemożliwić widok tabeli nadpisujący marginesy komórki. W niektórych przypadkach wydaje się, że nie działa poprawnie.

Drugi krok - tylko jeśli wszystko zawiedzie, możesz brutalnie wymusić marginesy widoku tabeli:

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

... i proszę bardzo! To powinno działać na iOS 8, a także iOS 7.

Uwaga: testowane na iOS 8.1 i 7.1, w moim przypadku potrzebowałem tylko pierwszego kroku tego wyjaśnienia.

Drugi krok jest wymagany tylko wtedy, gdy pod renderowanymi komórkami znajduje się niepopulowana komórka, tj. jeśli tabela jest większa niż liczba wierszy w modelu tabel. Nie wykonanie drugiego kroku spowoduje różne przesunięcia separatora.

King-Wizard
źródło
1
Nie musisz sprawdzać selektorów w willDisplayCellmetodzie, ponieważ sama metoda jest już iOS 8+ i nigdy nie będzie wywoływana ze starszych wersji.
Rivera
38

W Swift jest to trochę bardziej irytujące, ponieważ layoutMarginsjest właściwością, więc musisz zastąpić gettera i setera.

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

To skutecznie zrobi layoutMarginstylko do odczytu, co w moim przypadku jest w porządku.

Swilliams
źródło
Tylko to rozwiązanie działało dla mnie. I nie potrzebowałem dodawać dodatkowego kodu linii w metodach. Użyłem niestandardowych komórek.
Ramis
2
W przypadku komórki statycznej, z wyjątkiem nadpisywania layoutMargins, nadal musisz zmienić styl separatora komórki na „Własne wstawki” i ustawić lewą wartość na „0” w scenorysie.
hufeng03
22

W systemie iOS 9 musisz dodać:

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

Więcej informacji znajduje się w pytaniu .

Julian Król
źródło
12
zabawne jest dodanie kodu do każdej wersji, aby początkowy wygląd pozostał taki sam ...
Christian
20

Rozszerzenie Swift 2.0

Chciałem tylko udostępnić rozszerzenie, które zrobiłem, aby usunąć marginesy z separatorów komórek widoku tabeli.

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

Używany w kontekście:

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

    cell.removeMargins()
    return cell
Dan Beaulieu
źródło
15

Szybki:

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
}
Alexander Volkov
źródło
11

Sprawiłem, że działało to:

tableView.separatorInset = UIEdgeInsetsZero;
tableView.layoutMargins = UIEdgeInsetsZero;
cell.layoutMargins = UIEdgeInsetsZero;
ideawu
źródło
9

Jeśli chodzi o to, co sugeruje cdstamper zamiast widoku tabeli, dla mnie działa dodawanie poniżej linii w układzie layoutSubview komórki.

- (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];
        }
}
Vijay VS
źródło
9

Przykład 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
    }
}
mkz
źródło
9

Po długim dochodzeniu ...

Oto jedyny sposób, aby w pełni kontrolować te rzeczy (które mogłem znaleźć)

Aby w pełni kontrolować zarówno wstawki separatora, jak i marginesy układu w każdej komórce. Zrób to w willDisplayCellmetodzie na swoim 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)
}

Obiekt komórki kontroluje separator, a contentViewkontroluje wszystko inne. Jeśli wstawiane przestrzenie separatora są wyświetlane w nieoczekiwanym kolorze, powinno to rozwiązać:

cell.backgroundColor = cell.contentView.backgroundColor
Matjan
źródło
8

Proste rozwiązanie w Swift na iOS 8 z niestandardowymUITableViewCell

override func awakeFromNib() {
    super.awakeFromNib()

    self.layoutMargins = UIEdgeInsetsZero
    self.separatorInset = UIEdgeInsetsZero
}

W ten sposób ustawiasz layoutMargini separatorInsettylko raz zamiast robić to dla każdegowillDisplayCell jak sugeruje większość powyższych odpowiedzi.

Jeśli korzystasz z niestandardowego, UITableViewCelljest to właściwe miejsce, aby to zrobić. W przeciwnym razie powinieneś to zrobićtableView:cellForRowAtIndexPath .

Kolejna wskazówka: nie trzeba ustawiać, preservesSuperviewLayoutMargins = falseponieważ wartość domyślna już jest NO!

Francesco Vadicamo
źródło
8

Dla mnie prosta linia zadziałała

cell.layoutMargins = UIEdgeInsetsZero
apinho
źródło
wywołał to w metodzie delegowania cellForRowAtIndexPath. Dobra odpowiedź :)
saintjab
7

Wystarczy dodać poniższy kod, aby rozwiązać ten program.

Powodzenia!

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

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

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

}
JimmyChang
źródło
5

Łukasz odpowiedział w Swift:

    // 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
    }
Naka
źródło
5

Oto kod, który działa dla mnie w 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)
    }
}

Wydaje mi się to najczystsze (na razie), ponieważ wszystkie korekty krawędzi / marginesu cell / tableView są wykonywane w tableView:willDisplayCell:forRowAtIndexPath:metodzie, bez wrzucania niepotrzebnego kodu tableView:cellForRowAtIndexPath:.

Przy okazji, ustawiam tylko lewy separator komórki Inset / layoutMargins, ponieważ w tym przypadku nie chcę zepsuć moich ograniczeń, które ustawiłem w komórce.

Zaktualizowano kod do 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)
        }
    }
Ivan
źródło
Co dokładnie dla ciebie nie działa? Właśnie przetestowałem ten kod na symulatorze iPhone'a 5 z zainstalowanym pakietem iOS 8.1 SDK i wszystko jest tak, jak było, kiedy pierwotnie opublikowałem tę odpowiedź. Kod został skompilowany i uruchomiony z Xcode 6.1.1.
Ivan
4

Większość odpowiedzi pokazują wypustki separujące i marginesy układ jest ustawiony nad różnymi metodami (tj viewDidLayoutSubviews, willDisplayCellitp) do komórek i tableviews, ale odkryłem, że tylko wprowadzenie w nich cellForRowAtIndexPathdziała świetnie. Wydaje się, że to najczystszy sposób.

// 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];
inorganik
źródło
4

Użyj poniższego fragmentu kodu, aby uniknąć niepożądanego problemu wypełniania UITableView w IOS 8 i 7.

-(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];
    }
}
Anooj VM
źródło
4

Zamiast aktualizować preservesSuperviewLayoutMarginsi za layoutMarginskażdym razem, gdy komórka przewija się (używa willDisplayCell), sugeruję zrobić to raz cellForRowAtIndexPath::

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

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

    cell.preservesSuperviewLayoutMargins = false
    cell.layoutMargins = UIEdgeInsetsZero

    return cell

}
Rudolf Adamkovič
źródło
4

Oto prosty sposób na globalne usunięcie wstawki.

W UITableViewCell+Extensions.swift:

import UIKit

extension UITableViewCell {

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

}

W AppDelegate application:didFinishLaunchingWithOptions::

  UITableViewCell.appearance().separatorInset = UIEdgeInsetsZero

Możesz pomyśleć o a) po prostu zastąpić separatorInsetrozszerzenie lub b) layoutMarginszamiast tego ustawić proxy wyglądu . Żadne nie zadziała. Mimo że separatorInsetjest wskazana jako właściwość, próba zastąpienia jej jako właściwości (lub metody) generuje błędy kompilatora. Oraz ustawianie proxy wygląd UITableViewCell„s layoutMargins(lub, jeśli o to chodzi, również ustawienie proxy wygląd UITableView” s layoutMarginsi separatorInset) nie ma żadnego wpływu.

Scott Gardner
źródło
3

W iOS8:

Dodanie tego do mojej podklasy UITableViewCell:

- (UIEdgeInsets)layoutMargins {
    return UIEdgeInsetsZero;
}

i to do „tableView: cellForRowAtIndexPath” lub „tableView: willDisplayCell”:

[editCell setSeparatorInset:UIEdgeInsetsZero];

DZIAŁAŁ dla mnie.

Saru
źródło
2
-(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;
}

Dla dowolnej określonej komórki chcesz ukryć separator.

xmurobi
źródło
2

Po obejrzeniu odpowiedzi na 3. piętrze próbowałem dowiedzieć się, jaki jest związek między ustawieniem separatora między TableView a TableViewCell i wykonałem test. Oto moje wnioski:

  1. możemy rozważyć, że ustawienie separatora komórki na zero musi przesunąć separator w dwóch krokach: pierwszym krokiem jest ustawienie zestawu separatorów komórki na zero. drugim krokiem jest ustawienie marginesu komórki na zero.

  2. ustaw tabelę separatora TableView, a marginesout może wpływać na separator komórki . Jednak z testu wynika, że ​​zestaw separatora TableView wydaje się być bezużyteczny, marginesy TableView mogą faktycznie wpływać na marginesy komórki .

  3. set Cell's PreservesSuperviewLayoutMargins = false, może odciąć efekt marginlayout TableView na komórkach.

  4. jedno z rozwiązań:

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        var cell = UITableViewCell()
    
        cell.preservesSuperviewLayoutMargins = false
        cell.separatorInset = UIEdgeInsetsZero
        cell.layoutMargins = UIEdgeInsetsZero
    
        return cell
    }
Xin Chen
źródło
2

To jest moje rozwiązanie. Dotyczy to niestandardowej podklasy komórek, wystarczy dodać je obie do podklasy.

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

2)

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

Wygodne jest dostosowanie pozycji separatora bez konieczności rysowania go przez projektanta ..........

Guoyu
źródło
1

W bardziej zwarty sposób niż najczęściej głosowana odpowiedź ...

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

}

subharb
źródło
1

Dodanie tego fragmentu, prosty elegancki w Swift działa dla mnie w iOS8 :)

    // tableview single line
func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
    cell.preservesSuperviewLayoutMargins = false
    cell.layoutMargins = UIEdgeInsetsZero
}
ddnl
źródło
1

Działa to idealnie dla mnie w iOS 8 i iOS 9.

Dla 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;
    }
jithin
źródło