У меня есть UITableView со списком элементов. Выбор элемента подталкивает viewController, который затем выполняет следующие действия. из метода viewDidLoad я запускаю URLRequest для данных, которые требуются для одного из моих подпредставлений - подкласса UIView с переопределенным drawRect. Когда данные поступают из облака, я начинаю строить свою иерархию представлений. рассматриваемому подклассу передаются данные, и его метод drawRect теперь имеет все необходимое для визуализации.
Но.
Поскольку я не вызываю drawRect явно - Cocoa-Touch обрабатывает это - у меня нет способа сообщить Cocoa-Touch, что я действительно, очень хочу, чтобы этот подкласс UIView отображался. Когда? Теперь было бы хорошо!
Я пробовал [myView setNeedsDisplay]. Иногда это срабатывает. Очень пятнистый.
Я борюсь с этим часами. Может ли кто-нибудь, кто предоставит мне надежный и надежный подход к принудительному повторному рендерингу UIView.
Вот фрагмент кода, который передает данные в представление:
// 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];
Ура, Дуг
источник
setNeedsDisplay
вызовом и фактическим вызовомdrawRect:
. Хотя надежность вызова здесь и здесь, я бы не назвал это «самым надежным» решением - надежное решение для рисования теоретически должно выполнять все рисование непосредственно перед возвратом к клиентскому коду, который требует рисования.У меня возникла проблема с большой задержкой между вызовами setNeedsDisplay и drawRect: (5 секунд). Оказалось, что я вызвал setNeedsDisplay в другом потоке, чем основной поток. После перемещения этого вызова в основной поток задержка исчезла.
Надеюсь, это поможет.
источник
Гарантированный возврат денег, железобетонный твердый способ заставить представление рисовать синхронно (перед возвратом к вызывающему коду) - это настроить
CALayer
взаимодействия с вашимUIView
подклассом.В своем подклассе UIView создайте
displayNow()
метод, который сообщает слою « установить курс для отображения », а затем « сделать его таким »:стриж
Objective-C
Также реализуйте
draw(_: CALayer, in: CGContext)
метод, который будет вызывать ваш частный / внутренний метод рисования (который работает, поскольку каждыйUIView
равен aCALayerDelegate
) :стриж
Objective-C
И создайте свой собственный
internalDraw(_: CGRect)
метод вместе с отказоустойчивымdraw(_: CGRect)
:стриж
Objective-C
А теперь просто звоните,
myView.displayNow()
когда вам действительно-действительно нужно отрисовать (например, изCADisplayLink
обратного вызова) . НашdisplayNow()
метод сообщит объектуCALayer
todisplayIfNeeded()
, который синхронно обратится к намdraw(_:,in:)
и выполнит рисованиеinternalDraw(_:)
, обновляя визуал тем, что нарисовано в контексте, прежде чем двигаться дальше.Этот подход аналогичен описанному выше в @ RobNapier, но имеет преимущество вызова
displayIfNeeded()
в дополнение кsetNeedsDisplay()
, что делает его синхронным.Это возможно, потому что
CALayer
s предоставляют больше возможностей рисования, чемUIView
s, - слои являются более низкими, чем представления, и разработаны специально для целей высоконастраиваемого рисования в макете, и (как и многие вещи в Какао) спроектированы для гибкого использования ( как родительский класс, или как делегатор, или как мост к другим системам рисования, или просто самостоятельно).CALayerDelegate
Все это возможно благодаря правильному использованию протокола.Более подробную информацию о возможности настройки
CALayer
s можно найти в разделе « Настройка объектов слоя» Руководства по программированию базовой анимации .источник
drawRect:
явно сказано: «Вы никогда не должны вызывать этот метод напрямую». Кроме того, CALayerdisplay
явно говорит: «Не вызывайте этот метод напрямую». Если вы хотите синхронно рисовать на слояхcontents
напрямую, нет необходимости нарушать эти правила. Вы можете просто рисовать на слое вcontents
любое время (даже в фоновых потоках). Просто добавьте для этого подслой в представление. Но это отличается от того, чтобы вывести его на экран, когда нужно дождаться правильного времени композитинга.contents
(«Если объект слоя привязан к объекту представления, вам следует избегать установки содержимого этого свойства напрямую. Взаимодействие между представлениями и слоями обычно приводит к в представлении, заменяющем содержимое этого свойства во время последующего обновления. ") Я не особо рекомендую этот подход; Преждевременное рисование снижает производительность и качество рисования. Но если он вам нужен по какой-то причине, тоcontents
вот как это получить.drawRect:
прямом вызове . Не было необходимости демонстрировать эту технику, и она была исправлена.contents
техники, которую вы предлагаете ... звучит заманчиво. Сначала я пробовал что-то подобное, но не мог заставить его работать, и обнаружил, что указанное выше решение содержит гораздо меньше кода без каких-либо причин не быть таким же производительным. Однако, если у вас есть рабочее решение для этогоcontents
подхода, мне было бы интересно его прочитать (нет причин, по которым у вас не может быть двух ответов на этот вопрос, верно?)display
. Это просто настраиваемый общедоступный метод в подклассе UIView, точно такой же, как в GLKView (еще один подкласс UIView, и единственный известный мне Apple, который требует функциональности DRAW NOW! ).У меня была такая же проблема, и все решения от SO или Google у меня не работали. Обычно
setNeedsDisplay
это работает, но когда это не так ...Я пробовал вызывать
setNeedsDisplay
представление всеми возможными способами из всех возможных потоков и прочего - все равно безуспешно. Мы знаем, как сказал Роб, чтоНо почему-то на этот раз не сыграла. И единственное решение, которое я нашел, - это вызвать его вручную через некоторое время, чтобы все, что блокирует розыгрыш, исчезло, например:
Это хорошее решение, если вам не нужно очень часто перерисовывать представление. В противном случае, если вы занимаетесь движением (действием), обычно не возникает проблем с простым вызовом
setNeedsDisplay
.Надеюсь, это поможет кому-то, кто там заблудился, как и я.
источник
Хорошо, я знаю, что это может быть большим изменением или даже не подходящим для вашего проекта, но вы не рассматривали возможность не выполнять push, пока у вас уже не будут данные ? Таким образом, вам нужно нарисовать представление только один раз, и пользовательский интерфейс также будет лучше - push будет уже загружен.
Вы делаете это
UITableView
didSelectRowAtIndexPath
асинхронно, запрашивая данные. Получив ответ, вы вручную выполняете переход и передаете данные вашему viewController вprepareForSegue
. Между тем вы можете захотеть показать какой-нибудь индикатор активности, для простой проверки индикатора загрузки https://github.com/jdg/MBProgressHUDисточник