UITableView가 정적 셀로 설정되었습니다. 프로그래밍 방식으로 일부 셀을 숨길 수 있습니까?


132

UITableView 정적 셀로 설정합니다.

프로그래밍 방식으로 일부 셀을 숨길 수 있습니까?

답변:


48

이 솔루션을 찾고 있습니다.

StaticDataTableViewController 2.0

https://github.com/xelvenone/StaticDataTableViewController

애니메이션 유무에 관계없이 정적 셀을 표시하거나 숨기거나 다시로드 할 수 있습니다!

[self cell:self.outletToMyStaticCell1 setHidden:hide]; 
[self cell:self.outletToMyStaticCell2 setHidden:hide]; 
[self reloadDataAnimated:YES];

항상 (reloadDataAnimated : YES / NO) 만 사용하십시오 ([self.tableView reloadData]를 직접 호출하지 마십시오)

높이를 0으로 설정 한 해키 솔루션을 사용하지 않으며 변경 사항에 애니메이션을 적용하고 전체 섹션을 숨길 수 있습니다.


6
이 솔루션의 한 가지 문제는 숨겨진 셀이 있던 곳에 차이가 있다는 것입니다.
Jack

어떻게 차이를 의미합니까? github에서 직접 상황을 더 잘 설명 할 수 있습니까? 샘플을 실행 했습니까?
피터 라피 수

1
예를 들어 세 개의 섹션이 있고 중간 섹션에서 해당 섹션이 있던 공간에서 셀을 숨기면 의미합니다. 나는 샘플 프로젝트를 시도하지 않았지만 코드를 시도했다. 샘플을 시험해 볼게요.
Jack

1
샘플을 확인하십시오. 더 큰 업데이트가 있었을 것입니다. 아마도 오래된 코드가 있었을 것입니다 ... 저에게 완벽하게 작동합니다
Peter Lapisu

나는 샘플을 시험해 보았고 거기에서 효과가있는 것처럼 보입니다. 내가 다르게하고있는 유일한 것은 a를 사용하는 IBOutletCollection것이지만 어떻게 그것이 차이를 만들지 알지 못합니다. 어제 코드를 다운로드 했으므로 이전 버전은 생각하지 않습니다.
Jack

164

UITable에서 정적 셀을 숨기려면

  1. 이 방법을 추가하십시오 :

UITableView 컨트롤러 위임 클래스에서 :

목표 -C :

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell* cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];

    if(cell == self.cellYouWantToHide)
        return 0; //set the hidden cell's height to 0

    return [super tableView:tableView heightForRowAtIndexPath:indexPath];
}

빠른:

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    var cell = super.tableView(tableView, cellForRowAtIndexPath: indexPath)

    if cell == self.cellYouWantToHide {
        return 0
    }

    return super.tableView(tableView, heightForRowAtIndexPath: indexPath)
}

이 메소드는 UITable의 각 셀에 대해 호출됩니다. 숨기려는 셀을 호출하면 높이를 0으로 설정합니다. 콘센트를 만들어 대상 셀을 식별합니다.

  1. 디자이너에서 숨기려는 셀의 콘센트를 만듭니다. 이러한 셀 중 하나의 콘센트를 위의 "cellYouWantToHide"라고합니다.
  2. 숨길 셀에 대해서는 IB에서 "클립 서브 뷰"를 확인하십시오. 숨어있는 셀에는 ClipToBounds = YES가 있어야합니다. 그렇지 않으면 텍스트가 UITableView에 쌓입니다.

10
좋은 해결책. 이 ClipToBounds문제 를 피하기 위해 셀을 숨김으로 설정할 수도 있습니다. 이것은 나에게 더 깨끗해 보일 것입니다. ;-)
MonsieurDart

13
ClipToBounds = YES 인 경우 +1 다른 스레드의 Numeorus 솔루션은이를 놓쳤습니다.
Jeff

2
좋은 생각이야 이것이 내가 찾은 가장 쉬운 솔루션입니다. 다른 솔루션에는 둘 이상의 위치에 코드가 있습니다. BTW의 IB에서 ClipToBounds는 "Clip Subviews"로 표시됩니다.
VaporwareWolf

1
조금만 수정하면 .cellYouWantToHide 대신 self .cellYouWantToHide를 사용 하십시오.
Zoltan Vinkler

2
셀 객체를 만들지 않고도 "index.row"를 사용하여 "uitableviewcell"을 숨길 수 있습니다
g212gs

38

가장 좋은 방법은 다음 블로그 http://ali-reynolds.com/2013/06/29/hide-cells-in-static-table-view/에 설명 된대로입니다.

인터페이스 빌더에서 정적 테이블 뷰를 정상적으로 설계하십시오. 잠재적으로 숨겨진 셀이 모두 있습니다. 그러나 숨길 수있는 모든 잠재적 인 셀에 대해 수행해야 할 한 가지가 있습니다. 셀의 "클립 하위 뷰"속성을 확인하십시오. 그렇지 않으면 셀을 숨기려고 할 때 셀의 내용이 사라지지 않습니다 (높이를 줄임으로써) - 더 늦게).

