Each kivy carousel slide consists of an image at the top (with a checkbox) and text below. The direction of the carousel is 'right' (one after the other horizontally). Image and text data are fed to the carousel with a recycleview.
The minimum code results with a) Each slide stacked vertically; b) the checkbox not displaying.
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.recycleview import RecycleView
from kivy.properties import StringProperty, ListProperty, NumericProperty
Builder.load_string("""
<CarouselSlide>:
BoxLayout:
orientation: 'vertical'
size_hint_y: 1
AsyncImage:
source: root.tile
size_hint_y: 0.5
CheckBox:
id: cb
root_ref: root.index
on_press: app.on_checkbox_press(self, self.active, self.state, self.root_ref)
TextInput:
text: root.text
size_hint_y: 0.5
multiline: True
<CarouselScreen>:
name: 'carousel_screen'
Carousel:
direction: 'right'
ignore_perpendicular_swipes: True
size: root.width, root.height
RV:
id: rv
viewclass: 'CarouselSlide'
RecycleBoxLayout:
orientation: 'vertical'
size_hint_y: None
default_size_hint: 1, None
height: self.minimum_height
default_size: 1, root.height
""")
class CarouselScreen(Screen):
pass
class CarouselSlide(Screen):
tile = StringProperty('')
text = StringProperty('')
index = NumericProperty(-1)
cb_state = StringProperty('normal')
def __init__(self, **kwargs):
super(CarouselSlide, self).__init__(**kwargs)
self.bind(cb_state=self.set_cb_state)
def set_cb_state(self, carouselslide, cb_state_value):
self.ids.cb.state = cb_state_value
class RV(RecycleView):
data = ListProperty('[]')
def __init__(self, **kwargs):
super(RV, self).__init__(**kwargs)
self.get_slide_data()
def get_slide_data(self):
text="Ooh, a storm is threatening. My very life today. If I don't get some shelter. Ooh yeah I'm gonna fade away. War, children. It's just a shot away. It's just a shot away. War, children. It's just a shot away. It's just a shot away."
self.data = [{'tile': 'The Rolling Stones', 'text': text, "index": i, "cb_state": 'normal'} for i in range(41)]
class ThisApp(App):
def __init__(self, **kwargs):
super().__init__(**kwargs)
def build(self):
self.sm = ScreenManager()
self.sm.add_widget(CarouselScreen(name="carousel_screen"))
return self.sm
def on_checkbox_press(self, checkbox, active, state, root_ref):
if active:
print(active, state, root_ref)
else:
print(active, state, root_ref)
new_state = checkbox.state
checkbox.state = 'normal'
rv = self.root.get_screen('carousel_screen').ids.rv
rv.data[root_ref]['cb_state'] = new_state
rv.refresh_from_data()
if __name__ == "__main__":
ThisApp().run()
I believe the problem is that you are defining the CheckBox
as a child of AsyncImage
. The AsyncImage
is not intended to be a container. Try un-indenting the CheckBox
in your kv
, and adding size/position attributes:
<CarouselSlide>:
BoxLayout:
orientation: 'vertical'
size_hint_y: 1
AsyncImage:
source: root.tile
size_hint_y: 0.5
CheckBox:
id: cb
size_hint: None, None
size: 48, 48
pos_hint: {'center_x':0.5}
root_ref: root.index
on_press: app.on_checkbox_press(self, self.active, self.state, self.root_ref)
TextInput:
text: root.text
size_hint_y: 0.5
multiline: True