详解Qt动画框架(2)--- 实现网易云音乐tag切换

来源:互联网 发布:开淘宝店铺照片要求 编辑:程序博客网 时间:2024/06/06 21:50

详解Qt的动画框架(一)介绍了关于Qt动画框架一些基础知识,在这一节中,将会实际的看到有关与动画框架的实现,该案例主要实现的具体是网易云音乐tag的切换,网易云音乐中的切换如图所示:

本文介绍的方法也可以达到这种切换的简易效果。

  • 设计动画框架

首先我们需要设计对于动画框架,其需要的动画效果是什么?对于上图,我们需要的是三个tag可以不停的切换,可以抽象为左移以及右移,即一个tag从一个矩形区域,移动到另外的矩形区域,那么对于Tag的承载体选为什么较为合适呢?因为我们仅仅只需要图片的显示,因此QLabel引进足够,而且QLabel继承于QFrame(继承自QWidget),因此拥有geometry的属性,恰恰其类型是QRect,因此可以达到动画效果的所有需求,不需要另外的定制属性(property)。

  • 动画实现

设计好动画框架后,既可以开始代码实现所有的动作了。以下是头文件的声明定义:

#ifndef MAINWINDOW_H#define MAINWINDOW_H#include <QMainWindow>#include<vector>using namespace std;class QLabel;class QToolBar;class QPropertyAnimation;class MainWindow : public QMainWindow{    Q_OBJECTprotected slots:    void onTriggerAction(QAction *);public:    MainWindow(QWidget *parent = 0);    ~MainWindow();private:    void moveLeft();    void moveRight();    QRect center_rect;    QRect left_rect;    QRect right_rect;    QLabel *center_label;    QLabel *left_label;    QLabel *right_label;    QPropertyAnimation *moveAnimation;    QPropertyAnimation *moveAnimation_left;    QPropertyAnimation *moveAnimation_right;    int mainCnt;    //下方的2个横线控件    QToolBar *transferBar;    vector<QPixmap> label_group;};#endif // MAINWINDOW_H
代码分析

  • 首先,横线控件是为了定义左移和右移动作的发起,它们是属于QToolBar的两个按钮控件,即transferBar。三个QLabel是动作的承载体,即target。是QPropertyAnimation构造时需要使用的。
  • 然后是三个矩形框的定义,这是动画切换的起始位置的界定。
  • 其次是三个QPropertyAnimation的定义,是控制三个QLabel的移动的。
  • 最后mainCnt是为了很好的实时定位到tag切换到位置,从而控制动画的效果。
接着是具体的实现方式了,首先看初始化:

