iOS의 UITableView에서 섹션 확장 / 축소


답변:


109

사용자 정의 헤더 행을 만들고 각 섹션의 첫 번째 행에 넣어야합니다. UITableView또는 이미있는 헤더를 서브 클래 싱하는 것은 고통 스러울 것입니다. 현재 작동하는 방식으로 볼 때 쉽게 조치를 취할 수 있을지 모르겠습니다. 셀을 헤더처럼 LOOK tableView:didSelectRowAtIndexPath으로 설정하고 해당 섹션을 수동으로 확장하거나 축소하도록 설정할 수 있습니다.

각 섹션의 "expended"값에 해당하는 부울 배열을 저장합니다. 그런 다음 tableView:didSelectRowAtIndexPath각 사용자 지정 헤더 행에서이 값을 토글 한 다음 해당 특정 섹션을 다시로드하도록 할 수 있습니다.

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    if (indexPath.row == 0) {
        ///it's the first row of any section so it would be your custom section header

        ///put in your code to toggle your boolean value here
        mybooleans[indexPath.section] = !mybooleans[indexPath.section];

        ///reload this section
        [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:indexPath.section] withRowAnimation:UITableViewRowAnimationFade];
    }
}

그런 다음 값 numberOfRowsInSection을 확인하고 mybooleans섹션이 확장되지 않은 경우 1을 반환하고 확장 된 경우 섹션의 항목 수를 1+ 반환 하도록 설정 합니다 .

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {

    if (mybooleans[section]) {
        ///we want the number of people plus the header cell
        return [self numberOfPeopleInGroup:section] + 1;
    } else {
        ///we just want the header cell
        return 1;
    }
}

또한 업데이트해야합니다. cellForRowAtIndexPath 섹션의 첫 번째 행에 대한 사용자 정의 헤더 셀을 반환 .


2
Beejive 앱을 사용한 경우 일반 Apple 섹션 헤더와 마찬가지로 섹션의 일부를 스크롤 한 경우에도 축소 가능한 섹션 헤더가 실제로 테이블 상단에 "떠 다니는"것을 알 수 있습니다. 섹션 시작 부분에 단순히 셀을 추가하면 불가능합니다
user102008

멋진 우아한 솔루션! user102008은 부동 헤더에 포인트가 있지만 실제로 "섹션"을 스크롤하려는 시나리오에서는이 방법이 매우 유용합니다.
Nick Cipollina 2012-06-28

내가 사전에 특정 세포 숨기기 / 숨기기 취소 ..thanks 필요 BCZ @mjdth PLZ 나에게 어떤 샘플 코드를 제공
바자 즈

11
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section"자신의 사용자 정의 헤더"를 제공하는 더 좋은 방법입니다. 이것이 정확히 수행하도록 설계된 것입니다.
William Denniss 2013

처음에는 섹션이 하나만있을 때 효과가 있었지만 더 많은 섹션이 있으면 "잘못된 업데이트 잘못된 행 수"오류가 발생합니다. 이 솔루션이 오래되었다는 것을 알고 있지만 한 섹션에서만 작동합니까? 섹션이 두 개 이상인 경우 실제로 행을 추가 / 삭제하는 코드를 추가해야합니까?
skinsfan00atg 2014

103

테이블보기 섹션 헤더를 사용하여 확장 / 축소 동작을 애니메이션하는 일부 샘플 코드는 Apple에서 제공합니다. 테이블보기 애니메이션 및 제스처

이 접근 방식의 핵심 - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section은 버튼 (일반적으로 헤더 뷰 자체와 동일한 크기)을 포함하는 사용자 지정 UIView 를 구현 하고 반환하는 것입니다. UIView를 서브 클래 싱하고 헤더 뷰에 사용하면 (이 샘플 에서처럼) 섹션 번호와 같은 추가 데이터를 쉽게 저장할 수 있습니다.



기억 나지 않지만 샘플 코드가 iOS 4 이전 버전에서 작동하지 않는 이유는 무엇입니까?
samwize 2011

1
모르겠어요. "iOS 4.0.2 이상"만 표시됩니다.
user102008 2011

1
링크에있는 현재 업데이트 된 코드에는 버그가 있으며 쉽게 충돌 할 수 있습니다
Ankit Srivastava

1
앞서 언급 한 Ankit Srivastava처럼이 코드 예제를 깨는 것은 쉽습니다 : PlaysAndQuotations.plist에 모든 항목 사전을 복사하여 붙여 넣으십시오 (루트 사전에 30 개의 항목으로 테스트했습니다). 이제 앱을 시작하고 첫 번째 플레이를 엽니 다. 그 후 아래쪽을 가리키는 화살표가 보일 때까지 아래로 스크롤합니다 (이것이에서 온 것 같습니다 dequeueReusableHeaderFooterViewWithIdentifier)-화살표를 클릭하고 첫 번째 재생으로 스크롤하여 닫으십시오.-> NSInternalInconsistencyException (iOS 8.4 / iPhone 5s)
Raimund Wege

22

Apple의 Table View Animations and Gestures 에서 영감을받은 멋진 솔루션을 얻었습니다. . Apple의 샘플에서 불필요한 부분을 삭제하고 신속하게 번역했습니다.

대답이 꽤 길다는 것을 알고 있지만 모든 코드가 필요합니다. 다행히도 대부분의 코드를 복사하여 붙여 넣을 수 있으며 1 단계와 3 단계에서 약간의 수정 만하면됩니다.

1. 창조 SectionHeaderView.swift하고SectionHeaderView.xib

import UIKit

protocol SectionHeaderViewDelegate {
    func sectionHeaderView(sectionHeaderView: SectionHeaderView, sectionOpened: Int)
    func sectionHeaderView(sectionHeaderView: SectionHeaderView, sectionClosed: Int)
}

class SectionHeaderView: UITableViewHeaderFooterView {

    var section: Int?
    @IBOutlet weak var titleLabel: UILabel!
    @IBOutlet weak var disclosureButton: UIButton!
    @IBAction func toggleOpen() {
        self.toggleOpenWithUserAction(true)
    }
    var delegate: SectionHeaderViewDelegate?