SO – 셀에 스위치가 있고 스위치는 일부 정적 셀을 숨기고 표시해야합니다. IBAction에 연결하고 다음을 수행하십시오.

[self.tableView beginUpdates];
[self.tableView endUpdates];

그것은 세포가 나타나고 사라지는 멋진 애니메이션을 제공합니다. 이제 다음 테이블 뷰 델리게이트 메소드를 구현하십시오.

- (float)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    if (indexPath.section == 1 && indexPath.row == 1) { // This is the cell to hide - change as you need
    // Show or hide cell
        if (self.mySwitch.on) {
            return 44; // Show the cell - adjust the height as you need
        } else {
            return 0; // Hide the cell
        }
   }
   return 44;
}

그리고 그게 다야. 스위치를 뒤집 으면 멋지고 부드러운 애니메이션으로 셀이 숨겨지고 다시 나타납니다.


업데이트 : 셀 숨기기 / 표시를 사용하여 셀 레이블을 숨기기 / 표시로 설정해야합니다. 그렇지 않으면 레이블이 엉망이됩니다.
Mohamed Saleh

1
정적 셀의 내용 내 UIView에 cell.content에 대한 제약 조건이있는 경우 해당 제약 조건이 새 셀 높이에 유효하지 않으면 런타임 오류가 발생할 수 있습니다.
Pedro Borges

1
가장 좋은 답변입니다. 감사.
에릭 첸

1
이 트릭이 동적 콘텐츠와 함께 작동한다는 것을 알았습니다. 정적에서도 꽤 잘 작동합니다. 너무 간단합니다.
개미

2
이 기능은 실제로 작동하지만 누락 된 부분을 처리합니다. 숨기거나 표시 할 행에 날짜 선택기가 포함되어 있으면 [self.tableView beginUpdates]; [self.tableView endUpdates]; 숨기는 동안 여전히 결함이 남습니다. 결함을 제거하려면 [self.tableView reloadRowsAtIndexPaths : @ [indexPathOfTargetRow] withRowAnimation : UITableViewRowAnimationNone]; 또한 행 애니메이션이 어떻게 든 "비활성화"되어 있습니다.
Chris

34

내 솔루션은 Gareth와 비슷한 방향으로 진행되지만 몇 가지 작업은 다르게 수행합니다.

간다 :

1. 세포를 숨기십시오

셀을 직접 숨길 수는 없습니다. UITableViewController는 정적 셀을 제공하는 데이터 소스이며 현재 "셀 x 제공하지 않음"을 알 수있는 방법이 없습니다. 따라서 우리는 우리 자신의 데이터 소스를 제공해야합니다.UITableViewController 정적 셀을 얻으려면에 .

가장 쉬운 방법은 하위 클래스 UITableViewController를 만들고 셀을 숨길 때 다르게 동작해야하는 모든 메서드를 재정의 하는 것입니다. 입니다.

가장 간단한 경우 (단일 섹션 테이블, 모든 셀의 높이가 동일), 다음과 같습니다.

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section    
{
    return [super tableView:tableView numberOfRowsInSection:section] - numberOfCellsHidden;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Recalculate indexPath based on hidden cells
    indexPath = [self offsetIndexPath:indexPath];

    return [super tableView:tableView cellForRowAtIndexPath:indexPath];
}

- (NSIndexPath*)offsetIndexPath:(NSIndexPath*)indexPath
{
    int offsetSection = indexPath.section; // Also offset section if you intend to hide whole sections
    int numberOfCellsHiddenAbove = ... // Calculate how many cells are hidden above the given indexPath.row
    int offsetRow = indexPath.row + numberOfCellsHiddenAbove;

    return [NSIndexPath indexPathForRow:offsetRow inSection:offsetSection];
}

테이블에 여러 섹션이 있거나 셀의 높이가 다른 경우 더 많은 메서드를 재정의해야합니다. 동일한 원칙이 여기에 적용됩니다. super에 위임하기 전에 indexPath, section 및 row를 오프셋해야합니다.

또한 다음과 같은 메소드의 indexPath 매개 변수는 didSelectRowAtIndexPath: 같은 셀에 대해 같은 상태 (즉, 숨겨진 셀 수)에 따라 다를 수 있습니다. 따라서 항상 indexPath 매개 변수를 오프셋하고이 값으로 작업하는 것이 좋습니다.

2. 변화를 애니메이션

Gareth가 이미 언급했듯이 reloadSections:withRowAnimation:방법을 사용하여 변경 사항을 애니메이션하면 주요 결함이 발생합니다 .

reloadData:나중에 즉시 전화 하면 애니메이션이 훨씬 향상됩니다 (사소한 결함 만 남음). 애니메이션 후 테이블이 올바르게 표시됩니다.

그래서 내가하고있는 일은 :

- (void)changeState
{
     // Change state so cells are hidden/unhidden
     ...

    // Reload all sections
    NSIndexSet* reloadSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [self numberOfSectionsInTableView:tableView])];

    [tableView reloadSections:reloadSet withRowAnimation:UITableViewRowAnimationAutomatic];
    [tableView reloadData];
}

