iOS 7 TableView jak w aplikacji Ustawienia na iPadzie

99

Chcę mieć grupę UITableView w stylu takim samym jak widok szczegółów aplikacji Ustawienia iPada dla iOS 7 .

Jest to tableView z zaokrąglonym rogiem. Sprawdź szczegóły w załączniku.

Czy są jakieś domyślne ustawienia, aby tak wyglądało, czy też musimy zrobić niestandardowy rysunek dla tego samego.

Każda wskazówka we właściwym kierunku zostanie doceniona.

Dzięki

wprowadź opis obrazu tutaj

Ekra
źródło

Odpowiedzi:

197

Poszedłem dalej i dostosowałem willDisplayCell, aby uzyskać lepszą symulację stylów komórek w aplikacji ustawień.

Cel C

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    if ([cell respondsToSelector:@selector(tintColor)]) {
        if (tableView == self.tableView) {
            CGFloat cornerRadius = 5.f;
            cell.backgroundColor = UIColor.clearColor;
            CAShapeLayer *layer = [[CAShapeLayer alloc] init];
            CGMutablePathRef pathRef = CGPathCreateMutable();
            CGRect bounds = CGRectInset(cell.bounds, 10, 0);
            BOOL addLine = NO;
            if (indexPath.row == 0 && indexPath.row == [tableView numberOfRowsInSection:indexPath.section]-1) {
                CGPathAddRoundedRect(pathRef, nil, bounds, cornerRadius, cornerRadius);
            } else if (indexPath.row == 0) {
                CGPathMoveToPoint(pathRef, nil, CGRectGetMinX(bounds), CGRectGetMaxY(bounds));
                CGPathAddArcToPoint(pathRef, nil, CGRectGetMinX(bounds), CGRectGetMinY(bounds), CGRectGetMidX(bounds), CGRectGetMinY(bounds), cornerRadius);
                CGPathAddArcToPoint(pathRef, nil, CGRectGetMaxX(bounds), CGRectGetMinY(bounds), CGRectGetMaxX(bounds), CGRectGetMidY(bounds), cornerRadius);
                CGPathAddLineToPoint(pathRef, nil, CGRectGetMaxX(bounds), CGRectGetMaxY(bounds));
                addLine = YES;
            } else if (indexPath.row == [tableView numberOfRowsInSection:indexPath.section]-1) {
                CGPathMoveToPoint(pathRef, nil, CGRectGetMinX(bounds), CGRectGetMinY(bounds));
                CGPathAddArcToPoint(pathRef, nil, CGRectGetMinX(bounds), CGRectGetMaxY(bounds), CGRectGetMidX(bounds), CGRectGetMaxY(bounds), cornerRadius);
                CGPathAddArcToPoint(pathRef, nil, CGRectGetMaxX(bounds), CGRectGetMaxY(bounds), CGRectGetMaxX(bounds), CGRectGetMidY(bounds), cornerRadius);
                CGPathAddLineToPoint(pathRef, nil, CGRectGetMaxX(bounds), CGRectGetMinY(bounds));
            } else {
                CGPathAddRect(pathRef, nil, bounds);
                addLine = YES;
            }
            layer.path = pathRef;
            CFRelease(pathRef);
            layer.fillColor = [UIColor colorWithWhite:1.f alpha:0.8f].CGColor;

            if (addLine == YES) {
                CALayer *lineLayer = [[CALayer alloc] init];
                CGFloat lineHeight = (1.f / [UIScreen mainScreen].scale);
                lineLayer.frame = CGRectMake(CGRectGetMinX(bounds)+10, bounds.size.height-lineHeight, bounds.size.width-10, lineHeight);
                lineLayer.backgroundColor = tableView.separatorColor.CGColor;
                [layer addSublayer:lineLayer];
            }
            UIView *testView = [[UIView alloc] initWithFrame:bounds];
            [testView.layer insertSublayer:layer atIndex:0];
            testView.backgroundColor = UIColor.clearColor;
            cell.backgroundView = testView;
        }
    }
}

Szybki

override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
    if (cell.respondsToSelector(Selector("tintColor"))){
        if (tableView == self.tableView) {
            let cornerRadius : CGFloat = 12.0
            cell.backgroundColor = UIColor.clearColor()
            var layer: CAShapeLayer = CAShapeLayer()
            var pathRef:CGMutablePathRef = CGPathCreateMutable()
            var bounds: CGRect = CGRectInset(cell.bounds, 25, 0)
            var addLine: Bool = false

            if (indexPath.row == 0 && indexPath.row == tableView.numberOfRowsInSection(indexPath.section)-1) {
                CGPathAddRoundedRect(pathRef, nil, bounds, cornerRadius, cornerRadius)
            } else if (indexPath.row == 0) {
                CGPathMoveToPoint(pathRef, nil, CGRectGetMinX(bounds), CGRectGetMaxY(bounds))
                CGPathAddArcToPoint(pathRef, nil, CGRectGetMinX(bounds), CGRectGetMinY(bounds), CGRectGetMidX(bounds), CGRectGetMinY(bounds), cornerRadius)
                CGPathAddArcToPoint(pathRef, nil, CGRectGetMaxX(bounds), CGRectGetMinY(bounds), CGRectGetMaxX(bounds), CGRectGetMidY(bounds), cornerRadius)
                CGPathAddLineToPoint(pathRef, nil, CGRectGetMaxX(bounds), CGRectGetMaxY(bounds))
                addLine = true
            } else if (indexPath.row == tableView.numberOfRowsInSection(indexPath.section)-1) {
                CGPathMoveToPoint(pathRef, nil, CGRectGetMinX(bounds), CGRectGetMinY(bounds))
                CGPathAddArcToPoint(pathRef, nil, CGRectGetMinX(bounds), CGRectGetMaxY(bounds), CGRectGetMidX(bounds), CGRectGetMaxY(bounds), cornerRadius)
                CGPathAddArcToPoint(pathRef, nil, CGRectGetMaxX(bounds), CGRectGetMaxY(bounds), CGRectGetMaxX(bounds), CGRectGetMidY(bounds), cornerRadius)
                CGPathAddLineToPoint(pathRef, nil, CGRectGetMaxX(bounds), CGRectGetMinY(bounds))
            } else {
                CGPathAddRect(pathRef, nil, bounds)
                addLine = true
            }

            layer.path = pathRef
            layer.fillColor = UIColor(red: 255/255.0, green: 255/255.0, blue: 255/255.0, alpha: 0.8).CGColor

            if (addLine == true) {
                var lineLayer: CALayer = CALayer()
                var lineHeight: CGFloat = (1.0 / UIScreen.mainScreen().scale)
                lineLayer.frame = CGRectMake(CGRectGetMinX(bounds)+10, bounds.size.height-lineHeight, bounds.size.width-10, lineHeight)
                lineLayer.backgroundColor = tableView.separatorColor.CGColor
                layer.addSublayer(lineLayer)
            }
            var testView: UIView = UIView(frame: bounds)
            testView.layer.insertSublayer(layer, atIndex: 0)
            testView.backgroundColor = UIColor.clearColor()
            cell.backgroundView = testView
        }
    }
}