    func toggleOpenWithUserAction(userAction: Bool) {
        self.disclosureButton.selected = !self.disclosureButton.selected

        if userAction {
            if self.disclosureButton.selected {
                self.delegate?.sectionHeaderView(self, sectionClosed: self.section!)
            } else {
                self.delegate?.sectionHeaderView(self, sectionOpened: self.section!)
            }
        }
    }

    override func awakeFromNib() {
        var tapGesture: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "toggleOpen")
        self.addGestureRecognizer(tapGesture)
        // change the button image here, you can also set image via IB.
        self.disclosureButton.setImage(UIImage(named: "arrow_up"), forState: UIControlState.Selected)
        self.disclosureButton.setImage(UIImage(named: "arrow_down"), forState: UIControlState.Normal)
    }

}

SectionHeaderView.xib(회색 배경과보기) (당신은 물론, 사용자의 필요에 따라 사용자 정의 할 수 있습니다)가있는 tableview의 모양은 다음과 같습니다 여기에 이미지 설명 입력

노트:

a) toggleOpen작업이 연결되어야합니다.disclosureButton

b) disclosureButtontoggleOpen 조치가 필요하지 않습니다. 버튼이 필요하지 않으면이 두 가지를 삭제할 수 있습니다.

2. 만들기 SectionInfo.swift

import UIKit

class SectionInfo: NSObject {
    var open: Bool = true
    var itemsInSection: NSMutableArray = []
    var sectionTitle: String?

    init(itemsInSection: NSMutableArray, sectionTitle: String) {
        self.itemsInSection = itemsInSection
        self.sectionTitle = sectionTitle
    }
}

3. Tableview에서

import UIKit

class TableViewController: UITableViewController, SectionHeaderViewDelegate  {

    let SectionHeaderViewIdentifier = "SectionHeaderViewIdentifier"

    var sectionInfoArray: NSMutableArray = []

    override func viewDidLoad() {
        super.viewDidLoad()

        let sectionHeaderNib: UINib = UINib(nibName: "SectionHeaderView", bundle: nil)
        self.tableView.registerNib(sectionHeaderNib, forHeaderFooterViewReuseIdentifier: SectionHeaderViewIdentifier)

        // you can change section height based on your needs
        self.tableView.sectionHeaderHeight = 30

        // You should set up your SectionInfo here
        var firstSection: SectionInfo = SectionInfo(itemsInSection: ["1"], sectionTitle: "firstSection")
        var secondSection: SectionInfo = SectionInfo(itemsInSection: ["2"], sectionTitle: "secondSection"))
        sectionInfoArray.addObjectsFromArray([firstSection, secondSection])
    }

    // MARK: - Table view data source

    override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return sectionInfoArray.count
    }

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if self.sectionInfoArray.count > 0 {
            var sectionInfo: SectionInfo = sectionInfoArray[section] as! SectionInfo
            if sectionInfo.open {
                return sectionInfo.open ? sectionInfo.itemsInSection.count : 0
            }
        }
        return 0
    }

    override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        let sectionHeaderView: SectionHeaderView! = self.tableView.dequeueReusableHeaderFooterViewWithIdentifier(SectionHeaderViewIdentifier) as! SectionHeaderView
        var sectionInfo: SectionInfo = sectionInfoArray[section] as! SectionInfo

        sectionHeaderView.titleLabel.text = sectionInfo.sectionTitle
        sectionHeaderView.section = section
        sectionHeaderView.delegate = self
        let backGroundView = UIView()
        // you can customize the background color of the header here
        backGroundView.backgroundColor = UIColor(red:0.89, green:0.89, blue:0.89, alpha:1)
        sectionHeaderView.backgroundView = backGroundView
        return sectionHeaderView
    }

    func sectionHeaderView(sectionHeaderView: SectionHeaderView, sectionOpened: Int) {
        var sectionInfo: SectionInfo = sectionInfoArray[sectionOpened] as! SectionInfo
        var countOfRowsToInsert = sectionInfo.itemsInSection.count
        sectionInfo.open = true

        var indexPathToInsert: NSMutableArray = NSMutableArray()
        for i in 0..<countOfRowsToInsert {
            indexPathToInsert.addObject(NSIndexPath(forRow: i, inSection: sectionOpened))
        }
        self.tableView.insertRowsAtIndexPaths(indexPathToInsert as [AnyObject], withRowAnimation: .Top)
    }

    func sectionHeaderView(sectionHeaderView: SectionHeaderView, sectionClosed: Int) {
        var sectionInfo: SectionInfo = sectionInfoArray[sectionClosed] as! SectionInfo
        var countOfRowsToDelete = sectionInfo.itemsInSection.count
        sectionInfo.open = false
        if countOfRowsToDelete > 0 {
            var indexPathToDelete: NSMutableArray = NSMutableArray()
            for i in 0..<countOfRowsToDelete {
                indexPathToDelete.addObject(NSIndexPath(forRow: i, inSection: sectionClosed))
            }
            self.tableView.deleteRowsAtIndexPaths(indexPathToDelete as [AnyObject], withRowAnimation: .Top)
        }
    }
}

1
노력 해주셔서 감사합니다! GitHub의에 작은 샘플 프로젝트로 그것은 더 나은 해답이 될 것입니다
최대 MacLeod는

자세한 답변을 제공해 주셔서 감사합니다. 예제 프로젝트가 더 좋을 것입니다.
Thiha Aung

20

iOS에서 접을 수있는 테이블 섹션을 구현하려면 각 섹션의 행 수를 제어하거나 각 섹션의 행 높이를 관리 할 수 ​​있습니다.

또한 헤더 영역 (버튼이든 전체 헤더이든)에서 탭 이벤트를 수신 할 수 있도록 섹션 헤더를 사용자 정의해야합니다.

헤더는 어떻게 처리합니까? 매우 간단합니다. UITableViewCell 클래스를 확장하고 다음과 같이 사용자 지정 헤더 셀을 만듭니다.

import UIKit

class CollapsibleTableViewHeader: UITableViewCell {

    @IBOutlet var titleLabel: UILabel!
    @IBOutlet var toggleButton: UIButton!

}

