您当前的位置: 首页 > 

龚建波

暂无认证

  • 5浏览

    0关注

    312博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

QML 自定义 Loading 等待样式(一)

龚建波 发布时间:2021-01-17 15:58:13 ,浏览量:5

QML 自带的 BusyIndicator 自定义效果不大理响,所以自己做了一些 Loading 样式。

(新增了两种样式:https://gongjianbo1992.blog.csdn.net/article/details/122824084)

本文效果如下:

代码链接(CustomLoading1 / 2):https://github.com/gongjianbo/QmlComponentStyle

实现代码:

import QtQuick 2.12
import QtQuick.Controls 2.12

//自定义 loading 效果
//龚建波 2021-1-17
Item {
    id: control

    //item圆圈个数
    property int itemCount: 10
    //item圆圈直径大小
    property int itemSize: 16
    //item变大范围
    property int itemExpand: 10
    //item圆圈颜色
    property color itemColor: "green"
    //当前item,配合动画
    property int itemIndex: 0
    //轮转一次的时长
    property int duration: 1500
    //
    property bool running: visible

    implicitHeight: 160
    implicitWidth: 160

    //index从0到count轮转,转到对应item就变大且不透明
    //animation也可以换成timer
    NumberAnimation{
        target: control
        property: "itemIndex"
        from: 0
        to: control.itemCount-1
        loops: Animation.Infinite
        duration: control.duration
        running: control.running
    }

    //加一层item.margin来容纳item大小变化
    Item{
        id: content
        anchors.fill: parent
        anchors.margins: control.itemExpand/2+1

        Repeater{
            id: repeater
            model: control.itemCount
            Rectangle{
                id: item
                height: control.itemSize
                width: height
                x: content.width/2 - width/2
                y: content.height/2 - height/2
                radius: height/2
                color: control.itemColor

                //环绕在中心
                transform: [
                    Translate {
                        y: content.height/2-height/2
                    },
                    Rotation {
                        angle: index / repeater.count * 360
                        origin.x: width/2
                        origin.y: height/2
                    }
                ]

                //轮转到当前item时就切换状态
                state: control.itemIndex===index?"current":"normal"
                states: [
                    State {
                        name: "current"
                        PropertyChanges {
                            target: item
                            opacity: 1
                            height: control.itemSize+control.itemExpand
                        }
                    },
                    State {
                        name: "normal"
                        PropertyChanges {
                            target: item
                            opacity: 0.1
                            height: control.itemSize
                        }
                    }
                ]

                //大小和透明度的状态过渡
                transitions: [
                    Transition {
                        from: "current"
                        to: "normal"
                        NumberAnimation{
                            properties: "opacity,height"
                            duration: control.duration
                        }
                    },
                    Transition {
                        from: "normal"
                        to: "current"
                        NumberAnimation{
                            properties: "opacity,height"
                            duration: 0
                        }
                    }
                ]
            }
        }
    }
}
import QtQuick 2.12
import QtQuick.Controls 2.12

//自定义 loading 效果
//目前角度是设定死的,可以根据直径算
//龚建波 2021-1-17
Item {
    id: control

    //item圆圈个数
    property int itemCount: 4
    //item圆圈直径
    property int itemSize: 20
    //item圆圈颜色
    property color itemColor: "green"
    //转一次时长
    property int duration: 3000
    //
    property bool running: visible

    implicitHeight: 160
    implicitWidth: 160

    Item{
        id: content
        anchors.fill: parent
        anchors.margins: 5

        Repeater{
            id: repeater
            model: control.itemCount

            //长方形wrapper用来旋转
            Item{
                id: wrapper
                width: control.itemSize
                height: content.height
                x: content.width/2-width/2
                //todo 目前角度是设定死的,可以根据直径算
                rotation: -index*20

                //动画序列,根据顺序做了间隔
                SequentialAnimation {
                    running: control.running
                    loops: Animation.Infinite
                    NumberAnimation{
                        duration: index*100
                    }
                    ParallelAnimation{
                        RotationAnimation{
                            target: wrapper
                            from: -index*20
                            to: 360-index*20
                            duration: control.duration
                            easing.type: Easing.OutCubic
                        }
                        SequentialAnimation{
                            NumberAnimation{
                                target: item
                                property: "opacity"
                                from: 0
                                to: 1
                                duration: control.duration*1/8
                            }
                            NumberAnimation{
                                duration: control.duration*3/4
                            }
                        }
                    }
                    NumberAnimation{
                        duration: (control.itemCount-index)*100
                    }
                }

                //小圆圈
                Rectangle{
                    id: item
                    height: control.itemSize
                    width: height
                    radius: height/2
                    color: control.itemColor
                }
            }
        }
    }
}

2021-2-11 优化了第二个 loading:

import QtQuick 2.12
import QtQuick.Controls 2.12

//自定义 loading 效果
//目前角度是设定死的,可以根据直径算
//龚建波 2021-1-17
//2021-2-11代码优化
Item {
    id: control

    //item圆圈个数
    property int itemCount: 4
    //item圆圈直径
    property int itemSize: 20
    //item圆圈颜色
    property color itemColor: "green"
    //转一次时长
    property int duration: 3000
    //
    property bool running: visible

    implicitHeight: 160
    implicitWidth: 160

    Item{
        id: content
        anchors.fill: parent
        anchors.margins: 5 + control.itemSize/2

        Repeater{
            id: repeater
            model: control.itemCount

            //旋转的小球
            Rectangle{
                id: item
                width: control.itemSize
                height: control.itemSize
                color: control.itemColor
                radius: width/2
                //[1].圆边上点坐标计算公式(角度从右端逆时针增长)
                //x1 = x0 + r * cos(angle * PI / 180)
                //y1 = y0 + r * sin(angle * PI /180)
                //[2].js Math用的弧度
                //1弧度bai=180/pai 度
                //1度=pai/180 弧度
                //[3].Qt是屏幕坐标系,所以y值取反一下
                //y1 = y0 - r * sin(angle * PI /180)
                //再把相位调到90度从顶上开始转,这样三角函数可以简化下
                //sin(π/2+α)=cosα
                //cos(π/2+α)=-sinα
                //于是有了
                //x1 = x0 - r * sin(angle * PI / 180)
                //y1 = y0 - r * cos(angle * PI /180)
                //[4].此时逐渐增大角度就是逆时针转的,想要顺时针转又得再取反一次坐标
                //或者改为逐渐减小
                //我选择取反x
                //x1 = x0 + r * sin(angle * PI / 180)
                //[5].最后把小球的半径偏移去掉,就是围绕圆心转的效果了
                //不然默认起点为左上角,会往右下角偏离一点
                //(我把wrapper的margin加了size/2,这样就不用减掉半径放值越界了)
                x: content.width/2 - control.itemSize/2 + content.width/2 * Math.sin(rotate/360*6.283185307179)
                y: content.height/2 - control.itemSize/2 - content.height/2 * Math.cos(rotate/360*6.283185307179)
                //rotate表示角度,范围[0,360],初始值目前为固定的
                property real rotate: -index*20


                //动画序列,根据顺序做了间隔
                SequentialAnimation {
                    running: control.running
                    loops: Animation.Infinite
                    NumberAnimation{
                        duration: index*100
                    }
                    ParallelAnimation{
                        NumberAnimation{
                            target: item
                            property: "rotate"
                            from: -index*20
                            to: 360-index*20
                            duration: control.duration
                            easing.type: Easing.OutCubic
                        }
                        SequentialAnimation{
                            NumberAnimation{
                                target: item
                                property: "opacity"
                                from: 0
                                to: 1
                                duration: control.duration*1/8
                            }
                            NumberAnimation{
                                duration: control.duration*3/4
                            }
                        }
                    }
                    NumberAnimation{
                        duration: (control.itemCount-index)*100
                    }
                }
            }
        }
    }
}

关注
打赏
1655829268
查看更多评论
立即登录/注册

微信扫码登录

0.1040s