Szybki 3

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    let cornerRadius: CGFloat = 5
    cell.backgroundColor = .clear

    let layer = CAShapeLayer()
    let pathRef = CGMutablePath()
    let bounds = cell.bounds.insetBy(dx: 20, dy: 0)
    var addLine = false

    if indexPath.row == 0 && indexPath.row == tableView.numberOfRows(inSection: indexPath.section) - 1 {
        pathRef.__addRoundedRect(transform: nil, rect: bounds, cornerWidth: cornerRadius, cornerHeight: cornerRadius)
    } else if indexPath.row == 0 {
        pathRef.move(to: .init(x: bounds.minX, y: bounds.maxY))
        pathRef.addArc(tangent1End: .init(x: bounds.minX, y: bounds.minY), tangent2End: .init(x: bounds.midX, y: bounds.minY), radius: cornerRadius)
        pathRef.addArc(tangent1End: .init(x: bounds.maxX, y: bounds.minY), tangent2End: .init(x: bounds.maxX, y: bounds.midY), radius: cornerRadius)
        pathRef.addLine(to: .init(x: bounds.maxX, y: bounds.maxY))
        addLine = true
    } else if indexPath.row == tableView.numberOfRows(inSection: indexPath.section) - 1 {
        pathRef.move(to: .init(x: bounds.minX, y: bounds.minY))
        pathRef.addArc(tangent1End: .init(x: bounds.minX, y: bounds.maxY), tangent2End: .init(x: bounds.midX, y: bounds.maxY), radius: cornerRadius)
        pathRef.addArc(tangent1End: .init(x: bounds.maxX, y: bounds.maxY), tangent2End: .init(x: bounds.maxX, y: bounds.midY), radius: cornerRadius)
        pathRef.addLine(to: .init(x: bounds.maxX, y: bounds.minY))
    } else {
        pathRef.addRect(bounds)
        addLine = true
    }

    layer.path = pathRef
    layer.fillColor = UIColor(white: 1, alpha: 0.8).cgColor

    if (addLine == true) {
        let lineLayer = CALayer()
        let lineHeight = 1.0 / UIScreen.main.scale
        lineLayer.frame = CGRect(x: bounds.minX + 10, y: bounds.size.height - lineHeight, width: bounds.size.width - 10, height: lineHeight)
        lineLayer.backgroundColor = tableView.separatorColor?.cgColor
        layer.addSublayer(lineLayer)
    }

    let testView = UIView(frame: bounds)
    testView.layer.insertSublayer(layer, at: 0)
    testView.backgroundColor = .clear
    cell.backgroundView = testView
}

Swift 4.2