그런 다음 viewForHeaderInSection을 사용하여 헤더 셀을 연결하십시오.

override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
  let header = tableView.dequeueReusableCellWithIdentifier("header") as! CollapsibleTableViewHeader

  header.titleLabel.text = sections[section].name
  header.toggleButton.tag = section
  header.toggleButton.addTarget(self, action: #selector(CollapsibleTableViewController.toggleCollapse), forControlEvents: .TouchUpInside)

  header.toggleButton.rotate(sections[section].collapsed! ? 0.0 : CGFloat(M_PI_2))

  return header.contentView
}

이 함수는 UIView가 반환 될 것으로 예상하기 때문에 contentView를 반환해야합니다.

이제 접을 수있는 부분을 다루겠습니다. 여기에 각 섹션의 접을 수있는 소품을 토글하는 토글 기능이 있습니다.

func toggleCollapse(sender: UIButton) {
  let section = sender.tag
  let collapsed = sections[section].collapsed

  // Toggle collapse
  sections[section].collapsed = !collapsed

  // Reload section
  tableView.reloadSections(NSIndexSet(index: section), withRowAnimation: .Automatic)
}

섹션 데이터를 관리하는 방법에 따라 다릅니다.이 경우 섹션 데이터는 다음과 같습니다.

struct Section {
  var name: String!
  var items: [String]!
  var collapsed: Bool!

  init(name: String, items: [String]) {
    self.name = name
    self.items = items
    self.collapsed = false
  }
}

var sections = [Section]()

sections = [
  Section(name: "Mac", items: ["MacBook", "MacBook Air", "MacBook Pro", "iMac", "Mac Pro", "Mac mini", "Accessories", "OS X El Capitan"]),
  Section(name: "iPad", items: ["iPad Pro", "iPad Air 2", "iPad mini 4", "Accessories"]),
  Section(name: "iPhone", items: ["iPhone 6s", "iPhone 6", "iPhone SE", "Accessories"])
]

마지막으로 우리가해야 할 일은 각 섹션의 축소 가능한 소품을 기반으로 해당 섹션의 행 수를 제어하는 ​​것입니다.

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
  return (sections[section].collapsed!) ? 0 : sections[section].items.count
}

내 Github에서 완전히 작동하는 데모가 있습니다 : https://github.com/jeantimex/ios-swift-collapsible-table-section

데모

그룹화 된 스타일 테이블에서 축소 가능한 섹션을 구현하려면 여기에 소스 코드가있는 또 다른 데모가 있습니다. https://github.com/jeantimex/ios-swift-collapsible-table-section-in-grouped-section

도움이되기를 바랍니다.


안녕하세요, 저는 xib 파일에서 사용자 지정 헤더 섹션을 수행하고 테이블 뷰 컨트롤러에 펜촉을 등록했습니다. 섹션을 삭제하고 다시 확장 / 축소하려고하면 인덱스가 범위를 벗어난다는 치명적인 오류가 발생합니다. 이 문제를 해결할 방법이 있습니까? 감사!
iamhx

아주 좋고 깨끗한 솔루션!
Joel

10

섹션 헤더에 UIButton을 추가하고이 버튼의 크기를 섹션 크기와 동일하게 설정해야하지만 명확한 배경색으로 숨겨야하는 더 나은 솔루션이 있습니다. 그 후에는 어떤 섹션을 클릭하여 확장 또는 축소하는지 쉽게 확인할 수 있습니다.


3
내 생각에이 솔루션은 의미 상 헤더를 헤더로 유지하고 가짜 행을 사용하여 헤더를 시뮬레이션하지 않기 때문에 허용되는 답변보다 낫습니다. 방법 tableView:numberOfRowsInSection:은 변경되지 않으며 실제로 의미하는 바를 위해 계속 사용할 수 있습니다. 동일은 간다 tableView:cellForRowAtIndexPath:.
Cœur

따라서 섹션 헤더의 버튼을 탭합니다.하지만 어떤 섹션을 다시로드해야하는지 어떻게 결정할까요?
memmons

@Answerbot 안녕하세요, 섹션 인덱스와 동일한 값을 사용하여 버튼에 태그를 설정하는 것은 매우 쉽습니다.
Son Nguyen

그렇게 말할 까봐 두려웠습니다. tableView 인덱스와 같은 것에 태그 속성을 남용하는 것은 잘못된 디자인 선택입니다.
memmons

문제에 대한 "훌륭한"해결책을 본 적이 없기 때문에 다른 접근 방식을 사용하기를 바랐습니다. 내가 본 최고의 대답은 Apple 참조 프로젝트입니다. Apple 은 a 를 하위 클래스로 UITableViewHeaderFooterView만들고 section속성을 추가하며 SectionHeaderViewDelegate섹션을 열고 닫는 콜백을 제공하는를 정의합니다 . ( developer.apple.com/library/ios/samplecode/TableViewUpdates/... )
memmons

7

나는 버튼을 포함하는 headerView를 만들었습니다 ( 사실 후에 위 의 Son Nguyen의 솔루션을 보았지만 여기에 내 코드가 있습니다 .. 많이 보이지만 꽤 간단합니다) :

섹션에 대한 몇 가지 부울 선언

bool customerIsCollapsed = NO;
bool siteIsCollapsed = NO;

...암호

