Rozwiń / Zwiń sekcję w UITableView w systemie iOS
Może mi ktoś powiedzieć jak wykonać UITableView
rozszerzalne/zwijane animacje w sections
z UITableView
jak poniżej?
Lub
15 answers
Musisz stworzyć własny, niestandardowy wiersz nagłówka i umieścić go jako pierwszy wiersz każdej sekcji. Podklasowanie UITableView
lub nagłówków, które już są, Będzie bolało. W oparciu o sposób, w jaki działają teraz, nie jestem pewien, czy można łatwo uzyskać z nich działania. Możesz ustawić komórkę tak, aby wyglądała jak nagłówek i ustawić tableView:didSelectRowAtIndexPath
, aby ręcznie rozwijała lub zwijała sekcję, w której się znajduje.
Przechowywałbym tablicę wartości logicznych odpowiadającą "wydatkowanej" wartości każdej z Twoich sekcji. Wtedy ty może tableView:didSelectRowAtIndexPath
na każdym z niestandardowych wierszy nagłówka przełączyć tę wartość, a następnie przeładować tę konkretną sekcję.
- (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];
}
}
Następnie Ustaw numberOfRowsInSection
, aby sprawdzić wartość mybooleans
i zwróć 1, jeśli sekcja nie jest rozwinięta, lub 1+ liczbę pozycji w sekcji, jeśli jest rozwinięta.
- (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;
}
}
Ponadto, będziesz musiał zaktualizować cellForRowAtIndexPath
, aby zwrócić niestandardową komórkę nagłówka dla pierwszego wiersza w dowolnej sekcji.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-05 08:55:53
Przykładowy kod do animacji operacji Rozwiń/Zwiń za pomocą nagłówka sekcji widoku tabeli jest dostarczany przez Apple tutaj: animacje widoku tabeli i gesty
Kluczem do tego podejścia jest zaimplementowanie - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
i zwrócenie niestandardowego UIView zawierającego przycisk (zazwyczaj tego samego rozmiaru co sam widok nagłówka). Poprzez podklasowanie UIView i użycie go do widoku nagłówka (tak jak robi to ta próbka), można łatwo zapisać dodatkowe dane, takie jak numer sekcji.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-04 15:31:07
Mam fajne rozwiązanie inspirowane animacjami widoku tabeli i gestami Apple . Usunąłem niepotrzebne części z próbki Apple i przetłumaczyłem na swift.
Wiem, że odpowiedź jest dość długa, ale cały kod jest niezbędny. Na szczęście, można po prostu skopiować i przejść większość kodu i po prostu trzeba zrobić bitową modyfikację na kroku 1 i 3
1.Utwórz SectionHeaderView.swift
i 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
(widok z szarym tłem) powinien wyglądać mniej więcej tak w tableview(można go oczywiście dostosować do własnych potrzeb):
Uwaga:
A) akcja toggleOpen
powinna być powiązana z disclosureButton
B) działanie disclosureButton
i toggleOpen
nie jest konieczne. Możesz usunąć te 2 rzeczy, jeśli nie potrzebujesz przycisku.
2.Utwórz 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.in your 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)
}
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-25 06:39:22
Aby zaimplementować składaną sekcję tabeli w systemie iOS, magia polega na tym, jak kontrolować liczbę wierszy dla każdej sekcji lub możemy zarządzać wysokością wierszy dla każdej sekcji.
Musimy również dostosować nagłówek sekcji, abyśmy mogli odsłuchać Zdarzenie tap z obszaru nagłówka(czy to przycisk, czy cały nagłówek).
Jak radzić sobie z nagłówkiem? To bardzo proste, rozszerzamy klasę UITableViewCell i tworzymy własną Komórkę nagłówka w ten sposób:
import UIKit
class CollapsibleTableViewHeader: UITableViewCell {
@IBOutlet var titleLabel: UILabel!
@IBOutlet var toggleButton: UIButton!
}
Następnie użyj viewForHeaderInSection do podłączenia komórki nagłówka:
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
}
Pamiętaj, że musimy zwrócić contentView, ponieważ ta funkcja oczekuje, że zostanie zwrócony UIView.
Teraz zajmiemy się składaną częścią, oto funkcja przełączająca składaną podporę każdej sekcji:
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)
}
Zależy jak zarządzasz danymi sekcji, w tym przypadku mam dane sekcji coś takiego:
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"])
]
W końcu to, co musimy zrobić, opiera się na składanym prop każdej sekcji, kontroluj liczbę wierszy tej sekcji:
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return (sections[section].collapsed!) ? 0 : sections[section].items.count
}
Mam w pełni działające demo na moim Githubie: https://github.com/jeantimex/ios-swift-collapsible-table-section
Jeśli chcesz zaimplementować zwijane sekcje w tabeli w stylu grupowym, mam inne demo z kodem źródłowym tutaj: https://github.com/jeantimex/ios-swift-collapsible-table-section-in-grouped-section
Mam nadzieję, że to pomoże.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-02 00:16:37
Mam lepsze rozwiązanie, aby dodać UIButton do nagłówka sekcji i ustawić rozmiar tego przycisku równy rozmiarowi sekcji, ale aby był ukryty za pomocą wyraźnego koloru tła, po czym możesz łatwo sprawdzić, która sekcja jest kliknięta, aby rozwinąć lub zwinąć
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-07-13 07:10:03
Skończyło się na stworzeniu widoku nagłówka, który zawierał przycisk (widziałem rozwiązanie Son Nguyen powyżej po fakcie, ale oto mój kod.. wygląda na dużo ale to całkiem proste):
Zadeklaruj kilka boolów dla ciebie
bool customerIsCollapsed = NO;
bool siteIsCollapsed = NO;
...kod
Teraz w TableView deleguj metody...
- (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;
}
I na koniec funkcja, która zostanie wywołana po dotknięciu jednego z przycisków nagłówka sekcji:
- (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];
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:02:51
Jest to najlepszy sposób, jaki znalazłem, aby utworzyć rozszerzalne komórki widoku tabeli
.plik h
NSMutableIndexSet *expandedSections;
.m file
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];
Metody delegowania widoku tabeli
- (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);
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-26 13:23:21
Tak więc, w oparciu o rozwiązanie "przycisk w nagłówku", oto czysta i minimalistyczna implementacja:
- śledzisz zwinięte (lub rozszerzone) sekcje w właściwości
- oznaczamy przycisk indeksem sekcji
- ustawiasz wybrany stan na tym przycisku, aby zmienić kierunek strzałek (jak △ i▽)
Oto kod:
@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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-05 12:52:26
Znalazłem inny stosunkowo prosty sposób na rozwiązanie tego problemu. Używając tej metody nie będziemy musieli zmieniać naszej komórki, która jest prawie zawsze związana z indeksem macierzy danych, potencjalnie powodując bałagan w naszym kontrolerze widoku.
Najpierw dodajemy następujące właściwości do naszej klasy kontrolera:
@property (strong, nonatomic) NSMutableArray* collapsedSections;
@property (strong, nonatomic) NSMutableArray* sectionViews;
collapsedSections
zapisze zwinięte numery sekcji.
sectionViews
zapisze nasz niestandardowy widok sekcji.
@synthesize collapsedSections;
@synthesize sectionViews;
Initialize it:
- (void) viewDidLoad
{
[super viewDidLoad];
self.collapsedSections = [NSMutableArray array];
self.sectionViews = [NSMutableArray array];
}
Następnie musimy podłączyć nasz UITableView, aby mógł być dostępny z poziomu naszej klasy kontrolera widoku:
@property (strong, nonatomic) IBOutlet UITableView *tblMain;
Podłącz go z XIB do kontrolera widoku używając ctrl + drag
Jak zwykle.
Następnie tworzymy Widok jako niestandardowy nagłówek sekcji dla naszego widoku tabeli, implementując tego delegata 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;
}
Następnie zaimplementujemy metodę, aby zapisać nasz wcześniej utworzony niestandardowy nagłówek sekcji we właściwości klasy:
- (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];
}
}
}
Dodaj UIGestureRecognizerDelegate
do naszego widoku kontroler .plik h:
@interface MyViewController : UIViewController<UITableViewDelegate, UITableViewDataSource, UIGestureRecognizerDelegate>
Następnie tworzymy metodę attachTapGestureToView:
- (void) attachTapGestureToView:(UIView*) view
{
UITapGestureRecognizer* tapAction = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onTap:)];
[tapAction setDelegate:self];
[view addGestureRecognizer:tapAction];
}
Powyższa metoda doda rozpoznawanie gestów tap do wszystkich widoków sekcji, które utworzyliśmy wcześniej. Następnie należy zaimplementować selektor 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];
}
Powyższa metoda zostanie wywołana, gdy użytkownik dotknie dowolnej sekcji widoku tabeli. Ta metoda wyszukuje poprawny numer sekcji na podstawie tablicy sectionViews
, którą stworzyliśmy wcześniej.
Zaimplementujemy również metodę, aby uzyskać sekcję wihch widoku nagłówka za.
- (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;
}
Następnie musimy zaimplementować metodę toggleCollapseSection:
- (void) toggleCollapseSection:(NSInteger) section
{
if([self isCollapsedSection:section])
{
[self removeCollapsedSection:section];
}
else
{
[self addCollapsedSection:section];
}
[[self tblMain] reloadSections:[NSIndexSet indexSetWithIndex:section] withRowAnimation:UITableViewRowAnimationFade];
}
Ta metoda wstawi / usunie numer sekcji do naszej tablicy collapsedSections
, którą stworzyliśmy wcześniej. Gdy numer sekcji zostanie wstawiony do tej tablicy, oznacza to, że sekcja powinna zostać zwinięta i rozwinięta, jeśli jest inaczej.
Następnie realizujemy removeCollapsedSection:
, addCollapsedSection:section
i 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]];
}
Te trzy metody są tylko pomocnikami, aby ułatwić nam dostęp do tablicy collapsedSections
.
Na koniec zaimplementuj ten widok tabeli deleguj więc nasze niestandardowe widoki sekcji wyglądają ładnie.
- (CGFloat) tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
return 30.f; // Same as each custom section view height
}
Mam nadzieję, że to pomoże.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-10 07:26:36
Użyłem NSDictionary jako źródła danych, wygląda to na dużo kodu, ale jest naprawdę prosty i działa bardzo dobrze! Jak tu wygląda
Stworzyłem enum dla Sekcji
typedef NS_ENUM(NSUInteger, TableViewSection) {
TableViewSection0 = 0,
TableViewSection1,
TableViewSection2,
TableViewSectionCount
};
Właściwości sekcji:
@property (nonatomic, strong) NSMutableDictionary * sectionsDisctionary;
Metoda zwracająca moje sekcje:
-(NSArray <NSNumber *> * )sections{
return @[@(TableViewSection0), @(TableViewSection1), @(TableViewSection2)];
}
A następnie skonfiguruj moje dane soruce:
-(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;
}
Następne metody pomogą Ci dowiedzieć się, kiedy sekcja jest otwarta i jak odpowiedzieć na tableview datasource:
Odpowiedz na datasource:
/**
* 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;
}
Narzędzia:
/**
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];
}
Przełącz widoczność sekcji
/**
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];
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-13 17:34:42
// -------------------------------------------------------------------------------
// 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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-25 10:18:13
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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-26 12:21:53
Rozszerzając na tę odpowiedź napisaną w Objective C, dla tych, którzy piszą w Swift
Chodzi o to, aby użyć sekcji w tabeli i ustawić liczbę wierszy w sekcji na 1 (zwinięty) i 3(rozwinięty), gdy pierwszy wiersz w tej sekcji jest stuknięty
Tabela decyduje o liczbie wierszy do narysowania na podstawie tablicy wartości logicznych
Musisz utworzyć dwa wiersze w storyboardzie i nadać im identyfikatory ponownego użycia "CollapsingRow" i "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
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:02:51
Przykładowy kod do animacji operacji Rozwiń/Zwiń za pomocą nagłówka sekcji widoku tabeli jest dostarczany przez firmę Apple pod adresem animacje widoku tabeli i gesty .
Kluczem do tego podejścia jest wdrożenie
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
I zwraca Niestandardowy UIView zawierający przycisk (zazwyczaj taki sam rozmiar jak sam widok nagłówka). Poprzez podklasowanie UIView i użycie go do widoku nagłówka( tak jak robi to ta próbka), można łatwo zapisać dodatkowe dane, takie jak sekcja numer.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-05 03:11:28
Zrobiłem to samo, używając wielu sekcji .
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()
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-30 09:24:24