从 Kivy 中的多点触摸 类 继承时确定触摸执行层次

Determining touch execution hierarchy when inheriting from multiple touch classes in Kivy

我正在尝试结合 KivyMD MDCardSwipe 和 kivy_garden drag_n_drop 的功能。 MDCardSwipe 允许您将卡片滑动到一边以显示底层小部件——在我的例子中带有垃圾桶图标和删除功能——并且 drag_n_drop 允许您四处拖动小部件以在布局中重新排序它们。理想情况下,我想要可以通过拖动重新排列的可滑动卡片。

我创建了一个 class DragCard,如下所示,它继承自 MDCardSwipe 和 DraggableObjectBehavior。当我以这种方式订购时,MDCardSwipe 功能起作用,但 DraggableObjectBehavior 不起作用。当我颠倒顺序时,MDCardSwipe 不再起作用,但 DraggableObjectBehavior 起作用。

MDCardSwipe 有一个相对较小的区域,滑动必须在该区域内开始。我希望 MDCardSwipe 在该区域内接收触摸,如果触摸在所述区域外,则将触摸传递给 DraggableObjectBehavior。

如有任何帮助,我们将不胜感激!

.py 文件:

from kivy.lang import Builder
from kivymd.app import MDApp
from kivy.core.window import Window
from kivy.uix.label import Label
from kivy.uix.boxlayout import BoxLayout
from kivymd.uix.card import MDCardSwipe
from kivy.uix.widget import Widget
from kivy_garden.drag_n_drop import DraggableLayoutBehavior, DraggableObjectBehavior
from kivy.properties import StringProperty


class DraggableBoxLayout(DraggableLayoutBehavior, BoxLayout):
    def __init__(self, **kwargs):
        super().__init__(
            spacer_widget = MySpacer(),
            spacer_props = {'size_hint_y': None, 'height' : 150 },
             **kwargs)
        

    def compare_pos_to_widget(self, widget, pos):
        if self.orientation == 'vertical':
            return 'before' if pos[1] >= widget.center_y else 'after'
        return 'before' if pos[0] < widget.center_x else 'after'

    def handle_drag_release(self, index, drag_widget):
        self.add_widget(drag_widget, index)


class DragCard(MDCardSwipe, DraggableObjectBehavior):
    text = StringProperty()

    def initiate_drag(self):
        # during a drag, we remove the widget from the original location
        self.parent.remove_widget(self)
        

class MySpacer(Widget):
    """Widget inserted at the location where the dragged widget may be
    dropped to show where it'll be dropped.
    """
    pass

 
class MainApp(MDApp): 
    
    def build(self):
        self.theme_cls.theme_style = 'Dark'
        self.theme_cls.primary_palette = "Cyan"
        Window.size = (375, 740)
        

        return Builder.load_file("drag.kv")

    def on_start(self):
        pass

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

.kv 文件:

#:kivy 2.0.0

BoxLayout:
    orientation: 'vertical'

    DraggableBoxLayout:
        drag_classes: ['card']
        orientation: 'vertical'

        DragCard:
            text: 'A'
            drag_cls: 'card'
        DragCard:
            text: 'B'
            drag_cls: 'card'
        DragCard:
            text: 'C'
            drag_cls: 'card'
        DragCard:
            text: 'D'
            drag_cls: 'card'
        DragCard:
            text: 'E'
            drag_cls: 'card'
        DragCard:
            text: 'F'
            drag_cls: 'card'
        DragCard:
            text: 'G'
            drag_cls: 'card'
        DragCard:
            text: 'H'
            drag_cls: 'card'


<DragCard>:
    size_hint_y: None
    height: 150


    MDCardSwipeLayerBox:
        padding: "8dp"

        MDIconButton:
            icon: "trash-can"
            pos_hint: {"center_y": .5}
            # on_release: root.delete_template()

    MDCardSwipeFrontBox:

        Label:
            text: root.text
            pos_hint: {'center_x': .5, 'center_y': .5}
            halign: 'center'
            valign: 'center'
            font_style: 'H3'

<MySpacer>:
    canvas:
        Color:
            rgba: [.95, .57, .26, 1]
        Rectangle:
            size: self.size
            pos: self.pos

以下代码似乎可以执行您想要的操作。 DragCardon_touch_down() 方法根据 touchDragCard 上的位置调用 DraggableObjectBehaviorMDCardSwipeon_touch_down() 方法].其他touch方法根据touch(由DraggableObjectBehavior设置)的grab_current属性决定调用哪个方法:

class DragCard(DraggableObjectBehavior, MDCardSwipe):
    text = StringProperty()

    def initiate_drag(self):
        # during a drag, we remove the widget from the original location
        self.parent.remove_widget(self)
        
    def on_touch_down(self, touch):
        if self.collide_point(*touch.pos):
            if touch.x > self.center_x:
                return DraggableObjectBehavior.on_touch_down(self, touch)
            else:
                return MDCardSwipe.on_touch_down(self, touch)

    def on_touch_up(self, touch):
        if touch.grab_current == self:
            return DraggableObjectBehavior.on_touch_up(self, touch)
        else:
            return MDCardSwipe.on_touch_up(self, touch)

    def on_touch_move(self, touch):
        if touch.grab_current == self:
            return DraggableObjectBehavior.on_touch_move(self, touch)
        else:
            return MDCardSwipe.on_touch_move(self, touch)