英文:
Adjust offset with UIKit Dynamics
问题
这里可以找到复制品1。
我正在制作一个与Messages.app
相似的聊天视图,其中一部分是由UIKit Dynamics
实现的有弹性的消息。在吸收了所有公开可用的知识后,我已经成功实现了我的实现,但还有一个问题 - 我不能调整contentOffset
而不使一切变得糟糕。
聊天需要调整滚动偏移以实现一些功能,例如在上方添加更多页面时保持垂直滚动,添加新消息时保持底部偏移,或通过按钮或链接消息以编程方式滚动到底部。
当我进行任何手动偏移调整时,问题开始出现。最好的情况下,一些单元格似乎会交换属性并变得无序。最坏的情况下,动态效果会变得混乱,开始显示未定义的行为,有时甚至消失。
我尝试了我能想到的一切,包括在进行偏移调整之前/之间返回正常的流布局属性,但这并没有使我完成。
这是一个质量较差的缩小版GIF,显示了问题的示例 - 请注意,在使用scrollToItem(at: lastIndexPath)
后,包含1-10枚举的消息变得无序。
有人成功地在使用UIKit Dynamics时以编程方式调整偏移吗?我很愿意听取关于如何继续的任何指导。
英文:
Reproduction can be found here
I'm making a chat view that's pretty similar to Messages.app
. A part of this is the bouncy messages made possible by UIKit Dynamics
. I have gotten my implementation working pretty well after consuming every bit of publicly available knowledge, but I have one remaining problem - I can't adjust the contentOffset
without everything going bad.
The chat requires adjusting scroll offset for features like maintaining the vertical scroll when adding more pages above, maintaining bottom offset when adding new messages, or scrolling to the bottom via button or a linked message programatically.
When I do any manual offset adjustment, issues start to arise. At best, some cells appear to swap attributes and become out of order. At worst, the dynamics go bananas and start displaying undefined behaviour, sometimes disappearing entirely.
I've tried everything I can think of, including returning normal flow layout attributes before/during offset adjustments, but this hasn't brought me to completion.
Here's a poorly downscaled gif diplaying an example of the issue - note how the messages containing 1-10 enumerated becomes out of order after using scrollToItem(at: lastIndexPath)
.
Has anyone managed to adjust offset programatically while using UIKit Dynamics? I'd love any pointers on how to proceed.
答案1
得分: 1
我从这里发布了一个解决方案,从您的示例代码和在内容偏移被程序调整时禁用动态的想法出发。这个解决方案仅在模拟器上进行了测试。
对于动画内容偏移的更改,我使用了滚动视图代理方法scrollViewDidEndScrollingAnimation(_:)
作为重新启用动态的机会。对于非动画内容偏移的更改,重新启用动态是在内容偏移更改后立即完成的。
我还在DynamicLayout的prepare
重写中添加了一个丢失的super.prepare
调用,并稍微修改了shouldInvalidateLayout
的重写:
- 当动态启用时,始终返回false(因为动画器负责使布局失效)
- 当动态禁用时,返回超级实现
为了启用/禁用动态,我使用了您示例代码中已经存在的pauseDynamics
属性。
在测试不断启用动态的不同选项时,我注意到了一些事情:
-
碰撞行为导致项目互换位置和彼此粘在一起
-
对于内容偏移的高跳跃,动画效果非常糟糕,我认为动态动画可能已经针对与用户滚动行为一致的较小增量进行了优化。
英文:
I posted here a solution starting from your sample code and your idea of disabling dynamics while the content offset is being adjusted programmatically. This solution was tested only on a simulator.
For animated content offset changes, I am using the scroll view delegate method scrollViewDidEndScrollingAnimation(_:)
as an opportunity to re-enable dynamics. For non-animated content offset changes, re-enabling dynamics is done right after the content offset change.
I also added a missing super.prepare
call in the prepare
override of DynamicLayout and changed a bit the shouldInvalidateLayout
override to:
- always return false when dynamics is enabled (since the animator is taking care of invalidating the layout)
- return the super implementation when dynamics is disabled
To enable/disable dynamics I used the pauseDynamics property that was already present in your sample code.
Some things I noticed while testing different options with dynamics always enabled:
-
the collisions behaviour is causing the swapping of items and their stickiness to one another
-
animation artefacts are really bad for high jumps in content offset, I think the dynamic animator might have been optimised for smaller deltas which are consistent with user scrolling behaviour
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论