이제 tableview 대리자 메서드에서 ...

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, _tblSearchResults.frame.size.width, 35)];

    UILabel *lblSection = [UILabel new];
    [lblSection setFrame:CGRectMake(0, 0, 300, 30)];
    [lblSection setFont:[UIFont fontWithName:@"Helvetica-Bold" size:17]];
    [lblSection setBackgroundColor:[UIColor clearColor]];
    lblSection.alpha = 0.5;
    if(section == 0)
    {
        if(!customerIsCollapsed)
            [lblSection setText:@"Customers    --touch to show--"];
        else
            [lblSection setText:@"Customers    --touch to hide--"];
    }
    else
    {
        if(!siteIsCollapsed)
            [lblSection setText:@"Sites    --touch to show--"];
        else
            [lblSection setText:@"Sites    --touch to hide--"];    }

    UIButton *btnCollapse = [UIButton buttonWithType:UIButtonTypeCustom];
    [btnCollapse setFrame:CGRectMake(0, 0, _tblSearchResults.frame.size.width, 35)];
    [btnCollapse setBackgroundColor:[UIColor clearColor]];
    [btnCollapse addTarget:self action:@selector(touchedSection:) forControlEvents:UIControlEventTouchUpInside];
    btnCollapse.tag = section;


    [headerView addSubview:lblSection];
    [headerView addSubview:btnCollapse];

    return headerView;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    // Return the number of rows in the section.
    if(section == 0)
    {
        if(customerIsCollapsed)
            return 0;
        else
            return _customerArray.count;
    }
    else if (section == 1)
    {
        if(siteIsCollapsed)
            return 0;
        else
        return _siteArray.count;

    }
    return 0;
}

마지막으로 섹션 헤더 버튼 중 하나를 터치 할 때 호출되는 함수 :

- (IBAction)touchedSection:(id)sender
{
    UIButton *btnSection = (UIButton *)sender;

    if(btnSection.tag == 0)
    {
        NSLog(@"Touched Customers header");
        if(!customerIsCollapsed)
            customerIsCollapsed = YES;
        else
            customerIsCollapsed = NO;

    }
    else if(btnSection.tag == 1)
    {
        NSLog(@"Touched Site header");
        if(!siteIsCollapsed)
            siteIsCollapsed = YES;
        else
            siteIsCollapsed = NO;

    }
    [_tblSearchResults reloadData];
}

섹션이 애니메이션없이 축소 및 확장되는지 궁금합니다. 애니메이션이 없으면 매우 나빠 보일 것입니다. 애니메이션을 어떻게 추가 할 수 있습니까?
Sam

[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationFade];축소 / 접기 해제 방법 과 같은 것을 사용하면 @Sam이 멋지게 애니메이션됩니다.
William Denniss 2013

5

이것은 확장 가능한 테이블 뷰 셀을 만드는 가장 좋은 방법입니다.

.h 파일

  NSMutableIndexSet *expandedSections;

.m 파일

if (!expandedSections)
    {
        expandedSections = [[NSMutableIndexSet alloc] init];
    }
   UITableView *masterTable = [[UITableView alloc] initWithFrame:CGRectMake(0,100,1024,648) style:UITableViewStyleGrouped];
    masterTable.delegate = self;
    masterTable.dataSource = self;
    [self.view addSubview:masterTable];

테이블보기 대리자 메서드

- (BOOL)tableView:(UITableView *)tableView canCollapseSection:(NSInteger)section
{
    // if (section>0) return YES;

    return YES;
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    // Return the number of sections.
    return 4;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    if ([self tableView:tableView canCollapseSection:section])
    {
        if ([expandedSections containsIndex:section])
        {
            return 5; // return rows when expanded
        }

        return 1; // only top row showing
    }

    // Return the number of rows in the section.
    return 1;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] ;
    }

    // Configure the cell...

    if ([self tableView:tableView canCollapseSection:indexPath.section])
    {
        if (!indexPath.row)
        {
            // first row
            cell.textLabel.text = @"Expandable"; // only top row showing

            if ([expandedSections containsIndex:indexPath.section])
            {

                UIImageView *imView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"UITableContract"]];
                cell.accessoryView = imView;
            }
            else
            {

                UIImageView *imView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"UITableExpand"]];
                cell.accessoryView = imView;
            }
        }
        else
        {
            // all other rows
            if (indexPath.section == 0) {
                cell.textLabel.text = @"section one";
            }else if (indexPath.section == 1) {
                cell.textLabel.text = @"section 2";
            }else if (indexPath.section == 2) {
                cell.textLabel.text = @"3";
            }else {
                cell.textLabel.text = @"some other sections";
            }

            cell.accessoryView = nil;
            cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
        }
    }
    else
    {
        cell.accessoryView = nil;
        cell.textLabel.text = @"Normal Cell";

    }

    return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    if ([self tableView:tableView canCollapseSection:indexPath.section])
    {
        if (!indexPath.row)
        {
            // only first row toggles exapand/collapse
            [tableView deselectRowAtIndexPath:indexPath animated:YES];

            NSInteger section = indexPath.section;
            BOOL currentlyExpanded = [expandedSections containsIndex:section];
            NSInteger rows;


            NSMutableArray *tmpArray = [NSMutableArray array];

            if (currentlyExpanded)
            {
                rows = [self tableView:tableView numberOfRowsInSection:section];
                [expandedSections removeIndex:section];

            }
            else
            {
                [expandedSections addIndex:section];
                rows = [self tableView:tableView numberOfRowsInSection:section];
            }


            for (int i=1; i<rows; i++)
            {
                NSIndexPath *tmpIndexPath = [NSIndexPath indexPathForRow:i 
                                                               inSection:section];
                [tmpArray addObject:tmpIndexPath];
            }

            UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];

            if (currentlyExpanded)
            {
                [tableView deleteRowsAtIndexPaths:tmpArray 
                                 withRowAnimation:UITableViewRowAnimationTop];

                UIImageView *imView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"UITableExpand"]];
                cell.accessoryView = imView;
            }
            else
            {
                [tableView insertRowsAtIndexPaths:tmpArray 
                                 withRowAnimation:UITableViewRowAnimationTop];

                UIImageView *imView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"UITableContract"]];
                cell.accessoryView = imView;
            }
        }
    }

    NSLog(@"section :%d,row:%d",indexPath.section,indexPath.row);

}

8
모든 질문에 동일한 답변을 스팸으로 보내는 대신 질문을 정확한 중복으로 표시해야합니다.
casperOne

섹션이 이미 확장되고 다른 섹션을 클릭하면 오류가 발생합니다
shivam

안녕하세요 선생님, 선택한 인덱스 높이를 변경하는 방법? heightForRowAtIndexPath 코드로 작업하는 방법?
Gami Nilesh

안녕하세요, 확장 된 행의 didselected에서 다른 뷰 컨트롤러로 이동하는 방법은 무엇입니까?
Arbaz Shaikh

