Is there an easy way of finding some specific nodes in the recycleview? Like iterating through some list or something? (The recycleview could have loads of data, so using loops would freeze the app? Maybe?)
I would like to have a textInput so the user could search for specific data in the recycleview. When the user validates text or clicks a button the nodes with corresponding text should come to the top of the list.
I was using a boxlayout with labels and buttons instead of recycleview but generating all those widgets was causing the app to freeze, so I looked around a bit and found out about recycleview, tested it a little and it worked great. But still I don't really know how the recycleview stuff properly works...
Any help is greatly appreciated!
Thanks,
Matheus Baumgarten.
The recycle view will only create as many widgets as you can see at once, then creates the illusion of scrolling through them by recycling those widgets by reusing the widgets with new data applied.
The data for the recycle view is a list of dicts. Search and sort, I suggest the following:
Sort the recycleview data list based on the user search criteria.
Call refresh_from_data. https://kivy.org/doc/stable/api-kivy.uix.recycleview.html?highlight=refresh_from_data#kivy.uix.recycleview.RecycleViewBehavior.refresh_from_data
Use scroll_y to move the widgets to the top (set to 1 to move to the top) : https://kivy.org/doc/stable/api-kivy.uix.scrollview.html?highlight=scroll_y#kivy.uix.scrollview.ScrollView.scroll_y
Below is an example I put together to help another user that uses the keys up, down and delete to manipulate a Recycle view. This does not do what you are looking for – but shows how the pieces are used, so should be a useful start.
"""
Use up, down and delete keys to navigate a RecycleView
"""
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import StringProperty, ListProperty
from kivy.uix.recycleview import RecycleView
from kivy.core.window import Window
kv = """
<ThreeLabel>:
canvas:
Color:
rgba: root.highlight_color
Rectangle:
size: self.size
pos: self.pos
padding: 20,0
Label:
text: root.song
Label:
text: root.album
Label:
text: root.artist
TestBox:
orientation: 'vertical'
Label:
text: 'Song List'
size_hint_y: .1
TextInput:
hint_text: 'Click here and the keyboard is released'
size_hint_y: None
height: 30
multiline: False
BoxLayout:
Label:
text: 'Preview art here' # Just a place holder, note keyboard is released when clicking on a TextInput
TouchRecycleView:
id:rv
viewclass: 'ThreeLabel'
data: root.rv_data_list
scroll_type: ['bars','content']
bar_inactive_color: 1,1,1,1
bar_width: dp(20)
do_scroll_x: False
RecycleBoxLayout:
id: rbl
key_selection: 'song'
default_size: None, dp(56)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
"""
class TouchRecycleView(RecycleView):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self._keyboard = None
self.index = None # the index into self.data
def on_touch_up(self, touch):
app = App.get_running_app()
if self.collide_point(*touch.pos):
if not self._keyboard:
self._keyboard = Window.request_keyboard(self._keyboard_closed, self)
self._keyboard.bind(on_key_down=self._on_keyboard_down)
self.index = app.root.ids.rbl.get_view_index_at(self.to_local(*touch.pos)) # index based on touch
self.highlight()
return super().on_touch_up(touch)
def _keyboard_closed(self):
print('keyboard closed!')
self._keyboard.unbind(on_key_down=self._on_keyboard_down)
self._keyboard = None
self.remove_highlight()
def _on_keyboard_down(self, keyboard, keycode, text, modifiers):
# self.view_adapter.views dict k is index, v is widget of visible widgets
if self.index not in list(self.view_adapter.views):
return # if selected widget out of view, ignore keys
if keycode[1] == 'down':
self.next_item()
elif keycode[1] == 'up':
self.prev_item()
elif keycode[1] == 'delete':
self.delete_song()
def next_item(self):
view_widgets = list(self.view_adapter.views) # the indices in the current view
pos_in_view = view_widgets.index(self.index) # position in the current view
if self.index > len(self.data) - len(view_widgets): # if in last page of data go to bottom
self.scroll_y = 0
elif pos_in_view > len(view_widgets) - 3: # if near the bottom of the list, scroll
self.scroll_y -= len(view_widgets) / len(self.data)
self.index = min(self.index + 1, len(self.data) - 1) # increment, but not past the end
self.highlight()
def prev_item(self):
view_widgets = list(self.view_adapter.views)
pos_in_view = view_widgets.index(self.index)
if self.index < len(view_widgets):
self.scroll_y = 1 # if in first page of data go to top
elif pos_in_view < 2: # if near top of visible list, scroll
self.scroll_y += len(view_widgets) / len(self.data)
self.index = max(0, self.index - 1) # decrement, but not lower that zero
self.highlight()
def delete_song(self):
if not self.data: # if the list is empty, do nothing
return
del self.data[self.index]
self.refresh_from_data()
self.index = max(0, self.index - 1)
self.highlight()
def highlight(self):
if not self.data: # if the list is empty, do nothing
return
for d in self.data:
d['highlight_color'] = (0, 0, 0, 1)
self.data[self.index]['highlight_color'] = (.8, .8, .8, 1)
self.refresh_from_data()
def remove_highlight(self):
for d in self.data:
d['highlight_color'] = (0, 0, 0, 1)
self.refresh_from_data()
class ThreeLabel(BoxLayout):
song = StringProperty()
album = StringProperty()
artist = StringProperty()
highlight_color = ListProperty()
class TestBox(BoxLayout):
rv_data_list = ListProperty([{'song': f'song_{n}',
'album': f'album_{n}',
'artist': f'artist_{n}',
'highlight_color': [0, 0, 0, 1]} for n in range(50)])
class RVTestApp(App):
def build(self):
return Builder.load_string(kv)
RVTestApp().run()
--
You received this message because you are subscribed to the Google Groups "Kivy users support" group.
To unsubscribe from this group and stop receiving emails from it, send an email to kivy-users+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/9f54230c-bd42-4f42-8f8f-4237736d7414o%40googlegroups.com.
So, I just have to sort the data list of dicts and call refresh_from_data() then set the scroll to the top. That seems to be a very good approach and since its a list of dictionaries it won't take that long to traverse.
Thanks again, you helped a lot!
Best regards,
Matheus Baumgarten.