Kivy:滑动(旋转木马和屏幕管理器)

Kivy: Swiping (Carousel & ScreenManager)

我在 ScreenManager 中有两个屏幕,它们都包含 ScrollView 中的多个按钮。这个想法是通过单击按钮向前(向右)迈出一步。然后向后滑动(向左)。所以我试图添加一个轮播来实现第二页上的一次滑动。这是我试过的:

self.root = ScreenManager(id = 'screen_manager')

main_screen = Screen(name = 'main_screen')

scroller = Scroller()
button_text = ['teach', 'move', 'b3', 'b4', 'b5', 'b6', 'b7', 'b8']
for text in button_text:
    scroller.view.add_widget(Field(name=text, direction='left', current='teach'))
main_screen.add_widget(scroller)
self.root.add_widget(main_screen)

carousel = Carousel(direction='left', id='carousel')

teach = Screen(name = 'teach')
scroller2 = Scroller()
button_text = ['vocab', 'drills']
for text in button_text:
    scroller2.view.add_widget(Field(name=text, direction='right', current='main_screen'))
carousel.add_widget(scroller2)
teach.add_widget(carousel)
self.root.add_widget(teach)

但是由于我只添加了第二个屏幕,所以无法向任何方向滑动。 Carousel 的 load_slide() 方法将幻灯片作为参数。假设幻灯片是指轮播。鉴于我将有很多页面,我可能需要使用 add_widget()remove_widget() 动态加载轮播。希望得到一些指点。

我目前的代码工作示例:http://dpaste.com/33464R2

正如您在评论中所问。

I have bunch of pages. Each page will have a bunch of buttons. Some pages have more buttons than can fit on the screen, so they need to be scrollable.

现在,Scrollable 部分,你已经想通了。(你也可以在 kivy 文件中做到这一点),See here。您可以轻松地将其添加到下面的代码中。

Clicking on a button should take you to the next child screen (with a scroll effect). On any child it should be possible to go back to it's parent by swiping back.

在这里(下面的代码)您可以滑动或点击按钮进行导航。

现在,

Given I am going to have a lot pages, I probably need the Carousel to be loaded dynamically, using add_widget() and remove_widget().

这些示例会对您有所帮助。 Kivy-Showcase and Container

在 kivy-showcase 中查看 load_screen 方法以及 build 函数

这里是 add_widgets 单击按钮

的示例
Builder.load_string('''
[SideBar@BoxLayout]:
    content: content
    orientation: 'vertical'
    size_hint: .2,1
    BoxLayout:
        orientation: 'vertical'
        # just add a id that can be accessed later on
        id: content

<Root>:
    Button:
        center_x: root.center_x
        text: 'press to add_widgets'
        size_hint: .2, .2
        on_press:
            sb.content.clear_widgets()
            root.load_content(sb.content)
    SideBar:
        id: sb
''')

class Root(BoxLayout):

    def load_content(self, content):
        for but in range(20):
            content.add_widget(Button(text=str(but)))

class MyApp(App):
    def build(self):
        return Root()

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

这里是屏幕示例。

这是main.py文件

from kivy.app import App
from kivy.uix.screenmanager import Screen
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ObjectProperty

class ShowTime(BoxLayout):
    carousel = ObjectProperty(None)

class Screen1(Screen):
    pass

class Screen2(Screen):
    pass

class MainApp(App):
    def build(self):
         return ShowTime()

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

这是main.kv文件

<Screen1>:
    name: "screen1"
    BoxLayout:
        orientation: 'vertical'
        padding: 50
        spacing: 50
        Button:
            text: "Next (2)"
            on_release: self.parent.parent.parent.parent.parent.ids.carousel.load_next()
        Button:
            text: "Go back (2)"
            on_release: self.parent.parent.parent.parent.parent.ids.carousel.load_previous()

<Screen2>:
    name: "screen2"
    BoxLayout:
        orientation: 'vertical'
        padding: 100
        spacing: 100
        Button:
            text: "go back (3)"
            on_release: self.parent.parent.parent.parent.parent.ids.carousel.load_previous()

<Showtime>:
    carousel: carousel
    Carousel:
        id: carousel
        loop: True
        BoxLayout:
            padding: 100
            spacing: 100
            Button:
                text: 'Tap me or Swipe (1)'
                on_release: carousel.load_next()
        Screen1:
        Screen2:

编辑 1:

问- load_slide()方法如何使用?

load_slide() 方法将幻灯片作为其参数 def load_slide(self, slide):

Q- 那么现在如何获取幻灯片呢?

slide 是一个列表 属性 slides = ListProperty([]),

在按钮有文字的地方打印这个 "go back (3)"

on_release: print( self.parent.parent.parent.parent.parent.ids.carousel.slides) 您将在 id(carousel) 下获得所有幻灯片的列表。

这就是您的使用方式。 .....ids.carousel.load_slide(....ids.carousel..slides[2])

您可以使用 ScreenManagerGestures 来完成此操作。 (../kivy/examples/gestures/)

看这里kivy-github-gestures

我已经在评论中解释了代码中的所有内容。

首先您需要创建一个名为 gesture_box.py.

的新 Python 文件

gesture_strings copy from here

from kivy.gesture import GestureDatabase
from kivy.uix.boxlayout import BoxLayout
from kivy.gesture import Gesture 

[Paste gesture_strings here]

#This database can compare gestures the user makes to its stored     gestures 
#and tell us if the user input matches any of them.
gestures = GestureDatabase()
for name, gesture_string in gesture_strings.items():
    gesture = gestures.str_to_gesture(gesture_string)
    gesture.name = name
    gestures.add_gesture(gesture)

class GestureBox(BoxLayout):

    def __init__(self, **kwargs):
        for name in gesture_strings:
            self.register_event_type('on_{}'.format(name))
        super(GestureBox, self).__init__(**kwargs)

    def on_left_to_right_line(self):
        pass

#To recognize a gesture, you’ll need to start recording each individual event in the
#touch_down handler, add the data points for each call to touch_move , and then do the
#gesture calculations when all data points have been received in the touch_up handler.

    def on_touch_down(self, touch):
        #create an user defined variable and add the touch coordinates 
        touch.ud['gesture_path'] = [(touch.x, touch.y)]    
        super(GestureBox, self).on_touch_down(touch)

    def on_touch_move(self, touch):
        touch.ud['gesture_path'].append((touch.x, touch.y))
        super(GestureBox, self).on_touch_move(touch)

    def on_touch_up(self, touch):
        if 'gesture_path' in touch.ud:
            #create a gesture object
            gesture = Gesture()    
            #add the movement coordinates 
            gesture.add_stroke(touch.ud['gesture_path'])
            #normalize so thwu willtolerate size variations
            gesture.normalize()
            #minscore to be attained for a match to be true
            match = gestures.find(gesture, minscore=0.3)
            if match:
                print("{} happened".format(match[1].name))
                self.dispatch('on_{}'.format(match[1].name))
        super(GestureBox, self).on_touch_up(touch)

现在创建您的 main.py 文件。

import gesture_box as gesture
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout

class Runner(gesture.GestureBox):
    pass

class MainApp(App):
    def build(self):
        return Runner()

if __name__ == '__main__':
    app = MainApp()
    app.run()

还有你的 main.kv 文件

<Runner>:
    #Handling the gesture event.
    on_left_to_right_line: manager.current = 'main_screen';  manager.transition.direction = 'right'
    ScreenManager:
        id: manager
        Screen:
            name: "main_screen"
            BoxLayout:
                orientation: 'vertical'
                Label:
                Button:
                    text: "Child 1"
                    on_release: 
                        manager.current = "child1"
                        manager.transition.direction = 'left'

                Label:
                Button:
                    text: "Child 2"
                    on_release: 
                        manager.current = "child1"
                        manager.transition.direction = 'left'
                Label:

        Screen:
            name: "child1"
            Label:
                text: "Swipe from left to right to go to main screen (CHILD 1)"

        Screen:
            name: "child2"
            Label:
                text: "Swipe from left to right to go to main screen (CHILD 1)"

编辑:很多人问我这些手势字符串是如何生成的。

Kivy 人员在他们的示例中提供了这一点。

看这里https://github.com/kivy/kivy/blob/master/examples/gestures/gesture_board.py 运行 这个文件。

python gesture_board.py

它应该打开一个空白window。

使用鼠标或触摸在上面做一个手势。

当on_touch_up事件触发时,会在终端输出手势字符串

例如 right_to_left_line 的输出将是。这个

