Problem mit eigener UITableViewCell

  • Problem mit eigener UITableViewCell

    Hallo,

    ich hätte keine Pause mit Objective C machen sollen. Aber Abschlussprüfung geht nunmal vor...

    Ich verzweifel gerade an folgendem:

    Ich habe eine TableView indem ich die Cells selber gestalte.

    Dazu möchte ich jeder Cell einen Button in der Größe der Cell (höhe -1) hinzufügen.
    Auf den Button möchte ich oben Links angefangen ein Label einfügen.

    Das Funtkioniert auch wunderbar.
    Aber sobald ich einmal nach Unten gescrollt habe hat der mir der Unterste Objekt ganz Oben reingeschrieben und hat scheinbar versetzt alle Cells nochmal neu gezeichnet.


    Desweiterne bekomme ich kein Event mehr auf die Cell.

    Woran kann das liegen.

    Hier noch mein Code für die eigene Cell:


    Quellcode

    1. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    2. {
    3. static NSString *CellIdentifier = @"Cell";
    4. UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    5. if (cell == nil) {
    6. cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
    7. }
    8. // Configure the cell...
    9. UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
    10. [[button layer]setCornerRadius:12.0f];
    11. [[button layer]setMasksToBounds:YES];
    12. button.frame = CGRectMake(cell.frame.origin.x, cell.frame.origin.y, cell.frame.size.width, [[self.localroom.DateList objectAtIndex:indexPath.row]factor] * 2 -1);
    13. button.backgroundColor = [UIColor colorWithRed:(227.0/255.0) green:(0.0/255.0) blue:(74.0/225.0) alpha:1.0];
    14. UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(5.0, 5.0, 300.0, 50.0)];
    15. label.text = [[self.localroom.DateList objectAtIndex:indexPath.row] title];
    16. label.text = [label.text stringByAppendingString:@"\n"];
    17. label.text = [label.text stringByAppendingString:[[self.localroom.DateList objectAtIndex:indexPath.row]time]];
    18. label.backgroundColor = [UIColor colorWithRed:(227.0/255.0) green:(0.0/255.0) blue:(74.0/225.0) alpha:1.0];
    19. [button addSubview:label];
    20. [label release];
    21. [cell addSubview:button];
    22. //Wenn ich den Button hier freigebe habe ich den später keinen Text in der Cell.
    23. //Noch nee Lösung ausarbeiten...
    24. //[button release];
    25. return cell;
    26. }
    Alles anzeigen


    Danke und Gruß
    Andreas
  • And-Wolf schrieb:

    Hallo,

    ich hätte keine Pause mit Objective C machen sollen. Aber Abschlussprüfung geht nunmal vor...

    Ich verzweifel gerade an folgendem:

    Ich habe eine TableView indem ich die Cells selber gestalte.

    Dazu möchte ich jeder Cell einen Button in der Größe der Cell (höhe -1) hinzufügen.
    Auf den Button möchte ich oben Links angefangen ein Label einfügen.

    Das Funtkioniert auch wunderbar.
    Aber sobald ich einmal nach Unten gescrollt habe hat der mir der Unterste Objekt ganz Oben reingeschrieben und hat scheinbar versetzt alle Cells nochmal neu gezeichnet.


    Desweiterne bekomme ich kein Event mehr auf die Cell.

    Woran kann das liegen.

    Hier noch mein Code für die eigene Cell:


    Quellcode

    1. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    2. {
    3. static NSString *CellIdentifier = @"Cell";
    4. UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    5. if (cell == nil) {
    6. cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
    7. }
    8. // Configure the cell...
    9. UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
    10. [[button layer]setCornerRadius:12.0f];
    11. [[button layer]setMasksToBounds:YES];
    12. button.frame = CGRectMake(cell.frame.origin.x, cell.frame.origin.y, cell.frame.size.width, [[self.localroom.DateList objectAtIndex:indexPath.row]factor] * 2 -1);
    13. button.backgroundColor = [UIColor colorWithRed:(227.0/255.0) green:(0.0/255.0) blue:(74.0/225.0) alpha:1.0];
    14. UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(5.0, 5.0, 300.0, 50.0)];
    15. label.text = [[self.localroom.DateList objectAtIndex:indexPath.row] title];
    16. label.text = [label.text stringByAppendingString:@"\n"];
    17. label.text = [label.text stringByAppendingString:[[self.localroom.DateList objectAtIndex:indexPath.row]time]];
    18. label.backgroundColor = [UIColor colorWithRed:(227.0/255.0) green:(0.0/255.0) blue:(74.0/225.0) alpha:1.0];
    19. [button addSubview:label];
    20. [label release];
    21. [cell addSubview:button];
    22. //Wenn ich den Button hier freigebe habe ich den später keinen Text in der Cell.
    23. //Noch nee Lösung ausarbeiten...
    24. //[button release];
    25. return cell;
    26. }
    Alles anzeigen


    Danke und Gruß
    Andreas


    Implementier mal:

    Quellcode

    1. - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
    I would be embarrassed if they did not spy on me.
  • Habe ich mit drin.
    Sieht so aus:

    Quellcode

    1. - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    2. return [[self.localroom.DateList objectAtIndex:indexPath.row]factor] * 2;
    3. }



    Aber hat doch nichts mit meinem Problem zu tun.
    Oder sehe ich das falsch?
  • AR.DDev schrieb:

    Verschiebe mal das alles in
    if (cell == nil)

    Daran liegt es. Wenn eine Zelle wiederverwendet wird, fügst Du ihr erneut einen Button und ein Label hinzu, obwohl sie die bereits besitzt. Du solltest außerdem Tags verwenden, um dieses Views wiederzufinden. Also z. B.

    Quellcode

    1. UILabel *label ;
    2. ...
    3. if(cell == nil) {
    4. ...
    5. label = [[UILabel alloc] initWithFrame:...];
    6. label = 100;
    7. [cell.contentView addSubview:label];
    8. [label autorelease];
    9. }
    10. else {
    11. label = (UILabel *)[cell.contentView viewWithTag:100];
    12. }
    13. label.text = ...;
    Alles anzeigen

    Außerdem solltest Du alle Subviews der Zelle zu deren Content-View hinzufügen.
    „Meine Komplikation hatte eine Komplikation.“
  • Hallo,

    danke für die schnellen Antworten :)

    Das mit den Tags verstehe ich noch nicht ganz.

    Muss jedes Tag das ich irgendwie irgendwann mal erzeuge eine eindeutige ID haben?

    Muss ich in dem else Zweig der nil anweisung alles nochmal bauen nur mit den schon erzeugten Tags?


    Gruß
    Andreas
  • Eben nicht, sonst werden der Zelle bei jedem Scrollen X Label hinzugefügt.
    Was du aber im Else-Zweig setzen solltest wäre der Text. Um dann dort (und ggf. auch an anderer Stelle) an das Label zu kommen verwendest du Tags. Am Besten die Zeilennummer.
    Im Prinzip was macmoonshine schon gesagt hat:

    Quellcode

    1. if (cell == nil) {
    2. [label setTag:[indexPath row]];
    3. } else {
    4. label = (UILabel *)[[cell contentView] viewWithTag:[indexPath row]];
    5. }

    Ein Tag muss einen Integer-Wert haben.
  • AR.DDev schrieb:

    Eben nicht, sonst werden der Zelle bei jedem Scrollen X Label hinzugefügt.
    Was du aber im Else-Zweig setzen solltest wäre der Text. Um dann dort (und ggf. auch an anderer Stelle) an das Label zu kommen verwendest du Tags. Am Besten die Zeilennummer.
    Im Prinzip was macmoonshine schon gesagt hat:

    Quellcode

    1. if (cell == nil) {
    2. [label setTag:[indexPath row]];
    3. } else {
    4. label = (UILabel *)[[cell contentView] viewWithTag:[indexPath row]];
    5. }

    Ein Tag muss einen Integer-Wert haben.


    @macmoonshine hat es schon angedeutet: [label setTag:[indexPath row]+100]; denn Tag=0 haben alle Elemente, kann Probleme machen !
  • ramo schrieb:

    AR.DDev schrieb:

    Eben nicht, sonst werden der Zelle bei jedem Scrollen X Label hinzugefügt.
    Was du aber im Else-Zweig setzen solltest wäre der Text. Um dann dort (und ggf. auch an anderer Stelle) an das Label zu kommen verwendest du Tags. Am Besten die Zeilennummer.
    Im Prinzip was macmoonshine schon gesagt hat:

    Quellcode

    1. if (cell == nil) {
    2. [label setTag:[indexPath row]];
    3. } else {
    4. label = (UILabel *)[[cell contentView] viewWithTag: [indexPath row]];
    5. }

    Ein Tag muss einen Integer-Wert haben.


    @macmoonshine hat es schon angedeutet: [label setTag:[indexPath row]+100]; denn Tag=0 haben alle Elemente, kann Probleme machen !


    Ganz verstehe ich nicht, warum ihr dem Anhängsel noch den Index zuordnet, ob mit oder ohne konstantem Wert spielt keine Rolle.

    Weil eine Sammlung von Views immer mal wieder durchforstet werden muss, sind 'tags' eingeführt worden.
    Ein"tag" dient zum Identifizieren innerhalb der Hierarchie, und weil eine Zelle
    ('cell' oder Zelle, aber nicht Celle, das ist eine Stadt und ein Kreis in Niedersachsen)
    eine ebensolche Hierarchie besitzt, benutzt man das denn ebenso.
    Dafür hat jede besondere Art, beispielsweise eine Text, eine bestimmte Konstante als 'tag',
    die man dann ruckzuck mit einer speziellen Methode wieder finden kann:

    Aus der Doku:
    viewWithTag:
    Returns the view whose tag property contains the specified integer value.

    - (UIView *)viewWithTag: (NSInteger)tag
    Parameters
    tag
    The tag value to search for.
    Return Value
    The view in the receiver’s hierarchy whose tag property matches the value in the tag parameter.

    Discussion
    This method searches the current view and all of its subviews for the specified view.


    Man kann das natürlich so machen, vieles geht. Das läuft dann aber diametral zum Konzept der Datenquelle und der Delegation.
    I would be embarrassed if they did not spy on me.
  • Tags werden bei TableView-Zellen meistens für zwei Anwendungsfälle eingesetzt:
    1. Über das Tag lassen sich bestimmte Subviews über die Methode viewWithTag: wiederfinden. Hierbei muss der Tagwert konstant gewählt werden und am besten ungleich 0. Das ist mein Beispiel oben.
    2. Mit dem Tag lässt sich die Zeilennummer in Action-Methoden für Buttons o. Ä. rekonstruieren. Dabei bekommt der Tag des Button (bzw. Controls) die Zeilennummer der Zelle (von mir aus auch plus 100 ;-). Das ist das Beispiel von ramo.

    Was aber wichtig ist: Beides auf einmal geht nicht. Wenn der Tagwert variabel ist, kann ich viewWithTag: in tableView:cellForRowAtIndexPath: nicht dazu verwenden, den Button zu finden. Und wenn der Tagwert bei allen Buttons gleich ist, kann ich damit nicht die Zeilennummer ermitteln.

    Glücklicherweise lassen sich aber beide Anwendungsfälle auch noch über andere Wege lösen ;)
    „Meine Komplikation hatte eine Komplikation.“
  • Hallo,

    die Beschriftung passt nun und gerät nicht durcheinander.
    Aber bei einem Scrollen passen nicht mehr die größen der cells.

    Irgendwie kommt da alles durcheinander.
    Die eine Cell wird über die andere gezeichnet.

    Oder der Button den ich hinzufügen füllt nicht die cell aus.

    Hier mein aktueller Code.
    Evtl. könnt ihr mir ja nochmal helfen:

    Quellcode

    1. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    2. {
    3. static NSString *CellIdentifier = @"Cell";
    4. UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    5. UITextView *label;
    6. UIButton *button;
    7. if (cell == nil)
    8. {
    9. cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
    10. button = [UIButton buttonWithType:UIButtonTypeCustom];
    11. [[button layer]setCornerRadius:12.0f];
    12. [[button layer]setMasksToBounds:YES];
    13. button.frame = CGRectMake(cell.frame.origin.x +1, cell.frame.origin.y +1, cell.frame.size.width - 2, ([[self.localroom.DateList objectAtIndex:indexPath.row]factor] *2) -2);
    14. button.backgroundColor = [UIColor colorWithRed:(227.0/255.0) green:(0.0/255.0) blue:(74.0/225.0) alpha:1.0];
    15. label = [[UITextView alloc]initWithFrame:CGRectMake(5.0, 5.0, button.frame.size.width, button.frame.size.height)];
    16. label.backgroundColor = [UIColor colorWithRed:(227.0/255.0) green:(0.0/255.0) blue:(74.0/225.0) alpha:1.0];
    17. label.scrollEnabled = NO;
    18. label.editable = NO;
    19. label.userInteractionEnabled = YES;
    20. label.tag = 100;
    21. }
    22. else
    23. {
    24. label = (UITextView*)[cell.contentView viewWithTag:100];
    25. button = (UIButton*)[cell.contentView viewWithTag:200];
    26. }
    27. label.text = [[self.localroom.DateList objectAtIndex:indexPath.row]title];
    28. label.text = [label.text stringByAppendingString:@"\n"];
    29. label.text = [label.text stringByAppendingString:[[self.localroom.DateList objectAtIndex:indexPath.row]time]];
    30. label.text = [label.text stringByReplacingOccurrencesOfString:@"oe" withString:@"ö"];
    31. label.text = [label.text stringByReplacingOccurrencesOfString:@"ae" withString:@"ä"];
    32. [button addSubview:label];
    33. [cell.contentView addSubview:button];
    34. cell.contentView.userInteractionEnabled = NO;
    35. return cell;
    36. }
    37. - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    38. return ([[self.localroom.DateList objectAtIndex:indexPath.row]factor] *2);
    39. }
    Alles anzeigen



    Danke & Gruß
    Andreas
  • Hallo,

    habe ich mit drin.
    Nun wird es schonmal nichtmehr durcheinander geschmissen.
    Aber es wird an einigen Stellen immernoch eine Cell über die andere gezeichnet und zu klein gezeichnet.

    habt ihr da noch eine Idee?


    Ich denke das er vorher immer die alte View wieder übermalt hat und deswegen alles wirsch aussah?

    Ja ich bin mir sicher.
    Werde mir aber die Stringverarbeitung nochmal anschauen.

    danke :)