Mam UITableView z listą elementów. Wybranie elementu powoduje wypchnięcie elementu viewController, który następnie wykonuje następujące czynności. z metody viewDidLoad Odpalam żądanie URLRequest dla danych, które są wymagane przez jedną z moich podglądów podrzędnych - podklasę UIView z nadpisaniem funkcji drawRect. Gdy dane docierają z chmury, zaczynam budować swoją hierarchię widoków. dana podklasa otrzymuje dane, a jej metoda drawRect ma teraz wszystko, czego potrzebuje do renderowania.
Ale.
Ponieważ nie wywołuję drawRect jawnie - Cocoa-Touch to obsługuje - nie mam możliwości poinformowania Cocoa-Touch, że naprawdę chcę, aby ta podklasa UIView była renderowana. Kiedy? Teraz byłoby dobrze!
Próbowałem [myView setNeedsDisplay]. To czasami działa. Bardzo nierówny.
Zmagam się z tym przez wiele godzin. Czy może ktoś, kto zapewni mi solidne, gwarantowane podejście do wymuszania ponownego renderowania UIView.
Oto fragment kodu, który dostarcza dane do widoku:
// 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];
Pozdrawiam, Doug
źródło
setNeedsDisplay
wywołaniem a rzeczywistym wywołaniemdrawRect:
. Chociaż istnieje tutaj niezawodność wywołania, nie nazwałbym tego „najbardziej niezawodnym” rozwiązaniem - solidne rozwiązanie do rysowania powinno teoretycznie wykonywać cały rysunek bezpośrednio przed powrotem do kodu klienta, który żąda rysowania.Miałem problem z dużym opóźnieniem między wywołaniami setNeedsDisplay i drawRect: (5 sekund). Okazało się, że nazwałem setNeedsDisplay w innym wątku niż główny. Po przeniesieniu tego wywołania do głównego wątku opóźnienie zniknęło.
Mam nadzieję, że to pomoże.
źródło
Gwarantowany zwrot pieniędzy, solidny sposób na wymuszenie synchronicznego rysowania widoku (przed powrotem do kodu wywołującego) polega na skonfigurowaniu
CALayer
interakcji międzyUIView
podklasą.W swojej podklasie UIView utwórz
displayNow()
metodę, która powie warstwie, aby „ ustawiła kurs wyświetlania ”, a następnie „ uczyniła to ”:Szybki
Cel C
Zaimplementuj także
draw(_: CALayer, in: CGContext)
metodę, która wywoła twoją prywatną / wewnętrzną metodę rysowania (która działa, ponieważ każdyUIView
jest aCALayerDelegate
) :Szybki
Cel C
I stwórz własną
internalDraw(_: CGRect)
metodę wraz z niezawodnościądraw(_: CGRect)
:Szybki
Cel C
A teraz po prostu zadzwoń,
myView.displayNow()
kiedy naprawdę - naprawdę potrzebujesz go do rysowania (na przykład zCADisplayLink
oddzwonienia) . NaszadisplayNow()
metoda powieCALayer
todisplayIfNeeded()
, co będzie synchronicznie wywoływać z powrotem do naszegodraw(_:,in:)
i rysowaćinternalDraw(_:)
, aktualizując wizualizację o to, co zostało wciągnięte w kontekst, zanim przejdziemy dalej.To podejście jest podobne do powyższego @ RobNapier, ale ma tę zaletę, że
displayIfNeeded()
oprócz wywoływaniasetNeedsDisplay()
jest synchroniczne.Jest to możliwe, ponieważ
CALayer
udostępniają one więcej funkcji rysowania niż inne -UIView
warstwy są niższego poziomu niż widoki i zaprojektowane specjalnie w celu tworzenia wysoce konfigurowalnych rysunków w układzie i (podobnie jak wiele rzeczy w kakao) są zaprojektowane tak, aby można było ich używać elastycznie ( jako klasa nadrzędna lub delegator, lub jako pomost do innych systemów rysowania lub po prostu samodzielnie). To wszystko umożliwia właściwe wykorzystanieCALayerDelegate
protokołu.Więcej informacji na temat konfigurowalności
CALayer
s można znaleźć w sekcji Setting Up Layer Objects w przewodniku Core Animation Programming Guide .źródło
drawRect:
wyraźnie mówi: „Nigdy nie powinieneś bezpośrednio wywoływać tej metody”. Ponadto CALayerdisplay
wyraźnie mówi „Nie wywołuj tej metody bezpośrednio”. Jeśli chcesz synchronicznie rysowaćcontents
bezpośrednio na warstwach, nie ma potrzeby naruszania tych zasad. Możesz po prostu rysować na warstwie wcontents
dowolnym momencie (nawet w wątkach w tle). W tym celu wystarczy do widoku dodać podwarstwę. Ale to coś innego niż umieszczenie go na ekranie, który musi poczekać do właściwego czasu komponowania.contents
(„Jeśli obiekt warstwy jest powiązany z obiektem widoku, należy unikać bezpośredniego ustawiania zawartości tej właściwości. Interakcja między widokami i warstwami zwykle skutkuje w celu zastąpienia zawartości tej właściwości podczas kolejnej aktualizacji. ”) Nie polecam szczególnie tego podejścia; przedwczesne rysowanie obniża wydajność i jakość rysunku. Ale jeśli potrzebujesz tego z jakiegoś powodu,contents
to jak to zdobyć.drawRect:
bezpośrednio. Nie było potrzeby demonstrowania tej techniki i zostało naprawione.contents
technikę, którą proponujesz… brzmi zachęcająco. Próbowałem czegoś takiego na początku, ale nie mogłem go uruchomić i stwierdziłem, że powyższe rozwiązanie zawiera znacznie mniej kodu bez powodu, aby nie być tak wydajnym. Jeśli jednak masz działające rozwiązanie dla tegocontents
podejścia, byłbym zainteresowany jego przeczytaniem (nie ma powodu, dla którego nie możesz mieć dwóch odpowiedzi na to pytanie, prawda?)display
. Jest to po prostu niestandardowa metoda publiczna w podklasie UIView, tak jak to się robi w GLKView (kolejna podklasa UIView i jedyna napisana przez Apple, o której wiem, a która wymaga funkcji DRAW NOW! ).Miałem ten sam problem, a wszystkie rozwiązania z SO czy Google nie działały dla mnie. Zwykle
setNeedsDisplay
działa, ale jeśli nie ...Próbowałem wywoływać
setNeedsDisplay
widok w każdy możliwy sposób ze wszystkich możliwych wątków i innych rzeczy - nadal bez sukcesu. Wiemy, jak powiedział Rob, żeAle z jakiegoś powodu tym razem by nie rysował. Jedynym rozwiązaniem, które znalazłem, jest wywołanie go ręcznie po pewnym czasie, aby wszystko, co blokuje losowanie, przeminęło, na przykład:
To dobre rozwiązanie, jeśli widok nie jest potrzebny do częstego przerysowywania. W przeciwnym razie, jeśli robisz jakieś ruchy (akcje), zwykle nie ma problemów z samym sprawdzeniem
setNeedsDisplay
.Mam nadzieję, że pomoże to komuś, kto się tam zgubił, tak jak ja.
źródło
Cóż, wiem, że może to być duża zmiana lub nawet nieodpowiednia dla twojego projektu, ale czy rozważałeś niewykonanie wypychania, dopóki nie masz już danych ? W ten sposób wystarczy tylko raz narysować widok, a wrażenia użytkownika również będą lepsze - przycisk zostanie już załadowany.
Sposób, w jaki to robisz, polega na
UITableView
didSelectRowAtIndexPath
asynchronicznym pytaniu o dane. Po otrzymaniu odpowiedzi należy ręcznie wykonać płynność i przekazać dane do elementu viewController wprepareForSegue
. W międzyczasie możesz chcieć wyświetlić wskaźnik aktywności, aby uzyskać prosty wskaźnik ładowania, sprawdź https://github.com/jdg/MBProgressHUDźródło