2
당신을 축복합니다, 당신은 달콤한 달콤한 사람입니다.
guptron

사소한 애니메이션 결함에 대한 해결책을 찾았습니까? 나를 위해 셀 사이의 구분선은 올바르게 애니메이션되지 않으며 글리치가있는 것보다 애니메이션을 사용하지 않습니다. 그래도 훌륭한 솔루션!
Maximilian Körner

내 문제는 정적 셀을 사용 numberOfRowsInSection:하면 테이블이 처음로드 될 때만 호출 된다는 것입니다 . [self.tableView reloadData]를 호출하면 numberOfRowsInSection:다시 호출되지 않습니다. 만 cellForRowAtIndexPath:이라고합니다. 내가 무엇을 놓치고 있습니까?
로마

13
  1. 디자이너에서 숨기려는 셀의 콘센트를 만듭니다. 예를 들어 'cellOne'을 숨기려면 viewDidLoad () 에서이 작업을 수행하십시오.

cellOneOutlet.hidden = true

이제 아래 방법을 재정의하고 어떤 셀 상태가 숨겨져 있는지 확인하고 해당 셀의 높이 0을 반환하십시오. 이것은 정적 tableView의 모든 셀을 신속하게 숨길 수있는 많은 방법 중 하나입니다.

override func tableView(tableView: UITableView, heightForRowAtIndexPathindexPath: NSIndexPath) -> CGFloat 
{

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

        if tableViewCell.hidden == true
        {
            return 0
        }
        else{
             return super.tableView(tableView, heightForRowAtIndexPath: indexPath)
        }

}

지금까지 최고의 솔루션!
derdida

변경 후 tableView.reloadData ()를 추가하면 완벽합니다. 솔루션 변경에 많은 노력을 아끼지 않았습니다! 감사합니다
Shayan C

1
Swift 4에서는 사용할 수 없습니다 let tableViewCell = super.tableView(tableView,cellForRowAtIndexPath: indexPath). 나는로 대체되었다고 가정합니다 let tableViewCell = tableView.cellForRow(at: indexPath as IndexPath).
Clifton Labrum

에 정적 셀을 사용하고 있기 때문에 대리자 메서드 UITableViewController가 없습니다 UITableView. 호출 heightForRow하려면 다른 방법이 필요합니까?
Clifton Labrum 5

@CliftonLabrum 아니오,이 방법 만 무시할 수 있습니다.
Alexander Ershov

11

실제로 섹션을 숨기고 삭제하지 않는 대안을 생각해 냈습니다. @ henning77의 접근 방식을 시도했지만 정적 UITableView의 섹션 수를 변경하면 계속 문제가 발생합니다. 이 방법은 실제로 잘 작동했지만 주로 행 대신 섹션을 숨기려고합니다. 나는 즉시 행을 성공적으로 제거하고 있지만 훨씬 더 지저분하므로 표시하거나 숨길 필요가있는 섹션으로 항목을 그룹화하려고했습니다. 섹션을 숨기는 방법의 예는 다음과 같습니다.

먼저 NSMutableArray 속성을 선언합니다

@property (nonatomic, strong) NSMutableArray *hiddenSections;

viewDidLoad에서 (또는 데이터를 쿼리 한 후) 숨기려는 섹션을 배열에 추가 할 수 있습니다.

- (void)viewDidLoad
{
    hiddenSections = [NSMutableArray new];

    if(some piece of data is empty){
        // Add index of section that should be hidden
        [self.hiddenSections addObject:[NSNumber numberWithInt:1]];
    }

    ... add as many sections to the array as needed

    [self.tableView reloadData];
}

그런 다음 TableView 델리게이트 메소드를 다음과 같이 구현하십시오.

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
    if([self.hiddenSections containsObject:[NSNumber numberWithInt:section]]){
        return nil;
    }

    return [super tableView:tableView titleForHeaderInSection:section];
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if([self.hiddenSections containsObject:[NSNumber numberWithInt:indexPath.section]]){
        return 0;
    }

    return [super tableView:tableView heightForRowAtIndexPath:[self offsetIndexPath:indexPath]];
}

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    if([self.hiddenSections containsObject:[NSNumber numberWithInt:indexPath.section]]){
        [cell setHidden:YES];
    }
}

그런 다음 높이를 0으로 설정할 수 없기 때문에 숨겨진 섹션에 대해 머리글과 바닥 글 높이를 1로 설정하십시오. 이렇게하면 추가 2 픽셀 공간이 생길 수 있지만 다음에 보이는 머리글의 높이를 조정하여 보충 할 수 있습니다.

-(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section 
{
    CGFloat height = [super tableView:tableView heightForHeaderInSection:section];

    if([self.hiddenSections containsObject:[NSNumber numberWithInt:section]]){
        height = 1; // Can't be zero
    }
    else if([self tableView:tableView titleForHeaderInSection:section] == nil){ // Only adjust if title is nil
        // Adjust height for previous hidden sections
        CGFloat adjust = 0;

        for(int i = (section - 1); i >= 0; i--){
            if([self.hiddenSections containsObject:[NSNumber numberWithInt:i]]){
                adjust = adjust + 2;
            }
            else {
                break;
            }
        }

        if(adjust > 0)
        {                
            if(height == -1){
                height = self.tableView.sectionHeaderHeight;
            }

            height = height - adjust;

            if(height < 1){
                height = 1;
            }
        }
    }

    return height;
}

-(CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section 
{   
    if([self.hiddenSections containsObject:[NSNumber numberWithInt:section]]){
        return 1;
    }
    return [super tableView:tableView heightForFooterInSection:section];
}

그런 다음 숨길 특정 행이있는 경우 numberOfRowsInSection 및 cellForRowAtIndexPath에 리턴되는 행을 조정할 수 있습니다. 이 예에는 3 개의 행이 있으며 3 개가 비어 있고 제거 해야하는 섹션이 있습니다.

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    NSInteger rows = [super tableView:tableView numberOfRowsInSection:section];

    if(self.organization != nil){
        if(section == 5){ // Contact
            if([self.organization objectForKey:@"Phone"] == [NSNull null]){     
                rows--;
            }

            if([self.organization objectForKey:@"Email"] == [NSNull null]){     
                rows--;
            }

            if([self.organization objectForKey:@"City"] == [NSNull null]){     
                rows--;
            }
        }
    }

    return rows;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{    
    return [super tableView:tableView cellForRowAtIndexPath:[self offsetIndexPath:indexPath]];
}

조건부로 행을 제거하는 행에 대한 indexPath를 계산하려면이 offsetIndexPath를 사용하십시오. 섹션 만 숨기는 경우 필요하지 않습니다

- (NSIndexPath *)offsetIndexPath:(NSIndexPath*)indexPath
{
    int row = indexPath.row;

    if(self.organization != nil){
        if(indexPath.section == 5){
            // Adjust row to return based on which rows before are hidden
            if(indexPath.row == 0 && [self.organization objectForKey:@"Phone"] == [NSNull null] && [self.organization objectForKey:@"Email"] != [NSNull null]){     
                row++;
            }
            else if(indexPath.row == 0 && [self.organization objectForKey:@"Phone"] == [NSNull null] && [self.organization objectForKey:@"Address"] != [NSNull null]){     
                row = row + 2;
            }
            else if(indexPath.row == 1 && [self.organization objectForKey:@"Phone"] != [NSNull null] && [self.organization objectForKey:@"Email"] == [NSNull null]){     
                row++;
            }
            else if(indexPath.row == 1 && [self.organization objectForKey:@"Phone"] == [NSNull null] && [self.organization objectForKey:@"Email"] != [NSNull null]){     
                row++;
            }
        }
    }

    NSIndexPath *offsetPath = [NSIndexPath indexPathForRow:row inSection:indexPath.section];

    return offsetPath;
}

재정의 할 방법이 많이 있지만이 방법에 대해 내가 좋아하는 것은 재사용 할 수 있다는 것입니다. hiddenSections 배열을 설정하고 추가하면 올바른 섹션이 숨겨집니다. 행을 숨기는 것은 조금 까다 롭지 만 가능합니다. 테두리가 올바르게 그려지지 않기 때문에 그룹화 된 UITableView를 사용하는 경우 숨기려는 행의 높이를 0으로 설정할 수 없습니다.


1
아마 사용합니다 NSMutableSet위해 hiddenSections대신. 회원 자격을 테스트 할 때 속도가 훨씬 빠릅니다.
pixelfreak

좋은 대답입니다, 오스틴 나는 그 대답에 투표를했고 이것을 나중에 내 프로젝트를위한 참고 자료로 사용할 것입니다. pixelfreak은 NSMutableSetfor 사용 에 대해 좋은 지적을 hiddenSections하지만, 대답의 요점은 사용해야하는 데이터 구조 유형에 대해 nit-picky보다 개념적이라는 것을 이해합니다.
BigSauce

10

정적 UITableView에서 애니메이션을 사용하여 셀을 숨기거나 표시 할 수 있습니다. 그리고 그렇게 어렵지 않습니다.

데모 프로젝트

데모 프로젝트 비디오

요점:

  1. Use tableView:heightForRowAtIndexPath: 일부 상태를 기반으로 셀 높이를 동적으로 지정합니다.
  2. 상태가 변경 될 때 호출하여 표시 / 숨김 셀을 애니메이션 tableView.beginUpdates();tableView.endUpdates()
  3. tableView.cellForRowAtIndexPath:안으로 전화하지 마십시오 tableView:heightForRowAtIndexPath:. 캐시 된 indexPath를 사용하여 셀을 구별하십시오.
  4. 셀을 숨기지 마십시오. 대신 Xcode에서 "Clip Subviews"속성을 설정하십시오.
  5. 일반 셀이 아닌 사용자 정의 셀을 사용하여 멋진 숨기기 애니메이션을 얻으십시오. 또한 셀 높이 == 0 인 경우 자동 레이아웃을 올바르게 처리하십시오.

내 블로그에 추가 정보 (러시아어)


1
"셀을 숨기지 마십시오. 대신 Xcode에서"클립 하위 뷰 "속성을 설정하십시오."
balkoth

8

예, 현재 동일한 문제로 어려움을 겪고 있지만 확실히 가능합니다. 셀을 숨길 수 있었고 모든 것이 제대로 작동하지만 현재는 깔끔하게 애니메이션을 만들 수 없습니다. 내가 찾은 것은 다음과 같습니다.

첫 번째 섹션의 첫 번째 행에서 ON / OFF 스위치의 상태에 따라 행을 숨기고 있습니다. 스위치가 ON이면 같은 섹션에 그 아래에 1 개의 행이 있고, 그렇지 않으면 2 개의 다른 행이 있습니다.

스위치가 토글 될 때 호출되는 선택기가 있고 현재 상태를 나타내는 변수를 설정했습니다. 그런 다음 다음을 호출합니다.

[[self tableView] reloadData];

tableView : willDisplayCell : forRowAtIndexPath를 재정의합니다 . 함수를 셀을 과 같이하십시오.

[cell setHidden:YES];

셀과 내용을 숨기지 만 차지하는 공간을 제거하지는 않습니다.

공백을 제거하려면 tableView : heightForRowAtIndexPath를 . 함수를 숨겨져 야하는 행에 대해 0을 리턴하십시오.

또한 tableView : numberOfRowsInSection 을 대체해야합니다 . 하고 해당 섹션의 행 수를 리턴해야합니다. 테이블이 그룹화 된 스타일 인 경우 둥근 모서리가 올바른 셀에 나타나도록 이상한 것을 수행해야합니다. 정적 테이블에는 섹션에 대한 전체 셀 세트가 있으므로 옵션을 포함하는 첫 번째 셀이 있고 ON 상태 옵션에 대해 1 셀이 있고 OFF 상태 옵션에 대해 2 개 이상의 셀이 있습니다 (총 4 셀). 옵션이 ON이면 4를 반환해야합니다. 숨겨진 옵션이 포함되어 있으므로 표시된 마지막 옵션에 둥근 상자가 있습니다. 옵션이 꺼져 있으면 마지막 두 옵션이 표시되지 않으므로 2를 반환합니다. 이것이 명확하지 않으면 죄송하지만 설명하기가 어렵습니다. 설정을 설명하기 위해 IB의 테이블 섹션 구성입니다.

  • 행 0 : ON / OFF 스위치가있는 옵션
  • 1 행 : 옵션이 ON 일 때 표시
  • 2 행 : 옵션이 꺼져있을 때 표시
  • 3 행 : 옵션이 꺼져있을 때 표시

따라서 옵션이 ON이면 테이블은 다음 두 행을보고합니다.

  • 행 0 : ON / OFF 스위치가있는 옵션
  • 1 행 : 옵션이 ON 일 때 표시

옵션이 OFF이면 테이블은 다음과 같은 네 개의 행을보고합니다.

  • 행 0 : ON / OFF 스위치가있는 옵션
  • 1 행 : 옵션이 ON 일 때 표시
  • 2 행 : 옵션이 꺼져있을 때 표시
  • 3 행 : 옵션이 꺼져있을 때 표시

이 접근 방식은 여러 가지 이유로 정확하지 않습니다. 지금까지 실험을해온 한, 더 나은 방법을 찾으면 알려주십시오. 지금까지 내가 관찰 한 문제는 다음과 같습니다.

  • 테이블에 행 수가 기본 데이터에 포함 된 것과 다른 수를 알려주는 것은 잘못된 생각입니다.

  • 변경 사항을 애니메이션으로 표시 할 수 없습니다. 내가 사용하려고했습니다 reloadSections : withRowAnimation :있는 tableView를 reloadData하고 결과를 이해하지 않는 것 대신에, 나는 여전히이 작업을 얻기 위해 노력하고있어. 현재 일어날 것으로 보이는 것은 tableView가 올바른 행을 업데이트하지 않으므로 표시되어야하는 행이 숨겨져 있고 첫 번째 행 아래에 공백이 남아 있다는 것입니다. 나는 이것이 기본 데이터에 대한 첫 번째 지점과 관련이 있다고 생각합니다.

누군가가 다른 방법이나 애니메이션으로 확장하는 방법을 제안 할 수 있기를 희망하지만 이것이 시작될 수 있습니다. 함수에 대한 하이퍼 링크가 부족하다는 점에 사과를 드려 죄송하지만 새로운 사용자이므로 스팸 필터에 의해 거부되었습니다.


[[self tableView] reloadData];세포를 숨기고 나서 한 번 더 전화해야한다고 확신합니다
Shmidt

이것을 다시 유감스럽게 생각하지만 UITableViewController를 서브 클래스 화하여 정적 셀과 함께 사용하는 방법은 무엇입니까? Xcode에서 알려주지 않습니다.
Dany Joumaa

Nessup, UITableView를 서브 클래스화할 필요가 없습니다. 스토리 보드에서 TableViewController를 선택한 다음 TableView를 클릭하십시오. 이제 동적 / 정적 셀 중에서 선택할 수 있습니다.
Shmidt

1
정적 셀 숨기기 / 표시에 애니메이션을 적용하는 방법을 찾았습니다. 그냥 전화 return [super tableView:tableView cellForRowAtIndexPath:indexPath];UITableViewController정적 세포를 생성하기위한 서브 클래스입니다. 인덱스 경로는 정적 인덱스입니다 (동적 아님).
k06a

8

Justas의 답변에 따르면 Swift 4의 경우 :

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    let cell = super.tableView(tableView, cellForRowAt: indexPath)

    if cell == self.cellYouWantToHide {
        return 0
    }

    return super.tableView(tableView, heightForRowAt: indexPath)
}

1
tableView.reloadRows(at:, with:)행이 이미 표시된 상태에서 높이를 변경하면 셀을 업데이트 해야 할 수도 있습니다.
Frost-Lee

5

좋아, 약간의 시도 후에, 나는 일반적인 대답이 아닙니다. 이 셀을 숨겨야하는지 확인하기 위해 "isHidden"또는 "hidden"변수를 사용하고 있습니다.

  1. 뷰 컨트롤러에 IBOutlet을 작성하십시오. @IBOutlet weak var myCell: UITableViewCell!

  2. myCell사용자 정의 함수를 업데이트하십시오 ( 예 : viewDidLoad에 추가 할 수 있음).

override func viewDidLoad() { super.viewDidLoad() self.myCell.isHidden = true }

  1. 대리인 방법에서 :

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { let cell = super.tableView(tableView, cellForRowAt: indexPath) guard !cell.isHidden else { return 0 } return super.tableView(tableView, heightForRowAt: indexPath) }

이렇게하면 대리자 메서드의 논리가 줄어들고 비즈니스 요구 사항에만 집중하면됩니다.


4

자동 레이아웃 문제로 인해 셀 숨기기 / 표시, rowHeight 변경 또는 자동 레이아웃 제약 조건으로 인한 위의 답변이 작동하지 않았습니다. 코드는 참을 수 없게되었습니다.

간단한 정적 테이블의 경우 가장 효과적인 것은 다음과 같습니다.

  1. 정적 테이블의 모든 셀에 대한 콘센트를 만듭니다.
  2. 표시 할 셀의 콘센트 만있는 배열 만들기
  3. cellForRowAtIndexPath를 재정 의하여 배열에서 셀을 반환
  4. 배열의 개수를 반환하도록 numberOfRowsInSection을 재정의
  5. 해당 배열에 어떤 셀이 있어야하는지 결정하는 메소드를 구현하고 필요할 때마다 해당 메소드를 호출 한 다음 데이터를 다시로드하십시오.

다음은 테이블 뷰 컨트롤러의 예입니다.

@IBOutlet weak var titleCell: UITableViewCell!
@IBOutlet weak var nagCell: UITableViewCell!
@IBOutlet weak var categoryCell: UITableViewCell!

var cellsToShow: [UITableViewCell] = []

override func viewDidLoad() {
    super.viewDidLoad()
    determinCellsToShow()
}

func determinCellsToShow() {
    if detail!.duration.type != nil {
        cellsToShow = [titleCell, nagCell, categoryCell]
    }
    else {
        cellsToShow = [titleCell,  categoryCell]
    }
}

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    return cellsToShow[indexPath.row]
}

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return cellsToShow.count
}

