当前位置:   article > 正文

QML ListView实现TabBar标签拖拽交换位置效果_qml listview 滑动到指定位置

qml listview 滑动到指定位置

前言

QML中TabBar要实现标签移动效果比较麻烦,不像QTabBar控件那样可以设置属性后就能移动,虽然在父类Container中提供了moveItem接口,但是要实现拖拽交换的视觉效果还是没那么容易。
本demo使用QML的ListView来实现该功能,并动态切换对应的page内容。demo提供了动态添加页、删除页、移动交换标签位置功能。

先来看效果图:
在这里插入图片描述
Demo说明:

  • 1.点击顶部“Add Panel”按钮,可以动态添加tab标签及对应的页面,名称相对应;
  • 2.按住标签左右拖拽可交换标签位置;
  • 3.当前页在标签上会显示关闭按钮,点击后会删除标签项及对应的页面;

本文Demo在这里
点击下载


关键代码

ListView{
     id:tabBar
     anchors.left: parent.left
     anchors.right: parent.right
     interactive: false
     anchors.leftMargin: 20
     z:15
     height: 30
     spacing: 1
     orientation:ListView.Horizontal
     currentIndex: 0
     move: Transition {
         NumberAnimation { property: "x"; duration: 150 }
     }
     moveDisplaced: Transition {
         NumberAnimation { property: "x"; duration: 150 }
     }
     model:ListModel{
         id:tabModel
     }

     delegate: TabButton{
         id:tabButton
         height: 30
         width: 120

         contentItem: Text {
             font.pixelSize: 14
             font.family: "微软雅黑"
             text: name
             horizontalAlignment: Text.AlignHCenter
             verticalAlignment: Text.AlignVCenter
             color: tabBar.currentIndex === index ? "#3692F0" :"#525252"
             elide: Text.ElideMiddle
         }

         background:Item{
             Rectangle {
                 color: tabBar.currentIndex === index ? "#171717" : "transparent"
                 border.width: tabBar.currentIndex === index ? 1 : 0
                 border.color: "#404040"
                 height: parent.height+3
                 width: parent.width
                 x:-1;y:-2
                 Rectangle{
                     y:parent.height-1
                     width: parent.width
                     height: 3
                     color: "#171717"
                     visible: tabBar.currentIndex === index
                     z:20
                 }
             }
         }

         Image {
             id: closeBtn
             source: "qrc:/icon/close.png"
             anchors.verticalCenter: parent.verticalCenter
             anchors.right: parent.right
             anchors.rightMargin: 8
             visible: tabBar.currentIndex === index
             width: 10;height: 10
             smooth: true
             z:20

             MouseArea{
                 anchors.fill: parent
                 onClicked: {
                     removeData(name)
                 }
             }
         }

         MouseArea{
             id:ma2
             anchors.fill: parent
             preventStealing: true
             hoverEnabled: true
             onPositionChanged: {
                 var _index= tabBar.indexAt(ma2.mouseX + tabButton.x, ma2.mouseY + tabButton.y);
                 if (_index!== -1 && pressed) {
                     if (index !== _index) {
                         tabModel.move(index, _index,1);
                         tabBar.positionViewAtIndex(_index,ListView.Center)
                     }
                 }
             }
             onClicked: {
                 tabBar.currentIndex = index
             }
         }
     }
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94

ListView中每一项Item使用TabButton来实现,而拖拽交换位置是在MouseArea中onPositionChanged进行。
动画效果:

move: Transition {
    NumberAnimation { property: "x"; duration: 150 }
}
moveDisplaced: Transition {
    NumberAnimation { property: "x"; duration: 150 }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

可设定动画时间。

而tab对应的页面是放在栈布局中,通过Repeater结合ObjectModel来填充对应内容:

StackLayout{
    id:stackLayout
    anchors.top: tabBar.top
    anchors.topMargin: 1
    anchors.bottom: parent.bottom
    width: parent.width

    Repeater{

        model:ObjectModel{
            id:itemModel
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

model 数据填充是动态创建并添加

let _name = "Panel #" + panelIndex++
let component = Qt.createComponent("CusPanel.qml")
if(component.status === Component.Ready){
    var panel = component.createObject(stackLayout)
    panel.name = _name
    itemModel.append(panel)
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

需要注意的是,这里tabModel是标签对应的model,而itemModel是页面item的model,这两个model的当前索引不一样,因为移动tab标签时itemModel并没有改变。所以在tabModel的当前索引变化时,需要动态找到对应的页面并实时切换itemModel的当前索引。二者的联系是通过属性name来查找。


本文Demo在这里
点击下载


声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/煮酒与君饮/article/detail/806075
推荐阅读
相关标签
  

闽ICP备14008679号