override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {

    if (cell.responds(to: #selector(getter: UIView.tintColor))){
        if tableView == self.tableView {
            let cornerRadius: CGFloat = 12.0
            cell.backgroundColor = .clear
            let layer: CAShapeLayer = CAShapeLayer()
            let path: CGMutablePath = CGMutablePath()
            let bounds: CGRect = cell.bounds
            bounds.insetBy(dx: 25.0, dy: 0.0)
            var addLine: Bool = false

            if indexPath.row == 0 && indexPath.row == ( tableView.numberOfRows(inSection: indexPath.section) - 1) {
                path.addRoundedRect(in: bounds, cornerWidth: cornerRadius, cornerHeight: cornerRadius)

            } else if indexPath.row == 0 {
                path.move(to: CGPoint(x: bounds.minX, y: bounds.maxY))
                path.addArc(tangent1End: CGPoint(x: bounds.minX, y: bounds.minY), tangent2End: CGPoint(x: bounds.midX, y: bounds.minY), radius: cornerRadius)
                path.addArc(tangent1End: CGPoint(x: bounds.maxX, y: bounds.minY), tangent2End: CGPoint(x: bounds.maxX, y: bounds.midY), radius: cornerRadius)
                path.addLine(to: CGPoint(x: bounds.maxX, y: bounds.maxY))

            } else if indexPath.row == (tableView.numberOfRows(inSection: indexPath.section) - 1) {
                path.move(to: CGPoint(x: bounds.minX, y: bounds.minY))
                path.addArc(tangent1End: CGPoint(x: bounds.minX, y: bounds.maxY), tangent2End: CGPoint(x: bounds.midX, y: bounds.maxY), radius: cornerRadius)
                path.addArc(tangent1End: CGPoint(x: bounds.maxX, y: bounds.maxY), tangent2End: CGPoint(x: bounds.maxX, y: bounds.midY), radius: cornerRadius)
                path.addLine(to: CGPoint(x: bounds.maxX, y: bounds.minY))

            } else {
                path.addRect(bounds)
                addLine = true
            }

            layer.path = path
            layer.fillColor = UIColor.white.withAlphaComponent(0.8).cgColor

            if addLine {
                let lineLayer: CALayer = CALayer()
                let lineHeight: CGFloat = 1.0 / UIScreen.main.scale
                lineLayer.frame = CGRect(x: bounds.minX + 10.0, y: bounds.size.height - lineHeight, width: bounds.size.width, height: lineHeight)
                lineLayer.backgroundColor = tableView.separatorColor?.cgColor
                layer.addSublayer(lineLayer)
            }

            let testView: UIView = UIView(frame: bounds)
            testView.layer.insertSublayer(layer, at: 0)
            testView.backgroundColor = .clear
            cell.backgroundView = testView
        }
    }
}

Przykład na iOS7

jvanmetre
źródło
1
To niesamowita odpowiedź. Nadal nie mogę ukryć górnych i dolnych linii. Dowolny pomysł? Wszystko inne działa idealnie!
hishamaus
5
Działa. ustawienie stylu separatora całego widoku tabeli na none załatwia sprawę. Pozdrawiam
hishamaus
3
Aby uprościć kod, możesz również użyć[UIBezierPath bezierPathWithRoundedRect:bounds byRoundingCorners:corner cornerRadii:cornerSize];
Sergiy Salyuk
2
@jvanmetre Dobra odpowiedź, głosował za tobą. Wydaje się jednak, że powoduje to problem z ikoną ujawniania. Moja ikona ujawniania wychodzi poza komórkę. Czy możesz mi pomóc
Ganesh Somani,
4
Jak ustawić autorezację warstwy, aby po obróceniu mogła zmienić klatkę tak, jak jest to superview?
zgjie
13

W iOS 13 i nowszych ten styl tabeli jest ostatecznie udostępniany przez Apple, bez konieczności ponownego projektowania, dzięki nowemu UITableView.Style.insetGrouped stylem widoku tabeli .

W Xcode 11 i nowszych można to ustawić w ustawieniach konstruktora interfejsu dla widoku tabeli, wybierając opcję Inset Grouped dla stylu:

Ustawienia widoku tabeli konstruktora interfejsów

Andrew Bennet
źródło
1
Masz jakiś pomysł, jak ustawić tę właściwość dla listy w SwiftUI?
Sorin Lica
1
.listStyle (GroupedListStyle ()) @SorinLica
Digvijay
5

Odpowiadając @NarasimhaiahKolli, w jaki sposób ustawiam widok tła komórki, aby cała komórka nie wyglądała tak, jakby była podświetlona. Mam nadzieję że to pomoże.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    InfoCell *cell;
    ...

    if ([cell respondsToSelector:@selector(tintColor)]) {
        cell.selectedBackgroundView = [self backgroundCellView:cell indexPath:indexPath tableView:tableView];
    }

    return cell;
}

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    if ([cell respondsToSelector:@selector(tintColor)]) {
        cell.backgroundColor = UIColor.clearColor;
        UIColor *cellColor = [UIColor colorWithWhite:0.90f alpha:.95f];
        CAShapeLayer *layer = [self tableView:tableView layerForCell:cell forRowAtIndexPath:indexPath withColor:cellColor];

        CGRect bounds = CGRectInset(cell.bounds, 10, 0);

        UIView *testView = [[UIView alloc] initWithFrame:bounds];
        [testView.layer insertSublayer:layer atIndex:0];
        testView.backgroundColor = UIColor.clearColor;
        cell.backgroundView = testView;
    }
}

- (UIView *)backgroundCellView:(InfoCell *)cell indexPath:(NSIndexPath *)indexPath tableView:(UITableView *)tableView
{
    UIColor *cellColor = [UIColor lightGrayColor];
    CAShapeLayer *layer = [self tableView:tableView layerForCell:cell forRowAtIndexPath:indexPath withColor:cellColor];

    CGRect bounds = CGRectInset(cell.bounds, 10, 0);
    UIView *testView = [[UIView alloc] initWithFrame:bounds];
    [testView.layer insertSublayer:layer atIndex:0];
    return testView;
}

- (CAShapeLayer *)tableView:(UITableView *)tableView layerForCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath withColor:(UIColor *)color
{
    CGFloat cornerRadius = 5.f;
    CAShapeLayer *layer = [[CAShapeLayer alloc] init];
    CGMutablePathRef pathRef = CGPathCreateMutable();
    CGRect bounds = CGRectInset(cell.bounds, 10, 0);
    BOOL addLine = NO;
    if (indexPath.row == 0 && indexPath.row == [tableView numberOfRowsInSection:indexPath.section]-1) {
        CGPathAddRoundedRect(pathRef, nil, bounds, cornerRadius, cornerRadius);
    } else if (indexPath.row == 0) {
        CGPathMoveToPoint(pathRef, nil, CGRectGetMinX(bounds), CGRectGetMaxY(bounds));
        CGPathAddArcToPoint(pathRef, nil, CGRectGetMinX(bounds), CGRectGetMinY(bounds), CGRectGetMidX(bounds), CGRectGetMinY(bounds), cornerRadius);
        CGPathAddArcToPoint(pathRef, nil, CGRectGetMaxX(bounds), CGRectGetMinY(bounds), CGRectGetMaxX(bounds), CGRectGetMidY(bounds), cornerRadius);
        CGPathAddLineToPoint(pathRef, nil, CGRectGetMaxX(bounds), CGRectGetMaxY(bounds));
        addLine = YES;
    } else if (indexPath.row == [tableView numberOfRowsInSection:indexPath.section]-1) {
        CGPathMoveToPoint(pathRef, nil, CGRectGetMinX(bounds), CGRectGetMinY(bounds));
        CGPathAddArcToPoint(pathRef, nil, CGRectGetMinX(bounds), CGRectGetMaxY(bounds), CGRectGetMidX(bounds), CGRectGetMaxY(bounds), cornerRadius);
        CGPathAddArcToPoint(pathRef, nil, CGRectGetMaxX(bounds), CGRectGetMaxY(bounds), CGRectGetMaxX(bounds), CGRectGetMidY(bounds), cornerRadius);
        CGPathAddLineToPoint(pathRef, nil, CGRectGetMaxX(bounds), CGRectGetMinY(bounds));
    } else {
        CGPathAddRect(pathRef, nil, bounds);
        addLine = YES;
    }
    layer.path = pathRef;
    CFRelease(pathRef);
    //        layer.fillColor = [UIColor colorWithWhite:1.f alpha:1.0f].CGColor;
    layer.fillColor = color.CGColor;

    if (addLine == YES) {
        CALayer *lineLayer = [[CALayer alloc] init];
        CGFloat lineHeight = (1.f / [UIScreen mainScreen].scale);
        lineLayer.frame = CGRectMake(CGRectGetMinX(bounds)+10, bounds.size.height-lineHeight, bounds.size.width-10, lineHeight);
        lineLayer.backgroundColor = tableView.separatorColor.CGColor;
        [layer addSublayer:lineLayer];
    }

    return layer;
}
gaijin
źródło
ładne ... więc musisz zrobić kolejną warstwę jako tło. Jeśli utworzę kolejny bgView i ponownie użyję tej samej warstwy, nie działa, widzę.
karim,
Po zaznaczeniu komórki na dole komórki znajduje się biała linia.
gabbler
4

