基于qt实现网易云音乐的轮播效果
网易云轮播效果
前言
其实主要是想做点记录吧,本人比较喜欢音乐,所以在上周决定在搭建一个网易云的界面框架,不做不知道,做了才发现qt还有很多的框架是自己不太熟悉的。
一、准备
1.1.想要做好这个界面我感觉graphicsView以及的了解是必不可少的。因为在qt画图功能上与QPainter实现画图比,graphicsView功能反而就变得就更强大了。查阅了相关的博客:
1.1.1.Qt之QGraphicsView入门篇
1.1.2.Qt之QGraphicsView进阶篇
1.1.3.Qt之QGraphicsView实战篇
这三个博客我感觉写的其实挺好,也是带我初步了解GraphicsView。
1.2那么知道了QGraphicsView,怎么实现网易云的轮播效果呢?
1.2.1我感觉在QGraphicsView画布上主要关注的几点是:
- 图片的位置
- 图片的优先级(轮播效果中存在缩放效果)
- 图片的大小情况
- 轮播时的轮换效果
- 图片与按钮之间的映射
- 图片的轮播切换
这些是必不可少的。其中我参考了
二、实现
1.图片的的读取,位置,大小以及按钮映射图片的实现
代码如下(示例):
.h里面
void init();
qreal getOffset(int pictureNum);
int getZValue(int pictureNum);
void setPictureItem(int picId);
double getScaled(int num);
void setBtnGroup();
int getPictureNum(int id);
int getrightN(int num);
QGraphicsScene * m_scene;
QLineF m_lineF;
QVector<PictureItem*> m_pictures;
QList<QPointF> m_pointA;
QButtonGroup *m_BtnGroup;
QMap<int,PictureItem*> m_mapBtnToPicture;
.cpp里面
```#define POINT_SIST_FISRT 0
// 图片的位置
#define POINT_SIST_SECEND 0.15
#define POINT_SIST_OTHER 0.45
#define PICTURENUM 10 //图片的数量
#define SCALE_VIEW_PIXMAP (qreal)1/1 //View与图片比例
#define RAW_VIEW_SIZE QSize(950,198) //场景大小
//图片缩放大小
#define SCALEMIN 0.8
#define SCALEMAX 1
#define POINT_SIST_FISRT 0
#define POINT_SIST_SECEND 0.15
#define POINT_SIST_OTHER 0.45
// 初始化图片属性
m_lineF.setPoints(QPointF(0,0),
QPointF(this->width(),0));
for(int i =0
for(int i = 0; i < PICTURENUM; ++i)
{
// 给每个图片Item添加图片
QPixmap pixmap(QString("./images/picturewall/%1.png").arg(i + 1));
// 设置图片大小
pixmap.scaled(RAW_VIEW_SIZE / SCALE_VIEW_PIXMAP,
Qt::KeepAspectRatio,Qt::FastTransformation);
PictureItem * nn = new PictureItem(pixmap);
m_pictures.append(nn);
// 设置图片的位置
QPointF point =m_lineF.pointAt(getOffset(i));
m_pictures.at(i)->setPos(point);
//设置图片的优先级
m_pictures.at(i)->setZValue(getZValue(i));
// 用于后面的轮播相当于id
m_pictures.at(i)->setType(i);
// 因为中间的图片要设置为最大,所以在这做了一个判断来让第二张图片最大化
if(i == 1)
{
m_pictures.at(i)->setScale(SCALEMAX);
}
else
{
m_pictures.at(i)->setScale(SCALEMIN);
m_pictures.at(i)->setPos(m_pictures.at(i)->x(),(RAW_VIEW_SIZE.height() / 10));
}
// 把各个图片都加入到scene里面
m_scene->addItem(m_pictures.at(i));
m_pointA.append(m_pictures[i]->pos());
// 关联按钮,做一个map的映射
m_mapBtnToPicture.insert(static_cast<PictureButton*>(m_BtnGroup->button(i))->getId(),m_pictures[i]);
}
// 设置按钮的初始化的对应的图片
m_curBtnId = 1;
}
其中getOffset就是给对应的图片加上对应的位置,因为界面上必定有三张图片是显示在界面上的,其他都是被覆盖的情况
qreal PictureRollWgt::getOffset(int pictureNum)
{
switch (pictureNum) {
case 0:
return POINT_SIST_FISRT;
case 1:
return POINT_SIST_SECEND;
case 2:
return POINT_SIST_OTHER;
default:
return POINT_SIST_SECEND;
}
}
其中的getScaled就是设置对应图片的缩放效果,只有其中一张图片是最大的其他都是小图片
double PictureRollWgt::getScaled(int num)
{
if(num == 1)
return SCALEMAX;
else
return SCALEMIN;
}
getZValue表示图片优先级,显示的图片优先级分别是1,2,1,其他都是0;
int PictureRollWgt::getZValue(int pictureNum)
{
switch (pictureNum) {
case 0:
return 1;
case 1:
return 2;
case 2:
return 1;
default:
return 0;
}
}
这样就可以初步完成界面的效果了
2.完成动态效果
动态效果主要分为三种情况,
- 按钮切换
- 计时器切换
- 图片下面的鼠标进入到小Btn来切换
上面已经做了图片与按钮的映射,但是怎么实现这3种场景呢?
- 首先说一种就是图片下面的鼠标进入到小Btn来切换,当鼠标进入到小按钮内部就需要切换对应的图片到中间,做主图。因此普通QPushButton是实现不了的。所以必须要自定义按钮。也就是继承一个QAbstractButton类来实现对应的信号与槽以及重写鼠标进入事件,其中主要代码如下:
void PictureButton::enterEvent(QEvent *event)
{
if(!isChecked())
setChecked(true);
emit sigEntered(m_id);
return QAbstractButton::enterEvent(event);
}
这样就可以发送一个信号到主界面做出响应
2.关键逻辑部分,就是在做到按钮与图像item的映射后就可以去做到切换图片功能,这里主要是重新排序图片容器,QGraphicsItemAnimation与QTimeLine 都是用来实现动态效果。
void PictureRollWgt::setPictureItem(int picId)
{
QVector<QGraphicsItemAnimation*> items(10);//用于去做图片动态
for(int i = 0; i < 10; ++i)
{
items[i] = new QGraphicsItemAnimation;
}
QTimeLine *timeline = new QTimeLine(200);
timeline->setLoopCount(1);
int pic = getrightN(picId - 1);
qDebug() << pic;
for(int i = 0; i < 10; ++i)
{
m_pictures[i] = m_mapBtnToPicture.value(pic % 10);
pic++;
m_pictures[i]->setScale(getScaled(i));
m_pictures[i]->setZValue(getZValue(i));
m_pictures[i]->setTransformationMode(Qt::SmoothTransformation);//设置缩放模式
items[i]->setItem(m_pictures[i]);
items[i]->setTimeLine(timeline);
items[i]->setPosAt(0.5,m_pointA[i]);
}
timeline->start();
m_scene->invalidate();
items.clear();
}
总结
在实现网易云界面的界面上还有很多东西需要搭建。在实现轮播图时多亏了比卡丘不皮的网易云源代码以及博客
里面很多内容都是参考了他的,以及图片。