在 SwipeDelegate 上禁用滑动多个项目

Posted

技术标签:

【中文标题】在 SwipeDelegate 上禁用滑动多个项目【英文标题】:Disable swiping multi items on SwipeDelegate 【发布时间】:2017-09-25 06:46:57 【问题描述】:

默认情况下,SwipeDelegate 允许滑动多个项目,如下图:

如您所见,多次滑动项目一次打开,我一次只想要一个打开的项目,这意味着如果您打开项目 #1,通过打开项目 #2,项目 #1 应该关闭。我怎样才能做到这一点?

带有 SwipeDelegate 的 ListView 的示例代码:

ListView 
    id: listView
    anchors.fill: parent

    delegate: SwipeDelegate 
        id: delegate

        text: modelData
        width: parent.width

        swipe.right: Rectangle 
            width: parent.width
            height: parent.height

            Label 
                text: qsTr("SOME ACTION BUTTON")

                padding: 20
                anchors.fill: parent
            

        
    

    model: ListModel 
        id: listModel
        ListElement  text: "Lorem ipsum dolor sit amet" 
        ListElement  text: "Curabitur sit amet risus" 
        ListElement  text: "Suspendisse vehicula nisi" 
        ListElement  text: "Mauris imperdiet libero" 
        ListElement  text: "Sed vitae dui aliquet augue" 
        ListElement  text: "Praesent in elit eu nulla" 
        ListElement  text: "Etiam vitae magna" 
        ListElement  text: "Pellentesque eget elit euismod" 
        ListElement  text: "Nulla at enim porta" 
        ListElement  text: "Fusce tincidunt odio" 
        ListElement  text: "Ut non ex a ligula molestie" 
        ListElement  text: "Nam vitae justo scelerisque" 
        ListElement  text: "Vestibulum pulvinar tellus" 
        ListElement  text: "Quisque dignissim leo sed gravida" 
    


    ScrollIndicator.vertical: ScrollIndicator  

【问题讨论】:

请输入代码。 help/MCVE 能否提供minimal reproducible example @derM 我添加一个示例代码,代码是this official example的缩小版 @EligijusPupeikis 我添加一个例子。 【参考方案1】:

我会这样做:

import QtQuick 2.9
import QtQuick.Controls 2.3
import QtGraphicalEffects 1.0

ApplicationWindow 
    id: window
    width: 800
    height: 600
    visible: true

    ListView 
        id: listView
        anchors.fill: parent

        ButtonGroup 
            buttons: listView.contentItem.children
        

        delegate: SwipeDelegate 
            id: delegate

            checkable: true
            text: modelData
            width: parent.width
            checked: swipe.complete
            onCheckedChanged: if (!checked) swipe.close()

            swipe.right: Rectangle 
                width: parent.width
                height: parent.height
                color: "#666"

                Label 
                    text: qsTr("SOME ACTION BUTTON")
                    color: "white"
                    leftPadding: 20
                    anchors.verticalCenter: parent.verticalCenter
                
            
        

        model: ListModel 
            id: listModel
            ListElement  text: "Lorem ipsum dolor sit amet" 
            ListElement  text: "Curabitur sit amet risus" 
            ListElement  text: "Suspendisse vehicula nisi" 
            ListElement  text: "Mauris imperdiet libero" 
            ListElement  text: "Sed vitae dui aliquet augue" 
            ListElement  text: "Praesent in elit eu nulla" 
            ListElement  text: "Etiam vitae magna" 
            ListElement  text: "Pellentesque eget elit euismod" 
            ListElement  text: "Nulla at enim porta" 
            ListElement  text: "Fusce tincidunt odio" 
            ListElement  text: "Ut non ex a ligula molestie" 
            ListElement  text: "Nam vitae justo scelerisque" 
            ListElement  text: "Vestibulum pulvinar tellus" 
            ListElement  text: "Quisque dignissim leo sed gravida" 
        


        ScrollIndicator.vertical: ScrollIndicator  
    

ButtonGroup 确保一次只能检查一个“按钮”(SwipeDelegate 派生自 AbstractButton)。 SwipeDelegate 没有视觉效果来表示选中状态,因此我们可以安全地使用它来跟踪应该打开哪个状态。我们仍然需要关闭之前打开的委托,所以这就是

onCheckedChanged: if (!checked) swipe.close()

进来。

【讨论】:

如果您想在拖动另一个时立即关闭当前的,也可以使用checked: swipe.position !== 0 @GrecKo 您的解决方案不起作用,当项目 #1 开始打开时,项目 #2 应该开始关闭,因此两个项目的位置同时发生变化,并导致某种不可预测的行为。跨度> @Elsiete 很有趣,我做了一个快速测试,它可以正常工作,但它可能不是很健壮。可以改成pressed && swipe.position !== 0 || swipe.complete,可以去掉位置检查事件。 @GrecKo 是的,现在它就像一个魅力。有趣的是,我尝试了pressed && swipe.position !== 0 并没有弄清楚为什么它不起作用,但是当我看到你的评论时,一切都变得清晰了,谢谢。 @Elsiete:该死的......你不应该这样做,但很高兴知道。您可以关注此报告:bugreports.qt.io/browse/QTBUG-63470【参考方案2】:

受 ButtonGroup 答案的启发,这是我不需要修改代表的解决方案:

SwipeDelegateGroup.qml

import QtQuick 2.9
import QtQuick.Controls 2.2

Item 
    id: swipeGroup

    property ListView listView: parent
    QtObject 
        id: d
        property var delegates: swipeGroup.listView.contentItem.children
        property var delegateCache: []

        onDelegatesChanged: 
            for (var i = 0; i < d.delegates.length; i++) 
                var thisItem = d.delegates[i];
                if (!thisItem.hasOwnProperty("swipe")) 
                    continue;
                
                if (d.delegateCache.indexOf(thisItem) < 0) 
                    d.delegateCache.push(thisItem);

                    thisItem.Component.destruction.connect(function() 
                        d.delegateCache.splice(d.delegateCache.indexOf(thisItem), 1)
                    )

                    thisItem.swipe.opened.connect(function() 
                        for (var j = 0; j < d.delegates.length; j++) 
                            var otherItem = d.delegates[j];
                            if (thisItem === otherItem) 
                                continue;
                            
                            if (!otherItem.hasOwnProperty("swipe")) 
                                continue;
                            
                            otherItem.swipe.close();
                        
                    )
                
            
        
    


然后像这样把它放到 ListView 中:

ListView 

    SwipeDelegateGroup 

    delegate: SwipeDelegate 
        ...
    

【讨论】:

以上是关于在 SwipeDelegate 上禁用滑动多个项目的主要内容,如果未能解决你的问题,请参考以下文章

仅在 UIPageViewController 上的某个方向上禁用用户滑动?

当用户直接点击标签栏项目时,如何禁用滑动动画?

暂时禁用手势识别器滑动功能

在 xcode 的 SideMenu 库上禁用滑动/手势

禁用滑动以在 UIWebView 上滚动但保留拖动/平移

如何禁用 ScrollView 项目上的多个按钮颜色选择?