Odpowiedź @jvanmetre jest świetna i działa. Opierając się na tym i zgodnie z sugestią @SergiySalyuk w komentarzach. Zaktualizowałem kod, aby korzystał z UIBezierPath, dzięki czemu jest łatwiejszy do zrozumienia i nieco szybszy.

Moja wersja naprawia również błąd separatora i dodaje wybrany widok tła, który pasuje do komórki.

Pamiętaj, aby ustawić widok tabeli na brak separatora: tableView.separatorStyle = UITableViewCellSeparatorStyleNone;

Cel C

- (void)tableView:(UITableView*)tableView willDisplayCell:(UITableViewCell*)cell forRowAtIndexPath:(NSIndexPath*)indexPath {
  // Set transparent background so we can see the layer
  cell.backgroundColor = UIColor.clearColor;

  // Declare two layers: one for the background and one for the selecetdBackground
  CAShapeLayer *backgroundLayer = [CAShapeLayer layer];
  CAShapeLayer *selectedBackgroundLayer = [[CAShapeLayer alloc] init];

  CGRect bounds = CGRectInset(cell.bounds, 0, 0);//Cell bounds feel free to adjust insets.

  BOOL addSeparator = NO;// Controls if we should add a seperator

  // Determine which corners should be rounded
  if (indexPath.row == 0 && indexPath.row == [tableView numberOfRowsInSection:indexPath.section]-1) {
    // This is the only row in its section, round all corners
    backgroundLayer.path = [UIBezierPath bezierPathWithRoundedRect:bounds byRoundingCorners:UIRectCornerAllCorners cornerRadii:CGSizeMake(7, 7)].CGPath;

  } else if (indexPath.row == 0) {
    // First row, round the top two corners.
    backgroundLayer.path = [UIBezierPath bezierPathWithRoundedRect:bounds byRoundingCorners:UIRectCornerTopLeft | UIRectCornerTopRight cornerRadii:CGSizeMake(7, 7)].CGPath;
    addSeparator = YES;

  } else if (indexPath.row == [tableView numberOfRowsInSection:indexPath.section]-1) {
    // Bottom row, round the bottom two corners.
    backgroundLayer.path = [UIBezierPath bezierPathWithRoundedRect:bounds byRoundingCorners:UIRectCornerBottomLeft | UIRectCornerBottomRight cornerRadii:CGSizeMake(7, 7)].CGPath;

  } else {
    // Somewhere between the first and last row don't round anything but add a seperator
    backgroundLayer.path = [UIBezierPath bezierPathWithRect:bounds].CGPath;// So we have a background
    addSeparator = YES;
  }

  // Copy the same path for the selected background layer
  selectedBackgroundLayer.path = CGPathCreateCopy(backgroundLayer.path);

  // Yay colors!
  backgroundLayer.fillColor = [UIColor colorWithWhite:1.f alpha:0.8f].CGColor;
  selectedBackgroundLayer.fillColor = [UIColor grayColor].CGColor;

  // Draw seperator if necessary
  if (addSeparator == YES) {
    CALayer *separatorLayer = [CALayer layer];
    CGFloat separatorHeight = (1.f / [UIScreen mainScreen].scale);
    separatorLayer.frame = CGRectMake(CGRectGetMinX(bounds)+10, bounds.size.height-separatorHeight, bounds.size.width-10, separatorHeight);
    separatorLayer.backgroundColor = tableView.separatorColor.CGColor;

    [backgroundLayer addSublayer:separatorLayer];
  }

  // Create a UIView from these layers and set them to the cell's .backgroundView and .selectedBackgroundView
  UIView *backgroundView = [[UIView alloc] initWithFrame:bounds];
  [backgroundView.layer insertSublayer:backgroundLayer atIndex:0];
  backgroundView.backgroundColor = UIColor.clearColor;
  cell.backgroundView = backgroundView;

  UIView *selectedBackgroundView = [[UIView alloc] initWithFrame:bounds];
  [selectedBackgroundView.layer insertSublayer:selectedBackgroundLayer atIndex:0];
  selectedBackgroundView.backgroundColor = UIColor.clearColor;
  cell.selectedBackgroundView = selectedBackgroundView;

}
osioł
źródło
3