1

따라서 '헤더의 단추'솔루션을 기반으로 다음은 깔끔하고 미니멀 한 구현입니다.

  • 속성에서 접힌 (또는 확장 된) 섹션을 추적합니다.
  • 섹션 색인으로 버튼에 태그를 지정합니다.
  • 화살표 방향을 변경하기 위해 해당 버튼에서 선택한 상태를 설정합니다 (예 : △ 및 ▽)

다음은 코드입니다.

@interface MyTableViewController ()
@property (nonatomic, strong) NSMutableIndexSet *collapsedSections;
@end

...

@implementation MyTableViewController

- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (!self)
        return;
    self.collapsedSections = [NSMutableIndexSet indexSet];
    return self;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    // if section is collapsed
    if ([self.collapsedSections containsIndex:section])
        return 0;

    // if section is expanded
#warning incomplete implementation
    return [super tableView:tableView numberOfRowsInSection:section];
}

- (IBAction)toggleSectionHeader:(UIView *)sender
{
    UITableView *tableView = self.tableView;
    NSInteger section = sender.tag;

    MyTableViewHeaderFooterView *headerView = (MyTableViewHeaderFooterView *)[self tableView:tableView viewForHeaderInSection:section];

    if ([self.collapsedSections containsIndex:section])
    {
        // section is collapsed
        headerView.button.selected = YES;
        [self.collapsedSections removeIndex:section];
    }
    else
    {
        // section is expanded
        headerView.button.selected = NO;
        [self.collapsedSections addIndex:section];
    }

    [tableView beginUpdates];
    [tableView reloadSections:[NSIndexSet indexSetWithIndex:section] withRowAnimation:UITableViewRowAnimationAutomatic];
    [tableView endUpdates];
}

@end

1

나는 그 문제를 해결하는 또 다른 비교적 간단한 방법을 찾았습니다. 이 방법을 사용하면 거의 항상 데이터 배열 인덱스와 관련된 셀을 변경할 필요가 없어 뷰 컨트롤러가 엉망이 될 수 있습니다.

먼저 컨트롤러 클래스에 다음 속성을 추가합니다.

@property (strong, nonatomic) NSMutableArray* collapsedSections;
@property (strong, nonatomic) NSMutableArray* sectionViews;

collapsedSections접힌 섹션 번호를 저장합니다. sectionViews사용자 정의 단면도를 저장합니다.

그것을 합성하십시오 :

@synthesize collapsedSections;
@synthesize sectionViews;

초기화 :

- (void) viewDidLoad
{
    [super viewDidLoad];

    self.collapsedSections = [NSMutableArray array];
    self.sectionViews      = [NSMutableArray array];
}

그런 다음 뷰 컨트롤러 클래스 내에서 액세스 할 수 있도록 UITableView를 연결해야합니다.

@property (strong, nonatomic) IBOutlet UITableView *tblMain;

XIB에서 연결하여 컨트롤러보기 ctrl + drag일반적으로 .

그런 다음이 UITableView 대리자를 구현하여 테이블보기에 대한 사용자 지정 섹션 헤더로보기를 만듭니다.

- (UIView*) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    // Create View
    CGRect frame = CGRectZero;

    frame.origin = CGPointZero;

    frame.size.height = 30.f;
    frame.size.width  = tableView.bounds.size.width;

    UIView* view = [[UIView alloc] initWithFrame:frame];

    [view setBackgroundColor:[UIColor blueColor]];

    // Add label for title
    NSArray* titles = @[@"Title 1", @"Title 2", @"Title 3"];

    NSString* selectedTitle = [titles objectAtIndex:section];

    CGRect labelFrame = frame;

    labelFrame.size.height = 30.f;
    labelFrame.size.width -= 20.f;
    labelFrame.origin.x += 10.f;

    UILabel* titleLabel = [[UILabel alloc] initWithFrame:labelFrame];

    [titleLabel setText:selectedTitle];
    [titleLabel setTextColor:[UIColor whiteColor]];

    [view addSubview:titleLabel];

    // Add touch gesture
    [self attachTapGestureToView:view];

    // Save created view to our class property array
    [self saveSectionView:view inSection:section];

    return view;
}

다음으로, 이전에 생성 한 커스텀 섹션 헤더를 클래스 속성에 저장하는 메소드를 구현합니다.

- (void) saveSectionView:(UIView*) view inSection:(NSInteger) section
{
    NSInteger sectionCount = [self numberOfSectionsInTableView:[self tblMain]];

    if(section < sectionCount)
    {
        if([[self sectionViews] indexOfObject:view] == NSNotFound)
        {
            [[self sectionViews] addObject:view];
        }
    }
}

UIGestureRecognizerDelegate뷰 컨트롤러 .h 파일에 추가 합니다.

@interface MyViewController : UIViewController<UITableViewDelegate, UITableViewDataSource, UIGestureRecognizerDelegate>

그런 다음 메서드를 만듭니다. attachTapGestureToView:

- (void) attachTapGestureToView:(UIView*) view
{
    UITapGestureRecognizer* tapAction = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onTap:)];

    [tapAction setDelegate:self];

    [view addGestureRecognizer:tapAction];
}

위의 방법은 이전에 만든 모든 단면도에 탭 제스처 인식기를 추가합니다. 다음으로 onTap:선택자를 구현해야합니다.

- (void) onTap:(UITapGestureRecognizer*) gestureRecognizer
{
    // Take view who attach current recognizer
    UIView* sectionView = [gestureRecognizer view]; 

    // [self sectionViews] is Array containing our custom section views
    NSInteger section = [self sectionNumberOfView:sectionView];

    // [self tblMain] is our connected IBOutlet table view
    NSInteger sectionCount = [self numberOfSectionsInTableView:[self tblMain]];

    // If section more than section count minus one set at last
    section = section > (sectionCount - 1) ? 2 : section;

    [self toggleCollapseSection:section];
}

위의 메서드는 사용자가 테이블 뷰 섹션을 탭할 때 호출됩니다. 이 방법은 우리를 기반으로 올바른 섹션 번호를 검색합니다.sectionViews 은 이전에 만든 배열을 .

