Kivy的问题-滚动视图与其上方的框布局重叠 [英] Problem with Kivy - Scrollview overlapping with Box Layout above it
问题描述
即使在垂直Scrollview中有一个Button,我也会在顶部的固定菜单中单击该按钮,但它不会影响固定菜单.
I'm clicking the button in the fixed menu at the top even though there is a Button in the vertical Scrollview, it doesn't effect the fixed menu.
我试图单击顶部固定菜单中的按钮,但操作将发送到下面的水平Scrollview中.
I'm trying to click at the button in the fixed menu at the top but the actions are being sent to the horizontal Scrollview below.
我是使用kivy甚至是编程的新手,并且正在使用Python 3.7和Kivy(1.11.1)创建一个看起来像Netflix的Page布局的应用程序,其中在顶部和底部固定有一个菜单它有一个垂直的Scrollview,里面有一些水平的滚动视图(就像Netlix的目录一样,例如:我的列表",继续观看",系列"等).问题是,当我向下滚动垂直ScrollView并且水平滚动视图之一位于顶部的固定菜单之后时,事件将发送到该水平滚动视图,而不是滚动视图内容上方的固定菜单.如果我向下滚动垂直Scrollview,并且其中一个水平滚动视图落后"(用引号引起,因为我认为它们不应该相互碰撞),则位于顶部菜单,如果我单击菜单,则该事件正在发送到水平滚动视图.
I'm new with kivy and even programming and I'm creating an app with Python 3.7, and Kivy(1.11.1) that kinda looks like Netflix's Page layout, in which there is a menu fixed at the top and below it there is a vertical Scrollview with some horizontal scrollviews inside (just like the Netlix's catalogues, eg.: My List, Continue Watching, Series, etc). The problem is that when I scroll down the vertical ScrollView and one of the horizontal scrollview gets behind the fixed menu at the top, the events are sent to this horizontal scrollview and not to the fixed menu that is be above the Scrollview content. If I scroll the vertical Scrollview down and one of the horizontal scrollviews gets "behind" (in quotes because I imagine they aren't supposed to collide with each other) the menu at the top, if I click in the menu the event is being sent to the horizontal scrollview.
from kivy.app import App
from kivy.lang.builder import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.scrollview import ScrollView
Builder.load_string(
'''
<ScrollApp>:
orientation: 'vertical'
BoxLayout:
size_hint: 1, 0.12
Button:
text: 'Fixed Menu'
on_press: print('This button stops working if there is a horizontal scrollview "behind"')
ScrollView:
bar_width: 10
scroll_type: ['bars', 'content']
BoxLayout:
orientation: 'vertical'
size_hint: 1, None
height: self.minimum_height
padding: 22, 0, 22, 50
spacing: 50
canvas:
Color:
rgba: .15, .15, .15, .9
Rectangle:
size: self.size
pos: self.pos
Button:
size_hint: None, None
width: 100
height: 100
on_press: print('This button does not overlap the menu above')
# "ScrollViews containers"
Custom
Custom
Custom
Custom
Custom
BoxLayout:
size_hint: 1, 0.12
Button:
on_press: print("This menu at the bottom is not affected by the problem that occurs with the top one")
<Custom@BoxLayout>:
orientation: 'vertical'
size_hint: 1, None
height: self.minimum_height
Label:
size_hint: None, None
size: self.texture_size
id: label
font_size: 20
text: 'Teste'
ScrollView:
do_scroll: True, True
size_hint: 1, None
height: 150
GridLayout:
id: grid
size_hint: None, 1.01
width: self.minimum_width
spacing: 5
cols: 3
Button:
size_hint: None, None
size: 400, 150
on_press: print('ScrollView button pressed')
Button:
size_hint: None, None
size: 400, 150
on_press: print('ScrollView button pressed')
Button:
size_hint: None, None
size: 400, 150
on_press: print('ScrollView button pressed')
''' )
class ScrollApp(BoxLayout):
pass
class Test(App):
def build(self):
return ScrollApp()
Test().run()
推荐答案
您确实设法在奇异果中发现了晦涩的情况:-).
You do manage to find obscure situations in kivy :-).
我相信这里的问题是触摸事件处理的顺序.触摸事件通常由顶级窗口小部件处理,并且将事件一直分配给其子级,直到Widget
树.在具有多个子代的任何Widget
中,touch事件均以与添加到其父代的相反顺序分派给子代.并且在kv
中,子Widgets
按其出现的顺序添加(从上到下).因此,在您的情况下,ScrollApp
有三个子级,触摸事件将从包含底部菜单的BoxLayout
开始分派给其子级,然后分派给ScrollView
,最后分派给ScrollView
在顶部菜单之前获取touch事件,并将触摸分配给它的子级(包括Custom
实例).因此,Custom
中的Buttons
会在顶部菜单看到触摸事件之前先看到触摸事件,然后他们将其声明为自己的事件.解决该问题的明显方法是更改ScrollApp
中出现的Widgets
的顺序,但是由于ScrollApp
是BoxLayout
,因此将大大改变App
的外观.另一种解决方法是使用不依赖于其子顺序的Layout
. FloatLayout
之类的东西具有这种特征.因此,这是代码的修改版本,使ScrollApp
扩展FloatLayout
而不是BoxLayout
:
I believe the problem here is the order of touch event processing. The touch events are normally processed by the top level widgets, and they dispatch the event to their children, all the way down the Widget
tree. In any Widget
with multiple children, the touch event is dispatched to children in the reverse order that they have been add to their parent. And in kv
, child Widgets
are added in order as they appear (top to bottom). So, in your case, the ScrollApp
has three children, and the touch events will be dispatched to its children starting with the BoxLayout
that contains the bottom menu, then to the ScrollView
, and lastly, to the BoxLayout
that contains the top menu. So the ScrollView
gets the touch event before the top menu, and dispatches the touch to its children (including the Custom
instances). So the Buttons
in the Custom
see the touch event before the top menu sees it, and they claim it as their own. The obvious way to fix it would be to change the order of Widgets
that appear in the ScrollApp
, but since ScrollApp
is a BoxLayout
, that would dramatically change how your App
looks. A different fix is to use a Layout
that doesn't depend on the order of its children. Something like a FloatLayout
has that characteristic. So, here is a modified version of your code, that makes ScrollApp
extend FloatLayout
instead of BoxLayout
:
from kivy.app import App
from kivy.lang.builder import Builder
from kivy.uix.floatlayout import FloatLayout
Builder.load_string(
'''
<ScrollApp>:
ScrollView:
size_hint: 1.0, 0.76
pos_hint: {'center_y':0.5}
bar_width: 10
scroll_type: ['bars', 'content']
BoxLayout:
orientation: 'vertical'
size_hint: 1, None
height: self.minimum_height
padding: 22, 0, 22, 50
spacing: 50
canvas:
Color:
rgba: .15, .15, .15, .9
Rectangle:
size: self.size
pos: self.pos
Button:
size_hint: None, None
width: 100
height: 100
on_press: print('This button does not overlap the menu above')
# "ScrollViews containers"
Custom
Custom
Custom
Custom
Custom
BoxLayout:
size_hint: 1, 0.12
pos_hint: {'y':0}
Button:
on_press: print("This menu at the bottom is not affected by the problem that occurs with the top one")
BoxLayout:
size_hint: 1, 0.12
pos_hint: {'top':1.0}
Button:
text: 'Fixed Menu'
on_press: print('This button stops working if there is a horizontal scrollview "behind"')
<Custom@BoxLayout>:
orientation: 'vertical'
size_hint: 1, None
height: self.minimum_height
Label:
size_hint: None, None
size: self.texture_size
id: label
font_size: 20
text: 'Teste'
ScrollView:
do_scroll: True, True
size_hint: 1, None
height: 150
GridLayout:
id: grid
size_hint: None, 1.01
width: self.minimum_width
spacing: 5
cols: 3
Button:
text: 'button 1'
size_hint: None, None
size: 400, 150
on_press: print('ScrollView button pressed')
Button:
text: 'button 2'
size_hint: None, None
size: 400, 150
on_press: print('ScrollView button pressed')
Button:
text: 'button 3'
size_hint: None, None
size: 400, 150
on_press: print('ScrollView button pressed')
''' )
class ScrollApp(FloatLayout):
pass
class Test(App):
def build(self):
return ScrollApp()
Test().run()
因此,通过ScrollApp
中的此子顺序,顶部菜单和底部菜单会在ScrollView
之前的触摸事件中得到显示.
So, with this child order in ScrollApp
, the top and bottom menus get their shot at the touch events before the ScrollView
.
我实际上认为您的代码无需进行此更改即可工作,因此可能发生了其他我找不到的事情.
I actually think your code should work without this change, so there may be something else happening that I couldn't find.
这篇关于Kivy的问题-滚动视图与其上方的框布局重叠的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!