Próbowałem osiągnąć ten sam zaokrąglony wygląd aplikacji Ustawienia na komórkach tableviewcells. Moja odpowiedź jest również oparta na odpowiedzi SO, jak ustawić cornerRadius tylko dla lewego górnego i prawego górnego rogu UIView? .

wprowadź opis obrazu tutaj

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];

    [cell setClipsToBounds:YES];

    // rowsArray has cell titles for current group
    NSArray *rowsArray = [self.sectionsArray objectAtIndex:indexPath.section];

    [[cell textLabel] setText:[rowsArray objectAtIndex:indexPath.row]];

    float cornerSize = 11.0; // change this if necessary

    // round all corners if there is only 1 cell
    if (indexPath.row == 0 && [rowsArray count] == 1) {
        UIBezierPath *maskPath;
        maskPath = [UIBezierPath bezierPathWithRoundedRect:cell.bounds byRoundingCorners:(UIRectCornerTopLeft | UIRectCornerTopRight | UIRectCornerBottomLeft | UIRectCornerBottomRight) cornerRadii:CGSizeMake(cornerSize, cornerSize)];

        CAShapeLayer *mlayer = [[CAShapeLayer alloc] init];
        mlayer.frame = cell.bounds;
        mlayer.path = maskPath.CGPath;
        cell.layer.mask = mlayer;
    }

    // round only top cell and only top-left and top-right corners
    else if (indexPath.row == 0) {
        UIBezierPath *maskPath;
        maskPath = [UIBezierPath bezierPathWithRoundedRect:cell.bounds byRoundingCorners:(UIRectCornerTopLeft | UIRectCornerTopRight) cornerRadii:CGSizeMake(cornerSize, cornerSize)];

        CAShapeLayer *mlayer = [[CAShapeLayer alloc] init];
        mlayer.frame = cell.bounds;
        mlayer.path = maskPath.CGPath;
        cell.layer.mask = mlayer;
    }

    // round bottom-most cell of group and only bottom-left and bottom-right corners
    else if (indexPath.row == [rowsArray count] - 1) {
        UIBezierPath *maskPath;
        maskPath = [UIBezierPath bezierPathWithRoundedRect:cell.bounds byRoundingCorners:(UIRectCornerBottomLeft | UIRectCornerBottomRight) cornerRadii:CGSizeMake(cornerSize, cornerSize)];

        CAShapeLayer *mlayer = [[CAShapeLayer alloc] init];
        mlayer.frame = cell.bounds;
        mlayer.path = maskPath.CGPath;
        cell.layer.mask = mlayer;

    }

}
Korey Hinton
źródło
Cześć Korey, użyłem tego i działało świetnie z tym, co mam na myśli. Jednak boki okrągłego prostokąta są zbyt blisko krawędzi ekranu. czy istnieje możliwość zmniejszenia komórek (jak w przypadku cieńszych)? Wielkie dzięki za wszelkie wskazówki.
Septronic
3

Po wypróbowaniu niektórych odpowiedzi tutaj, zdecydowałem się pójść na całość i zaimplementować całą podklasę oprócz UITableViewiUITableViewCell powielić zaokrąglony styl widoku tabeli zgrupowanej w iOS 7.

https://github.com/TimOliver/TORoundedTableView

TORoundedTableView

Okazało się, że był to bardzo skomplikowany proces:

  • Miałem do podklasy layoutSubviewswUITableView celu relayout każdą komórkę i akcesoriów widok tak były już od krawędzi do krawędzi.
  • Musiałem wykonać podklasę UITableViewCell, aby usunąć górny i dolny widok linii włosów separatora (ale pozostawiając nietknięte te wewnątrz sekcji).
  • Następnie utworzyłem niestandardowy UITableViewCellwidok tła, który opcjonalnie mógł mieć zaokrąglone rogi na górze i na dole, aby można go było użyć dla pierwszej i ostatniej komórki w każdej sekcji. Elementy te miały na CALayercelu uniknięcie UITableViewukrytego zachowania polegającego na zmianie koloru widoków tła, gdy użytkownik dotknie komórki.
  • Ponieważ są to teraz CALayerinstancje, na które nie reagują layoutSubviews, musiałem następnie zrobić trochę majsterkowania w ramach animacji podstawowej, aby upewnić się, że rozmiar górnych i dolnych komórek zmienia się z taką samą prędkością jak inne komórki, gdy użytkownik obraca urządzenie.

Podsumowując, jest to możliwe, ale ponieważ wymaga to sporego wysiłku i kosztuje niewielką ilość wydajności (ponieważ nieustannie walczy z kodem Apple, próbując wszystko cofnąć), najlepiej jest złożyć radar z prośbą Apple o to. oficjalnie eksponuj ten styl. Do tego czasu zachęcam do korzystania z mojej biblioteki. :)

TiM
źródło
2

Stworzyłem metodę o nazwie addRoundedCornersWithRadius:(CGFloat)radius ForCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath która utworzy zaokrąglone rogi na górze i na dole każdej sekcji.

Zaletą używania maskViewwłaściwości of UITableViewCelljest to, że po zaznaczeniu komórki zaokrąglone rogi są nadal widoczne.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"CellIdentifier"];
    [cell.textLabel setText:[NSString stringWithFormat:@"Row %d in Section %d", indexPath.row, indexPath.section]];
    [tableView addRoundedCornersWithRadius:12.0f ForCell:cell atIndexPath:indexPath];
    return cell;
}

