I could not run your code - I didn't have the required json file, but I got an idea of what you want to do.
With a ScrollView, each widget is instanced. You can store state in the widget. In a RecycleView, only the visible widgets are instanced the state come from the RecycleView data list (or can come from another list outside of the widget). This puts some restrictions on how the viewclass is designed.
In the example below, I use the key_viewclass attribute and multiple widgets, based on the number of items in each widget. For this example there can be 1, 2 or 3 Labels in the BoxLayout. The can be extended. This implementation is a little tedious - but I can not thing of a better way to make this work with a RecycleView.
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import StringProperty
from kivy.uix.label import Label
from kivy.clock import Clock
kv = """
<ListHolderBase>:
size_hint_y: None
orientation: 'vertical'
spacing: dp(2)
padding: dp(2)
canvas:
Color:
rgb: .7, .7, .7
Rectangle:
pos: self.pos
size: self.size
<ListHolder1>: # a BoxLayout that holds a number of list items.
ListItem:
text: root.text
<ListHolder2>:
ListItem:
text: root.text_0
ListItem:
text: root.text_1
<ListHolder3>:
ListItem:
text: root.text_0
ListItem:
text: root.text_1
ListItem:
text: root.text_2
<ListItem>: # A label
size_hint: 1, None
text_size: self.width, None
height: self.texture_size[1]
font_size: dp(100)
canvas.before:
Color:
rgba: .1, .2, .3, 1
RoundedRectangle:
pos: self.pos
size: self.size
BoxLayout:
orientation: 'vertical'
Label:
size_hint_y: None
height: dp(30)
text: 'Labels in a BoxLayout under a RecycleView'
RecycleView:
id: rv
key_viewclass: 'widget' # multiple viewclass widgets in the data list with the key 'widget'
RecycleBoxLayout:
id: rb
orientation: 'vertical'
key_size: 'ks' # new property for me!
default_size: None, None
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
spacing: dp(15) # added spacing to show individual viewclass instances
"""
class ListHolderBase(BoxLayout):
pass
class ListHolder1(ListHolderBase):
text = StringProperty()
class ListHolder2(ListHolderBase):
text_0 = StringProperty() # using a list property did not work to hold text
text_1 = StringProperty()
class ListHolder3(ListHolderBase):
text_0 = StringProperty() # using a list property did not work to hold text
text_1 = StringProperty()
text_2 = StringProperty()
class ListItem(Label):
pass
class RecycleBoxApp(App):
def build(self):
return Builder.load_string(kv)
def on_start(self):
Clock.schedule_once(self.create_content) # enter kivy loop to allow widgets to size
def create_content(self, *args):
contents = [['One'], ['Two', 'Three'], ['Four'], ['Five', 'Six', 'Seven'], ['Eight'], ['Nine', 'Ten']]
self.list_item = ListItem() # used to size Labels
width = self.list_item.width = self.root.ids.rb.width
for content in contents:
height = 0 # used to calculate the height of the ListHolder
for item in content:
self.list_item.text = item
self.list_item.texture_update()
height += self.list_item.texture_size[1]
if len(content) == 1:
self.root.ids.rv.data.append({'text': content[0],
'widget': f'ListHolder{len(content)}',
'ks': (width, height + 4)}) # + padding
elif len(content) == 2:
self.root.ids.rv.data.append({'text_0': content[0], 'text_1': content[1],
'widget': f'ListHolder{len(content)}',
'ks': (width, height + 6)}) # + padding and spacing
elif len(content) == 3:
self.root.ids.rv.data.append({'text_0': content[0], 'text_1': content[1], 'text_2': content[2],
'widget': f'ListHolder{len(content)}',
'ks': (width, height + 8)}) # + padding and spacing
print(self.root.ids.rv.data)
RecycleBoxApp().run()