UIView drawRect via setNeedsDisplay - geringe Framerate wenn zu viel Objekte gezeichnet werden müssen

  • UIView drawRect via setNeedsDisplay - geringe Framerate wenn zu viel Objekte gezeichnet werden müssen

    Hallo,

    ich habe wieder mal ein altes Problem und bekomme das einfach nicht gelöst. :S

    Ich habe eine UIView in der ich via drawRect() etwas zeichnen möchte. Hierbei wird eine Textur benötigt die hochauflösend ist. Idealerweise möchte ich die UIView - dessen Content - mehrmals in einer Sekunde zeichnen und nutze den Aufruf [self setNeedsDisplay].

    Also, angenommen ich möchte das Rectangle mehrmals in einer Sekunde neu zeichnen, dann dauert das ca. 0.5 Sekunden. In dieser Zeit ist es beispielsweise nicht möglich in der TableView zu scrollen.

    Es liegt definitiv am Aufruf [self setNeedsDisplay].

    Zu gerne würde ich das Zeichnen auf die GPU auslagern aber hierfür habe ich keinen Ansatz.


    Ich habe schon in einiger Literatur nachgeschlagen - finde aber keinerlei Ansätze.

    Bei meiner Lösung muss das Rectangle tatsächlich immer wieder neu gezeichnet werden - auch komplett. Das geht leider nicht anders, weil ich da mit einer Maske arbeite und die Textur bei jedem Frame um einen definierten Winkel gedreht und danach neu gezeichnet werden muss. Ein primitives Objekt erhält dann diese um ein paar Grad gedrehte Textur.



    Ich würde mich sehr freuen wenn Ihr mir ein paar Ratschläge oder konstruktive Ansätze geben könnt. Meine Lösung funktioniert zwar - aber absolut nicht zufriedenstellend.

    Recht herzlichen Dank im Voraus! :)
  • Mein Ansatz als Code

    macmoonshine schrieb:

    CABasicAnimation
    Hey ;)

    vielen Dank für deine Unterstützung!

    Ich veröffentliche mal meinen Code, damit du meinen Ansatz besser nachvollziehen kannst:

    PHP-Quellcode

    1. - (id)initWithFrame:(CGRect)frame
    2. {
    3. self = [super initWithFrame:frame];
    4. if (self) {
    5. // Initialization code
    6. self.opaque = YES;
    7. self.backgroundColor = [UIColor clearColor];
    8. [[NSNotificationCenter defaultCenter] addObserver:self
    9. selector:@selector(receiveNotification:)
    10. name:@"StartupRadian"
    11. object:nil];
    12. [self setNeedsDisplay];
    13. }
    14. return self;
    15. }
    16. - (void)receiveNotification:(NSNotification*)_notification;
    17. {
    18. if ([[_notification name] isEqualToString:@"StartupRadian"])
    19. {
    20. //NSLog(@"StartupRadian");
    21. radian = [(NSNumber*)_notification.object floatValue];
    22. [self setNeedsDisplay];
    23. }
    24. return;
    25. }
    26. - (void)drawRect:(CGRect)inRectangle;
    27. {
    28. CGContextRef theContext = UIGraphicsGetCurrentContext();
    29. CGContextSaveGState(theContext);
    30. [self drawMask:theContext];
    31. CGContextClip(theContext);
    32. [self draw:theContext];
    33. CGContextEOFillPath(theContext);
    34. CGContextRestoreGState(theContext);
    35. }
    36. - (void)drawMask:(CGContextRef)theContext;
    37. {
    38. float position = (320. - 287.) / 2.;
    39. CGRect theBounds = CGRectMake(position, position, 287., 287.);
    40. //CGContextSetStrokeColorWithColor (theContext, [[UIColor redColor] CGColor]);
    41. UIImage *image = IMAGE; // UIImage als Textur
    42. image =
    43. [image imageRotatedByRadians:-radian];
    44. [Graphics getContextStrokePatternImage:image
    45. context:theContext
    46. width:image.size.width
    47. height:image.size.width
    48. x:-(image.size.width - self.bounds.size.width) / 2.f
    49. y:-(image.size.width - self.bounds.size.width) / 2.f
    50. alpha:1.f
    51. invertTexture:YES];
    52. CGContextAddEllipseInRect(theContext, theBounds);
    53. CGContextSetShouldAntialias(theContext, YES);
    54. }
    55. - (void)draw:(CGContextRef)theContext;
    56. {
    57. CGRect theBounds = self.bounds;
    58. CGFloat theRadius = CGRectGetWidth(theBounds) / 2.0;
    59. theBounds.size.width = 28;
    60. theBounds.size.height = 28;
    61. theBounds.origin.x = theRadius - (theBounds.size.width / 2.0);
    62. theBounds.origin.y = 24.;
    63. CGContextAddEllipseInRect(theContext, theBounds); // Scheibe
    64. CGContextSetLineWidth(theContext, 3.0);
    65. CGContextSetShouldAntialias(theContext, YES);
    66. CGContextSetFillColorWithColor (theContext, [[UIColor redColor] CGColor]);
    67. CGContextSetShouldAntialias(theContext, YES);
    68. CGContextStrokePath(theContext);
    69. }
    Alles anzeigen



    Was gezeichnet wird ist ein Kreis der durch die Maske texturiert wird. Allerdings soll die Textur selbst in definierten Intervallen gedreht werden - NICHT der Kreis selbst - sondern nur die Textur die den Kreis überdeckt - der Kreis bleibt fix.


    Das zu zeichnende Objekt ist also als feste Einheit anzusehen.


    Ich bin mir nicht ganz sicher wie sich das mit einer Layerklasse realisieren lassen könnte. ?(


    Ich hoffe, du kannst meinen Ansatz nachvollziehen.



    :)
  • Das sollte mit Core Animation eigentlich kein Problem sein. Schau Dir mal das hier an. Das sollte Dir einen ersten Eindruck geben, wie Du einen eigenen Layer damit umsetzen kannst. Im Prinzip musst Du den Layer so implementieren, dass sich die Animation anhand Änderungen der Werte einer Property durchführen lassen.
    „Meine Komplikation hatte eine Komplikation.“
  • it works fine^^

    macmoonshine schrieb:

    Das sollte mit Core Animation eigentlich kein Problem sein. Schau Dir mal das hier an. Das sollte Dir einen ersten Eindruck geben, wie Du einen eigenen Layer damit umsetzen kannst. Im Prinzip musst Du den Layer so implementieren, dass sich die Animation anhand Änderungen der Werte einer Property durchführen lassen.
    Hey macmoonshine,

    ich könnte die Animation dank deiner Hinweise erfolgreich so umsetzen wie ich es mir vorstellte!

    Gut, man sollte also tatsächlich immer sofort an Layer denken, wenn man etwas animieren möchte.


    Vielen Dank für deine Unterstützung ;)


    Du hast mir sehr geholfen!