| 3422 | if (previous == StickyPositionTop && position != StickyPositionTop && _viewNodeTree != nullptr) { |
| 3423 | _viewNodeTree->withLock([&]() { |
| 3424 | auto& scope = _viewNodeTree->getCurrentViewTransactionScope(); |
| 3425 | getAttributesApplier().removeAttribute( |
| 3426 | scope, DefaultAttributeTranslationY, AttributeOwner::getNativeOverridenAttributeOwner(), nullptr); |
| 3427 | getAttributesApplier().flush(scope); |
| 3428 | }); |
| 3429 | } else if (previous != StickyPositionTop && position == StickyPositionTop && _viewNodeTree != nullptr) { |
| 3430 | // Runtime toggle none -> top: walk up to the nearest scroll ancestor with |
| 3431 | // nativeStickyEnabled=true and refresh its sticky cache. Without this, a header |
| 3432 | // that becomes sticky after the enclosing scroll has already run its layout pass |
| 3433 | // won't have parentY/parentH/childH populated and will read defaults on next scroll. |
| 3434 | for (auto* p = getParent().get(); p != nullptr; p = p->getParent().get()) { |
| 3435 | if (p->_flags[kScrollAttributesBound]) { |
| 3436 | if (p->_scrollState != nullptr && p->_scrollState->getNativeStickyEnabled()) { |
| 3437 | p->updateStickyHeaders(/*refreshCache=*/true); |