简体   繁体   English

在Kivy中将ScreenManager与RecycleView一起使用

[英]Using the ScreenManager with RecycleView in Kivy

I have a RecycleView widget that responds to touch input. 我有一个RecycleView小部件,可以响应触摸输入。 I need each row on the RecycleView to take the user to a specific screen. 我需要RecycleView上的每一行将用户带到特定屏幕。 For now I only have two screens setup. 目前,我只有两个屏幕设置。

Here is the Python code: 这是Python代码:

class Navigator(NavigationDrawer):
    image_source = StringProperty('images/1canaa.jpg')
    title = StringProperty('Navigation')

# This is the screen that is initiated when the app runs 
class MainScreen(Screen):
    pass

# This is the screen that is suppose to initiate when the first row is 
# touched
class MapScreen(Screen):
    pass


class Manager(ScreenManager):
    main_screen_obj = ObjectProperty(None)
    map_screen_obj = ObjectProperty(None)


class SelectableRecycleBoxLayout(FocusBehavior, LayoutSelectionBehavior,
                             RecycleBoxLayout):
    ''' Adds selection and focus behaviour to the view. '''


class SelectableLabel(RecycleDataViewBehavior, Label):
    ''' 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
        return super(SelectableLabel, self).refresh_view_attrs(
        rv, index, data)

    def on_touch_down(self, touch):
        ''' Add selection on touch down '''
        if super(SelectableLabel, 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 is_selected:
            print("selection changed to {0}".format(rv.data[index]))
            if rv.data[index] == {'text': 'FIRST ROW'}:
                Manager.current = 'mapScreen'
                print('The evaluation was executed')


        else:
            print("selection removed for {0}".format(rv.data[index]))


class RV(RecycleView):
    def __init__(self, **kwargs):
        super(RV, self).__init__(**kwargs)

        Unidades = ['FIRST ROW', 'SECOND ROW', 'THIRD ROW', 'FORTH ROW']

        self.data = [{'text': x} for x in Unidades]


class Main(App):
    theme_cls = ThemeManager()
    nav_drawer = ObjectProperty()

    def build(self):
        self.nav_drawer = Navigator()
        return Manager()


if __name__ == '__main__':
    Main().run()

If you look at the apply_selection method, which is in the SelectableLabel class, you will see that I have tried to sort this out by checking: 如果查看SelectableLabel类中的apply_selection方法,您将看到我已尝试通过检查以下内容进行解决:

if the rv.data[index] == {'text': 'FIRST ROW'}:
    Manager.current = 'mapScreen'
    print('The evaluation was executed')

This did not work. 这没有用。 Notice that I printed a message to check if the evaluation had happened, and it did. 请注意,我打印了一条消息以检查评估是否已经完成,并且确实如此。 When I run the app I get the message: 'The evaluation was executed'. 当我运行该应用程序时,我收到消息:“评估已执行”。 The user was not taken to the MapScreen though. 但是,用户并未被带到MapScreen。

And here is the kv code: 这是kv代码:

#:import MapSource mapview.MapSource
#:import Toolbar kivymd.toolbar.Toolbar
#:import hex kivy.utils.get_color_from_hex


<SelectableLabel>:
# Draw a background to indicate selection
    canvas.before:
        Color:
            rgba: hex('#867979') if self.selected else hex('#808080')
        Rectangle:
            pos: self.pos
            size: self.size


<RV>:
    viewclass: 'SelectableLabel'

    SelectableRecycleBoxLayout:

        default_size: None, dp(56)
        default_size_hint: 1, None
        size_hint_y: None
        height: self.minimum_height
        orientation: 'vertical'
        multiselect: False
        touch_multiselect: True


<MainScreen>:
    BoxLayout:
        orientation: 'vertical'

        Label:
            size_hint: None, None
            height: 45
            width: 100
            pos_hint: {'center_y': 0.5, 'center_x': 0.5}
            text: '[size=40]Unidades de Assistência[/size]'
            color: hex('#676767')
            markup: True
            font_name: 'alex-brush.regular.ttf'

        RV: 

<MapScreen>:
    BoxLayout:
        Label:
            text: 'MapScreen'



<Manager>:
    id: screen_manager
    main_screen_obj: main_screen
    map_screen_obj: map_screen

    MainScreen:
        id: main_screen
        name: 'mainScreen'
        manager: screen_manager


    MapScreen:
        id: map_screen
        name: 'mapScreen'
        manager: screen_manager

So, what I am trying to accomplish here is very simple, or at least it should be. 因此,我在这里想要完成的工作非常简单,或者至少应该如此。 It all boils down to this: If the first row is touched, take the user to MapScreen... If the second row is touched, take the user to some other screen ...so on. 归结为:如果触摸了第一行,则将用户带到MapScreen ...如果触摸了第二行,则将用户带到其他屏幕...依此类推。

I hope this is not very confusing. 我希望这不是很令人困惑。 Thanks for any help. 谢谢你的帮助。

There are two ways to do this, off the top of my head. 有两种方法可以解决此问题。 One is to use the router module in the kivy garden: 一种是在奇异果园中使用路由器模块:

https://github.com/kivy-garden/garden.router https://github.com/kivy-garden/garden.router

The other one would be by passing a reference of the screenmanager to the widgets in the recycle view so that you can just say self.manager.current = self.text , but this means that you would have had to add all screens previously to the manager. 另一种方法是将screenmanager的引用传递给回收视图中的小部件,这样您就可以说self.manager.current = self.text ,但这意味着您必须先前将所有屏幕添加到经理。

I would use the factory for this: 我会为此使用工厂:

from kivy.factory import Factory

class MyScreenManager(ScreenManager):
    def create_and_switch_screen(self, name):
        # This creates an instance of the class name you passed
        new_screen = getattr(Factory, name)()
        self.switch_to(my_screen)

This way you can programatically create each screen and define them as separate classes. 这样,您可以以编程方式创建每个屏幕并将它们定义为单独的类。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM