development

UITableView가 정적 셀로 설정되었습니다.

big-blog 2020. 7. 6. 06:58
반응형

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


UITableView 정적 셀로 설정합니다.

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


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

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으로 설정 한 해키 솔루션을 사용하지 않으며 변경 사항에 애니메이션을 적용하고 전체 섹션을 숨길 수 있습니다.


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에 쌓입니다.

가장 좋은 방법은 다음 블로그 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;
}

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


내 솔루션은 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를 오프셋해야합니다.

또한 didSelectRowAtIndexPath:같은 셀에 대해 같은 메소드에 대한 indexPath 매개 변수는 상태 (예 : 숨겨진 셀 수)에 따라 달라집니다. 따라서 항상 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];
}

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

}

실제로 섹션을 숨기고 삭제하지 않는 대안을 생각해 냈습니다. @ 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으로 설정할 수 없습니다.


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

데모 프로젝트

데모 프로젝트 비디오

요점:

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

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


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

첫 번째 섹션의 첫 번째 행에서 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가 올바른 행을 업데이트하지 않으므로 표시되어야하는 행이 숨겨져 있고 첫 번째 행 아래에 공백이 남아 있다는 것입니다. 나는 이것이 기본 데이터에 대한 첫 번째 지점과 관련이 있다고 생각합니다.

누군가가 다른 방법이나 애니메이션으로 확장하는 방법을 제안 할 수 있기를 바랍니다. 그러나 이것이 당신을 시작할 것입니다. 함수에 대한 하이퍼 링크가 부족하다는 점에 사과를 드려서 스팸 필터에 의해 거부되었습니다. 이는 상당히 새로운 사용자이기 때문입니다.


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

자동 레이아웃 문제로 인해 셀 숨기기 / 표시, 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
}

좋아, 약간의 시도 후에, 나는 일반적인 대답이 아닙니다. 이 셀을 숨겨야하는지 확인하기 위해 "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) }

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


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

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

신속한 답변 :

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

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

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

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


> 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으로 설정하고 싶습니다.


간단한 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 가능하면.


스위프트 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
}

테이블 뷰 맨 아래에서 셀을 숨기는 가장 쉬운 시나리오의 경우 셀을 숨긴 후 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);
}

이것은 https://github.com/k06a/ABStaticTableViewController를 사용 하여이 작업을 수행하는 새로운 방법입니다.

NSIndexPath *ip = [NSIndexPath indexPathForRow:1 section:1];
[self deleteRowsAtIndexPaths:@[ip] withRowAnimation:UITableViewRowAnimationFade]

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

물론 가능합니다. 먼저 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))
}

@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으로 설정하면 행을 숨길 수 있지만 전체 행을 숨기고 일부 행을 숨기더라도 행을 숨기더라도 작동하지 않습니다.

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

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

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이상 높이가 없습니다.

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

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

참고 : https://stackoverflow.com/questions/8260267/uitableview-set-to-static-cells-is-it-possible-to-hide-some-of-the-cells-progra

반응형