`RecycleView` with `viewclass` using dynamic `height` is not smooth
See original GitHub issueVersions
- Python: 3.7.4
- OS: Arch Linux
- Kivy: v2.0.0.dev0, git-7947abf, 20191025
- Kivy installation method:
pip install --user git+https://github.com/kivy/kivy.git
Description`
When using RecycleView
with a viewclass
using dynamic height, the scrolling is “jumping”, it’s not smooth at all. Each time a new item appears on screen, there is a little “jump” (the scroll bar is going in the opposite direction then the right size is set), which is really bad when scrolling many items at once. Once the entire list of data has been scrolled once, the next time we scroll it is smooth as expected.
This bug is related to https://github.com/kivy/kivy/issues/6580 but it’s a different issue.
Code and Logs
from kivy.app import App
from kivy.lang import Builder
KV = '''
<CustomView@BoxLayout>:
size_hint: 1, None
text: ''
Label:
id: test_label
size_hint: 1, None
on_size: root.height = self.height
text_size: root.width, None
size: self.texture_size
text: root.text
RecycleView:
viewclass: 'CustomView'
data: [{"text": f"{i} {'test'*i}"} for i in range(300)]
scroll_y: 0
RecycleBoxLayout:
id: layout
default_size: None, None
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
'''
class TestApp(App):
def build(self):
return Builder.load_string(KV)
if __name__ == '__main__':
TestApp().run()
This script is displaying a 300 BoxLayout
containing a Label
were text is growing on purpose (to augment the height
of each item).
expected result: when you scroll the RecycleView
, the scrolling should me smooth, quick, and nice looking
actual result: there are jumps on each items. If you scroll slowly, you can notice clearly that the jump happen when a new item appears in the view. If you scroll quickly, there are many jumps and the scrolling is not smooth at all. Once the entire list has been scrolled once, everything is smooth as expected.
Issue Analytics
- State:
- Created 4 years ago
- Comments:10 (5 by maintainers)
if you can pre-compute a sufficiently good approximation of the size of the item before displaying it, and put that value in the key_size key of your dict (that you can then update when the actual size is computed), then you can significantly improve the experience.
If the size is dynamic, it gets the sizes whenever the size of any widget changes and does a re-layout. This is costly and can lead to jumps in scrollview if the new size is very different than the original size.
As @tshirtman said, you can improve the performance if you can initially estimate the size of the dynamic widgets, because that leads to less jumping. Similarly, if you can save the last known widget size in the data dict, that size will be used initially when re-showing a previously shown widget. This will save the cost of laying it out again, as in the example he posted.