또한 우리는 헤더 뷰의 wihch 섹션이 속한 섹션을 가져 오는 방법을 구현합니다.

- (NSInteger) sectionNumberOfView:(UIView*) view
{
    UILabel* label = [[view subviews] objectAtIndex:0];

    NSInteger sectionNum = 0;

    for(UIView* sectionView in [self sectionViews])
    {
        UILabel* sectionLabel = [[sectionView subviews] objectAtIndex:0];

        //NSLog(@"Section: %d -> %@ vs %@", sectionNum, [label text], [sectionLabel text]);

        if([[label text] isEqualToString:[sectionLabel text]])
        {
            return sectionNum;
        }

        sectionNum++;
    }

    return NSNotFound;
}

다음으로 메소드를 구현해야합니다. toggleCollapseSection:

- (void) toggleCollapseSection:(NSInteger) section
{
    if([self isCollapsedSection:section])
    {
        [self removeCollapsedSection:section];
    }
    else
    {
        [self addCollapsedSection:section];
    }

    [[self tblMain] reloadSections:[NSIndexSet indexSetWithIndex:section] withRowAnimation:UITableViewRowAnimationFade];
}

이 방법은 섹션 번호를 삽입 / 제거합니다. collapsedSections 이전에 만든 배열에 . 섹션 번호가 해당 배열에 삽입되면 섹션이 축소되고 확장되어야 함을 의미합니다.

다음으로 우리는 removeCollapsedSection:, addCollapsedSection:section그리고isCollapsedSection:section

- (BOOL)isCollapsedSection:(NSInteger) section
{
    for(NSNumber* existing in [self collapsedSections])
    {
        NSInteger current = [existing integerValue];

        if(current == section)
        {
            return YES;
        }
    }

    return NO;
}

- (void)removeCollapsedSection:(NSInteger) section
{
    [[self collapsedSections] removeObjectIdenticalTo:[NSNumber numberWithInteger:section]];
}

- (void)addCollapsedSection:(NSInteger) section
{
    [[self collapsedSections] addObject:[NSNumber numberWithInteger:section]];
}

이 세 가지 방법은 액세스를 더 쉽게 만드는 도우미 일뿐입니다. collapsedSections 배열에 입니다.

마지막으로이 테이블 뷰 델리게이트를 구현하여 사용자 정의 단면 뷰가 멋지게 보이도록합니다.

- (CGFloat) tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
    return 30.f; // Same as each custom section view height
}

도움이 되었기를 바랍니다.


1

NSDictionary를 데이터 소스로 사용했습니다. 이것은 많은 코드처럼 보이지만 정말 간단하고 잘 작동합니다! 여기 어때

섹션에 대한 열거 형을 만들었습니다.

typedef NS_ENUM(NSUInteger, TableViewSection) {

    TableViewSection0 = 0,
    TableViewSection1,
    TableViewSection2,
    TableViewSectionCount
};

섹션 속성 :

@property (nonatomic, strong) NSMutableDictionary * sectionsDisctionary;

내 섹션을 반환하는 방법 :

-(NSArray <NSNumber *> * )sections{

    return @[@(TableViewSection0), @(TableViewSection1), @(TableViewSection2)];
}

그리고 내 데이터 소스를 설정합니다.

-(void)loadAndSetupData{

    self.sectionsDisctionary = [NSMutableDictionary dictionary];

    NSArray * sections = [self sections];

    for (NSNumber * section in sections) {

    NSArray * sectionObjects = [self objectsForSection:section.integerValue];

    [self.sectionsDisctionary setObject:[NSMutableDictionary dictionaryWithDictionary:@{@"visible" : @YES, @"objects" : sectionObjects}] forKey:section];
    }
}

-(NSArray *)objectsForSection:(NSInteger)section{

    NSArray * objects;

    switch (section) {

        case TableViewSection0:

            objects = @[] // objects for section 0;
            break;

        case TableViewSection1:

            objects = @[] // objects for section 1;
            break;

        case TableViewSection2:

            objects = @[] // objects for section 2;
            break;

        default:
            break;
    }

    return objects;
}

다음 메소드는 섹션이 열릴 때와 tableview 데이터 소스에 응답하는 방법을 아는 데 도움이됩니다.

데이터 소스에 섹션에 응답하십시오.

/**
 *  Asks the delegate for a view object to display in the header of the specified section of the table view.
 *
 *  @param tableView The table-view object asking for the view object.
 *  @param section   An index number identifying a section of tableView .
 *
 *  @return A view object to be displayed in the header of section .
 */
- (UIView *) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{

    NSString * headerName = [self titleForSection:section];

    YourCustomSectionHeaderClass * header = (YourCustomSectionHeaderClass *)[tableView dequeueReusableHeaderFooterViewWithIdentifier:YourCustomSectionHeaderClassIdentifier];

    [header setTag:section];
    [header addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapGesture:)]];
    header.title = headerName;
    header.collapsed = [self sectionIsOpened:section];


    return header;
}

/**
 * Asks the data source to return the number of sections in the table view
 *
 * @param An object representing the table view requesting this information.
 * @return The number of sections in tableView.
 */
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
    // Return the number of sections.

    return self.sectionsDisctionary.count;
}

/**
 * Tells the data source to return the number of rows in a given section of a table view
 *
 * @param tableView: The table-view object requesting this information.
 * @param section: An index number identifying a section in tableView.
 * @return The number of rows in section.
 */
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{

    BOOL sectionOpened = [self sectionIsOpened:section];
    return sectionOpened ? [[self objectsForSection:section] count] : 0;
}

도구 :

/**
 Return the section at the given index

 @param index the index

 @return The section in the given index
 */
-(NSMutableDictionary *)sectionAtIndex:(NSInteger)index{

    NSString * asectionKey = [self.sectionsDisctionary.allKeys objectAtIndex:index];

    return [self.sectionsDisctionary objectForKey:asectionKey];
}

/**
 Check if a section is currently opened

 @param section the section to check

 @return YES if is opened
 */
