2010-04-01 7 views
6

Mam kontroler widoku tabeli z wieloma kontrolkami UISwitch w nich. Ustawiam delegata na kontroler widoku tabeli z tą samą akcją dla wszystkich przełączników. Muszę być w stanie określić, który przełącznik został zmieniony, więc tworzę tablicę łańcuchów, która zawiera nazwę każdego przełącznika. Indeksy w tablicy zostaną umieszczone we właściwościach tagu każdego przełącznika UIS.Obsługa wielu elementów sterujących UISwitch w widoku tabeli bez użycia właściwości znacznika

Jednak jestem gotowy, używając właściwości znacznika do czegoś innego, mianowicie do znalezienia właściwej kontroli w komórce w komórceForRowAtIndexPath z viewWithTag! (Jest kilka rzeczy, które muszę ustawić w każdej komórce.)

Tak więc, czy myślę tu o właściwych liniach? Czuję, że jestem raczej ograniczony w tym, jak dokładnie wiem, który UISwitch zmienił jego wartość, więc mogę zrobić z nim coś pożytecznego.

Odpowiedz

5

naprawiłem to przez instacji UISwitch tak:

@interface NamedUISwitch : UISwitch { 
NSString *name; 

}

Wydaje elegancki (wymagane żadne tablice indeksowe) i właściwość Tag to robić, co chce.

Czytałem, że trzeba być ostrożnym z podklasy w Objective-C, chociaż ...

+0

Po prostu zrobiłem to samo, moim jedynym komentarzem byłoby uczynić nazwę nieruchomością. – typemismatch

0

Jesteś blisko swojego podejścia. W podobnych sytuacjach stworzyłem oddzielne podklasy UITableViewCell, ustawiłem znacznik UISwitch na index.row ścieżki indeksu i używam tylko tej podklasy UITableViewCell w określonej sekcji widoku tabeli. Dzięki temu możesz użyć znacznika komórki, aby jednoznacznie określić, która komórka ma wydarzenie bez utrzymywania osobnej listy indeksu (jak to brzmi, jakbyś robił).

Ponieważ typ komórki jest unikalny, można łatwiej uzyskać dostęp do innych elementów komórki, tworząc metody/właściwości w podklasie UITableViewCell.

Na przykład:

@interface TableViewToggleCell : UITableViewCell { 
    IBOutlet UILabel *toggleNameLabel; 
    IBOutlet UILabel *detailedTextLabel; 
    IBOutlet UISwitch *toggle; 
    NSNumber *value; 
    id owner; 
} 

@property (nonatomic, retain) UILabel *toggleNameLabel; 
@property (nonatomic, retain) UILabel *detailedTextLabel; 
@property (nonatomic, retain) UISwitch *toggle; 
@property (nonatomic, retain) id owner; 

-(void) setLable:(NSString*)aString; 
-(void) setValue:(NSNumber*)aNum; 
-(NSNumber*)value; 
-(void) setTagOnToggle:(NSInteger)aTag; 

-(IBAction)toggleValue:(id)sender; 

@end 

w:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    // ... prior iniitalization code for creating cell is assumed 
toggleCell.owner = self; 
[toggleCell setLable:@"some string value"]; 
[toggleCell setTagOnToggle:indexPath.row]; 
toggleCell.owner = self; 
return toggleCell; 
    //... handle cell set up for other cell types as needed 
} 

Właściciel jest delegatem na komórki i mogą być następnie wykorzystane do wszczęcia działań w kontrolerze. Upewnij się, że podłączenie UISwitch do działania toggleValue, tak aby można było inicjować działania w delegata gdy UISwitch zmienia stan:

-(IBAction)toggleValue:(id)sender; 
{ 
    BOOL oldValue = [value boolValue]; 
    [value release]; 
    value = [[NSNumber numberWithBool:!oldValue] retain]; 
    [owner performSelector:@selector(someAction:) withObject:toggle]; 
} 

