Odpowiedzi:
Szukasz tego rozwiązania:
StaticDataTableViewController 2.0
https://github.com/xelvenone/StaticDataTableViewController
który może pokazać / ukryć / przeładować dowolne statyczne komórki z animacją lub bez!
[self cell:self.outletToMyStaticCell1 setHidden:hide];
[self cell:self.outletToMyStaticCell2 setHidden:hide];
[self reloadDataAnimated:YES];
Uwaga, aby zawsze używać tylko (reloadDataAnimated: YES / NO) (nie wywołuj [self.tableView reloadData] bezpośrednio)
Nie wykorzystuje to hackerskiego rozwiązania z ustawieniem wysokości na 0 i pozwala animować zmianę i ukrywać całe sekcje
IBOutletCollection
ale nie widzę, jak to by miało znaczenie. Ściągnąłem kod dopiero wczoraj, więc nie sądzę, że jest to stara wersja.
Aby ukryć komórki statyczne w UITable:
W klasie delegata kontrolera UITableView:
Cel 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];
}
Szybki:
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)
}
Ta metoda zostanie wywołana dla każdej komórki w UITable. Po wywołaniu komórki, którą chcesz ukryć, ustawiamy jej wysokość na 0. Identyfikujemy komórkę docelową, tworząc dla niej gniazdo:
ClipToBounds
problemu, możesz również ustawić komórkę jako ukrytą. Wydaje mi się to czystsze. ;-)
Najlepszy sposób jest opisany na następującym blogu http://ali-reynolds.com/2013/06/29/hide-cells-in-static-table-view/
Zaprojektuj swój statyczny widok tabeli w normalny sposób w konstruktorze interfejsu - wraz ze wszystkimi potencjalnie ukrytymi komórkami. Ale jest jedna rzecz, którą musisz zrobić dla każdej potencjalnej komórki, którą chcesz ukryć - zaznacz właściwość „Clip subviews” komórki, w przeciwnym razie zawartość komórki nie zniknie, gdy spróbujesz ją ukryć (zmniejszając jej wysokość - więcej później).
A więc - masz przełącznik w komórce, a przełącznik ma ukrywać i pokazywać statyczne komórki. Podłącz go do IBAction i tam zrób to:
[self.tableView beginUpdates]; [self.tableView endUpdates];
Daje to przyjemne animacje dla pojawiających się i znikających komórek. Teraz zaimplementuj następującą metodę delegata widoku tabeli:
- (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; }
I to wszystko. Przesuń przełącznik, a komórka ukryje się i pojawi się ponownie z ładną, płynną animacją.
Moje rozwiązanie idzie w podobnym kierunku, co Gareth, chociaż niektóre rzeczy robię inaczej.
Tutaj idzie:
1. Ukryj komórki
Nie ma możliwości bezpośredniego ukrycia komórek. UITableViewController
to źródło danych, które udostępnia komórki statyczne i obecnie nie ma sposobu, aby powiedzieć „nie dostarczaj komórki x”. Musimy więc zapewnić własne źródło danych, które jest delegowane do UITableViewController
w celu uzyskania statycznych komórek.
Najłatwiej jest tworzyć podklasy UITableViewController
i zastępować wszystkie metody, które muszą zachowywać się inaczej podczas ukrywania komórek .
W najprostszym przypadku (tabela z pojedynczą sekcją, wszystkie komórki mają tę samą wysokość) wyglądałoby to tak:
- (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];
}
Jeśli tabela ma wiele sekcji lub komórki mają różne wysokości, musisz zastąpić więcej metod. Ta sama zasada obowiązuje tutaj: musisz przesunąć indexPath, sekcję i wiersz przed delegowaniem do super.
Należy również pamiętać, że parametr indexPath dla metod takich jak didSelectRowAtIndexPath:
będzie różny dla tej samej komórki, w zależności od stanu (tj. Liczby komórek ukrytych). Dlatego prawdopodobnie dobrym pomysłem jest zawsze kompensowanie dowolnego parametru indexPath i praca z tymi wartościami.
2. Ożyw zmianę
Jak już powiedział Gareth, możesz mieć poważne usterki, jeśli animujesz zmiany za pomocą reloadSections:withRowAnimation:
metody.
Dowiedziałem się, że jeśli zadzwonisz reloadData:
zaraz potem, animacja znacznie się poprawi (pozostały tylko drobne usterki). Tabela jest wyświetlana poprawnie po animacji.
Więc to co robię to:
- (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:
wywoływana jest tylko przy pierwszym ładowaniu tabeli. Kiedy wywołuję [self.tableView reloadData] - numberOfRowsInSection:
nigdy nie jestem ponownie wywoływany. Tylko cellForRowAtIndexPath:
jest wezwany. czego mi brakuje?
cellOneOutlet.hidden = true
teraz zastąp poniższą metodę, sprawdź, który stan komórki jest ukryty i zwróć wysokość 0 dla tych komórek. Jest to jeden z wielu sposobów na ukrycie dowolnej komórki w statycznym widoku tableView.
override func tableView(tableView: UITableView, heightForRowAtIndexPathindexPath: NSIndexPath) -> CGFloat
{
let tableViewCell = super.tableView(tableView,cellForRowAtIndexPath: indexPath)
if tableViewCell.hidden == true
{
return 0
}
else{
return super.tableView(tableView, heightForRowAtIndexPath: indexPath)
}
}
let tableViewCell = super.tableView(tableView,cellForRowAtIndexPath: indexPath)
. Zakładam, że jest zastąpiony przez let tableViewCell = tableView.cellForRow(at: indexPath as IndexPath)
.
UITableViewController
, nie mam żadnych UITableView
metod delegata. Aby to zadzwoniło heightForRow
, czy muszę mieć również inne metody?
Wymyśliłem alternatywę, która faktycznie ukrywa sekcje i ich nie usuwa. Wypróbowałem podejście @ henning77, ale napotykałem problemy, gdy zmieniałem liczbę sekcji statycznego widoku UITableView. Ta metoda zadziałała dla mnie naprawdę dobrze, ale przede wszystkim próbuję ukryć sekcje zamiast wierszy. Z powodzeniem usuwam niektóre wiersze w locie, ale jest dużo bardziej bałaganiarski, więc próbowałem pogrupować elementy w sekcje, które muszę pokazać lub ukryć. Oto przykład tego, jak ukrywam sekcje:
Najpierw deklaruję właściwość NSMutableArray
@property (nonatomic, strong) NSMutableArray *hiddenSections;
W viewDidLoad (lub po przeszukaniu danych) możesz dodać sekcje, które chcesz ukryć do tablicy.
- (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];
}
Następnie zaimplementuj następujące metody delegata TableView
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
if([self.hiddenSections containsObject:[NSNumber numberWithInt:section]]){
return nil;
}
return [super tableView:tableView titleForHeaderInSection:section];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if([self.hiddenSections containsObject:[NSNumber numberWithInt:indexPath.section]]){
return 0;
}
return [super tableView:tableView heightForRowAtIndexPath:[self offsetIndexPath:indexPath]];
}
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
if([self.hiddenSections containsObject:[NSNumber numberWithInt:indexPath.section]]){
[cell setHidden:YES];
}
}
Następnie ustaw wysokość nagłówka i stopki na 1 dla ukrytych sekcji, ponieważ nie możesz ustawić wysokości na 0. Powoduje to dodatkowe 2 piksele, ale możemy to nadrobić, dostosowując wysokość następnego widocznego nagłówka.
-(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];
}
Następnie, jeśli masz określone wiersze do ukrycia, możesz dostosować numberOfRowsInSection i które wiersze są zwracane w cellForRowAtIndexPath. W tym przykładzie mam sekcję, która ma trzy wiersze, gdzie dowolne trzy mogą być puste i należy je usunąć.
- (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]];
}
Użyj tego offsetIndexPath, aby obliczyć indexPath dla wierszy, w których warunkowo usuwasz wiersze. Nie jest potrzebne, jeśli ukrywasz tylko sekcje
- (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;
}
Istnieje wiele metod do zastąpienia, ale w tym podejściu podoba mi się to, że można je ponownie wykorzystać. Skonfiguruj tablicę hiddenSections, dodaj do niej, a spowoduje to ukrycie właściwych sekcji. Ukrywanie rzędów jest trochę trudniejsze, ale możliwe. Nie możemy po prostu ustawić wysokości wierszy, które chcemy ukryć, na 0, jeśli używamy zgrupowanego UITableView, ponieważ obramowania nie zostaną poprawnie narysowane.
NSMutableSet
dla hiddenSections
zamiast. Jest to o wiele szybsze, ponieważ najczęściej testujesz członkostwo.
NSMutableSet
for hiddenSections
, chociaż rozumiem, że punkt twojej odpowiedzi był bardziej koncepcyjny niż drobiazgowy co do tego, jakiego typu struktury danych powinieneś użyć.
Okazuje się, że możesz ukrywać i wyświetlać komórki w statycznym widoku UITableView - i za pomocą animacji. I nie jest to takie trudne.
Film z projektu demonstracyjnego
Istota:
Use tableView:heightForRowAtIndexPath:
do dynamicznego określania wysokości komórek na podstawie pewnego stanu.tableView.beginUpdates();tableView.endUpdates()
tableView.cellForRowAtIndexPath:
środka tableView:heightForRowAtIndexPath:
. Użyj zapisanych w pamięci podręcznej indexPaths, aby rozróżnić komórki.Tak, na pewno jest to możliwe, chociaż obecnie borykam się z tym samym problemem. Udało mi się zmusić komórki do ukrycia i wszystko działa dobrze, ale obecnie nie mogę sprawić, by obiekt był dobrze ożywiony. Oto co znalazłem:
Ukrywam wiersze na podstawie stanu przełącznika WŁ. / WYŁ. W pierwszym rzędzie pierwszej sekcji. Jeśli przełącznik jest włączony, pod nim znajduje się 1 rząd w tej samej sekcji, w przeciwnym razie są 2 różne rzędy.
Mam selektor wywoływany, gdy przełącznik jest przełączany, i ustawiam zmienną, aby wskazać, w jakim stanie jestem. Następnie wzywam:
[[self tableView] reloadData];
I przesłonić tableView: willDisplayCell: forRowAtIndexPath: funkcję i jeśli komórka ma być ukryty zrobić to:
[cell setHidden:YES];
To ukrywa komórkę i jej zawartość, ale nie usuwa zajmowanej przez nią przestrzeni.
Aby usunąć spację, nadpisz tableView: heightForRowAtIndexPath: function i zwróć 0 dla wierszy, które powinny być ukryte.
Musisz także nadpisać tableView: numberOfRowsInSection: i zwrócić liczbę wierszy w tej sekcji. Musisz zrobić tutaj coś dziwnego, aby jeśli twoja tabela jest stylem zgrupowanym, zaokrąglone rogi wystąpiły we właściwych komórkach. W mojej statycznej tabeli znajduje się pełny zestaw komórek dla sekcji, więc jest pierwsza komórka zawierająca opcję, następnie 1 komórka dla opcji stanu WŁĄCZENIA i 2 kolejne komórki dla opcji stanu WYŁĄCZENIA, łącznie 4 komórki. Kiedy opcja jest WŁĄCZONA, muszę zwrócić 4, obejmuje to opcję ukrytą, tak aby ostatnia wyświetlona opcja miała zaokrąglone pole. Gdy opcja jest wyłączona, dwie ostatnie opcje nie są wyświetlane, więc zwracam 2. To wszystko wydaje się niezgrabne. Przepraszam, jeśli nie jest to zbyt jasne, trudno to opisać. Aby zilustrować konfigurację, oto konstrukcja sekcji tabeli w IB:
Więc gdy opcja jest WŁĄCZONA, w tabeli pojawiają się dwa wiersze:
Gdy opcja jest WYŁĄCZONA, tabela wyświetla cztery wiersze, które są:
To podejście nie wydaje się poprawne z kilku powodów, tak daleko, jak osiągnąłem z moich dotychczasowych eksperymentów, więc daj mi znać, jeśli znajdziesz lepszy sposób. Problemy, które zaobserwowałem do tej pory to:
Nieprawidłowe jest informowanie tabeli, że liczba wierszy różni się od tego, co przypuszczalnie zawiera dane bazowe.
Nie mogę ożywić zmiany. Próbowałem użyć tableView: reloadSections: withRowAnimation: zamiast reloadData i wyniki wydają się nie mieć sensu, nadal próbuję to uruchomić. Obecnie wydaje się, że tableView nie aktualizuje poprawnych wierszy, więc jeden pozostaje ukryty, który powinien zostać wyświetlony, a pod pierwszym wierszem pozostaje puste miejsce. Myślę, że może to być związane z pierwszym punktem dotyczącym danych bazowych.
Miejmy nadzieję, że ktoś będzie w stanie zasugerować alternatywne metody lub może to, jak rozszerzyć animację, ale może to pomoże Ci zacząć. Przepraszam za brak hiperłączy do funkcji, wstawiłem je, ale zostały odrzucone przez filtr spamu, ponieważ jestem dość nowym użytkownikiem.
[[self tableView] reloadData];
jeszcze raz po ukryciu
return [super tableView:tableView cellForRowAtIndexPath:indexPath];
na UITableViewController
podklasy dla tworzenia komórek statycznych. Ścieżki indeksu są indeksowane statycznie - nie dynamicznie ...
Zgodnie z odpowiedzią Justasa, ale dla 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:)
zaktualizowanie komórek, jeśli zmienisz wysokość, gdy wiersz jest już widoczny.
OK, po kilku próbach mam rzadką odpowiedź. Używam zmiennej „isHidden” lub „hidden”, aby sprawdzić, czy ta komórka powinna być ukryta.
utwórz IBOutlet do kontrolera widoku.
@IBOutlet weak var myCell: UITableViewCell!
Zaktualizuj myCell
w swojej funkcji niestandardowej, na przykład możesz dodać ją w viewDidLoad:
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)
}
Zmniejszy to logikę w metodzie delegowania i wystarczy skupić się na wymaganiach biznesowych.
Powyższe odpowiedzi, które ukrywają / pokazują komórki, zmieniają rowHeight lub bałagan z ograniczeniami automatycznego układu, nie działają dla mnie z powodu problemów z automatycznym układem. Kod stał się nie do zniesienia.
W przypadku prostego statycznego stołu najlepiej działało dla mnie:
Oto przykład z mojego kontrolera widoku tabeli:
@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
}
W przypadku iOS 11 stwierdziłem, że zmodyfikowana wersja odpowiedzi Mohameda Saleha działa najlepiej, z pewnymi ulepszeniami opartymi na dokumentacji Apple. Animuje się ładnie, unika wszelkich brzydkich hacków lub zakodowanych wartości i używa wysokości wierszy już ustawionych w Interface Builder .
Podstawową koncepcją jest ustawienie wysokości wiersza na 0 dla wszystkich ukrytych wierszy. Następnie użyj, tableView.performBatchUpdates
aby wywołać animację, która działa konsekwentnie.
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)
}
Będziesz chciał się upewnić cellIsHidden
i indexPathOfHiddenCell
są ustawione odpowiednio do twojego przypadku użycia. Dla mojego kodu są to właściwości mojego kontrolera widoku tabeli.
Bez względu na metodę kontrolującą widoczność (prawdopodobnie działanie przycisku lub didSelectRow
), przełącz stan cellIsHidden wewnątrz performBatchUpdates
bloku:
tableView.performBatchUpdates({
// Use self to capture for block
self.cellIsHidden = !self.cellIsHidden
}, completion: nil)
Apple zaleca performBatchUpdates
ponad beginUpdates
/endUpdates
kiedy tylko jest to możliwe.
Znalazłem rozwiązanie do animacji ukrywania komórek w statycznej tabeli.
// 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
Potrzebny jest tylko jeden dodatkowy słownik:
@interface MyTableViewController ()
@property (nonatomic) NSMutableDictionary * hidableCellsDict;
@property (weak, nonatomic) IBOutlet UISwitch * birthdaySwitch;
@end
I spójrz na implementację MyTableViewController. Potrzebujemy dwóch metod, aby przekonwertować indexPath między widocznymi i niewidocznymi indeksami ...
- (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];
}
Jedna IBAction w sprawie zmiany wartości UISwitch:
- (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];
}
Niektóre metody UITableViewDataSource i UITableViewDelegate:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
int numberOfRows = [super tableView:tableView numberOfRowsInSection:section];
for (NSIndexPath * indexPath in [self.hidableCellsDict allKeys])
if (indexPath.section == section)
{
BlockExecutor * executor = [self.hidableCellsDict objectForKey:indexPath];
numberOfRows -= (executor.block()?0:1);
}
return numberOfRows;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
indexPath = [self recoverIndexPath:indexPath];
return [super tableView:tableView cellForRowAtIndexPath:indexPath];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
indexPath = [self recoverIndexPath:indexPath];
return [super tableView:tableView heightForRowAtIndexPath:indexPath];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// initializing dictionary
self.hidableCellsDict = [NSMutableDictionary dictionary];
[self.hidableCellsDict setObject:[BlockExecutor executorWithBlock:^(){return self.birthdaySwitch.on;}] forKey:[NSIndexPath indexPathForRow:1 inSection:1]];
}
- (void)viewDidUnload
{
[self setBirthdaySwitch:nil];
[super viewDidUnload];
}
@end
Odpowiedz szybko :
Dodaj następującą metodę w TableViewController:
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return indexPathOfCellYouWantToHide == indexPath ? 0 : super.tableView(tableView, heightForRowAtIndexPath: indexPath)
}
jeśli tableView spróbuje narysować komórkę, którą chcesz ukryć, nie wyświetli jej, ponieważ jej wysokość zostanie ustawiona na 0pt dzięki powyższej metodzie, wszystko inne pozostaje niezmienione.
Należy pamiętać, że indexPathOfCellYouWantToHide
można to zmienić w dowolnym momencie :)
W> Swift 2.2 połączyłem tutaj kilka odpowiedzi.
Zrób gniazdko ze scenorysu, aby połączyć się z staticCell.
@IBOutlet weak var updateStaticCell: UITableViewCell!
override func viewDidLoad() {
...
updateStaticCell.hidden = true
}
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
if indexPath.row == 0 {
return 0
} else {
return super.tableView(tableView, heightForRowAtIndexPath: indexPath)
}
}
Chcę ukryć moją pierwszą komórkę, więc ustawiłem wysokość na 0, jak opisano powyżej.
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
}
Aby uzyskać najłatwiejszy scenariusz, gdy ukryjesz komórki na samym dole widoku tabeli, możesz dostosować contentInset tableView po ukryciu komórki:
- (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);
}
To nowy sposób na zrobienie tego za pomocą https://github.com/k06a/ABStaticTableViewController
NSIndexPath *ip = [NSIndexPath indexPathForRow:1 section:1];
[self deleteRowsAtIndexPaths:@[ip] withRowAnimation:UITableViewRowAnimationFade]
Rozwiązanie z k06a ( https://github.com/k06a/ABStaticTableViewController ) jest lepsze, ponieważ ukrywa całą sekcję, w tym nagłówki i stopki komórek, gdzie to rozwiązanie ( https://github.com/peterpaulis/StaticDataTableViewController ) ukrywa wszystko oprócz stopki.
EDYTOWAĆ
Właśnie znalazłem rozwiązanie, jeśli chcesz ukryć stopkę StaticDataTableViewController
. Oto, co musisz skopiować w pliku StaticTableViewController.m:
- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section {
if ([tableView.dataSource tableView:tableView numberOfRowsInSection:section] == 0) {
return nil;
} else {
return [super tableView:tableView titleForFooterInSection:section];
}
}
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
CGFloat height = [super tableView:tableView heightForFooterInSection:section];
if (self.originalTable == nil) {
return height;
}
if (!self.hideSectionsWithHiddenRows) {
return height;
}
OriginalSection * os = self.originalTable.sections[section];
if ([os numberOfVissibleRows] == 0) {
//return 0;
return CGFLOAT_MIN;
} else {
return height;
}
//return 0;
return CGFLOAT_MIN;
}
Na pewno możesz. Najpierw wróć do swojej tabeli, wyświetl liczbę komórek, które chcesz wyświetlić, a następnie wywołaj, super
aby uzyskać określoną komórkę ze swojego storyboardu i zwróć ją dla tableView:
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.mode.numberOfCells()
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = super.tableView(tableView, cellForRowAtIndexPath: self.mode.indexPathForIndexPath(indexPath))
return cell
}
Jeśli twoje komórki mają inną wysokość, zwróć ją również:
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return super.tableView(tableView, heightForRowAtIndexPath: self.mode.indexPathForIndexPath(indexPath))
}
Oprócz rozwiązania @Saleh Masum:
Jeśli wystąpią błędy automatycznego układu , możesz po prostu usunąć ograniczenia z plikutableViewCell.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)
}
}
To rozwiązanie zależy od przepływu Twojej aplikacji . Jeśli chcesz pokazać / ukryć komórkę w tej samej instancji kontrolera widoku, może to nie być najlepszy wybór, ponieważ usuwa ograniczenia .
Mam lepszy sposób na dynamiczne ukrywanie statycznych komórek, a nawet sekcji, bez żadnych hacków.
Ustawienie wysokości wiersza na 0 może ukryć wiersz, ale to nie działa, jeśli chcesz ukryć całą sekcję, która będzie zawierać spacje, nawet jeśli ukryjesz wszystkie wiersze.
Moje podejście polega na zbudowaniu tablicy sekcji komórek statycznych. Następnie zawartość widoku tabeli będzie sterowana przez tablicę sekcji.
Oto przykładowy kod:
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]
}
W ten sposób możesz złożyć cały kod konfiguracji bez konieczności pisania nieprzyjemnego kodu do obliczania liczby wierszy i sekcji. I oczywiście nie ma 0
już wysokości.
Ten kod jest również bardzo łatwy w utrzymaniu. Na przykład, jeśli chcesz dodać / usunąć więcej komórek lub sekcji.
Podobnie, możesz utworzyć tablicę tytułów nagłówków sekcji i tablicę tytułów stopek sekcji, aby dynamicznie skonfigurować tytuły sekcji.