- (void)addRoundedCornersWithRadius:(CGFloat)radius ForCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {
    NSInteger MBRows = [self numberOfRowsInSection:indexPath.section] - 1;
    CAShapeLayer    *MBLayer = [[CAShapeLayer alloc] init];
    CGRect cellBounds = CGRectMake(0, 0, self.bounds.size.width, cell.bounds.size.height);

    BOOL shouldAddSeperator = NO;

    if (indexPath.row == 0 && indexPath.row == MBRows) {
        [MBLayer setPath:[UIBezierPath bezierPathWithRoundedRect:cellBounds cornerRadius:radius].CGPath];
    } else if (indexPath.row == 0) {
        [MBLayer setPath:[UIBezierPath bezierPathWithRoundedRect:cellBounds
                                               byRoundingCorners:(UIRectCornerTopLeft|UIRectCornerTopRight)
                                                     cornerRadii:CGSizeMake(radius, radius)].CGPath];
        shouldAddSeperator = YES;
    } else if (indexPath.row == MBRows) {
        [MBLayer setPath:[UIBezierPath bezierPathWithRoundedRect:cellBounds
                                               byRoundingCorners:(UIRectCornerBottomLeft|UIRectCornerBottomRight)
                                                     cornerRadii:CGSizeMake(radius, radius)].CGPath];
    } else {
        [MBLayer setPath:[UIBezierPath bezierPathWithRect:cell.bounds].CGPath];
        shouldAddSeperator = YES;
    }

    [cell setMaskView:[[UIView alloc] initWithFrame:cell.bounds]];
    [cell.maskView.layer insertSublayer:MBLayer atIndex:0];

    if (shouldAddSeperator == YES) {
        CGFloat seperator = (1.0f / [UIScreen mainScreen].scale);
        CALayer *cellSeperator = [[CALayer alloc] init];

        [cellSeperator setFrame:CGRectMake(15.0f, cell.bounds.size.height - seperator, cell.bounds.size.width - 15.0f, seperator)];
        [cellSeperator setBackgroundColor:self.separatorColor.CGColor];
        [cell.layer addSublayer:cellSeperator];
    }

    [cell.maskView.layer setMasksToBounds:YES];
    [cell setClipsToBounds:YES];
}

UITableView zgrupowany w iOS 9 z zaokrąglonymi narożnikami

Berendschot
źródło
Dodałem mój kod do repozytorium Github . Myślę nawet o stworzeniu do tego kapsuły kakaowej.
Berendschot
1
Zmieszałem Twój kod z kodem @vanmetre (zaakceptowana odpowiedź) i idealnie pasuje do moich potrzeb! +1 za użycie maskView, która pozwala na ładny wybór. Wielkie dzięki !
AnthoPak
Świetny. Wystąpił tylko jeden problem: nie mogłem użyć cell.bounds, ponieważ był niepoprawny ... Zamiast tego utworzyłem własne granice z metody tableView.bounds.size.width i heightForRowAtIndexPath
Marek Manduch
1

Moja odpowiedź może być za późno, ale dla wersji Swift (dowolnej) z pewnością będzie przydatna i bardzo łatwa w użyciu.

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
        if (tableView == self.tableViewMovies) {
            //Top Left Right Corners
            let maskPathTop = UIBezierPath(roundedRect: cell.bounds, byRoundingCorners: [.topLeft, .topRight], cornerRadii: CGSize(width: 5.0, height: 5.0))
            let shapeLayerTop = CAShapeLayer()
            shapeLayerTop.frame = cell.bounds
            shapeLayerTop.path = maskPathTop.cgPath

            //Bottom Left Right Corners
            let maskPathBottom = UIBezierPath(roundedRect: cell.bounds, byRoundingCorners: [.bottomLeft, .bottomRight], cornerRadii: CGSize(width: 5.0, height: 5.0))
            let shapeLayerBottom = CAShapeLayer()
            shapeLayerBottom.frame = cell.bounds
            shapeLayerBottom.path = maskPathBottom.cgPath

            if (indexPath as NSIndexPath).section == 0 {
                if indexPath.row == 0 {
                    cell.layer.mask = shapeLayerTop
                }else if indexPath.row == 2 {
                    cell.layer.mask = shapeLayerBottom
                }
            }else if (indexPath as NSIndexPath).section == 1 {
                if indexPath.row == 0 {
                    cell.layer.mask = shapeLayerTop
                }else {
                    cell.layer.mask = shapeLayerBottom
                }
            }else if (indexPath as NSIndexPath).section == 2 {
                if indexPath.row == 0 {
                    cell.layer.mask = shapeLayerTop
                }else if indexPath.row == 2 {
                    cell.layer.mask = shapeLayerBottom
                }
            }
        }
    }

PS: Użyłem następującego kodu dla Swift 3.0.

Mehul Solanki
źródło
1
 func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath)
{
    if (tableView == self.orderDetailsTableView)
    {
        //Top Left Right Corners
        let maskPathTop = UIBezierPath(roundedRect: cell.bounds, byRoundingCorners: [.TopLeft, .TopRight], cornerRadii: CGSize(width: 5.0, height: 5.0))
        let shapeLayerTop = CAShapeLayer()
        shapeLayerTop.frame = cell.bounds
        shapeLayerTop.path = maskPathTop.CGPath

        //Bottom Left Right Corners
        let maskPathBottom = UIBezierPath(roundedRect: cell.bounds, byRoundingCorners: [.BottomLeft, .BottomRight], cornerRadii: CGSize(width: 5.0, height: 5.0))
        let shapeLayerBottom = CAShapeLayer()
        shapeLayerBottom.frame = cell.bounds
        shapeLayerBottom.path = maskPathBottom.CGPath

        //All Corners
        let maskPathAll = UIBezierPath(roundedRect: cell.bounds, byRoundingCorners: [.TopLeft, .TopRight, .BottomRight, .BottomLeft], cornerRadii: CGSize(width: 5.0, height: 5.0))
        let shapeLayerAll = CAShapeLayer()
        shapeLayerAll.frame = cell.bounds
        shapeLayerAll.path = maskPathAll.CGPath

        if (indexPath.row == 0 && indexPath.row == tableView.numberOfRowsInSection(indexPath.section)-1)
        {
            cell.layer.mask = shapeLayerAll
        }
     else if (indexPath.row == 0)
        {
        cell.layer.mask = shapeLayerTop
        }
        else if (indexPath.row == tableView.numberOfRowsInSection(indexPath.section)-1)
        {
            cell.layer.mask = shapeLayerBottom
        }
    }
}