이것은 5 년 후에도 훌륭하게 작동했습니다! 정말 고맙습니다.
Schrockwell

2020 그리고 이것이 가장 큰 해결책입니다. 해킹이 필요하지 않습니다.
mdonati

3

간단한 iOS 11 및 IB / Storyboard 호환 방법

iOS 11의 경우 수정 된 버전의 Mohamed Saleh의 답변이 Apple의 문서를 기반으로 한 개선 사항과 함께 가장 잘 작동 한다는 것을 알았습니다 . 멋지게 애니메이션을 만들고 추악한 해킹이나 하드 코딩 된 값을 피하고 Interface Builder에 이미 설정된 행 높이를 사용합니다. .

기본 개념은 숨겨진 행에 대해 행 높이를 0으로 설정하는 것입니다. 그런 다음 tableView.performBatchUpdates일관되게 작동하는 애니메이션을 트리거하는 데 사용하십시오 .

셀 높이 설정

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    if indexPath == indexPathOfHiddenCell {
        if cellIsHidden {
            return 0
        }
    }
    // Calling super will use the height set in your storyboard, avoiding hardcoded values
    return super.tableView(tableView, heightForRowAt: indexPath)
}

확인 cellIsHidden하고 indexPathOfHiddenCell사용 사례에 맞게 설정해야합니다. 내 코드의 경우 테이블 뷰 컨트롤러의 속성입니다.