Przekazując UISwitch z wywołania metody, można wtedy uzyskać dostęp do ścieżki indeksu komórka. Można również ominąć użycie właściwości znacznika, jawnie posiadając element ivar do przechowywania NSIndexPath komórki, a następnie przekazując całą komórkę za pomocą wywołania metody.

+0

Jak o podklasowaniu UISwitcha i dodaniu do niego identyfikatora? Czy to byłby zły projekt? – Thaurin

+0

Hmmm, jeden problem z twoim podejściem polega na tym, że nie używam IB, więc dodaję wszystkie kontrolki do contentView w komórce. Następnie, gdy potrzebuję ich ponownie w sterowniku tabeli, aby ustawić ich wartości dla pokazanego wiersza, otrzymuję je z powrotem za pomocą viewWithTag. To problem, ponieważ używam już tagu do identyfikacji zmiany przełącznika. Za pomocą NIB wystarczy podłączyć kilka gniazdek. Czy tęskniłem za czymś istotnym tutaj? Spróbuję teraz podklasować UISwitch, chociaż nie jestem pewien, czy UISwitch został zbudowany tak, aby kiedykolwiek został zklasyfikowany. – Thaurin

+0

Polecam nurkowanie w IB i podklasy całego UITableViewCell, a nie tylko UISwitch. Będzie to (jak sądzę) skutkować większym możliwym do utrzymania kodem na dłuższą metę. Ponadto, gdy utworzysz jedną podklasę za pomocą IB/XCode, naprawdę stanie się to bardzo proste. –

1

Pisałem podklasę UISwitch z zakrętu bloku sterowania opartego na zdarzeniach zmiany wartości, które mogą pomóc, gdy próbuje śledzić która wartość przełącznika uległa zmianie. Idealnie byłoby, gdybyśmy zrobili coś podobnego, jak kompozycja, a nie podklasy, ale to działa dobrze na moje potrzeby.

https://gist.github.com/3958325

Można go używać tak:

ZUISwitch *mySwitch = [ZUISwitch alloc] init]; 

[mySwitch onValueChange:^(UISwitch *uiSwitch) { 
     if (uiSwitch.on) { 
      // do something 
     } else { 
      // do something else 
     } 
    }]; 

Można również używać go z pliku XIB, przeciągając przełącznik na widoku, a następnie zmieniając jego klasę ZUISwitch

+0

To jest świetne podejście, szczególnie w przypadku iterowania nad nieznaną liczbą przełączników. Ciekawi mnie, dlaczego robisz '[self commonInit]' w awakeFromNib, a także init. –

0

Zdaję sobie sprawę, że jestem spóźniony o trzy lata, ale opracowałem rozwiązanie bez podklasy, która moim zdaniem jest lepsza (i prostsza). Pracuję w dokładnie tym samym scenariuszu, co opisywany przez Thaurina scenariusz.

- (void)toggleSwitch:(id) sender 
{ 
    // declare the switch by its type based on the sender element 
    UISwitch *switchIsPressed = (UISwitch *)sender; 
    // get the indexPath of the cell containing the switch 
    NSIndexPath *indexPath = [self indexPathForCellContainingView:switchIsPressed]; 
    // look up the value of the item that is referenced by the switch - this 
    // is from my datasource for the table view 
    NSString *elementId = [dataSourceArray objectAtIndex:indexPath.row]; 
} 

Następnie należy zadeklarować metodę pokazaną powyżej, indexPathForCellContainingView. Jest to metoda pozornie niepotrzebny, ponieważ wydaje się na pierwszy rzut oka, że ​​wszystko, co musisz zrobić, to określić Superview przełącznika, ale istnieje różnica między superviews z ios7 i wcześniejszych wersji, więc ten obsługuje wszystkie:

- (NSIndexPath *)indexPathForCellContainingView:(UIView *)view { 
    while (view != nil) { 
     if ([view isKindOfClass:[UITableViewCell class]]) { 
      return [self.myTableView indexPathForCell:(UITableViewCell *)view]; 
     } else { 
      view = [view superview]; 
     } 
    } 
    return nil; 
} 
Powiązane problemy