działający kod dla swift ... tak naprawdę robimy, jeśli sekcja ma tylko jeden wiersz, to robimy to ze wszystkich stron, jeśli sekcja ma wiele wierszy, robimy to na górze w pierwszym wierszu i na dole w ostatnim wierszu ... właściwości BottomLeft, BottomRight, topLeft, TopRight powinny być typu rect corner (Sugestie z xcode podczas pisania ... istnieje inny narożnik zawartości właściwości o tej samej nazwie ... więc sprawdź to)

SaiPavanParanam
źródło
0

Obawiam się, że nie ma na to łatwego sposobu. Będziesz musiał dostosować swoje UITableViewCell, coś takiego działa:wprowadź opis obrazu tutaj

Ustaw styl tableView na grouped.

Ustaw kolor tła TableView, aby wyczyścić kolor.

Na swoim - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)wyczyść tło komórki i utwórz UIView z pożądanymi zaokrąglonymi rogami jako tłem. Coś takiego:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];

    if(cell == nil)
    {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"];
    }

    [cell setBackgroundColor:[UIColor clearColor]];

    UIView *roundedView = [[UIView alloc] initWithFrame:cell.frame];
    [roundedView setBackgroundColor:[UIColor whiteColor]];
    roundedView.layer.cornerRadius = 10.0;
    [[cell contentView] addSubview:roundedView];


    return cell;
}

Może być konieczne dalsze polerowanie, ale to jest główna idea.

Juan Carlos Ospina Gonzalez
źródło
Biorąc pod uwagę twój kod, jak możesz zmienić szerokość komórek lub dodać marginesy po bokach tabeli?
brain56,
0

Chciałem osiągnąć to samo, ale z obramowaniem wokół każdej sekcji (linia w iOS6). Ponieważ nie znalazłem łatwej modyfikacji sugerowanych rozwiązań, wymyśliłem własne. Jest to modyfikacja odpowiedzi udzielonej przez @Roberto Ferraz w tym temacie. Utworzyłem niestandardową klasę, która dziedziczy po UITableViewCell. Dodałem w nim widok kontenera o odpowiednim rozmiarze (u mnie obkurczony z obu stron o 15px). Niż w klasie zrobiłem to:

- (void)layoutSubviews
{
    [super layoutSubviews];
    
    CGFloat cornerRadius = 10.0f;
    
    self.vContainerView.layer.cornerRadius = cornerRadius;
    self.vContainerView.layer.masksToBounds = YES;
    self.vContainerView.layer.borderWidth = 1.0f;
    
    if (self.top && self.bottom)
    {
        // nothing to do - cell is initialized in prepareForReuse
    }
    else if (self.top)
    {
        // cell is on top - extend height to hide bottom line and corners
        CGRect frame = self.vContainerView.frame;
        frame.size.height += cornerRadius;
        self.vContainerView.frame = frame;
    
        self.vSeparatorLine.hidden = NO;
    }
    else if (self.bottom)
    {
        // cell is on bottom - extend height and shift container view up to hide top line and corners
        CGRect frame = self.vContainerView.frame;
        frame.size.height += cornerRadius;
        frame.origin.y -= cornerRadius;
        self.vContainerView.frame = frame;
    
        self.vSeparatorLine.hidden = YES;
    }
    else
    {
        // cell is in the middle - extend height twice the height of corners and shift container view by the height of corners - therefore hide top and bottom lines and corners.
        CGRect frame = self.vContainerView.frame;
        frame.size.height += (2 * cornerRadius);
        frame.origin.y -= cornerRadius;
        self.vContainerView.frame = frame;
    
        self.vSeparatorLine.hidden = NO;
    }
}

- (void)prepareForReuse
{
    // establish original values when cell is reused
    CGRect frame = self.vBorderView.frame;
    frame.size.height = BORDER_VIEW_HEIGHT;
    frame.origin.y = 0;
    self.vBorderView.frame = frame;
    
    self.vSeparatorLine.hidden = YES;
}

Następnie w swoim źródle danych robisz to:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    ...
    
    // only one cell in section - must be rounded on top & bottom
    if (indexPath.row == 0 && indexPath.row == [tableView numberOfRowsInSection:indexPath.section]-1)
    {
        cell.top    = YES;
        cell.bottom = YES;
    }
    // first cell - must be rounded on top
    else if (indexPath.row == 0)
    {
        cell.top    = YES;
        cell.bottom = NO;
    }
    // last cell - must be rounded on bottom
    else if (indexPath.row == [tableView numberOfRowsInSection:indexPath.section]-1)
    {
        cell.top    = NO;
        cell.bottom = YES;
    }
    else
    {
        cell.top    = NO;
        cell.top    = NO;
    }
    
    return cell;
}

I voila - masz zaokrąglone rogi ORAZ obramowania na swoich odcinkach.

Mam nadzieję że to pomoże!

PS Dokonałem kilku zmian, ponieważ znalazłem kilka błędów w oryginalnym kodzie - głównie nie ustawiłem wszystkich wartości we wszystkich przypadkach, co powoduje bardzo oszałamiające efekty przy ponownym użyciu komórek :)

TOPÓR
źródło
0

swift 4 Jeśli chcesz dołączyć również nagłówek sekcji, spróbuj poniżej

zadeklaruj cornerLayerWidth jako zmienną globalną