셀 토글

가시성 (예 : 버튼 동작 또는 didSelectRow)을 제어하는 모든 방법 에서 performBatchUpdates블록 내에서 cellIsHidden 상태를 전환하십시오 .

tableView.performBatchUpdates({
                // Use self to capture for block
                self.cellIsHidden = !self.cellIsHidden 
            }, completion: nil)

애플은 권장 performBatchUpdates이상 beginUpdates/endUpdates 가능하면.


1

정적 테이블에서 셀 숨기기 애니메이션에 대한 솔루션을 찾았습니다.

// Class for wrapping Objective-C block
typedef BOOL (^HidableCellVisibilityFunctor)();
@interface BlockExecutor : NSObject
@property (strong,nonatomic) HidableCellVisibilityFunctor block;
+ (BlockExecutor*)executorWithBlock:(HidableCellVisibilityFunctor)block;
@end
@implementation BlockExecutor
@synthesize block = _block;
+ (BlockExecutor*)executorWithBlock:(HidableCellVisibilityFunctor)block
{
    BlockExecutor * executor = [[BlockExecutor alloc] init];
    executor.block = block;
    return executor;
}
@end

하나의 추가 사전 만 필요했습니다.

@interface MyTableViewController ()
@property (nonatomic) NSMutableDictionary * hidableCellsDict;
@property (weak, nonatomic) IBOutlet UISwitch * birthdaySwitch;
@end