-(BOOL)sectionIsOpened:(NSInteger)section{

    NSDictionary * asection = [self sectionAtIndex:section];
    BOOL sectionOpened = [[asection objectForKey:@"visible"] boolValue];

    return sectionOpened;
}


/**
 Handle the section tap

 @param tap the UITapGestureRecognizer
 */
- (void)handleTapGesture:(UITapGestureRecognizer*)tap{

    NSInteger index = tap.view.tag;

    [self toggleSection:index];
}

섹션 가시성 전환

/**
 Switch the state of the section at the given section number

 @param section the section number
 */
-(void)toggleSection:(NSInteger)section{

    if (index >= 0){

        NSMutableDictionary * asection = [self sectionAtIndex:section];

        [asection setObject:@(![self sectionIsOpened:section]) forKey:@"visible"];

        [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:section] withRowAnimation:UITableViewRowAnimationFade];
    }
}

0
// -------------------------------------------------------------------------------
//  tableView:viewForHeaderInSection:
// -------------------------------------------------------------------------------
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {

    UIView *mView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 20, 20)];
    [mView setBackgroundColor:[UIColor greenColor]];

    UIImageView *logoView = [[UIImageView alloc]initWithFrame:CGRectMake(0, 5, 20, 20)];
    [logoView setImage:[UIImage imageNamed:@"carat.png"]];
    [mView addSubview:logoView];

    UIButton *bt = [UIButton buttonWithType:UIButtonTypeCustom];
    [bt setFrame:CGRectMake(0, 0, 150, 30)];
    [bt setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
    [bt setTag:section];
    [bt.titleLabel setFont:[UIFont systemFontOfSize:20]];
    [bt.titleLabel setTextAlignment:NSTextAlignmentCenter];
    [bt.titleLabel setTextColor:[UIColor blackColor]];
    [bt setTitle: @"More Info" forState: UIControlStateNormal];
    [bt addTarget:self action:@selector(addCell:) forControlEvents:UIControlEventTouchUpInside];
    [mView addSubview:bt];
    return mView;

}

#pragma mark - Suppose you want to hide/show section 2... then
#pragma mark  add or remove the section on toggle the section header for more info

- (void)addCell:(UIButton *)bt{

    // If section of more information
    if(bt.tag == 2) {

        // Initially more info is close, if more info is open
        if(ifOpen) {
            DLog(@"close More info");

            // Set height of section
            heightOfSection = 0.0f;

            // Reset the parameter that more info is closed now
            ifOpen = NO;
        }else {
            // Set height of section
            heightOfSection = 45.0f;
            // Reset the parameter that more info is closed now
            DLog(@"open more info again");
            ifOpen = YES;
        }
        //[self.tableView reloadData];
        [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:2] withRowAnimation:UITableViewRowAnimationFade];
    }

}// end addCell
#pragma mark -
#pragma mark  What will be the height of the section, Make it dynamic

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{

    if (indexPath.section == 2) {
        return heightOfSection;
    }else {
        return 45.0f;
    }

// vKj


0
This action will happen in your didSelectRowAtIndexPath, when you will try to hide or show number of cell in a  section

first of all declare a global variable numberOfSectionInMoreInfo in .h file and in your viewDidLoad set suppose to numberOfSectionInMoreInfo = 4.

Now use following logic: 


 // More info link
        if(row == 3) {

            /*Logic: We are trying to hide/show the number of row into more information section */

            NSString *log= [NSString stringWithFormat:@"Number of section in more %i",numberOfSectionInMoreInfo];

            [objSpineCustomProtocol showAlertMessage:log];

            // Check if the number of rows are open or close in view
            if(numberOfSectionInMoreInfo > 4) {

                // close the more info toggle
                numberOfSectionInMoreInfo = 4;

            }else {

                // Open more info toggle
                numberOfSectionInMoreInfo = 9;

            }

            //reload this section
            [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:1] withRowAnimation:UITableViewRowAnimationFade];

// vKj


왜 두 가지 대답이 있습니까? 문제에 대해 두 가지 다른 해결책을 제공하지 않은 것 같습니다.
Cristik

0

Objective C로 작성된 답변을 확장하여 Swift로 작성하는 사람들을 위해 다음을 작성했습니다.

아이디어는 테이블 내의 섹션을 사용하고 해당 섹션의 첫 번째 행을 탭할 때 섹션의 행 수를 1 (축소됨) 및 3 (확장 됨)으로 설정하는 것입니다.

테이블은 부울 값의 배열을 기반으로 그릴 행 수를 결정합니다.

스토리 보드에 두 개의 행을 만들고 재사용 식별자 'CollapsingRow'및 'GroupHeading'을 제공해야합니다.

import UIKit

class CollapsingTVC:UITableViewController{

    var sectionVisibilityArray:[Bool]!// Array index corresponds to section in table

    override func viewDidLoad(){
        super.viewDidLoad()
        sectionVisibilityArray = [false,false,false]
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
    }

    override func numberOfSections(in tableView: UITableView) -> Int{
        return sectionVisibilityArray.count
    }
    override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat{
        return 0
    }

    // numberOfRowsInSection - Get count of entries
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        var rowsToShow:Int = 0
        if(sectionVisibilityArray[section]){
            rowsToShow = 3 // Or however many rows should be displayed in that section
        }else{
            rowsToShow = 1
        }
        return rowsToShow
    }// numberOfRowsInSection


    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath){
        if(indexPath.row == 0){
            if(sectionVisibilityArray[indexPath.section]){
                sectionVisibilityArray[indexPath.section] = false
            }else{
                sectionVisibilityArray[indexPath.section] = true
            }
            self.tableView.reloadSections([indexPath.section], with: .automatic)
        }
    }

    // cellForRowAtIndexPath - Get table cell corresponding to this IndexPath
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        var cell:UITableViewCell

        if(indexPath.row == 0){
             cell = tableView.dequeueReusableCell(withIdentifier: "GroupHeading", for: indexPath as IndexPath)
        }else{
            cell = tableView.dequeueReusableCell(withIdentifier: "CollapsingRow", for: indexPath as IndexPath)
        }

        return cell

    }// cellForRowAtIndexPath

}

