趁着放假又拾起了很久不动的Qt了,本想在假期写点什么程序,但是到现在一点想法也没有,也就算了。今天写这个Coverflow效果纯属无聊的Play,没有太多技术含量,重要的是没用到数学和几何知识。程序用了Qt 5.2 + QtQuick 2.0架构,纯qml语言,有兴趣的童鞋可以试着完善它,我已经将源代码提交到Github上了。
好了我们切入主题:
为了写这个效果,我非常仔细的研究了Finder中的Coverflow效果,发现它是这样的:
我认为写出Finder中的那种效果应该还需要一定的数学知识,毕竟它是实时变化的,也就是画面的布局是随窗口大小而动态调整的。于是我设计了一个一屏只有三页的Coverflow效果:
还是非常的小清新嘛- -
来讲一下实现原理吧。
准备工作:
首先需要创建一个Rectangle元素,在里面放一个Text元素:
Text {
color: "#ffffff"
font.family: "ArialBlack"
font.pointSize: 60
anchors.centerIn: parent
text: index
}
为了方便定位,我使用了anchors属性:
anchors.centerIn:parent
然后一个比较重要的属性transform我给它赋了Rotation和Translate两种变换,我们一会要用到它:
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,角度:55,x轴变换: -180
2. 透明度:1,角度:50,x轴变换: -150
3. 透明度:1,角度:0,x轴变换:0
4. 透明度:1,角度:-50,x轴变换:150
5. 透明度:0,角度:-55,x轴变换: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组件来批量生成20个Rectangle对象,并为这个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