MyTableViewController의 구현을 살펴보십시오. 보이는 인덱스와 보이지 않는 인덱스 사이에서 indexPath를 변환하는 두 가지 방법이 필요합니다.

- (NSIndexPath*)recoverIndexPath:(NSIndexPath *)indexPath
{
    int rowDelta = 0;
    for (NSIndexPath * ip in [[self.hidableCellsDict allKeys] sortedArrayUsingSelector:@selector(compare:)])
    {
        BlockExecutor * executor = [self.hidableCellsDict objectForKey:ip];
        if (ip.section == indexPath.section
            && ip.row <= indexPath.row + rowDelta
            && !executor.block())
        {
            rowDelta++;
        }
    }
    return [NSIndexPath indexPathForRow:indexPath.row+rowDelta inSection:indexPath.section];
}

- (NSIndexPath*)mapToNewIndexPath:(NSIndexPath *)indexPath
{
    int rowDelta = 0;
    for (NSIndexPath * ip in [[self.hidableCellsDict allKeys] sortedArrayUsingSelector:@selector(compare:)])
    {
        BlockExecutor * executor = [self.hidableCellsDict objectForKey:ip];
        if (ip.section == indexPath.section
            && ip.row < indexPath.row - rowDelta
            && !executor.block())
        {
            rowDelta++;
        }
    }
    return [NSIndexPath indexPathForRow:indexPath.row-rowDelta inSection:indexPath.section];
}

UISwitch 값 변경에 대한 하나의 IBAction :

- (IBAction)birthdaySwitchChanged:(id)sender
{
    NSIndexPath * indexPath = [self mapToNewIndexPath:[NSIndexPath indexPathForRow:1 inSection:1]];
    if (self.birthdaySwitch.on)
        [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
    else
        [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}

일부 UITableViewDataSource 및 UITableViewDelegate 메소드 :

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    int numberOfRows = [super tableView:tableView numberOfRowsInSection:section];
    for (NSIndexPath * indexPath in [self.hidableCellsDict allKeys])
        if (indexPath.section == section)
        {
            BlockExecutor * executor = [self.hidableCellsDict objectForKey:indexPath];
            numberOfRows -= (executor.block()?0:1);
        }
    return numberOfRows;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    indexPath = [self recoverIndexPath:indexPath];
    return [super tableView:tableView cellForRowAtIndexPath:indexPath];
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    indexPath = [self recoverIndexPath:indexPath];
    return [super tableView:tableView heightForRowAtIndexPath:indexPath];
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    // initializing dictionary
    self.hidableCellsDict = [NSMutableDictionary dictionary];
    [self.hidableCellsDict setObject:[BlockExecutor executorWithBlock:^(){return self.birthdaySwitch.on;}] forKey:[NSIndexPath indexPathForRow:1 inSection:1]];
}

- (void)viewDidUnload
{
    [self setBirthdaySwitch:nil];
    [super viewDidUnload];
}

@end

1

신속한 답변 :

TableViewController에 다음 메소드를 추가하십시오.

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    return indexPathOfCellYouWantToHide == indexPath ? 0 : super.tableView(tableView, heightForRowAtIndexPath: indexPath)
}

tableView가 숨기려는 셀을 그리려고하면 위의 방법으로 높이가 0pt로 설정되어 다른 모든 것이 변경되지 않으므로 표시되지 않습니다.

그주의 사항 indexPathOfCellYouWantToHide언제든지 변경 될 수 있습니다 :)


1

> Swift 2.2에서는 몇 가지 답변을 결합했습니다.

스토리 보드에서 콘센트를 만들어 staticCell에 연결하십시오.

@IBOutlet weak var updateStaticCell: UITableViewCell!

override func viewDidLoad() {
    ...
    updateStaticCell.hidden = true
}

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    if indexPath.row == 0 {
        return 0
    } else {
        return super.tableView(tableView, heightForRowAtIndexPath: indexPath)
    }
}

첫 번째 셀을 숨기고 위에서 설명한대로 높이를 0으로 설정하고 싶습니다.


1

