Расширьтесь/сверните раздел в UITableView в iOS

Я исправил некоторую синтаксическую ошибку в данных package.json Package.json, просто сверьтесь с https://jsonlint.com/ веб-сайтом, действительны ли данные json или нет.

В моем случае пропущен один символ. Итак, исправлено. она.

113
задан Meet Doshi 6 January 2016 в 10:47
поделиться

7 ответов

Вы должны создать свою собственную строку заголовка и поместить ее в качестве первой строки каждого раздела. Создание подкласса UITableView или заголовков, которые уже есть, будет проблемой. Судя по тому, как они работают сейчас, я не уверен, что вы легко сможете добиться от них действий. Вы можете настроить ячейку так, чтобы она выглядела как заголовок, и настройте tableView: didSelectRowAtIndexPath , чтобы вручную развернуть или свернуть раздел, в котором она находится.

Я бы сохранил массив логических значений, соответствующий " израсходовано "значение каждого из ваших разделов". Затем вы могли бы tableView: didSelectRowAtIndexPath в каждой из ваших настраиваемых строк заголовка переключать это значение, а затем перезагружать этот конкретный раздел.

107
ответ дан 24 November 2019 в 02:40
поделиться

Я добавляю это решение для полноты и показываю, как работать с заголовками разделов.

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
ответ дан ayaio 24 November 2019 в 02:40
поделиться
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

0
ответ дан Vinod Joshi 24 November 2019 в 02:40
поделиться

Это лучший способ, который я нашел для создания расширяемых ячеек табличного представления

.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);

}
5
ответ дан vamsi575kg 24 November 2019 в 02:40
поделиться

У меня есть лучшее решение, что вы должны добавить UIButton в заголовок раздела и установить размер этой кнопки равным размеру раздела, но сделать его скрытым с помощью прозрачного фона, после чего вы легко можете проверить, какой раздел нажимается для расширения или коллапс

10
ответ дан Son Nguyen 24 November 2019 в 02:40
поделиться

Я получил хорошее решение, вдохновленное Apple Table View Animations и Gestures . Я удалил ненужные части из образца Apple и перевел его на swift.

Я знаю, что ответ довольно длинный, но весь код необходим. К счастью, вы можете просто скопировать и пропустить большую часть кода, и вам нужно всего лишь немного изменить его на шаге 1 и 3 ] SectionHeaderView.xib (вид с серым фоном) должен выглядеть примерно так в виде таблицы (конечно, вы можете настроить его в соответствии со своими потребностями): ]

a) действие toggleOpen должно быть связано с disclosureButton

b) действие disclosureButton и toggleOpen необязательно. Вы можете удалить эти две вещи, если вам не нужна кнопка.

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.в вашей таблице

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)
        }
    }
}
22
ответ дан Brian 24 November 2019 в 02:40
поделиться

Я нашел другой относительно простой способ решения этой проблемы. Используя этот метод, мы не будем обязаны изменять нашу ячейку, которая почти всегда связана с индексом массива данных, что может вызвать беспорядок в нашем контроллере представления.

Сначала мы добавим следующие свойства в наш класс контроллера:

@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, который мы создали ранее.

Кроме того, мы реализуем метод, чтобы получить часть, к которой принадлежит представление заголовка.

- (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
ответ дан yunhasnawa 24 November 2019 в 02:40
поделиться
Другие вопросы по тегам:

Похожие вопросы: