Frage

Ich habe ein UITableView mit einer Liste von Elementen. Auswahl eines Elements drückt einen Viewcontroller, die geht dann folgendes zu tun. von Verfahren viewDidLoad ich einen URLRequest für Daten abfeuern, das durch auf meiner Subviews erforderlich ist - eine UIView Unterklasse mit drawRect außer Kraft gesetzt. Wenn die Daten aus der Wolke kommen beginne ich meine Ansicht Hierarchie aufzubauen. die Unterklasse in Frage wird die Daten übergeben und es ist drawRect Methode hat nun alles, was es zu machen braucht.

Aber.

Weil ich nicht nennen drawRect explizit - Cocoa-Touch-Griffe, dass - ich habe keine Möglichkeit, Cocoa-Touch of mitteilen, dass ich wirklich, wirklich diese UIView Unterklasse will zu machen. Wann? Jetzt wäre es gut!

Ich habe versucht, [myView setNeedsDisplay]. Diese irgendwie funktioniert manchmal. Sehr fleckig.

Ich habe stundenlang mit diesem werden Ringen. Könnte jemand, der mir bitte fest, garantiert Ansatz mit einem Felsen bieten eine UIView Wieder machen zu zwingen.

Hier ist der Code-Schnipsel, die Daten in der Ansicht-Feeds:

// Create the subview
self.chromosomeBlockView = [[[ChromosomeBlockView alloc] initWithFrame:frame] autorelease];

// Set some properties
self.chromosomeBlockView.sequenceString     = self.sequenceString;
self.chromosomeBlockView.nucleotideBases    = self.nucleotideLettersDictionary;

// Insert the view in the view hierarchy
[self.containerView          addSubview:self.chromosomeBlockView];
[self.containerView bringSubviewToFront:self.chromosomeBlockView];

// A vain attempt to convince Cocoa-Touch that this view is worthy of being displayed ;-)
[self.chromosomeBlockView setNeedsDisplay];

Cheers, Doug

War es hilfreich?

Lösung

Das garantiert, absolut solide Art und Weise eine UIView zu zwingen, wieder zu machen ist [myView setNeedsDisplay]. Wenn Sie Probleme haben, mit, dass Sie mit großer Wahrscheinlichkeit in eine dieser Fragen ausgeführt wird:

  • Sie nennen es, bevor Sie die Daten tatsächlich haben oder Ihre -drawRect: ist über Cachen etwas.

  • Sie erwarten die Sicht zur Zeit Sie diese Methode aufrufen zu ziehen. Es ist absichtlich keine Möglichkeit, „zieht jetzt in dieser Sekunde“ mit dem Cocoa Zeichensystem zu verlangen. Das würde das gesamte Ansicht Compositing-System, Müll Leistung stören und schafft wahrscheinlich alle Arten von artifacting. Es gibt nur Möglichkeiten zu sagen „dies muss in den nächsten Entnahmezyklus gezogen werden.“

Wenn das, was Sie brauchen, ist „eine gewisse Logik, zeichnen, etwas mehr Logik“, dann müssen Sie in einem separaten Verfahren, die „etwas mehr Logik“ setzen und rufen Sie es mit einer Verzögerung von 0 mit -performSelector:withObject:afterDelay:, dass „einige setzen wird mehr Logik“nach dem nächsten Ziehung Zyklus. Siehe diese Frage für ein Beispiel diese Art von Code, und einem Fall, in dem es erforderlich sein könnte (obwohl es in der Regel am besten für andere Lösungen, wenn möglich aussehen, da sie den Code komplizieren).

Wenn Sie nicht denken, die Dinge gezogen zu werden, setzen Sie einen Haltepunkt in -drawRect: und sehen Sie, wenn Sie immer genannt. Wenn Sie -setNeedsDisplay anrufen, aber -drawRect: ist nicht im nächsten Ereignisschleife aufgerufen zu werden, dann in der Ansichtshierarchie gräbt und stellen Sie sicher, dass Sie nicht auszutricksen versuchen, irgendwo ist. Über Klugheit ist die # 1 Ursache der schlechten Zeichnung in meiner Erfahrung. Wenn Sie denken, Sie wissen am besten, wie das System dazu zu bringen, zu tun, was Sie wollen, erhalten Sie in der Regel genau das tun, was Sie nicht wollen.

Andere Tipps

Ich hatte ein Problem mit einer großen Verzögerung zwischen Aufruf setNeedsDisplay und drawRect: (5 Sekunden). Es stellte sich heraus, dass ich setNeedsDisplay in einem anderen Thread als dem Hauptthread genannt. Nach dem Umzug der Verzögerung diesen Aufruf an den Haupt-Thread ging.

Hope dies ist eine Hilfe.

Die Geld-zurück-Garantie, Stahlbetonfeste Art und Weise einen Blick auf zu zwingen synchron zeichnen (bevor sie an den anrufenden Code zurückkehrt) die CALayer Interaktionen mit Ihrer UIView Unterklasse zu konfigurieren.

In Ihrer UIView Unterklasse, erstellen Sie eine - display Methode, die die Schicht sagt, dass „ Ja, es braucht Anzeige “, dann „ es so zu machen “:

/// Redraws the view's contents immediately.
/// Serves the same purpose as the display method in GLKView.
/// Not to be confused with CALayer's `- display`; naming's really up to you.
- (void)display
{
    CALayer *layer = self.layer;
    [layer setNeedsDisplay];
    [layer displayIfNeeded];
}

Auch eine - drawLayer:inContext: Methode implementieren, die Ihre private / interne Zeichenmethode nennen wollen (die da jedes UIView arbeitet, ist ein CALayerDelegate) :

/// Called by our CALayer when it wants us to draw
///     (in compliance with the CALayerDelegate protocol).
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)context
{
    UIGraphicsPushContext(context);
    [self internalDrawWithRect:self.bounds];
    UIGraphicsPopContext();
}

und erstellen Sie Ihre individuelle - internalDrawWithRect: Methode, zusammen mit ausfallsicheren - drawRect::

/// Internal drawing method; naming's up to you.
- (void)internalDrawWithRect:(CGRect)rect
{
    // @FILLIN: Custom drawing code goes here.
    //  (Use `UIGraphicsGetCurrentContext()` where necessary.)
}

/// For compatibility, if something besides our display method asks for draw.
- (void)drawRect:(CGRect)rect {
    [self internalDrawWithRect:rect];
}

Und jetzt gerade [myView display] nennen, wenn Sie wirklich-wirklich brauchen zu ziehen. - display die CALayer sagen displayIfNeeded, die synchron zurück in unsere - drawLayer:inContext: anrufen und tun, um die Zeichnung in - internalDrawWithRect:, die visuellen mit der Aktualisierung, was in den Kontext gezogen ist, bevor er auf.


Dieser Ansatz ähnelt @ RobNapier oben ist, hat aber den Vorteil, - displayIfNeeded zusätzlich Aufruf - setNeedsDisplay, die es synchron macht.

Dies ist möglich, weil CALayers mehr Zeichnung aussetzen Funktionalität als UIViews do- Schichten sind auf niedrigere Ebene als Ansichten und ausdrücklich zum Zweck der hoch konfigurierbare Zeichnung im Layout entworfen, und (wie viele Dinge in Cocoa) ausgelegt sind flexibel (als Elternklasse oder als delegator oder als Brücke zu anderen Zeichensystemen, oder einfach nur auf ihre eigenen) verwendet wird.

Weitere Informationen über die Konfigurierbarkeit von CALayers kann in der Einrichten Layer-Objekte Abschnitt des Core Animation Programming Guide .

Ich hatte das gleiche Problem, und alle Lösungen von SO oder Google nicht für mich arbeiten. Normalerweise setNeedsDisplay funktioniert, aber wenn es nicht ...
Ich habe setNeedsDisplay der Ansicht versuchte Aufruf nur jede mögliche Art und Weise von allen möglichen Themen und Sachen - noch ohne Erfolg. Wir wissen, wie Rob sagte, dass

  

„dies muss in den nächsten Entnahmezyklus gezogen werden.“

Aber aus irgendeinem Grunde wäre es diesmal nicht ziehen. Und die einzige Lösung, die ich gefunden habe, ist es manuell nach einiger Zeit fordern, alles zu lassen, die blockiert die Auslosung vergehen, wie folgt aus:

dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, 
                                        (int64_t)(0.005 * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void) {
    [viewToRefresh setNeedsDisplay];
});

Es ist eine gute Lösung, wenn Sie die Ansicht nicht wirklich oft neu zu zeichnen. Andernfalls, wenn Sie etwas zu bewegen (Aktion) Sachen tun, gibt es in der Regel keine Probleme mit nur anrufen setNeedsDisplay.

Ich hoffe, dass es jemanden helfen wird, die dort verloren, wie ich war.

Nun weiß ich, könnte dies eine große Veränderung sein oder auch nicht geeignet für Ihr Projekt, aber haben Sie betrachten nicht die Push-Durchführung, bis Sie bereits die Daten haben ? Auf diese Weise müssen Sie nur einmal den Blick ziehen und die User Experience wird auch besser sein - der Push bewegt sich in bereits geladen

.

Die Art und Weise Sie dies tun, ist in der UITableView didSelectRowAtIndexPath Sie asynchron für die Daten fragen. Sobald Sie die Antwort erhalten, führen Sie manuell die Segue und die Daten auf den Viewcontroller in prepareForSegue passieren. Inzwischen können Sie einige Aktivitätsindikator zeigen, für die einfache Ladeanzeige überprüfen https://github.com/jdg/MBProgressHUD

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top