var cornerLayerWidth: CGFloat = 0,0

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    let cornerRadius: CGFloat = 10
    cell.backgroundColor = .clear

    let layer = CAShapeLayer()
    let pathRef = CGMutablePath()
    let bounds = cell.bounds.insetBy(dx: 0, dy: 0)
    cornerLayerWidth = bounds.width
    var addLine = false



    if indexPath.row == 0 && indexPath.row == tableView.numberOfRows(inSection: indexPath.section) - 1 {
        pathRef.__addRoundedRect(transform: nil, rect: bounds, cornerWidth: cornerRadius, cornerHeight: cornerRadius)
    }
    else if indexPath.row == 0 {


    }
    else if indexPath.row == tableView.numberOfRows(inSection: indexPath.section) - 1 {
        pathRef.move(to: .init(x: bounds.minX, y: bounds.minY))
        pathRef.addArc(tangent1End: .init(x: bounds.minX, y: bounds.maxY), tangent2End: .init(x: bounds.midX, y: bounds.maxY), radius: cornerRadius)
        pathRef.addArc(tangent1End: .init(x: bounds.maxX, y: bounds.maxY), tangent2End: .init(x: bounds.maxX, y: bounds.midY), radius: cornerRadius)
        pathRef.addLine(to: .init(x: bounds.maxX, y: bounds.minY))
    } else {
        pathRef.addRect(bounds)
        addLine = true
    }

    layer.path = pathRef
    layer.fillColor = UIColor(white: 1, alpha: 1).cgColor

    if (addLine == true) {
        let lineLayer = CALayer()
        let lineHeight = 1.0 / UIScreen.main.scale
        lineLayer.frame = CGRect(x: bounds.minX, y: bounds.size.height - lineHeight, width: bounds.size.width , height: lineHeight)
        lineLayer.backgroundColor = tableView.separatorColor?.cgColor
        layer.addSublayer(lineLayer)
    }

    let testView = UIView(frame: bounds)
    testView.layer.insertSublayer(layer, at: 0)
    testView.backgroundColor = .clear
    cell.backgroundView = testView
}

i

func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {

    let cell = tableView.dequeueReusableCell(withIdentifier: "eMPOIListHeaderViewCell") as! eMPOIListHeaderViewCell

    let cornerRadius: CGFloat = 10

    let layer = CAShapeLayer()
    let pathRef = CGMutablePath()
    let bounds =  CGRect(x: 0, y: 0, width: cornerLayerWidth, height: 50)//cell.bounds.insetBy(dx: 0, dy: 0)

    pathRef.__addRoundedRect(transform: nil, rect: bounds, cornerWidth: cornerRadius, cornerHeight: cornerRadius)

    pathRef.move(to: .init(x: bounds.minX, y: bounds.maxY))
    pathRef.addArc(tangent1End: .init(x: bounds.minX, y: bounds.minY), tangent2End: .init(x: bounds.midX, y: bounds.minY), radius: cornerRadius)
    pathRef.addArc(tangent1End: .init(x: bounds.maxX, y: bounds.minY), tangent2End: .init(x: bounds.maxX, y: bounds.midY), radius: cornerRadius)
    pathRef.addLine(to: .init(x: bounds.maxX, y: bounds.maxY))



    layer.path = pathRef
    layer.fillColor = UIColor(white: 1, alpha: 1).cgColor

         let lineLayer = CALayer()
        let lineHeight = 1.0 / UIScreen.main.scale
        lineLayer.frame = CGRect(x: bounds.minX, y: bounds.size.height - lineHeight, width: bounds.size.width , height: lineHeight)
        lineLayer.backgroundColor = tableView.separatorColor?.cgColor
        layer.addSublayer(lineLayer)

    let testView = UIView(frame: bounds)
    testView.layer.insertSublayer(layer, at: 0)
    testView.backgroundColor = .clear

    cell.backgroundView = testView


    return cell

}
Rajath Kornaya
źródło
Nie działa z mojego powodu, czy jest jakaś konkretna właściwość, o której należy pamiętać?
Jasmit
0

W Swift 4.2:

class MyCell: UITableViewCell {

var top = false
var bottom = false

override func layoutSubviews() {
    super.layoutSubviews()

    if top && bottom {
        layer.cornerRadius = 10
        layer.masksToBounds = true
        return
    }

    let shape = CAShapeLayer()
    let rect = CGRect(x: 0, y: 0, width: bounds.width, height: bounds.size.height)
    let corners: UIRectCorner = self.top ? [.topLeft, .topRight] : [.bottomRight, .bottomLeft]

    shape.path = UIBezierPath(roundedRect: rect, byRoundingCorners: corners, cornerRadii: CGSize(width: 10, height: 10)).cgPath
    layer.mask = shape
    layer.masksToBounds = true
  }
}

Używać:

Jeśli komórka jest pierwszą komórką w grupie, ustaw top = True, jeśli jest to ostatnia komórka bottom = true, jeśli komórka jest jedyną w grupie, ustaw oba na true.

Jeśli chcesz bardziej lub mniej zaokrąglone, po prostu zmień radia z 10 na inną wartość.

Roberto Ferraz
źródło
Jeśli chcesz zastosować cień i promień narożnika do pierwszej i ostatniej komórki, jak mogę to zrobić?
HardikS
-1

Ten kod ustawi zaokrąglone rogi dla całego widoku tabeli zamiast pojedynczej komórki.

UIView *roundedView = [[UIView alloc] initWithFrame:CGRectInset(table.frame, 5, 0)];
roundedView.backgroundColor = [UIColor colorWithWhite:1.f alpha:0.8f];
roundedView.layer.cornerRadius = 5.f;
[self.view addSubview:roundedView];
[roundedView release];
[self.view addSubview:table];

I wyczyść kolor tła każdej komórki w cellForRow

cell.backgroundColor=[UIColor clearColor];
Droid 404
źródło
1
To nie daje odpowiedzi na pytanie.
sosborn
-1

Dodaj to, aby usunąć górną linię w tableview self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;

MasterGoGo
źródło
To powinien być komentarz, a nie odpowiedź.
osioł