Antworten:
Sie suchen diese Lösung:
StaticDataTableViewController 2.0
https://github.com/xelvenone/StaticDataTableViewController
die statische Zellen mit oder ohne Animation ein- / ausblenden / neu laden können!
[self cell:self.outletToMyStaticCell1 setHidden:hide];
[self cell:self.outletToMyStaticCell2 setHidden:hide];
[self reloadDataAnimated:YES];
Hinweis: Verwenden Sie immer nur (reloadDataAnimated: YES / NO) (rufen Sie [self.tableView reloadData] nicht direkt auf.)
Dies verwendet nicht die Hacky-Lösung mit der Einstellung Höhe auf 0 und ermöglicht es Ihnen, die Änderung zu animieren und ganze Abschnitte auszublenden
IBOutletCollection
aber ich sehe nicht, wie das einen Unterschied machen würde. Ich habe den Code erst gestern heruntergeladen, daher glaube ich nicht, dass es sich um eine alte Version handelt.
So verbergen Sie statische Zellen in UITable:
In Ihrer UITableView-Controller-Delegatenklasse:
Ziel c:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell* cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];
if(cell == self.cellYouWantToHide)
return 0; //set the hidden cell's height to 0
return [super tableView:tableView heightForRowAtIndexPath:indexPath];
}
Schnell:
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
var cell = super.tableView(tableView, cellForRowAtIndexPath: indexPath)
if cell == self.cellYouWantToHide {
return 0
}
return super.tableView(tableView, heightForRowAtIndexPath: indexPath)
}
Diese Methode wird für jede Zelle in der UITable aufgerufen. Sobald es für die Zelle aufgerufen wird, die Sie ausblenden möchten, setzen wir ihre Höhe auf 0. Wir identifizieren die Zielzelle, indem wir einen Ausgang dafür erstellen:
ClipToBounds
Problem zu vermeiden , können Sie die Zelle auch auf "Ausgeblendet" setzen. Das scheint mir sauberer zu sein. ;-)
Der beste Weg ist wie im folgenden Blog beschrieben: http://ali-reynolds.com/2013/06/29/hide-cells-in-static-table-view/
Entwerfen Sie Ihre statische Tabellenansicht wie gewohnt im Interface Builder - einschließlich aller möglicherweise ausgeblendeten Zellen. Für jede potenzielle Zelle, die Sie ausblenden möchten, müssen Sie jedoch eines tun: Überprüfen Sie die Eigenschaft „Clip-Unteransichten“ der Zelle. Andernfalls verschwindet der Inhalt der Zelle nicht, wenn Sie versuchen, sie auszublenden (indem Sie ihre Höhe verringern) - später mehr).
SO - Sie haben einen Schalter in einer Zelle und der Schalter soll einige statische Zellen ausblenden und anzeigen. Schließen Sie es an eine IBAction an und machen Sie dort Folgendes:
[self.tableView beginUpdates]; [self.tableView endUpdates];
Das gibt Ihnen schöne Animationen für die Zellen, die erscheinen und verschwinden. Implementieren Sie nun die folgende Delegatenmethode für die Tabellenansicht:
- (float)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { if (indexPath.section == 1 && indexPath.row == 1) { // This is the cell to hide - change as you need // Show or hide cell if (self.mySwitch.on) { return 44; // Show the cell - adjust the height as you need } else { return 0; // Hide the cell } } return 44; }
Und das ist es. Wenn Sie den Schalter umlegen, wird die Zelle ausgeblendet und mit einer schönen, flüssigen Animation wieder angezeigt.
Meine Lösung geht in eine ähnliche Richtung wie Gareth, obwohl ich einige Dinge anders mache.
Hier geht:
1. Verstecken Sie die Zellen
Es gibt keine Möglichkeit, die Zellen direkt auszublenden. UITableViewController
ist die Datenquelle, die die statischen Zellen bereitstellt, und derzeit gibt es keine Möglichkeit, "keine Zelle x bereitzustellen" anzugeben. Wir müssen also unsere eigene Datenquelle bereitstellen, die an die delegiert UITableViewController
, um die statischen Zellen zu erhalten.
Am einfachsten ist es UITableViewController
, alle Methoden zu unterordnen und zu überschreiben , die sich beim Ausblenden von Zellen anders verhalten müssen .
Im einfachsten Fall (Einzelabschnitts-Tabelle, alle Zellen haben die gleiche Höhe) würde dies folgendermaßen aussehen:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [super tableView:tableView numberOfRowsInSection:section] - numberOfCellsHidden;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Recalculate indexPath based on hidden cells
indexPath = [self offsetIndexPath:indexPath];
return [super tableView:tableView cellForRowAtIndexPath:indexPath];
}
- (NSIndexPath*)offsetIndexPath:(NSIndexPath*)indexPath
{
int offsetSection = indexPath.section; // Also offset section if you intend to hide whole sections
int numberOfCellsHiddenAbove = ... // Calculate how many cells are hidden above the given indexPath.row
int offsetRow = indexPath.row + numberOfCellsHiddenAbove;
return [NSIndexPath indexPathForRow:offsetRow inSection:offsetSection];
}
Wenn Ihre Tabelle mehrere Abschnitte enthält oder die Zellen unterschiedliche Höhen haben, müssen Sie weitere Methoden überschreiben. Hier gilt das gleiche Prinzip: Sie müssen indexPath, section und row versetzen, bevor Sie an super delegieren.
Beachten Sie auch, dass der indexPath-Parameter für Methoden wie didSelectRowAtIndexPath:
für dieselbe Zelle je nach Status unterschiedlich ist (dh die Anzahl der ausgeblendeten Zellen). Daher ist es wahrscheinlich eine gute Idee, jeden indexPath-Parameter immer zu versetzen und mit diesen Werten zu arbeiten.
2. Animieren Sie die Änderung
Wie Gareth bereits sagte, treten große Störungen auf, wenn Sie Änderungen mithilfe der reloadSections:withRowAnimation:
Methode animieren .
Ich habe herausgefunden, dass reloadData:
die Animation erheblich verbessert wird, wenn Sie unmittelbar danach anrufen (nur noch kleine Störungen). Die Tabelle wird nach der Animation korrekt angezeigt.
Was ich also mache ist:
- (void)changeState
{
// Change state so cells are hidden/unhidden
...
// Reload all sections
NSIndexSet* reloadSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [self numberOfSectionsInTableView:tableView])];
[tableView reloadSections:reloadSet withRowAnimation:UITableViewRowAnimationAutomatic];
[tableView reloadData];
}
numberOfRowsInSection:
nur aufgerufen wird, wenn die Tabelle zum ersten Mal geladen wird. Wenn ich [self.tableView reloadData] aufrufe - numberOfRowsInSection:
wird nie wieder aufgerufen. Nur cellForRowAtIndexPath:
heißt. Was vermisse ich?
cellOneOutlet.hidden = true
Überschreiben Sie nun die folgende Methode, überprüfen Sie, welcher Zellenstatus ausgeblendet ist, und geben Sie die Höhe 0 für diese Zellen zurück. Dies ist eine von vielen Möglichkeiten, wie Sie jede Zelle in statischer tableView schnell ausblenden können.
override func tableView(tableView: UITableView, heightForRowAtIndexPathindexPath: NSIndexPath) -> CGFloat
{
let tableViewCell = super.tableView(tableView,cellForRowAtIndexPath: indexPath)
if tableViewCell.hidden == true
{
return 0
}
else{
return super.tableView(tableView, heightForRowAtIndexPath: indexPath)
}
}
let tableViewCell = super.tableView(tableView,cellForRowAtIndexPath: indexPath)
. Ich gehe davon aus, dass es durch ersetzt wird let tableViewCell = tableView.cellForRow(at: indexPath as IndexPath)
.
UITableViewController
, habe ich keine UITableView
Delegatmethoden. heightForRow
Benötige ich auch andere Methoden , um es zum Aufrufen zu bringen ?
Ich habe mir eine Alternative ausgedacht, bei der Abschnitte tatsächlich ausgeblendet und nicht gelöscht werden. Ich habe den Ansatz von @ henning77 ausprobiert, bin aber immer wieder auf Probleme gestoßen, als ich die Anzahl der Abschnitte der statischen UITableView geändert habe. Diese Methode hat bei mir sehr gut funktioniert, aber ich versuche hauptsächlich, Abschnitte anstelle von Zeilen auszublenden. Ich entferne einige Zeilen im laufenden Betrieb erfolgreich, aber es ist viel chaotischer, deshalb habe ich versucht, Dinge in Abschnitte zu gruppieren, die ich ein- oder ausblenden muss. Hier ist ein Beispiel, wie ich Abschnitte verstecke:
Zuerst deklariere ich eine NSMutableArray-Eigenschaft
@property (nonatomic, strong) NSMutableArray *hiddenSections;
In viewDidLoad (oder nachdem Sie Ihre Daten abgefragt haben) können Sie dem Array Abschnitte hinzufügen, die Sie ausblenden möchten.
- (void)viewDidLoad
{
hiddenSections = [NSMutableArray new];
if(some piece of data is empty){
// Add index of section that should be hidden
[self.hiddenSections addObject:[NSNumber numberWithInt:1]];
}
... add as many sections to the array as needed
[self.tableView reloadData];
}
Implementieren Sie anschließend die folgenden TableView-Delegatmethoden
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
if([self.hiddenSections containsObject:[NSNumber numberWithInt:section]]){
return nil;
}
return [super tableView:tableView titleForHeaderInSection:section];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if([self.hiddenSections containsObject:[NSNumber numberWithInt:indexPath.section]]){
return 0;
}
return [super tableView:tableView heightForRowAtIndexPath:[self offsetIndexPath:indexPath]];
}
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
if([self.hiddenSections containsObject:[NSNumber numberWithInt:indexPath.section]]){
[cell setHidden:YES];
}
}
Setzen Sie dann die Höhe der Kopf- und Fußzeile für ausgeblendete Abschnitte auf 1, da Sie die Höhe nicht auf 0 setzen können. Dies führt zu einem zusätzlichen Abstand von 2 Pixel. Wir können dies jedoch ausgleichen, indem wir die Höhe der nächsten sichtbaren Kopfzeile anpassen.
-(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
CGFloat height = [super tableView:tableView heightForHeaderInSection:section];
if([self.hiddenSections containsObject:[NSNumber numberWithInt:section]]){
height = 1; // Can't be zero
}
else if([self tableView:tableView titleForHeaderInSection:section] == nil){ // Only adjust if title is nil
// Adjust height for previous hidden sections
CGFloat adjust = 0;
for(int i = (section - 1); i >= 0; i--){
if([self.hiddenSections containsObject:[NSNumber numberWithInt:i]]){
adjust = adjust + 2;
}
else {
break;
}
}
if(adjust > 0)
{
if(height == -1){
height = self.tableView.sectionHeaderHeight;
}
height = height - adjust;
if(height < 1){
height = 1;
}
}
}
return height;
}
-(CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{
if([self.hiddenSections containsObject:[NSNumber numberWithInt:section]]){
return 1;
}
return [super tableView:tableView heightForFooterInSection:section];
}
Wenn Sie dann bestimmte Zeilen ausblenden müssen, können Sie die Anzahl der ZeilenInSection anpassen und festlegen, welche Zeilen in cellForRowAtIndexPath zurückgegeben werden. In diesem Beispiel habe ich hier einen Abschnitt mit drei Zeilen, in denen drei leer sein könnten und entfernt werden müssen.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSInteger rows = [super tableView:tableView numberOfRowsInSection:section];
if(self.organization != nil){
if(section == 5){ // Contact
if([self.organization objectForKey:@"Phone"] == [NSNull null]){
rows--;
}
if([self.organization objectForKey:@"Email"] == [NSNull null]){
rows--;
}
if([self.organization objectForKey:@"City"] == [NSNull null]){
rows--;
}
}
}
return rows;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
return [super tableView:tableView cellForRowAtIndexPath:[self offsetIndexPath:indexPath]];
}
Verwenden Sie diesen offsetIndexPath, um den indexPath für Zeilen zu berechnen, in denen Sie Zeilen bedingt entfernen. Wird nicht benötigt, wenn Sie nur Abschnitte ausblenden
- (NSIndexPath *)offsetIndexPath:(NSIndexPath*)indexPath
{
int row = indexPath.row;
if(self.organization != nil){
if(indexPath.section == 5){
// Adjust row to return based on which rows before are hidden
if(indexPath.row == 0 && [self.organization objectForKey:@"Phone"] == [NSNull null] && [self.organization objectForKey:@"Email"] != [NSNull null]){
row++;
}
else if(indexPath.row == 0 && [self.organization objectForKey:@"Phone"] == [NSNull null] && [self.organization objectForKey:@"Address"] != [NSNull null]){
row = row + 2;
}
else if(indexPath.row == 1 && [self.organization objectForKey:@"Phone"] != [NSNull null] && [self.organization objectForKey:@"Email"] == [NSNull null]){
row++;
}
else if(indexPath.row == 1 && [self.organization objectForKey:@"Phone"] == [NSNull null] && [self.organization objectForKey:@"Email"] != [NSNull null]){
row++;
}
}
}
NSIndexPath *offsetPath = [NSIndexPath indexPathForRow:row inSection:indexPath.section];
return offsetPath;
}
Es gibt viele Methoden zum Überschreiben, aber was mir an diesem Ansatz gefällt, ist, dass er wiederverwendbar ist. Richten Sie das Array hiddenSections ein, fügen Sie es hinzu, und die richtigen Abschnitte werden ausgeblendet. Das Ausblenden der Reihen ist etwas kniffliger, aber möglich. Wir können nicht einfach die Höhe der Zeilen, die wir ausblenden möchten, auf 0 setzen, wenn wir eine gruppierte UITableView verwenden, da die Rahmen nicht korrekt gezeichnet werden.
NSMutableSet
für hiddenSections
verwenden. Es ist viel schneller, da Sie meistens auf Mitgliedschaft testen.
NSMutableSet
für hiddenSections
, obwohl ich verstehe, dass der Punkt Ihrer Antwort eher konzeptionell als wählerisch war, welche Art von Datenstruktur Sie verwenden sollten.
Es stellt sich heraus, dass Sie Zellen in einer statischen UITableView ein- und ausblenden können - und zwar mit Animation. Und es ist nicht so schwer zu erreichen.
Das Wesentliche:
Use tableView:heightForRowAtIndexPath:
um Zellenhöhen basierend auf einem bestimmten Status dynamisch anzugeben.tableView.beginUpdates();tableView.endUpdates()
tableView.cellForRowAtIndexPath:
innerhalbtableView:heightForRowAtIndexPath:
. Verwenden Sie zwischengespeicherte indexPaths, um die Zellen zu unterscheiden.Ja, das ist definitiv möglich, obwohl ich im Moment mit dem gleichen Problem zu kämpfen habe. Ich habe es geschafft, die Zellen zum Verstecken zu bringen und alles funktioniert in Ordnung, aber ich kann das Ding derzeit nicht ordentlich animieren. Folgendes habe ich gefunden:
Ich verstecke Zeilen basierend auf dem Status eines EIN / AUS-Schalters in der ersten Zeile des ersten Abschnitts. Wenn der Schalter auf ON steht, befindet sich im selben Abschnitt 1 Zeile darunter, andernfalls befinden sich 2 verschiedene Zeilen.
Ich habe einen Selektor aufgerufen, wenn der Schalter umgeschaltet ist, und ich setze eine Variable, um anzuzeigen, in welchem Zustand ich mich befinde. Dann rufe ich auf:
[[self tableView] reloadData];
Ich überschreibe die Funktion tableView: willDisplayCell: forRowAtIndexPath: und wenn die Zelle ausgeblendet werden soll, mache ich Folgendes :
[cell setHidden:YES];
Das verbirgt die Zelle und ihren Inhalt, entfernt aber nicht den Platz, den sie einnimmt.
Überschreiben Sie zum Entfernen des Leerzeichens die tableView: heightForRowAtIndexPath: und geben Sie 0 für Zeilen zurück, die ausgeblendet werden sollen.
Sie müssen auch tableView: numberOfRowsInSection: überschreiben und die Anzahl der Zeilen in diesem Abschnitt zurückgeben. Sie müssen hier etwas Seltsames tun, damit bei einer gruppierten Tabelle die abgerundeten Ecken in den richtigen Zellen auftreten. In meiner statischen Tabelle befindet sich der vollständige Satz von Zellen für den Abschnitt, sodass die erste Zelle die Option enthält, dann 1 Zelle für die EIN-Statusoptionen und 2 weitere Zellen für die AUS-Statusoptionen, insgesamt 4 Zellen. Wenn die Option aktiviert ist, muss ich 4 zurückgeben. Dies schließt die versteckte Option ein, damit die zuletzt angezeigte Option ein abgerundetes Feld enthält. Wenn die Option deaktiviert ist, werden die letzten beiden Optionen nicht angezeigt, sodass ich 2 zurückgebe. Dies alles fühlt sich klobig an. Entschuldigung, wenn dies nicht sehr klar ist, ist es schwierig zu beschreiben. Um den Aufbau zu veranschaulichen, ist dies der Aufbau des Tabellenabschnitts in IB:
Wenn die Option aktiviert ist, werden in der Tabelle zwei Zeilen angezeigt:
Wenn die Option deaktiviert ist, werden in der Tabelle vier Zeilen angezeigt:
Dieser Ansatz fühlt sich aus mehreren Gründen nicht richtig an. Er ist genau so weit wie ich bisher mit meinen Experimenten gekommen bin. Bitte lassen Sie mich wissen, wenn Sie einen besseren Weg finden. Die Probleme, die ich bisher beobachtet habe, sind:
Es fühlt sich falsch an, der Tabelle mitzuteilen, dass sich die Anzahl der Zeilen von der vermutlich in den zugrunde liegenden Daten enthaltenen unterscheidet.
Ich kann die Veränderung nicht animieren. Ich habe versucht, tableView: reloadSections: withRowAnimation: anstelle von reloadData zu verwenden, und die Ergebnisse scheinen keinen Sinn zu ergeben. Ich versuche immer noch, dies zum Laufen zu bringen. Derzeit scheint die tableView nicht die richtigen Zeilen zu aktualisieren, sodass eine verborgen bleibt, die angezeigt werden soll, und eine Leere unter der ersten Zeile verbleibt. Ich denke, dies könnte mit dem ersten Punkt über die zugrunde liegenden Daten zusammenhängen.
Hoffentlich kann jemand alternative Methoden vorschlagen oder vielleicht die Animation erweitern, aber vielleicht können Sie damit anfangen. Ich entschuldige mich für das Fehlen von Hyperlinks zu Funktionen. Ich habe sie eingefügt, aber sie wurden vom Spamfilter abgelehnt, weil ich ein ziemlich neuer Benutzer bin.
[[self tableView] reloadData];
nachdem Sie die Zellen versteckt haben
return [super tableView:tableView cellForRowAtIndexPath:indexPath];
in UITableViewController
Unterklasse statische Zellen zu schaffen.
Nach Justas 'Antwort, aber für Swift 4:
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let cell = super.tableView(tableView, cellForRowAt: indexPath)
if cell == self.cellYouWantToHide {
return 0
}
return super.tableView(tableView, heightForRowAt: indexPath)
}
tableView.reloadRows(at:, with:)
, um die Zellen zu aktualisieren, wenn Sie die Höhe ändern, während die Zeile bereits sichtbar ist.
Okay, nach einigem Versuch habe ich eine nicht häufige Antwort. Ich verwende die Variable "isHidden" oder "hidden", um zu überprüfen, ob diese Zelle ausgeblendet werden soll.
Erstellen Sie ein IBOutlet für Ihren View Controller.
@IBOutlet weak var myCell: UITableViewCell!
Aktualisieren Sie die myCell
in Ihrer benutzerdefinierten Funktion. Beispiel: Sie können sie in viewDidLoad hinzufügen:
override func viewDidLoad() {
super.viewDidLoad()
self.myCell.isHidden = true
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let cell = super.tableView(tableView, cellForRowAt: indexPath)
guard !cell.isHidden else {
return 0
}
return super.tableView(tableView, heightForRowAt: indexPath)
}
Dies reduziert Ihre Logik bei der Delegate-Methode und Sie müssen sich nur auf Ihre Geschäftsanforderungen konzentrieren.
Die obigen Antworten, die Zellen ausblenden / anzeigen, rowHeight ändern oder mit Einschränkungen für das automatische Layout herumspielen, haben bei mir aufgrund von Problemen mit dem automatischen Layout nicht funktioniert. Der Code wurde unerträglich.
Für eine einfache statische Tabelle funktionierte das Beste für mich:
Hier ist ein Beispiel von meinem Table View Controller:
@IBOutlet weak var titleCell: UITableViewCell!
@IBOutlet weak var nagCell: UITableViewCell!
@IBOutlet weak var categoryCell: UITableViewCell!
var cellsToShow: [UITableViewCell] = []
override func viewDidLoad() {
super.viewDidLoad()
determinCellsToShow()
}
func determinCellsToShow() {
if detail!.duration.type != nil {
cellsToShow = [titleCell, nagCell, categoryCell]
}
else {
cellsToShow = [titleCell, categoryCell]
}
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
return cellsToShow[indexPath.row]
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return cellsToShow.count
}
Für iOS 11 stellte ich fest, dass eine modifizierte Version von Mohamed Salehs Antwort am besten funktioniert, wobei einige Verbesserungen auf der Dokumentation von Apple basieren. Es animiert gut, vermeidet hässliche Hacks oder fest codierte Werte und verwendet Zeilenhöhen, die bereits im Interface Builder festgelegt wurden .
Das Grundkonzept besteht darin, die Zeilenhöhe für alle ausgeblendeten Zeilen auf 0 zu setzen. Verwenden Sie dann tableView.performBatchUpdates
, um eine Animation auszulösen, die konsistent funktioniert.
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath == indexPathOfHiddenCell {
if cellIsHidden {
return 0
}
}
// Calling super will use the height set in your storyboard, avoiding hardcoded values
return super.tableView(tableView, heightForRowAt: indexPath)
}
Sie wollen sicherstellen cellIsHidden
und indexPathOfHiddenCell
werden in geeigneter Weise auf Ihren Anwendungsfall eingestellt. Für meinen Code sind sie Eigenschaften auf meinem Table View Controller.
Um die Sichtbarkeit zu steuern (wahrscheinlich eine Schaltflächenaktion oder didSelectRow
), schalten Sie den cellIsHidden-Status innerhalb eines performBatchUpdates
Blocks um:
tableView.performBatchUpdates({
// Use self to capture for block
self.cellIsHidden = !self.cellIsHidden
}, completion: nil)
Apple empfiehlt performBatchUpdates
über beginUpdates
/endUpdates
wann immer möglich.
Ich habe eine Lösung gefunden, um versteckte Zellen in einer statischen Tabelle zu animieren.
// Class for wrapping Objective-C block
typedef BOOL (^HidableCellVisibilityFunctor)();
@interface BlockExecutor : NSObject
@property (strong,nonatomic) HidableCellVisibilityFunctor block;
+ (BlockExecutor*)executorWithBlock:(HidableCellVisibilityFunctor)block;
@end
@implementation BlockExecutor
@synthesize block = _block;
+ (BlockExecutor*)executorWithBlock:(HidableCellVisibilityFunctor)block
{
BlockExecutor * executor = [[BlockExecutor alloc] init];
executor.block = block;
return executor;
}
@end
Es wird nur ein zusätzliches Wörterbuch benötigt:
@interface MyTableViewController ()
@property (nonatomic) NSMutableDictionary * hidableCellsDict;
@property (weak, nonatomic) IBOutlet UISwitch * birthdaySwitch;
@end
Schauen Sie sich auch die Implementierung von MyTableViewController an. Wir benötigen zwei Methoden, um indexPath zwischen sichtbaren und unsichtbaren Indizes zu konvertieren ...
- (NSIndexPath*)recoverIndexPath:(NSIndexPath *)indexPath
{
int rowDelta = 0;
for (NSIndexPath * ip in [[self.hidableCellsDict allKeys] sortedArrayUsingSelector:@selector(compare:)])
{
BlockExecutor * executor = [self.hidableCellsDict objectForKey:ip];
if (ip.section == indexPath.section
&& ip.row <= indexPath.row + rowDelta
&& !executor.block())
{
rowDelta++;
}
}
return [NSIndexPath indexPathForRow:indexPath.row+rowDelta inSection:indexPath.section];
}
- (NSIndexPath*)mapToNewIndexPath:(NSIndexPath *)indexPath
{
int rowDelta = 0;
for (NSIndexPath * ip in [[self.hidableCellsDict allKeys] sortedArrayUsingSelector:@selector(compare:)])
{
BlockExecutor * executor = [self.hidableCellsDict objectForKey:ip];
if (ip.section == indexPath.section
&& ip.row < indexPath.row - rowDelta
&& !executor.block())
{
rowDelta++;
}
}
return [NSIndexPath indexPathForRow:indexPath.row-rowDelta inSection:indexPath.section];
}
Eine IBAction zur Änderung des UISwitch-Werts:
- (IBAction)birthdaySwitchChanged:(id)sender
{
NSIndexPath * indexPath = [self mapToNewIndexPath:[NSIndexPath indexPathForRow:1 inSection:1]];
if (self.birthdaySwitch.on)
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
else
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}
Einige UITableViewDataSource- und UITableViewDelegate-Methoden:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
int numberOfRows = [super tableView:tableView numberOfRowsInSection:section];
for (NSIndexPath * indexPath in [self.hidableCellsDict allKeys])
if (indexPath.section == section)
{
BlockExecutor * executor = [self.hidableCellsDict objectForKey:indexPath];
numberOfRows -= (executor.block()?0:1);
}
return numberOfRows;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
indexPath = [self recoverIndexPath:indexPath];
return [super tableView:tableView cellForRowAtIndexPath:indexPath];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
indexPath = [self recoverIndexPath:indexPath];
return [super tableView:tableView heightForRowAtIndexPath:indexPath];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// initializing dictionary
self.hidableCellsDict = [NSMutableDictionary dictionary];
[self.hidableCellsDict setObject:[BlockExecutor executorWithBlock:^(){return self.birthdaySwitch.on;}] forKey:[NSIndexPath indexPathForRow:1 inSection:1]];
}
- (void)viewDidUnload
{
[self setBirthdaySwitch:nil];
[super viewDidUnload];
}
@end
Antworte schnell :
Fügen Sie Ihrem TableViewController die folgende Methode hinzu:
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return indexPathOfCellYouWantToHide == indexPath ? 0 : super.tableView(tableView, heightForRowAtIndexPath: indexPath)
}
Wenn die tableView versucht, die Zelle zu zeichnen, die Sie ausblenden möchten, wird sie nicht angezeigt, da ihre Höhe dank der obigen Methode auf 0pt gesetzt wird. Alles andere bleibt unverändert.
Bitte beachten Sie, dass indexPathOfCellYouWantToHide
dies jederzeit geändert werden kann :)
In> Swift 2.2 habe ich hier einige Antworten zusammengefasst.
Stellen Sie eine Verbindung zum Storyboard her, um eine Verknüpfung zu Ihrer staticCell herzustellen.
@IBOutlet weak var updateStaticCell: UITableViewCell!
override func viewDidLoad() {
...
updateStaticCell.hidden = true
}
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
if indexPath.row == 0 {
return 0
} else {
return super.tableView(tableView, heightForRowAtIndexPath: indexPath)
}
}
Ich möchte meine erste Zelle ausblenden, also setze ich die Höhe wie oben beschrieben auf 0.
Swift 4:
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
var height = super.tableView(tableView, heightForRowAt: indexPath)
if (indexPath.row == HIDDENROW) {
height = 0.0
}
return height
}
Für das einfachste Szenario, wenn Sie Zellen ganz unten in der Tabellenansicht ausblenden, können Sie das contentInset von tableView anpassen, nachdem Sie die Zelle ausgeblendet haben:
- (void)adjustBottomInsetForHiddenSections:(NSInteger)numberOfHiddenSections
{
CGFloat bottomInset = numberOfHiddenSections * 44.0; // or any other 'magic number
self.tableView.contentInset = UIEdgeInsetsMake(self.tableView.contentInset.top, self.tableView.contentInset.left, -bottomInset, self.tableView.contentInset.right);
}
Dies ist eine neue Methode, um dies mit https://github.com/k06a/ABStaticTableViewController zu tun
NSIndexPath *ip = [NSIndexPath indexPathForRow:1 section:1];
[self deleteRowsAtIndexPaths:@[ip] withRowAnimation:UITableViewRowAnimationFade]
Die Lösung von k06a ( https://github.com/k06a/ABStaticTableViewController ) ist besser, da sie den gesamten Abschnitt einschließlich der Kopf- und Fußzeilen der Zellen verbirgt, wobei diese Lösung ( https://github.com/peterpaulis/StaticDataTableViewController ) alles außer der Fußzeile verbirgt.
BEARBEITEN
Ich habe gerade eine Lösung gefunden, wenn Sie die Fußzeile verstecken möchten StaticDataTableViewController
. Folgendes müssen Sie in die Datei StaticTableViewController.m kopieren:
- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section {
if ([tableView.dataSource tableView:tableView numberOfRowsInSection:section] == 0) {
return nil;
} else {
return [super tableView:tableView titleForFooterInSection:section];
}
}
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
CGFloat height = [super tableView:tableView heightForFooterInSection:section];
if (self.originalTable == nil) {
return height;
}
if (!self.hideSectionsWithHiddenRows) {
return height;
}
OriginalSection * os = self.originalTable.sections[section];
if ([os numberOfVissibleRows] == 0) {
//return 0;
return CGFLOAT_MIN;
} else {
return height;
}
//return 0;
return CGFLOAT_MIN;
}
Sicher kannst du. Kehren Sie zunächst zu Ihrer tableView-Anzahl der Zellen zurück, die Sie anzeigen möchten, und rufen Sie dann super
auf, um eine bestimmte Zelle aus Ihrem Storyboard zu erhalten, und geben Sie sie für tableView zurück:
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.mode.numberOfCells()
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = super.tableView(tableView, cellForRowAtIndexPath: self.mode.indexPathForIndexPath(indexPath))
return cell
}
Wenn Ihre Zellen eine andere Höhe haben, geben Sie diese ebenfalls zurück:
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return super.tableView(tableView, heightForRowAtIndexPath: self.mode.indexPathForIndexPath(indexPath))
}
Zusätzlich zur @ Saleh Masum-Lösung:
Wenn Sie Fehler beim automatischen Layout erhalten , können Sie die Einschränkungen einfach aus dem entfernentableViewCell.contentView
Swift 3:
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let tableViewCell = super.tableView(tableView, cellForRowAt: indexPath)
if tableViewCell.isHidden == true
{
tableViewCell.contentView.removeConstraints(tableViewCell.contentView.constraints)
return 0
}
else{
return super.tableView(tableView, heightForRowAt: indexPath)
}
}
Diese Lösung hängt vom Ablauf Ihrer App ab . Wenn Sie die Zelle in derselben View Controller-Instanz ein- / ausblenden möchten, ist dies möglicherweise nicht die beste Wahl, da dadurch die Einschränkungen aufgehoben werden .
Ich habe eine bessere Möglichkeit, statische Zellen und sogar Abschnitte dynamisch ohne Hacks auszublenden.
Wenn Sie die Zeilenhöhe auf 0 setzen, kann eine Zeile ausgeblendet werden. Dies funktioniert jedoch nicht, wenn Sie einen gesamten Abschnitt ausblenden möchten, der einige Leerzeichen enthält, selbst wenn Sie alle Zeilen ausblenden.
Mein Ansatz ist es, ein Abschnittsarray statischer Zellen zu erstellen. Dann wird der Inhalt der Tabellenansicht vom Abschnittsarray gesteuert.
Hier ist ein Beispielcode:
var tableSections = [[UITableViewCell]]()
private func configTableSections() {
// seciton A
tableSections.append([self.cell1InSectionA, self.cell2InSectionA])
// section B
if shouldShowSectionB {
tableSections.append([self.cell1InSectionB, self.cell2InSectionB])
}
// section C
if shouldShowCell1InSectionC {
tableSections.append([self.cell1InSectionC, self.cell2InSectionC, self.cell3InSectionC])
} else {
tableSections.append([self.cell2InSectionC, self.cell3InSectionC])
}
}
func numberOfSections(in tableView: UITableView) -> Int {
return tableSections.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tableSections[section].count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
return tableSections[indexPath.section][indexPath.row]
}
Auf diese Weise können Sie Ihren gesamten Konfigurationscode zusammenstellen, ohne den bösen Code schreiben zu müssen, um die Anzahl der Zeilen und Abschnitte zu berechnen. Und natürlich nein0
Höhen mehr.
Dieser Code ist auch sehr einfach zu pflegen. Zum Beispiel, wenn Sie weitere Zellen oder Abschnitte hinzufügen / entfernen möchten.
Ebenso können Sie ein Titelarray für Abschnittsüberschriften und ein Titelarray für Abschnittsfußzeilen erstellen, um Ihre Abschnittsüberschriften dynamisch zu konfigurieren.