0

테이블보기 섹션 헤더를 사용하여 확장 / 축소 동작을 애니메이션하는 일부 샘플 코드는 Apple에서 Table View Animations and Gestures 에서 제공합니다 .

이 접근 방식의 핵심은

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section

버튼을 포함하는 사용자 정의 UIView를 반환합니다 (일반적으로 헤더 뷰 자체와 동일한 크기). UIView를 서브 클래 싱하고이를 헤더보기에 사용하면 (이 샘플처럼) 섹션 번호와 같은 추가 데이터를 쉽게 저장할 수 있습니다.


0

여러 섹션을 사용하여 동일한 작업을 수행했습니다.

class SCTierBenefitsViewController: UIViewController {
    @IBOutlet private weak var tblTierBenefits: UITableView!
    private var selectedIndexPath: IndexPath?
    private var isSelected:Bool = false

    override func viewDidLoad() {
        super.viewDidLoad()

        tblTierBenefits.register(UINib(nibName:"TierBenefitsTableViewCell", bundle: nil), forCellReuseIdentifier:"TierBenefitsTableViewCell")
        tblTierBenefits.register(UINib(nibName:"TierBenefitsDetailsCell", bundle: nil), forCellReuseIdentifier:"TierBenefitsDetailsCell")

        tblTierBenefits.rowHeight = UITableViewAutomaticDimension;
        tblTierBenefits.estimatedRowHeight = 44.0;
        tblTierBenefits.tableFooterView = UIView()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

}

extension SCTierBenefitsViewController : UITableViewDataSource{

    func numberOfSections(in tableView: UITableView) -> Int {
        return 7
    }
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return (isSelected && section == selectedIndexPath?.section) ? 2 : 1 
    }

    func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
        return  0.01
    }

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

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        switch indexPath.row {
        case 0:
            let cell:TierBenefitsTableViewCell = tableView.dequeueReusableCell(withIdentifier: "TierBenefitsTableViewCell")! as! TierBenefitsTableViewCell
            cell.selectionStyle = .none
            cell.contentView.setNeedsLayout()
            cell.contentView.layoutIfNeeded()
            return cell

        case 1:
            let cell:TierBenefitsDetailsCell = tableView.dequeueReusableCell(withIdentifier: "TierBenefitsDetailsCell")! as! TierBenefitsDetailsCell
            cell.selectionStyle = .none
            return cell

        default:
            break
        }

        return UITableViewCell()
    }
}

extension SCTierBenefitsViewController : UITableViewDelegate{

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        if indexPath.row == 0 {

            if let _selectedIndexPath = selectedIndexPath ,selectedIndexPath?.section == indexPath.section {
                tblTierBenefits.beginUpdates()
                expandCollapse(indexPath: _selectedIndexPath, isExpand: false)
                selectedIndexPath = nil
            }
            else{
                tblTierBenefits.beginUpdates()
                if selectedIndexPath != nil {
                    tblTierBenefits.reloadSections([(selectedIndexPath?.section)!], with: .none)
                }
                expandCollapse(indexPath: indexPath, isExpand: true)
            }
        }
    }

    private func  expandCollapse(indexPath: IndexPath?,isExpand: Bool){
        isSelected = isExpand
        selectedIndexPath = indexPath
        tblTierBenefits.reloadSections([(indexPath?.section)!], with: .none)
        tblTierBenefits.endUpdates()
    }

}

0

완전성을 위해이 솔루션을 추가하고 섹션 헤더로 작업하는 방법을 보여줍니다.

import UIKit

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

    @IBOutlet var tableView: UITableView!
    var headerButtons: [UIButton]!
    var sections = [true, true, true]

    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.dataSource = self
        tableView.delegate = self

        let section0Button = UIButton(type: .detailDisclosure)
        section0Button.setTitle("Section 0", for: .normal)
        section0Button.addTarget(self, action: #selector(section0Tapped), for: .touchUpInside)

        let section1Button = UIButton(type: .detailDisclosure)
        section1Button.setTitle("Section 1", for: .normal)
        section1Button.addTarget(self, action: #selector(section1Tapped), for: .touchUpInside)

        let section2Button = UIButton(type: .detailDisclosure)
        section2Button.setTitle("Section 2", for: .normal)
        section2Button.addTarget(self, action: #selector(section2Tapped), for: .touchUpInside)

        headerButtons = [UIButton]()
        headerButtons.append(section0Button)
        headerButtons.append(section1Button)
        headerButtons.append(section2Button)
    }

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

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return sections[section] ? 3 : 0
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cellReuseId = "cellReuseId"
        let cell = UITableViewCell(style: .default, reuseIdentifier: cellReuseId)
        cell.textLabel?.text = "\(indexPath.section): \(indexPath.row)"
        return cell
    }

    func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        return headerButtons[section]
    }

    func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
        return 44
    }

    @objc func section0Tapped() {
        sections[0] = !sections[0]
        tableView.reloadSections([0], with: .fade)
    }

    @objc func section1Tapped() {
        sections[1] = !sections[1]
        tableView.reloadSections([1], with: .fade)
    }

    @objc func section2Tapped() {
        sections[2] = !sections[2]
        tableView.reloadSections([2], with: .fade)
    }

}

요점 링크 : https://gist.github.com/pawelkijowskizimperium/fe1e8511a7932a0d40486a2669316d2c


0

@ jean.timex 솔루션을 지원하기 위해 언제든지 한 섹션을 열려면 아래 코드를 사용하십시오. 다음과 같은 변수를 만듭니다. var extendedSection = -1;

func toggleSection(_ header: CollapsibleTableViewHeader, section: Int) {
    let collapsed = !sections[section].collapsed
    // Toggle collapse
    sections[section].collapsed = collapsed
    header.setCollapsed(collapsed)
    tableView.reloadSections(NSIndexSet(index: section) as IndexSet, with: .automatic)
    if (expandedSection >= 0 && expandedSection != section){
        sections[expandedSection].collapsed = true
        tableView.reloadSections(NSIndexSet(index: expandedSection) as IndexSet, with: .automatic)
    }
    expandedSection = section;
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.