MainWindow::MainWindow(QWidget *parent)    : QMainWindow(parent){    resize(1000,400);    mainCnt=3;    //在widget上画三个矩形框,实现动画切换,第一个大小为200 & 540 左右两边大小均为188*110    for(int label_num=0;label_num<3;label_num++)    {        QPixmap temp_label=QPixmap(":/images/"+QString::number(label_num+1)+".png");        label_group.push_back(temp_label);    }    int width=this->width();    int height=this->height();/**  设置中心控件的位置以及大小*/    int pos_x=(width-center_width)/2;    int pos_y=(height-center_hieght)/2;    center_rect.setRect(pos_x,pos_y,center_width,center_hieght);    center_label =new QLabel(this);    center_label->setPixmap(label_group[0]);    //center_label->setScaledContents(true);    center_label->setGeometry(pos_x,pos_y,center_width,center_hieght);//---------------------------------------------------------------------------------//  /**       设置底部窗口转换的工具栏属性   */       transferBar = new QToolBar(this);       transferBar->setGeometry(pos_x+center_width/2-40,pos_y+center_hieght+20,90,10);       transferBar->setStyleSheet("background:transparent");       transferBar->setIconSize(QSize(20,5));       for(int actions_num=0;actions_num<2;actions_num++)       {          QAction *action=new QAction(QIcon(":/images/line.png"),"",transferBar);          action->setData(actions_num);          transferBar->addAction(action);       }      connect(transferBar,SIGNAL(actionTriggered(QAction *)),this,SLOT(onTriggerAction(QAction*))); /**    设置右边控件的位置和大小*/    right_rect.setRect(pos_x+center_width,pos_y+(center_hieght-margin_height),margin_width,margin_height);    right_label =new QLabel(this);    right_label->setPixmap(label_group[1]);    //right_label->setScaledContents(true);    right_label->setGeometry(pos_x+center_width,pos_y+(center_hieght-margin_height),margin_width,margin_height);  /**    设置左边控件的位置和大小*/    pos_x=(pos_x-margin_width);    pos_y=pos_y+(center_hieght-margin_height);    left_rect.setRect(pos_x,pos_y,margin_width,margin_height);    left_label =new QLabel(this);    left_label->setPixmap(label_group[2]);    //left_label->setScaledContents(true);    left_label->setGeometry(pos_x,pos_y,margin_width,margin_height);    center_label->raise();//------------------------------------------------------------------------------//}
代码分析

1、首先是定位三个矩形框的位置,为了达到和网易的效果,特意量了尺寸,定义如下:

#define center_width 540#define center_hieght 200#define margin_width 110#define margin_height 188
骚年,如果感兴趣,可以草图画出来,就可以知道以上关于三个矩形框位置的计算方式是怎么得来的了。当然了,这仅仅只是我的计算方式,可以不予采来,嘻嘻。

2、其次是定位三个QLabel的位置,初始的时候,与三个矩形框保持一致。

3、最后是底部按钮的设计,主要是Icon的设计以及位置,还有toolBar的响应事件。


关键代码在于响应事件的设计,即两个函数moveLeft()以及moveRight();

#define ToLeft 0#define ToRight 1

void MainWindow::onTriggerAction(QAction *action){   int action_num=action->data().toInt();   if (action_num==ToLeft)       moveLeft();   else if(action_num==ToRight)      moveRight();}void MainWindow::moveLeft(){    mainCnt+=1;    moveAnimation_left=new QPropertyAnimation(left_label,"geometry");    moveAnimation_left->setDuration(200);    moveAnimation_left->setStartValue(left_rect);    moveAnimation_left->setEndValue(right_rect);    moveAnimation_left->setEasingCurve(QEasingCurve::Linear);    moveAnimation_left->start();    moveAnimation=new QPropertyAnimation(center_label,"geometry");    moveAnimation->setDuration(200);    moveAnimation->setStartValue(center_rect);    moveAnimation->setEndValue(left_rect);    moveAnimation->setEasingCurve(QEasingCurve::Linear);    moveAnimation->start();    moveAnimation_right=new QPropertyAnimation(right_label,"geometry");    moveAnimation_right->setDuration(200);    moveAnimation_right->setStartValue(right_rect);    moveAnimation_right->setEndValue(center_rect);    moveAnimation_right->setEasingCurve(QEasingCurve::Linear);    moveAnimation_right->start();    /**        方向和label移动的方向恰恰相反    */    QRect rect(right_rect);    right_rect=center_rect;    center_rect=left_rect;    left_rect=rect;    if(mainCnt==6)        mainCnt=3;    if(mainCnt==4)    {        right_label->raise();    }    else if(mainCnt==5)    {        left_label->raise();    }    else if(mainCnt==1)    {       center_label->raise();    }}void MainWindow::moveRight(){    mainCnt-=1;    moveAnimation_left=new QPropertyAnimation(left_label,"geometry");    moveAnimation_left->setDuration(200);    moveAnimation_left->setStartValue(left_rect);    moveAnimation_left->setEndValue(center_rect);    moveAnimation_left->setEasingCurve(QEasingCurve::Linear);    moveAnimation_left->start();    moveAnimation=new QPropertyAnimation(center_label,"geometry");    moveAnimation->setDuration(200);    moveAnimation->setStartValue(center_rect);    moveAnimation->setEndValue(right_rect);    moveAnimation->setEasingCurve(QEasingCurve::Linear);    moveAnimation->start();    moveAnimation_right=new QPropertyAnimation(right_label,"geometry");    moveAnimation_right->setDuration(200);    moveAnimation_right->setStartValue(right_rect);    moveAnimation_right->setEndValue(left_rect);    moveAnimation_right->setEasingCurve(QEasingCurve::Linear);    moveAnimation_right->start();    /**        方向和label移动的方向恰恰相反    */    QRect rect(left_rect);    left_rect=center_rect;    center_rect=right_rect;    right_rect=rect;    if(mainCnt==-1)        mainCnt=3;    if(mainCnt==2)    {        left_label->raise();    }    else if(mainCnt==1)    {        right_label->raise();    }    else if(mainCnt==0)    {       center_label->raise();    }}

代码分析

1首先是动画的构造以及初始化

moveAnimation_left是控制left_label的动画的,左移是从left_rect移动到right_rect的位置,控制属性是geometry,移动的曲线方式是直线型的。

moveAnimation_center是控制center_label动画的,左移是从center_rect的位置移动到left_rect的位置

moveAnimation_right是控制right_label动画的,左移是从right_rect的位置移动到center_rect的位置。

2、其次是需要设置矩形框的位置,其设置效果为为了达到与label的同步,同时达到一种循环王府的效果。这点要重点理解。

3、mainCnt的控制,当达到移动图片的最大数量以后,需要重新开始,同时在不同的移动时,需要label展现效果,即置顶效果,raise();

最后实现的的效果如下:


0 0