스위프트 4 :

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    var height = super.tableView(tableView, heightForRowAt: indexPath)
    if (indexPath.row == HIDDENROW) {
        height = 0.0
    }
    return height
}

0

테이블 뷰의 맨 아래에서 셀을 숨기는 가장 쉬운 시나리오의 경우 셀을 숨긴 후 tableView의 contentInset을 조정할 수 있습니다.

- (void)adjustBottomInsetForHiddenSections:(NSInteger)numberOfHiddenSections
{
    CGFloat bottomInset = numberOfHiddenSections * 44.0; // or any other 'magic number
    self.tableView.contentInset = UIEdgeInsetsMake(self.tableView.contentInset.top, self.tableView.contentInset.left, -bottomInset, self.tableView.contentInset.right);
}


0

k06a ( https://github.com/k06a/ABStaticTableViewController )의 솔루션은 셀 헤더 및 바닥 글을 포함한 전체 섹션을 숨기므로 더 좋습니다.이 솔루션 ( https://github.com/peterpaulis/StaticDataTableViewController )은 바닥 글을 제외한 모든 항목을 숨 깁니다.

편집하다

바닥 글을에 숨기려면 해결책을 찾았습니다 StaticDataTableViewController. 이것은 StaticTableViewController.m 파일에 복사해야하는 것입니다.

- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section {
    if ([tableView.dataSource tableView:tableView numberOfRowsInSection:section] == 0) {
        return nil;
    } else {
        return [super tableView:tableView titleForFooterInSection:section];
    }
}

- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {

    CGFloat height = [super tableView:tableView heightForFooterInSection:section];

    if (self.originalTable == nil) {
        return height;
    }

    if (!self.hideSectionsWithHiddenRows) {
        return height;
    }

    OriginalSection * os = self.originalTable.sections[section];
    if ([os numberOfVissibleRows] == 0) {
       //return 0;
        return CGFLOAT_MIN;
    } else {
        return height;
    }

    //return 0;
    return CGFLOAT_MIN;
}

0

물론 가능합니다. 먼저 tableView로 돌아가서 표시하려는 셀 수를 지정한 다음 super스토리 보드에서 특정 셀을 달성하기 위해 호출 하여 tableView에 반환하십시오.

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return self.mode.numberOfCells()
}

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = super.tableView(tableView, cellForRowAtIndexPath: self.mode.indexPathForIndexPath(indexPath))

    return cell
}

세포가 다른 hieght를 가지고 있다면 그것을 반환하십시오 :

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    return super.tableView(tableView, heightForRowAtIndexPath: self.mode.indexPathForIndexPath(indexPath))
}

0

@Saleh Masum 솔루션 외에도 :

자동 레이아웃 오류가 발생하는 경우 자동 레이아웃 오류가 발생 하면tableViewCell.contentView

스위프트 3 :

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    let tableViewCell = super.tableView(tableView, cellForRowAt: indexPath)

    if tableViewCell.isHidden == true
    {
        tableViewCell.contentView.removeConstraints(tableViewCell.contentView.constraints)
        return 0
    }
    else{
        return super.tableView(tableView, heightForRowAt: indexPath)
    }

}

솔루션은 앱의 흐름에 따라 다릅니다 . 동일한 뷰 컨트롤러 인스턴스에서 셀을 표시하거나 숨기려면 제약 조건제거 되므로 최선의 선택이 아닐 수 있습니다 .


0

해킹없이 정적 셀과 섹션을 동적으로 숨기는 더 좋은 방법을 얻었습니다.

행 높이를 0으로 설정하면 행을 숨길 수 있지만 전체 행을 숨기고 일부 행을 숨기더라도 행을 숨기더라도 작동하지 않습니다.

내 접근법은 정적 셀의 섹션 배열을 만드는 것입니다. 그러면 테이블 뷰 내용이 섹션 배열에 의해 구동됩니다.

샘플 코드는 다음과 같습니다.

var tableSections = [[UITableViewCell]]()

private func configTableSections() {
    // seciton A
    tableSections.append([self.cell1InSectionA, self.cell2InSectionA])

    // section B
    if shouldShowSectionB {
        tableSections.append([self.cell1InSectionB, self.cell2InSectionB])
    }

    // section C
    if shouldShowCell1InSectionC {
        tableSections.append([self.cell1InSectionC, self.cell2InSectionC, self.cell3InSectionC])
    } else {
        tableSections.append([self.cell2InSectionC, self.cell3InSectionC])
    }
}

func numberOfSections(in tableView: UITableView) -> Int {
    return tableSections.count
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return tableSections[section].count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    return tableSections[indexPath.section][indexPath.row]
}

이런 식으로 행과 섹션 수를 계산하기 위해 불쾌한 코드를 작성하지 않고도 모든 구성 코드를 하나로 묶을 수 있습니다. 그리고 물론0 더 이상 높이가 없습니다.

이 코드는 유지 관리가 매우 쉽습니다. 예를 들어, 더 많은 셀 또는 섹션을 추가 / 제거하려는 경우.

마찬가지로 섹션 제목 제목 배열과 섹션 바닥 글 제목 배열을 만들어 섹션 제목을 동적으로 구성 할 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.