用Qt Quick实现Coverflow效果

来源:互联网 发布:360全景系统源码 编辑:程序博客网 时间:2024/05/01 02:43

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

 

好了我们切入主题:

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


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


还是非常的小清新嘛- -

 

来讲一下实现原理吧。

准备工作:

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

[plain] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. Text {  
  2.                 color: "#ffffff"  
  3.                 font.family: "ArialBlack"  
  4.                 font.pointSize: 60  
  5.    
  6.                 anchors.centerIn: parent  
  7.    
  8.                 text: index  
  9.             }  


 

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

anchors.centerIn:parent

 

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

[plain] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. transform: [  
  2.                 Rotation {  
  3.                     id: rotate; angle: 0;origin.y: 125; origin.x: 125;  axis { x:0; y: 1; z: 0 }  
  4.                     Behavior on angle {  
  5.                         NumberAnimation {easing.overshoot: 1; easing.type: Easing.OutBack; duration: 600 }  
  6.                     }  
  7.                 },  
  8.                 Translate {  
  9.                     id: trans; x: 0  
  10.                     Behavior on x {  
  11.                         NumberAnimation {easing.overshoot: 1; easing.type: Easing.OutBack; duration: 600;  }  
  12.                     }  
  13.                 }  
  14.             ]  


 

为了实现动画效果,可以看到我在变换对象中直接用了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

 

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

[plain] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. states: [  
  2.                 State {  
  3.                     name: "pos3"  
  4.                     PropertyChanges {  
  5.                         target: rotate  
  6.                         angle: 0  
  7.                     }  
  8.                     PropertyChanges {  
  9.                         target: trans  
  10.                         x: 0  
  11.                     }  
  12.                     PropertyChanges {  
  13.                         target: rect1  
  14.                         z: 1  
  15.                     }  
  16.                 },  
  17.    
  18.                 State {  
  19.                     name: "pos2"  
  20.                     PropertyChanges {  
  21.                         target: rotate  
  22.                         angle: 50  
  23.                     }  
  24.                     PropertyChanges {  
  25.                         target: trans  
  26.                         x: -150  
  27.                     }  
  28.                     PropertyChanges {  
  29.                         target: rect1  
  30.                         z: 0  
  31.                     }  
  32.                 },  
  33.    
  34.                 State {  
  35.                     name: "pos1"  
  36.                     PropertyChanges {  
  37.                         target: rotate  
  38.                         angle: 55  
  39.                     }  
  40.                     PropertyChanges {  
  41.                         target: trans  
  42.                         x: -180  
  43.                     }  
  44.                     PropertyChanges {  
  45.                         target: rect1  
  46.                         opacity: 0  
  47.                     }  
  48.                     PropertyChanges {  
  49.                         target: rect1  
  50.                         z: 0  
  51.                     }  
  52.                 },  
  53.    
  54.                 State {  
  55.                     name: "pos5"  
  56.                     PropertyChanges {  
  57.                         target: rotate  
  58.                         angle: -55  
  59.                     }  
  60.                     PropertyChanges {  
  61.                         target: trans  
  62.                         x: 180  
  63.                     }  
  64.                     PropertyChanges {  
  65.                         target: rect1  
  66.                         opacity: 0  
  67.                     }  
  68.                     PropertyChanges {  
  69.                         target: rect1  
  70.                         z: 0  
  71.                     }  
  72.                 },  
  73.    
  74.                 State {  
  75.                     name: "pos4"  
  76.                     PropertyChanges {  
  77.                         target: rotate  
  78.                         angle: -50  
  79.                     }  
  80.                     PropertyChanges {  
  81.                         target: trans  
  82.                         x: 150  
  83.                     }  
  84.                     PropertyChanges {  
  85.                         target: rect1  
  86.                         opacity: 1  
  87.                     }  
  88.                     PropertyChanges {  
  89.                         target: rect1  
  90.                         z: 0  
  91.                     }  
  92.                 }  
  93.             ]  


 

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

 

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

[plain] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. Repeater {  
  2.         id: repeater  
  3.         model: 20  
  4.    
  5.         property int currentItem  
  6.         ...  
  7. }  


 

 

代码实现:

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

[plain] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. Component.onCompleted:{  
  2.         repeater.currentItem = 2;  
  3.    
  4.         for (var i = 0; i < repeater.count;i++)  
  5.         {  
  6.             var item = repeater.itemAt(i);  
  7.             item.currentState = i + 1;  
  8.    
  9.             item.color =Qt.rgba(Math.random(125), Math.random(125), Math.random(125), 255);  
  10.    
  11.             if (item.currentState >= 1&& item.currentState <= 5)  
  12.             {  
  13.                 item.state = "pos" +item.currentState;  
  14.             } else {  
  15.                 item.state = "pos5";  
  16.             }  
  17.         }  
  18.    
  19.         label.text = "Current: " +repeater.currentItem;  
  20.     }  


 

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

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

[plain] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. onClicked: {  
  2.             repeater.currentItem += 1;  
  3.    
  4.             if (repeater.currentItem >repeater.count - 1)  
  5.             {  
  6.                 repeater.currentItem = 0;  
  7.             }  
  8.    
  9.             for (var i = 0; i <repeater.count; i++)  
  10.             {  
  11.                 var item = repeater.itemAt(i);  
  12.    
  13.                 item.currentState -= 1;  
  14.    
  15.                 if (item.currentState < 1)  
  16.                 {  
  17.                     item.currentState =repeater.count;  
  18.                 }  
  19.    
  20.                 if (item.currentState >= 1&& item.currentState <= 5)  
  21.                 {  
  22.                     item.state ="pos" + item.currentState;  
  23.                 }  
  24.             }  
  25.    
  26.             label.text = "Current: "+ repeater.currentItem;  
  27.         }  


 

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

0 0
原创粉丝点击