TableViewCell Sections

  • TableViewCell Sections

    Hallo erstmal, ich bin neuling in diesem forum und habe auch gleich schon eine frage. Mein vorhaben: Ich habe ein Textfield und gebe dort einen int wert ein Z.b. 5... Ist es möglich dass mir daraus 5 grouped cell sections erstellt werden mit jeweils 3 rows?
  • Gibbson schrieb:

    Hallo erstmal, ich bin neuling in diesem forum und habe auch gleich schon eine frage.

    Mein vorhaben:
    Ich habe ein Textfield und gebe dort einen int wert ein Z.b. 5... Ist es möglich dass mir daraus 5 grouped cell sections erstellt werden mit jeweils 3 rows?


    Klar, musst die Datasource der TableView anpassen, nachdem der Wert eingetragen wurde und die TableView reloaden
  • Hallo, danke erstmal!

    ich habe es geschafft dass mir soviele sections angezeigt werden wie ich vorher in einem anderen viewcontroller angegeben habe.

    ich schaffe es aber nicht, dass je section die cell atindex:0 durch cell atindex:1 geteilt wird.

    der code ist folgender:

    Quellcode

    1. #import "ViewController.h"
    2. @interface ViewController ()
    3. {
    4. NSMutableArray *sectionsArray;
    5. NSMutableArray *rowsInSectionsArray;
    6. }
    7. @end
    8. @implementation ViewController
    9. - (void)viewDidLoad
    10. {
    11. [super viewDidLoad];
    12. // Do any additional setup after loading the view, typically from a nib.
    13. [[self myTableView]setDelegate:self];
    14. [[self myTableView]setDataSource:self];
    15. sectionsArray = [[NSMutableArray alloc]init];
    16. rowsInSectionsArray = [[NSMutableArray alloc]init];
    17. }
    18. - (void)didReceiveMemoryWarning
    19. {
    20. [super didReceiveMemoryWarning];
    21. // Dispose of any resources that can be recreated.
    22. }
    23. - (IBAction)addSectionButton:(id)sender {
    24. [sectionsArray addObject:[NSString stringWithFormat:@"Palette %d",sectionsArray.count+1]];
    25. [[self myTableView]reloadData];
    26. }
    27. - (IBAction)rechneButton:(id)sender {
    28. }
    29. #pragma datasource tableview methods
    30. -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
    31. {
    32. int anzahl = [_AnzahlStationen intValue];//aus dem text wird ein int gemacht
    33. //fügt soviele sections ein wie vorher eingegeben
    34. if ([sectionsArray count] < anzahl) {
    35. [sectionsArray addObject:[NSString stringWithFormat:@"Palette %d",sectionsArray.count+1]];
    36. [[self myTableView]reloadData];//tableview wird aktualisiert
    37. }
    38. return sectionsArray.count;
    39. /*if (sectionsArray.count == 0) {
    40. [sectionsArray addObject:[NSString stringWithFormat:@"Palette %d",sectionsArray.count+1]];
    41. }
    42. return sectionsArray.count;
    43. */
    44. }
    45. -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    46. {
    47. return 3;
    48. }
    49. -(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
    50. {
    51. return [sectionsArray objectAtIndex:section];
    52. }
    53. -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    54. {
    55. static NSString *CellIdentifier = @"Cell";
    56. UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    57. if(!cell)
    58. {
    59. cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
    60. cell.selectionStyle = UITableViewCellSelectionStyleNone;
    61. //Textfelder innerhalb der cells
    62. UITextField *textfelder = [[UITextField alloc] initWithFrame:CGRectMake(15, 10, 185, 30)];
    63. [textfelder setFont:[UIFont fontWithName:@"Gujarati Sangam MN" size:14]];
    64. [textfelder setTextColor:[UIColor blueColor]];
    65. [[cell contentView] addSubview:textfelder];
    66. if ([indexPath row] == 0) {
    67. textfelder.placeholder = @"Bogen auf Palette";
    68. }
    69. if ([indexPath row] == 1) {
    70. textfelder.placeholder = @"Stangen auf Palette";
    71. }
    72. if ([indexPath row] == 2) {
    73. textfelder.placeholder = @"...oder Bogen auf Stange";
    74. }
    75. }
    76. return cell;
    77. }
    78. @end
    Alles anzeigen
  • Hmm. Ich würde in meiner Klasse vielleicht das UITextFieldDelegate Protokoll implementieren und self als den delegate an den Textfeldern setzen. Zum Unterscheiden kannst Du ja Tags an die Textfelder setzen, damit Du weißt, welches Feld gerade einen neuen Wert bekommen hat.

    Beim Berechnen greifst Du dann nicht auf die Textfelder zu, sondern auf die lokal gespeicherten Daten (die Du Dir beim Aufruf der TextFieldDelegate Methode gemerkt hast).

    Denke immer dran, dass TabelViewCells neu genutzt werden. Also wenn Du einen Teil der TableView aus dem Bildschirm scrollst, sind die Textfelder weg und werden neu genutzt. Das kann auch jetzt schon passieren, wenn Du im ersten Feld mal etwas einträgst und dann die Tabelle soweit hoch scrollst, dass das Textfeld verschwindet. Wenn es wieder kommt, kann es sein, dass der Wert, den Du vorher eingegeben hast, wieder weg ist oder irgendeiner alten Eingabe entspricht.

    Deswegen hat man zur reinen Repräsentation in der TableView immer noch ein Datenmodel im Hintergrund, dass die eigentlichen Objekte (bei Dir die Zahlen) speichert. Du könntest dafür ja ein Array mit Arrays von Zahlen nehmen.

    Oder so ähnlich.
  • Ach, und bei [UITableView reloadData] innerhalb einer TableViewDataSource Methode zucke ich intuitiv zusammen. Ich glaube das ist keine gute Idee. Offenbar funktioniert das ja, ich hätte da aber Angst vor einer möglichen Endlosschleife.

    Berechnungen zur Anzahl der Sektionen solltest Du außerhalb der TableViewDataSource Methoden machen. Zum Beispiel in viewWillAppear.
  • Dann fang doch erstmal einfacher an: nur eine Sektion, eine Zelle und darin ein Textfield.

    Dann nimmst Du eine Membervariable in Deinen ViewController hinzu, die den Wert im Textfeld repräsentiert (später macht man sich dann eigene Model-Klassen für sowas).

    Im tableView:cellForRowAtIndexPath: weist Du dem Textfeld den Wert Deiner Membervariablen zu.

    Im textFieldDidEndEditing: liest Du den vom Benutzer eingegebenen Wert aus und merkst ihn Dir wieder in Deiner Membervariable (Deinem "Model für Arme"). ;)

    Im rechneButton:sender: greifst Du dann gar nicht auf die TableViewCell oder das Textfield zu, sondern rechnest einfach mit Deiner Membervariablen. Als allererstes schreibst Du da nur NSLog(@"%@", Membervariable); rein, um zu kontrollieren dass die ganze Kette funktioniert.

    Danach nimmst Du dann mehrere Textfelder in die eine Sektion - dabei musst Du Dir überlegen, wie Du die Textfelder voneinander unterscheidest. Da gibt es mehrere Varianten, aber soweit bist Du ja noch nicht. Erstmal ein Textfeld. Und jetzt los! ;)
  • Ich habe mir Deinen Rat zu Herzen genommen und habe erstmal nur eine section mit einer row erstellt.
    Jetzt weiss ich nicht wie ich das Textfield erstelle, ohne dass es beim (aus dem bild scrollen) die Daten durcheinander wirft.

    Quellcode

    1. #import "ViewController.h"
    2. @interface ViewController ()
    3. {
    4. NSMutableArray *sectionsArray;
    5. }
    6. @end
    7. @implementation ViewController
    8. - (void)viewDidLoad
    9. {
    10. [super viewDidLoad];
    11. [[self meinTableView]setDelegate:self];
    12. [[self meinTableView]setDataSource:self];
    13. sectionsArray = [[NSMutableArray alloc]init];
    14. }
    15. - (void)didReceiveMemoryWarning
    16. {
    17. [super didReceiveMemoryWarning];
    18. // Dispose of any resources that can be recreated.
    19. }
    20. - (IBAction)erstelleSectionsButton:(id)sender {
    21. }
    22. -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
    23. {
    24. do {
    25. [sectionsArray addObject:[NSString stringWithFormat:@"Palette %d",sectionsArray.count+1]];
    26. } while (sectionsArray.count < 1);
    27. return sectionsArray.count;
    28. }
    29. -(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
    30. {
    31. return [sectionsArray objectAtIndex:section];
    32. }
    33. -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    34. {
    35. return 1;
    36. }
    37. -(UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    38. {
    39. static NSString *CellIdentifier = @"Cell";
    40. UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    41. if(!cell)
    42. {
    43. cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
    44. cell.selectionStyle = UITableViewCellSelectionStyleNone;
    45. }
    46. return cell;
    47. }
    48. @end
    Alles anzeigen
  • Öhm. Ich sehe da gar kein UITextField im Code ...

    Aber wie gesagt: der "Trick" ist, dass Du eine extra Membervariable für den Inhalt des Textfeldes in dem ViewController hast.

    In cellForRowAtIndexPath bekommt die neue Zelle ein TextField und den Text des Feldes füllst Du mit dem Wert der Membervariablen. So steht dort immer das richtige drin.

    Hast Du denn schon etwas über textFieldDidEndEditing gelesen? Dort holst Du den vom Benutzer eingegebenen Wert wieder aus dem Textfeld heraus und frischst Deine Membervariable damit auf.
  • nun habe ich in der h datei die variable deklariert...

    Quellcode

    1. @property (strong, nonatomic) NSString *bogenAufPalette;


    das textfield habe ich eingefügt und es der variablen zugewiesen, hoffe dass es so richtig ist!?

    Quellcode

    1. -(UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    2. {
    3. static NSString *CellIdentifier = @"Cell";
    4. UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    5. if(!cell)
    6. {
    7. cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
    8. cell.selectionStyle = UITableViewCellSelectionStyleNone;
    9. UITextField *textfeld = [[UITextField alloc] initWithFrame:CGRectMake(15, 10, 185, 30)];
    10. [textfeld setFont:[UIFont fontWithName:@"Gujarati Sangam MN" size:14]];
    11. [textfeld setTextColor:[UIColor blueColor]];
    12. [[cell contentView] addSubview:textfeld];
    13. _bogenAufPalette = textfeld.text;
    14. }
    15. return cell;
    16. }
    Alles anzeigen
  • So in etwa würde ich das auch machen. Ich hab parallel mal schnell das hier gebaut:

    Quellcode

    1. @interface MasterViewController ()
    2. @property NSInteger value;
    3. @end
    4. @implementation MasterViewController
    5. - (void)viewDidLoad
    6. {
    7. [super viewDidLoad];
    8. self.value = 7;
    9. }
    10. - (void)viewWillAppear:(BOOL)animated
    11. {
    12. [super viewWillAppear:animated];
    13. [self.tableView reloadData];
    14. }
    15. #pragma mark - Table View
    16. - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
    17. {
    18. return 1;
    19. }
    20. - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    21. {
    22. return 1;
    23. }
    24. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    25. {
    26. UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];
    27. if (!cell) {
    28. cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"];
    29. UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(10, 10, 300, 24)];
    30. textField.autoresizingMask = UIViewAutoresizingFlexibleWidth;
    31. textField.tag = 17;
    32. [cell.contentView addSubview:textField];
    33. textField.delegate = self;
    34. }
    35. UITextField *textField = (UITextField *)[cell.contentView viewWithTag:17];
    36. textField.text = [NSString stringWithFormat:@"%d", self.value];
    37. return cell;
    38. }
    39. #pragma mark - UITextFieldDelegate
    40. - (BOOL)textFieldShouldReturn:(UITextField *)textField
    41. {
    42. [textField resignFirstResponder];
    43. return YES;
    44. }
    45. - (void)textFieldDidEndEditing:(UITextField *)textField
    46. {
    47. self.value = [textField.text integerValue];
    48. }
    49. @end
    Alles anzeigen


    Sicher hat jeder noch seine künstlerische Freiheit, aber Du siehst mal grundsätzlich das Konzept.
  • Sprachlos!!! Danke :D
    Werd mich gleich mal ran trauen und versuchen zu verstehen was dort passiert.


    ok, also es wird ein fehler angezeit und zwar bei:

    Quellcode

    1. textField.delegate = self;

    assigning to id UITextfielddelegate from incompatible type Viewcontroller *const_strong

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von Gibbson ()

  • Da liegt der Trick in der Header-Datei des ViewControllers:

    Quellcode

    1. @interface MasterViewController : UITableViewController<UITextFieldDelegate>


    Das Ding in den spitzen Klammern sagt: "Ja, also, ich hier, ich implementiere die Methoden dieses Protokolls" - und dann kann ein Objekt dieser Klasse überall genutzt werden, wo das Protokoll eben gesprochen wird. Zufällig verschwindet dann auch der Fehler (der eigentlich nur eine Warnung ist). ;)
  • Ok, also soweit habe ich das glaube ich verstanden. Die Variable value übernimmt jetzt den Wert des Textfeldes.

    Ich habe jetzt mehrere sections eingefügt mit je 4 rows und es wird logischerweise in jedem Textfeld immer der gleiche Wert angezeigt, nämlich der von value.
    Nachdem ich die ganze Woche herumprobiert habe es irgendwie durch "Nachforschung im Internet" hinzubekommen die Werte in ein NSMutableArray einzufügen und wieder herauszuholen...brauche ich wohl doch noch ewas Hilfe.
  • Ich möchte ja das valueArray nach dem editieren mit dem Text füllen...

    Quellcode

    1. - (void)textFieldDidEndEditing:(UITextField *)textField
    2. {
    3. self.value = [textField.text integerValue];
    4. [valueArray addObject:textField.text];
    5. [self.myTableView reloadData];
    6. }






    Das Problem ist nun aber dass ich erstmal ein leeres Array habe und der Simulator abstürzt, da ich ja hier sage dass das Textfeld seinen Text aus dem Array nehmen soll.

    Quellcode

    1. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    2. {
    3. UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];
    4. if (!cell) {
    5. cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"];
    6. UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(10, 10, 300, 24)];
    7. textField.autoresizingMask = UIViewAutoresizingFlexibleWidth;
    8. textField.tag = 17;
    9. [cell.contentView addSubview:textField];
    10. textField.delegate = self;
    11. }
    12. UITextField *textField = (UITextField *)[cell.contentView viewWithTag:17];
    13. textField.text = [valueArray objectAtIndex:indexPath.row];
    14. return cell;
    15. }
    Alles anzeigen




    Wenn ich folgendes versuche...

    Quellcode

    1. - (void)textFieldDidEndEditing:(UITextField *)textField
    2. {
    3. self.value = [textField.text integerValue];
    4. [rowsArray addObject:textField.text];
    5. [self.myTableView reloadData];
    6. }

    ...erstellt er mir zu den 4 rows eine weitere row samt eingegebenen Text.
  • Na dann sind wir ja schon an der entscheidenden Stelle angekommen: dem Datenmodell.

    Das Datenmodell gibt es immer, auch wenn der Benutzer noch nichts eingegeben hat. Das Datenmodell ist immer konsistent. Das heißt in Deinem Fall, dass Dein Datenmodell (also das MutableArray) schon gleich am Anfang vier Zahlen enthält. Wenn ein Leerzeichen in Deinem Datenmodell auch erlaubt ist, dann musst Du Zeichenketten speichern und nicht Zahlen und dann im Moment der Berechnung erst aus den Zeichenketten die Zahlen extrahieren.

    Also:
    1.) im viewDidLoad das Array mit vier ordentlichen Werten initialisieren
    2.) in cellForRowAtIndexPath den Wert aus dem Array holen (machst Du ja schon ordentlich)
    3.) in textFieldDidEndEditing
    3.a) erstmal heraus bekommen, welches Feld gerade editiert wurde
    3.b) den neuen Wert an die richtige Stelle des MutableArrays schreiben - und zwar nicht mit addObject (das hängt immer hinten an), sondern mit replaceObjectAtIndex:withObject: oder setObject:atIndexedSubscript: (Achtung! Die Methode gibt es erst ab iOS 6)

    Das Datenmodell repräsentiert "im Hintergrund" das, was der Benutzer "im Vordergrund" sieht. Ich würde z.B. in tableView:numberOfRowsInSection: gar nicht fest 4 zurück geben, sondern [rowsArray count] - das stimmt immer, selbst wenn Du danach einfach mal mit 5 oder 7 Werten testest. Nur rowsArray muss von Anfang an die richtige Zahl Elemente haben.


    Es gibt bestimmt auch noch andere Wege, jeder der sonst hier im Forum unterwegs ist, wird das irgendwie anders lösen. Aber programmieren ist ja auch kreative Arbeit. Ich hätte zu 3.a gerade gar keine so richtig schöne Lösung. Man könnte das Tag der TextViews immer um eins hoch zählen und dann wieder zurück rechnen. Aber das fühlt sich komisch an. So eine blitzsaubere Idee habe ich da noch gar nicht. Du siehst ... man lernt immer noch irgendwas ... :rolleyes: