I am using Python-2.7 and kivy.
I run test.py then show a menu Test.When i click on it then show list o
The trick is to change the viewclass to fit your needs. You had used Button but it looked to me like that was just to try to sync up your two RecycleViews so I used Labels instead. However, since the TwoLabelListItem that I created is just a BoxLayout you can easily manipulate it to exactly fit your needs.
Once you create the appropriate layout for the viewclass you then just need to make sure that your the data passed to it is correctly applied. Here I apply the data to the two different labels. I also grab the data as your notes indicated you wanted to be able to have something popup for the different line items.
def refresh_view_attrs(self, rv, index, data):
''' Catch and handle the view changes '''
self.index = index
self.ids.label1.text = data['text1']
self.ids.label2.text = data['text2']
self.data = data
So keeping the data will let you reference it when an element is selected.
def apply_selection(self, rv, index, is_selected):
''' Respond to the selection of items in the view. '''
self.selected = is_selected
if self.selected:
print(self.data)
Adding a scroll bar to the RecycleView is then simply a matter of telling it in kv that you want to use it. If you want to have the user be able to either move the content or the bars just add content to the list. ['bars', 'content']
RecycleView:
scroll_type: ['bars']
bar_width: 25
...
testApp.py
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import BooleanProperty, ListProperty, ObjectProperty, NumericProperty, DictProperty
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.uix.button import Button
from kivy.uix.recyclegridlayout import RecycleGridLayout
from kivy.uix.behaviors import FocusBehavior
from kivy.uix.recycleview.layout import LayoutSelectionBehavior
from kivy.uix.popup import Popup
from kivy.core.window import Window
from kivy.clock import Clock
Window.size = (600, 325)
class SelectableRecycleGridLayout(FocusBehavior, LayoutSelectionBehavior,
RecycleGridLayout):
''' Adds selection and focus behaviour to the view. '''
selected_row = NumericProperty(0)
def get_nodes(self):
nodes = self.get_selectable_nodes()
if self.nodes_order_reversed:
nodes = nodes[::-1]
if not nodes:
return None, None
selected = self.selected_nodes
if not selected: # nothing selected, select the first
self.select_node(nodes[0])
self.selected_row = 0
return None, None
if len(nodes) == 1: # the only selectable node is selected already
return None, None
last = nodes.index(selected[-1])
self.clear_selection()
return last, nodes
def select_next(self):
''' Select next row '''
last, nodes = self.get_nodes()
if not nodes:
return
if last == len(nodes) - 1:
self.select_node(nodes[0])
self.selected_row = nodes[0]
else:
self.select_node(nodes[last + 1])
self.selected_row = nodes[last + 1]
def select_previous(self):
''' Select previous row '''
last, nodes = self.get_nodes()
if not nodes:
return
if not last:
self.select_node(nodes[-1])
self.selected_row = nodes[-1]
else:
self.select_node(nodes[last - 1])
self.selected_row = nodes[last - 1]
def select_current(self):
''' Select current row '''
last, nodes = self.get_nodes()
if not nodes:
return
self.select_node(nodes[self.selected_row])
class TwoLabelListItem(RecycleDataViewBehavior, BoxLayout):
''' Add selection support to the Label '''
index = None
selected = BooleanProperty(False)
selectable = BooleanProperty(True)
def refresh_view_attrs(self, rv, index, data):
''' Catch and handle the view changes '''
self.index = index
self.ids.label1.text = data['text1']
self.ids.label2.text = data['text2']
self.data = data
def on_touch_down(self, touch):
''' Add selection on touch down '''
if super(TwoLabelListItem, self).on_touch_down(touch):
return True
if self.collide_point(*touch.pos) and self.selectable:
return self.parent.select_with_touch(self.index, touch)
def apply_selection(self, rv, index, is_selected):
''' Respond to the selection of items in the view. '''
self.selected = is_selected
if self.selected:
print(self.data)
class RV(BoxLayout):
data_items = ListProperty([])
row_data = DictProperty({})
data = ListProperty([])
col_row_controller = ObjectProperty(None)
def __init__(self, **kwargs):
super(RV, self).__init__(**kwargs)
self.get_states()
Clock.schedule_once(self.set_default_first_row, .0005)
self._request_keyboard()
def _request_keyboard(self):
self._keyboard = Window.request_keyboard(
self._keyboard_closed, self, 'text'
)
if self._keyboard.widget:
# If it exists, this widget is a VKeyboard object which you can use
# to change the keyboard layout.
pass
self._keyboard.bind(on_key_down=self._on_keyboard_down)
def _keyboard_closed(self):
self._keyboard.unbind(on_key_down=self._on_keyboard_down)
self._keyboard = None
def _on_keyboard_down(self, keyboard, keycode, text, modifiers):
if keycode[1] == 'down': # keycode[274, 'down'] pressed
# Respond to keyboard down arrow pressed
self.display_keystrokes(keyboard, keycode, text, modifiers)
self.col_row_controller.select_next()
elif keycode[1] == 'up': # keycode[273, 'up] pressed
# Respond to keyboard up arrow pressed
self.display_keystrokes(keyboard, keycode, text, modifiers)
self.col_row_controller.select_previous()
# Keycode is composed of an integer + a string
# If we hit escape, release the keyboard
if keycode[1] == 'escape':
keyboard.release()
# Return True to accept the key. Otherwise, it will be used by
# the system.
return True
def display_keystrokes(self, keyboard, keycode, text, modifiers):
print("\nThe key", keycode, "have been pressed")
print(" - text is %r" % text)
print(" - modifiers are %r" % modifiers)
def on_keyboard_select(self):
''' Respond to keyboard event to call Popup '''
# setup row data for Popup
self.row_data = self.data[self.col_row_controller.selected_row]
# call Popup
self.popup_callback()
def on_mouse_select(self, instance):
''' Respond to mouse event to call Popup '''
if (self.col_row_controller.selected_row != instance.index):
# Mouse clicked on row is not equal to current selected row
self.col_row_controller.selected_row = instance.index
# Hightlight mouse clicked/selected row
self.col_row_controller.select_current()
# setup row data for Popup
self.row_data = self.data[instance.index]
# call Popup
self.popup_callback()
def popup_callback(self):
# enable keyboard request
self._request_keyboard()
def set_default_first_row(self, dt):
''' Set default first row as selected '''
self.col_row_controller.select_next()
def update(self):
self.data = [{'text1': str(x[0]), 'text2': x[1], 'Id': str(x[0]), 'Name': x[1], 'key': 'Id', 'selectable': True}
for x in self.data_items]
def get_states(self):
rows = [(x, 'abc') for x in range(25)]
i = 0
for row in rows:
self.data_items.append([row[0], row[1], i])
i += 1
print(self.data_items)
self.update()
class MainMenu(BoxLayout):
states_cities_or_areas = ObjectProperty(None)
rv = ObjectProperty(None)
def display_states(self):
self.remove_widgets()
self.rv = RV()
self.states_cities_or_areas.add_widget(self.rv)
def remove_widgets(self):
self.states_cities_or_areas.clear_widgets()
class TestApp(App):
title = "test"
def build(self):
return MainMenu()
if __name__ == '__main__':
TestApp().run()
test.kv
#:kivy 1.10.0
:
# Draw a background to indicate selection
canvas.before:
Color:
rgba: (.0, 0.9, .1, .3) if self.selected else (0, 0, 0, 1)
Rectangle:
pos: self.pos
size: self.size
Label:
id: label1
Label:
id: label2
:
col_row_controller: col_row_controller
RecycleView:
scroll_type: ['bars']
bar_width: 25
size_hint_x: .1
data: root.data
viewclass: 'TwoLabelListItem'
SelectableRecycleGridLayout:
padding: 0,0,25,0
id: col_row_controller
key_selection: 'selectable'
cols: 1
default_size: None, dp(26)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
multiselect: False
touch_multiselect: True
:
text_size: self.size
valign: "middle"
padding_x: 5
size : (80,30)
size_hint : (None, None)
background_color: 90 , 90, 90, 90
background_normal: ''
color: 0, 0.517, 0.705, 1
border: (0, 10, 0, 0)
:
states_cities_or_areas: states_cities_or_areas
BoxLayout:
orientation: 'vertical'
#spacing : 10
BoxLayout:
canvas.before:
Rectangle:
pos: self.pos
size: self.size
size_hint_y: 1
MenuButton:
id: btn
text: 'Test'
size : (60,30)
on_release: root.display_states()
BoxLayout:
canvas.before:
Rectangle:
pos: self.pos
size: self.size
Color:
rgb: (1,1,1)
Label:
size_hint_x: 45
BoxLayout:
id: states_cities_or_areas
size_hint_y: 10
Label:
size_hint_y: 1