忽略 ScrollView 中用于滚动交互的区域

Posted

技术标签:

【中文标题】忽略 ScrollView 中用于滚动交互的区域【英文标题】:Ignore area in ScrollView for scrolling interactions 【发布时间】:2016-06-13 03:04:46 【问题描述】:

假设我的 UI 改编自 ScrollView 示例:

from kivy.app import App
from kivy.uix.slider import Slider
from kivy.uix.label import Label
from kivy.uix.scrollview import ScrollView
from kivy.uix.gridlayout import GridLayout
from kivy.uix.boxlayout import BoxLayout

class ScrollViewApp(App):
    def build(self):
        layout = GridLayout(cols=1, padding=10, spacing=10,
                size_hint=(None, None), width=500)
        layout.bind(minimum_height=layout.setter('height'))
        for i in range(15):
            blt = BoxLayout(size_hint=(None, None), size=(480, 40))
            blt.add_widget(Label(text="Slider %d" % i))
            btn = Slider(value=i, min=0, max=42, size=(400, 40),
                         size_hint=(None, None))
            blt.add_widget(btn)
            layout.add_widget(blt)
        scroll = ScrollView(size_hint=(None, None), size=(500, 320),
                pos_hint='center_x': .5, 'center_y': .5, do_scroll_x=False)
        scroll.add_widget(layout)
        return scroll

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

由于scroll_timeout,与Sliders 的交互被延迟。是否可以在 ScrollView 中定义区域,其中 touch 事件只是无延迟(并且不启动滚动)传递给子级?

【问题讨论】:

等待船长 一年前我想要类似的东西,但没有成功。我认为这甚至可能无法实施。但为了确定起见,请在 irc 上询问。 @KeyWeeUsr 在下面看到我的答案,这似乎对我有用 【参考方案1】:

看看Widget touch event bubbling。

我从来不需要和你做同样的事情,但也许你可以创建一个自定义类来继承 ScrollView 并在你可以覆盖的地方覆盖 on_touch_down 事件:

    禁用滚动 致电super.on_touch_down 启用滚动。

另一种方法可能是创建一个自定义小部件,该小部件继承用户单击的 Slider 类。然后用return True 重载它的on_touch_down 方法。 Documentation says:

为了阻止此事件冒泡,这些方法之一必须返回 True

ScrollView 也会触发 on_scroll_start 事件,所以也许你可以在那里做类似的事情。

【讨论】:

感谢您的回答,@Martin。我知道我必须篡改on_touch_down,但不太清楚怎么做。好像我找到了一种方法(与您的建议不同)。【参考方案2】:

我想出了一个简单的覆盖ScrollViewon_touch_down,到目前为止似乎满足了我的需求。这个想法是测试触摸事件是否落入“排除区域”(在下面的示例中,仅检查 x 维度,但将其扩展到任意矩形区域是微不足道的)。如果它确实落入该禁区,on_touch_down 事件将被分派给ScrollView 的孩子。如果一个孩子抓住了它,这个事件就被吞没了。在所有其他情况下,将调用super.on_touch_down,即启动正常的滚动行为。如果触摸没有落在Slider 上(在问题的示例中),这样做的好处是仍然能够滚动。

class MSV(ScrollView):
    x_exclusion_lower = NumericProperty(None, allownone=True)
    x_exclusion_upper = NumericProperty(None, allownone=True)
    x_exclusion = ReferenceListProperty(x_exclusion_lower, x_exclusion_upper)

    def on_touch_down(self, touch):
        pos_in_sv = self.to_local(*touch.pos)
        if (self.x_exclusion_lower is not None or self.x_exclusion_upper is not None) and (self.x_exclusion_lower is None or self.x_exclusion_lower <= pos_in_sv[0]) and \
                (self.x_exclusion_upper is None or self.x_exclusion_upper >= pos_in_sv[0]):
            touch.push()
            touch.apply_transform_2d(self.to_local)
            if self.dispatch_children('on_touch_down', touch):
                return True
            touch.pop()
        super(MSV, self).on_touch_down(touch)

【讨论】:

以上是关于忽略 ScrollView 中用于滚动交互的区域的主要内容,如果未能解决你的问题,请参考以下文章

使用垂直 ScrollView 忽略水平安全区域

Scrollview 只检测特定区域的滚动?

如何设置scrollview的滚动区域在本身的上方

UIScrollView 可滚动区域未随 scrollView 框架约束更新而更新

UIColectionView Vertical Scrolling inside a Scrollview - 在集合视图区域中滚动时禁用滚动视图的滚动

在 SwiftUI 中,如何通过动态变化的滚动区域来缩放 scrollView 内的内容?