setNeedsLayout should be called on main thread