You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kivy中使用Draggable在ScrollView间拖拽Widget时方向异常的问题求助

Kivy中使用Draggable在ScrollView间拖拽Widget时方向异常的问题求助

我最近在做一个Kivy项目,用到了kivy-garden的Draggable组件,遇到了一个奇怪的拖拽方向限制问题——只能从右侧的ScrollView往左侧拖,反过来完全不行,想请教下大家怎么解决!

我的环境

  • 操作系统:Windows 10 Home
  • Python版本:3.11.5
  • Kivy版本:2.2.1
  • kivy-garden-draggable版本:0.2.0

我的代码

lists.py

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.uix.scrollview import ScrollView
from kivy_garden.draggable import KXDraggableBehavior, KXReorderableBehavior

class ListApp(App):
    def build(self):
        return MainLayout()

class MainLayout(BoxLayout):
    pass

class ReorderableBoxLayout(KXReorderableBehavior, BoxLayout):
    pass

class Card(KXDraggableBehavior, Label):
    pass

ListApp().run()

list.kv

<ReorderableBoxLayout@KXReorderableBehavior+BoxLayout>

<MainLayout>
    canvas.before:
        Color:
            rgba: .6, .7, .8, 1
        Rectangle:
            pos: self.pos
            size: self.size
    BoxLayout:
        padding: '10dp'
        spacing: '10dp'
        ScrollView:
            id: left_box
            height: self.parent.height
            ReorderableBoxLayout:
                drag_classes: ['test',]
                orientation: 'vertical'
                padding: '5dp'
                spacing: '10dp'
                size_hint_y: None
                on_minimum_height: self.height = self.minimum_height
                Card:
                Card:
        ScrollView:
            id: center_box
            height: self.parent.height
            ReorderableBoxLayout:
                drag_classes: ['test',]
                orientation: 'vertical'
                padding: '5dp'
                spacing: '10dp'
                size_hint_y: None
                on_minimum_height: self.height = self.minimum_height
                Card:
                Card:
        ScrollView:
            id: right_box
            height: self.parent.height
            ReorderableBoxLayout:
                drag_classes: ['test',]
                orientation: 'vertical'
                padding: '5dp'
                spacing: '10dp'
                size_hint_y: None
                on_minimum_height: self.height = self.minimum_height
                Card:
                Card:

<Card>
    drag_cls: 'test'
    drag_timeout: 0
    text: 'Card'
    font_size: '30sp'
    size_hint_y: None
    canvas.before:
        Color:
            rgba: .5, .8, .5, 1
        Rectangle:
            pos: self.pos
            size: self.size

问题详情

我设置了三个横向排列的ScrollView,每个里面都有可拖拽的Card组件。现在遇到的情况是:

  • 正常工作的拖拽方向:
    • 最右侧的ScrollView → 中间/左侧的ScrollView
    • 中间的ScrollView → 左侧的ScrollView
  • 完全无法工作的拖拽方向:
    • 左侧的ScrollView → 中间/右侧的ScrollView
    • 中间的ScrollView → 右侧的ScrollView

简单说就是只能从右往左拖,反过来拖的时候,目标ScrollView根本不会接收这个拖拽的Card,完全没反应。有没有大佬知道怎么解决这个问题?万分感谢!


解决思路与方案

这个问题大概率是**Widget的绘制层级(Z轴顺序)**导致的:Kivy中先添加到父布局的Widget会在下层,后添加的在上层。你的三个ScrollView是从左到右依次添加的,所以左侧的在最下层,右侧的在最上层。当你从左往右拖的时候,拖拽的Card其实是在右侧ScrollView的下方,导致右侧的ReorderableBoxLayout无法捕捉到拖拽事件。

分享两种亲测有效的解决方法:

方法1:拖拽开始时将Card移到所在布局的最上层

修改你的Card类,重写on_drag_start方法,在拖拽启动时把自己加到父布局的末尾(也就是最上层):

class Card(KXDraggableBehavior, Label):
    def on_drag_start(self, touch, ctx):
        super().on_drag_start(touch, ctx)
        # 将当前Card移到父布局的最上层
        if self.parent:
            self.parent.add_widget(self)

这样每次拖拽开始时,这个Card都会被放到所在布局的最顶层,就能被右侧的ScrollView里的容器检测到了,左右拖拽都能正常工作。

方法2:给可接收拖拽的容器设置更高的层级

如果你不想修改Python代码,也可以在kv文件里给ReorderableBoxLayout设置zindex属性(Kivy 2.0及以上版本支持),提升它的事件优先级:

<ReorderableBoxLayout@KXReorderableBehavior+BoxLayout>
    zindex: 10  # 设置一个较高的数值,确保能优先捕捉到拖拽事件

这样每个可接收拖拽的容器都有更高的层级,不管从哪个方向拖拽,都能检测到拖拽的Card。

你可以先试试第一种方法,应该就能快速解决问题啦!

备注:内容来源于stack exchange,提问作者大橋和季

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.20 06:28:09