漂亮!用Qt Quick实现Coverflow效果

趁着放假又拾起了很久不动的Qt了,本想在假期写点什么程序,但是到现在一点想法也没有,也就算了。今天写这个Coverflow效果纯属无聊的Play,没有太多技术含量,重要的是没用到数学和几何知识。程序用了Qt 5.2 + QtQuick 2.0架构,纯qml语言,有兴趣的童鞋可以试着完善它,我已经将源代码提交到Github上了。

 

好了我们切入主题:

为了写这个效果,我非常仔细的研究了Finder中的Coverflow效果,发现它是这样的:

漂亮!用Qt Quick实现Coverflow效果_第1张图片

我认为写出Finder中的那种效果应该还需要一定的数学知识,毕竟它是实时变化的,也就是画面的布局是随窗口大小而动态调整的。于是我设计了一个一屏只有三页的Coverflow效果:

漂亮!用Qt Quick实现Coverflow效果_第2张图片

还是非常的小清新嘛- -

 

来讲一下实现原理吧。

准备工作:

首先需要创建一个Rectangle元素,在里面放一个Text元素:

Text {
                color: "#ffffff"
                font.family: "ArialBlack"
                font.pointSize: 60
 
                anchors.centerIn: parent
 
                text: index
            }


 

为了方便定位,我使用了anchors属性:

anchors.centerIn:parent

 

然后一个比较重要的属性transform我给它赋了RotationTranslate两种变换,我们一会要用到它:

transform: [
                Rotation {
                    id: rotate; angle: 0;origin.y: 125; origin.x: 125;  axis { x:0; y: 1; z: 0 }
                    Behavior on angle {
                        NumberAnimation {easing.overshoot: 1; easing.type: Easing.OutBack; duration: 600 }
                    }
                },
                Translate {
                    id: trans; x: 0
                    Behavior on x {
                        NumberAnimation {easing.overshoot: 1; easing.type: Easing.OutBack; duration: 600;  }
                    }
                }
            ]


 

为了实现动画效果,可以看到我在变换对象中直接用了Behavior动画,这样比较方便。

 

状态的定义:

然后我们来看一下这个效果整体应该怎么实现。

首先一个元素拥有五种状态,分别是:在最左边(消失)、在左边、在中间、在右边、在最右边(消失)。也就是能够看到的只有三个状态。然后我们定义一下五种状态:

1.      透明度:0,角度:55x轴变换: -180

2.      透明度:1,角度:50x轴变换: -150

3.      透明度:1,角度:0x轴变换:0

4.      透明度:1,角度:-50x轴变换:150

5.      透明度:0,角度:-55x轴变换:180

 

那么我们就可以定义一个元素的状态了:

states: [
                State {
                    name: "pos3"
                    PropertyChanges {
                        target: rotate
                        angle: 0
                    }
                    PropertyChanges {
                        target: trans
                        x: 0
                    }
                    PropertyChanges {
                        target: rect1
                        z: 1
                    }
                },
 
                State {
                    name: "pos2"
                    PropertyChanges {
                        target: rotate
                        angle: 50
                    }
                    PropertyChanges {
                        target: trans
                        x: -150
                    }
                    PropertyChanges {
                        target: rect1
                        z: 0
                    }
                },
 
                State {
                    name: "pos1"
                    PropertyChanges {
                        target: rotate
                        angle: 55
                    }
                    PropertyChanges {
                        target: trans
                        x: -180
                    }
                    PropertyChanges {
                        target: rect1
                        opacity: 0
                    }
                    PropertyChanges {
                        target: rect1
                        z: 0
                    }
                },
 
                State {
                    name: "pos5"
                    PropertyChanges {
                        target: rotate
                        angle: -55
                    }
                    PropertyChanges {
                        target: trans
                        x: 180
                    }
                    PropertyChanges {
                        target: rect1
                        opacity: 0
                    }
                    PropertyChanges {
                        target: rect1
                        z: 0
                    }
                },
 
                State {
                    name: "pos4"
                    PropertyChanges {
                        target: rotate
                        angle: -50
                    }
                    PropertyChanges {
                        target: trans
                        x: 150
                    }
                    PropertyChanges {
                        target: rect1
                        opacity: 1
                    }
                    PropertyChanges {
                        target: rect1
                        z: 0
                    }
                }
            ]


 

注意一个细节,为了使最中间的元素在最前端,我还设置了z值,它决定了元素的排列顺序,最中间的z值为1,其他为0,这样中间的元素就不会被遮挡了。

 

然后我们再用Repeater组件来批量生成20Rectangle对象,并为这个Repeater定义一个property来指示当前在中间的元素的index

Repeater {
        id: repeater
        model: 20
 
        property int currentItem
        ...
}


 

 

代码实现:

好了,准备工作就绪了,我们来实现初始化操作,首先响应onCompleted事件:

Component.onCompleted:{
        repeater.currentItem = 2;
 
        for (var i = 0; i < repeater.count;i++)
        {
            var item = repeater.itemAt(i);
            item.currentState = i + 1;
 
            item.color =Qt.rgba(Math.random(125), Math.random(125), Math.random(125), 255);
 
            if (item.currentState >= 1&& item.currentState <= 5)
            {
                item.state = "pos" +item.currentState;
            } else {
                item.state = "pos5";
            }
        }
 
        label.text = "Current: " +repeater.currentItem;
    }


 

上面的代码为Rectangle设置了颜色,并给它们设置了各自的状态,从左边依次状态数递增1,其中有效的状态数是1~5,所以只有1~5的状态被应用到Rectangle的状态机中,其余的我们然他的状态为5,也就是先在最右面藏着。

然后我们建一个Next按钮,响应它的onClicked事件:

onClicked: {
            repeater.currentItem += 1;
 
            if (repeater.currentItem >repeater.count - 1)
            {
                repeater.currentItem = 0;
            }
 
            for (var i = 0; i = 1&& item.currentState <= 5)
                {
                    item.state ="pos" + item.currentState;
                }
            }
 
            label.text = "Current: "+ repeater.currentItem;
        }


 

这样,Coverflow的雏形就完成了,而且基本没用到什么算法,就是对列表的一个简单的应用!是不是比较简单呢?

 

下面是视频展示:

http://v.youku.com/v_show/id_XNjY2ODA0NDY0.html

 

源代码Github

 

 


你可能感兴趣的:(Qt)