('gesture representation:', 'eNq1WMtSHEcQvM+PiIs36t3dP4CujuADHFhsACEZNmBlW3/vnOrZxyCWmYPFQQu5OdlVldXVPbp6/Pr494/N/fZ1//1lO3yePnc0XN3teLj59HT71/bTsBP8ig8dXm8+ve5fnr9uX/GnDVffdj5cvStyk7RhF6NUwfO758en/fhYHR9rFx77fWQNO+4RjCH8wCMsw/VvtCFhZWuspJXZfQzn3/FrHa5pE6WIca0NH00agv3z9uNFLBfx4f6i/v0krRKspZE7PnyFdKbNZYU0mykjZo3mXlZI15Ruy9Lu4ZWKSiFi9bIoLVl14RXSHI3xHQuLqyxHLZLS+iuk00ZZYaMFmqOYYAEn5hUFSRtlhY0mptZQ6mJsXpeV00Vp/7+ypom6wkQ0dEGRpXqgtW250pom6goT1biQRWth0Ddflk4T9cxErkSNpTRG3vVcm4TUpVR2GMoUy+Jpo57ZyFZI1aCOddjbSV0CO9FRkohCpdQVoaeV2n6NuqWddmYntWIW4UwmCvtO4oLODlPn0qyYy7J4GmpnhhKer7W0VkngXZSjOjdz9EtwiBf3FZ1o6amdeYrKQJdEGmae1ob9dZQPTEGBtw0UjMIV8umqTa6mehXEJVVauHLBpDyqq1NDsZpiZUeSy+rpqrWTulqphuHfEGr4eL4cxJmbSyiaEt5ili+Ke5rqfBLHucKKbega3BqdxOlNx7Rl8TTV9SQeCFwCa3hg59ip6KRNMGSDYLhSkxWRp6fua8Q5qFoNDC/sVCq8LJ6OelkU76MHuhHaGrQxJJa73dNSb6vkrWrBNrJWYSm226J6pKdx8pSxU4nMEaIX8jPtWsmKRuAfzMm2bGmkpXGyFIeXoZmrEKaukcpJnXGhaAptw4hwXZ4wkZaGrxJHw1QMN6/NcBtaUZW0NMoqcVyCzDB9WA0jhpYdjXQ02nLNhfAnYEyBEAzmRemSdhZe0yzYobhnRcMSaEpaHi4l/Sy6uP9HcVw+MXQKegYt4ysiTz+LL8/FUb1h7uJ72KoYYHkHGC/5X16226fjlb3EeGcvZbi6xiStGxqug6E87HelDreJ2gxtHTU5Ryt1VGYKlTtKM4UqiSLoGaodtbmCdZTnXE+UY64bHaWYoSVR8rlC5oazcAZmam3ObJkZfNu085+RYJ2QSWKM96dqBzPHSl1fJmamiNteBydmZoiZkaBOzEywUI9EwTz74ZGQucYkZVOomWpYlzJ+EzEImXUP/H1CVsDrpNCDwc5LdOqOI5p54x4/RzNx5zdoZo53tzmaqeNSMEczd3OfR2fDlNlIyeztsHSd0EzfpqWdfioaU+ZvRJcZWQCtlzU4i6HlsgZnYXRqiHcZ0hkfaGTB1D5gZPFUP2BkIVXmVeKsnR564IBm7XTaOkc06yXTLjmiWSOpc1SoozRHsxYyVevgn2T+uDHP0cxZfN4kknmKzVtSvKPz1pHMTdTmaOnom3Yv55SeqLQPKD1rKe9Qft5ImHmd7ivpvU7joDj/0Uv0XkChlfReWa4r6b3kl8cEzoTOoMuMbsW01aYBxdqH8WEOHNB+0Eyt8860w90kGSUuMqwfQNOJMI1RvF8m6jFH+wE0bb8j2g+g6fw5oqhFPzgfto/3D/vx/6Tw3nNtbzYctiM4/zze7R+SEsN4ao0rAN4/f9u+3D592eZXJd8sRnw65f/YvTzfff/StetwrRu8huCVAFT0PS484+V98x/WYONd') ('cross:', -1.2199187170964643) ('check:', -2.052277818300959) ('circle:', 0.4973932910874005) ('square:', 0.2907537534396739)

就是这样,你有你的字符串 :D

我还有一个方法可以用。它不是通过旋转木马,但它允许您通过滑动来更改屏幕。您可以创建一个方法,将屏幕初始接触点的 x 点和屏幕最终接触点的 x 点相减。这是视频的link(https://www.youtube.com/watch?v=8pqtMAUEUyo&t=65s)

    def on_touch_move(self, touch):
        if touch.ox - touch.x > 50:  # check for swiping gestures
            # ScreenManger change screen

touch.ox是屏幕(x轴)的初始接触点,touch.x是最终接触点。如果差异大于设定值,它会更改屏幕。