当前位置: 首页 > news >正文

如何建网站遂宁wordpress新手入门教程

如何建网站遂宁,wordpress新手入门教程,包头网站建设价格,企业名录数据库目标 实现一个像网易云音乐播放器一样的卡片轮播窗口1.分析UI布局垂直布局,该布局主要分为两个窗口,上面是显示图片的滚动窗口,下面是显示图片当前索引的索引窗口,明显上面的窗口需要占据剩余的所有空间,所以主布局是一…

目标 实现一个像网易云音乐播放器一样的卡片轮播窗口

1.分析UI布局

垂直布局,该布局主要分为两个窗口,上面是显示图片的滚动窗口,下面是显示图片当前索引的索引窗口,明显上面的窗口需要占据剩余的所有空间,所以主布局是一个垂直布局,滚动窗口只是一个窗口没有任何布局,导航条窗口是水平布局,负责管理所有的导航点

void CoverFlowWidget::BuildUI()
{// 创建根布局 垂直布局QVBoxLayout* root = new QVBoxLayout(this);// 创建滚动窗口scroll_ = new QWidget(this);scroll_->setMouseTracking(true);scroll_->resize(780, 220);root->addWidget(scroll_, 1);                                                                    // 占据除去索引框的所有空间// 创建圆点导航条(水平布局)dotBar_ = new QWidget(this);dotBar_->setMouseTracking(true);QHBoxLayout* dotLayout = new QHBoxLayout(dotBar_);                                                  dotLayout->setContentsMargins(0, 0, 0, 0);dotLayout->setSpacing(10);root->addWidget(dotBar_, 0, Qt::AlignHCenter);                                                  // 索引框在水平居中
}

1.1 滚动窗口(图片绘制)

重点在于图片位置的绘制,只会展示三张图片,那么该如何绘制这种近大远小的感觉呢?

也就是在整体的窗口大小确定时计算出三张图片在窗口中的布局显示

也就是三个矩形的位置

也就是下面这种感觉

图片堆叠的效果如下

1.1.1 确定矩形框位置和大小

首先要根据整个窗口的大小来确认

左右两侧预留够足够大小的宽度,上下两侧预留够足够大小的宽度,最后得到的是中心图片的宽度

根据中心图层的大小获取到侧边图片的大小,然后根据这三个图片的大小获取对应的矩形位置

void CoverFlowWidget::updateRects() 
{// 计算中心与侧边大小与位置(保持上下留白)const int Width = scroll_->width(), Hight = scroll_->height();const int margin = 12;// 让左右各露出固定宽度(更接近参考图)const int peek = qRound(Width * 0.17);                                                              // 左右各露出 ~17%(可调)// 中心尺寸:整体宽度扣掉左右露出szCenter_ = QSizeF(Width - 2 * peek, qMin(220, Hight - 2 * margin));// 侧边比例(略小于中心)const qreal sideScale = 0.78;                                                                       // 可调 0.74~0.82szSide_ = QSizeF(szCenter_.width() * sideScale, szCenter_.height() * sideScale);rcCenter_ = QRectF((Width - szCenter_.width()) / 2.0,(Hight - szCenter_.height()) / 2.0,szCenter_.width(), szCenter_.height());rcLeft_ = QRectF(LEFT_MARGIN,(Hight - szSide_.height()) / 2.0,szSide_.width(), szSide_.height());rcRight_ = QRectF(Width - szSide_.width() - RIGHT_MARGIN,(Hight - szSide_.height()) / 2.0,szSide_.width(), szSide_.height());
}

1.1.2 设置过渡动画

在动画里进行实时的绘制,动画开启时会伴随着数值的改变,其实就是虚幻中的线性插值,从0到1进行插值,插值的时间就是动画的速度罢了,当动画结束后重置图片索引即可

anim_ = new QVariantAnimation(this);
anim_->setDuration(320);
anim_->setStartValue(0.0);
anim_->setEndValue(1.0);connect(anim_, &QVariantAnimation::valueChanged, this, [this](const QVariant& v) {t_ = v.toReal(); update();});connect(anim_, &QVariantAnimation::finished, this, [this] {// 动画结束后,落位为新的中心center_ = (center_ + (dir_ > 0 ? 1 : -1) + slides_.size()) % slides_.size();t_ = 0.0; update();});

什么时候进行一次动画的播放是用定时器控制的,当然这是自动轮播

connect(&timer_, &QTimer::timeout, this, [this]{if (!hovering_) next();});void CoverFlowWidget::next() 
{if (slides_.size() <= 1 || anim_->state() == QAbstractAnimation::Running) return;dir_ = +1; anim_->stop(); anim_->setStartValue(0.0); anim_->setEndValue(1.0); anim_->start();
}

1.1.3 绘制UI

观察下面的绘制可以大致推断一下原理也就是说,每一帧都会绘制一张图片,而每一张图片都会带有一些偏移,这里如果不清除掉之前绘制的图片,就很容易导致出现残影的效果

所以首先对画笔进行设置

QPainter p(this);
p.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform, true);p.setCompositionMode(QPainter::CompositionMode_Source);                                                     // 覆盖目标区域
p.fillRect(rect(), Qt::transparent);                                                                        // 清空画布
p.setCompositionMode(QPainter::CompositionMode_SourceOver);                                                 // 与背景自然融合

然后获取要绘制的三张图片,由于我们的轮播是从左到右进行的,而center_就是中间那张图片的索引

const int n = slides_.size();                                                                               // 获取图片的大小
int idxC = center_;                                                                                         // 当前图片
int idxL = (center_ - 1 + n) % n;                                                                           // 左边那一张
int idxR = (center_ + 1) % n;                                                                               // 右边那一张

图片移动的感觉实际上是每一帧进行绘制不同位置和大小的图片造成的视觉效果,就像翻小人书一样

得到动画中矩形的位置,目前最左边的矩形位置是不变的,中间的图片往左边偏移,右边的图片往中间进行偏移

偏移开始就是动画开始的时候,动画开始的每一帧都进行图片位置的计算

// 计算动画中的矩形(dir_ 决定谁往中心、谁往侧边)
QRectF rcC = rcCenter_, rcToSide, rcToCenter, rcStatic;                                                     // 创建三个矩形,分别对应“去侧边”、“到中心”、“静态”
int    idxToSide = idxC, idxToCenter = (dir_ > 0 ? idxR : idxL), idxStatic = (dir_ > 0 ? idxL : idxR);      // 获取对应的图片索引(左边的图片是保持不动的)// 然后根据起始坐标和结束坐标做线性插值,得到动画中的矩形坐标
if (dir_ > 0) 
{             // 向右:中心 -> 左;右 -> 中心;左保持rcToSide = lerp(rcCenter_, rcLeft_, t_);rcToCenter = lerp(rcRight_, rcCenter_, t_);rcStatic = rcLeft_;
}
else 
{                   // 向左:中心 -> 右;左 -> 中心;右保持rcToSide = lerp(rcCenter_, rcRight_, t_);rcToCenter = lerp(rcLeft_, rcCenter_, t_);rcStatic = rcRight_;
}

线性插值

QRectF CoverFlowWidget::lerp(const QRectF& a, const QRectF& b, qreal t) const 
{return QRectF(a.x() + (b.x() - a.x()) * t,a.y() + (b.y() - a.y()) * t,a.width() + (b.width() - a.width()) * t,a.height() + (b.height() - a.height()) * t);
}

绘制UI

首先基础知识是后绘制的UI在先绘制的UI之前

最后的三张图片,实际上就是三个圆角矩形框,只需要创建绘制路径,然后将上面得到的矩形的起点拿到,最后根据图片索引获取到图片直接进行绘制即可

auto drawRounded = [&](const QPixmap& pm, const QRectF& r){QPainterPath path;                                                                                              // 创建圆角矩形路径path.addRoundedRect(r, radius_, radius_);                                                                       // 画圆角矩形p.save();p.setClipPath(path);                                                                                            // 只在当前区域进行绘制// 简单的“裁切铺满”效果(保持比例裁剪)QPixmap scaled = pm.scaled(r.size().toSize(), Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);        // 缩放图片p.drawPixmap(QPointF(r.x(), r.y()), scaled);p.restore();};// 先画静态侧边(在底层)
drawRounded(slides_[idxStatic], rcStatic);// 再画“去侧边”的(在中层)
drawRounded(slides_[idxToSide], rcToSide);// 最后画“到中心”的(在顶层,保证中心遮住其它)
drawRounded(slides_[idxToCenter], rcToCenter);

最后在动画没有启动时也就是一开始也会进行UI的绘制

// 未在动画中时,直接三张:左、右、中心(中心最后画)
if (!anim_->state()) {drawRounded(slides_[idxL], rcLeft_);drawRounded(slides_[idxR], rcRight_);drawRounded(slides_[idxC], rcCenter_);
}

完整代码如下

void CoverFlowWidget::paintEvent(QPaintEvent*) 
{QPainter p(this);p.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform, true);p.setCompositionMode(QPainter::CompositionMode_Source);                                                     // 覆盖目标区域p.fillRect(rect(), Qt::transparent);                                                                        // 清空画布p.setCompositionMode(QPainter::CompositionMode_SourceOver);                                                 // 与背景自然融合if (slides_.isEmpty()) return;const int n = slides_.size();                                                                               // 获取图片的大小int idxC = center_;                                                                                         // 当前图片int idxL = (center_ - 1 + n) % n;                                                                           // 左边那一张int idxR = (center_ + 1) % n;                                                                               // 右边那一张// 计算动画中的矩形(dir_ 决定谁往中心、谁往侧边)QRectF rcC = rcCenter_, rcToSide, rcToCenter, rcStatic;                                                     // 创建三个矩形,分别对应“去侧边”、“到中心”、“静态”int    idxToSide = idxC, idxToCenter = (dir_ > 0 ? idxR : idxL), idxStatic = (dir_ > 0 ? idxL : idxR);      // 获取对应的图片索引(左边的图片是保持不动的)// 然后根据起始坐标和结束坐标做线性插值,得到动画中的矩形坐标if (dir_ > 0) {             // 向右:中心 -> 左;右 -> 中心;左保持rcToSide = lerp(rcCenter_, rcLeft_, t_);rcToCenter = lerp(rcRight_, rcCenter_, t_);rcStatic = rcLeft_;}else {                   // 向左:中心 -> 右;左 -> 中心;右保持rcToSide = lerp(rcCenter_, rcRight_, t_);rcToCenter = lerp(rcLeft_, rcCenter_, t_);rcStatic = rcRight_;}auto drawRounded = [&](const QPixmap& pm, const QRectF& r){QPainterPath path;                                                                                              // 创建圆角矩形路径path.addRoundedRect(r, radius_, radius_);                                                                       // 画圆角矩形p.save();p.setClipPath(path);                                                                                            // 只在当前区域进行绘制// 简单的“裁切铺满”效果(保持比例裁剪)QPixmap scaled = pm.scaled(r.size().toSize(), Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);        // 缩放图片p.drawPixmap(QPointF(r.x(), r.y()), scaled);p.restore();};// 先画静态侧边(在底层)drawRounded(slides_[idxStatic], rcStatic);// 再画“去侧边”的(在中层)drawRounded(slides_[idxToSide], rcToSide);// 最后画“到中心”的(在顶层,保证中心遮住其它)drawRounded(slides_[idxToCenter], rcToCenter);// 未在动画中时,直接三张:左、右、中心(中心最后画)if (!anim_->state()) {drawRounded(slides_[idxL], rcLeft_);drawRounded(slides_[idxR], rcRight_);drawRounded(slides_[idxC], rcCenter_);}
}

1.2 滚动窗口(自定义标签)

由于绘制的图片不支持点击状态

所以这里创建一个可支持标签,通过标签的缩放和移动来模拟绘制

1.2.1 标签的移动

确认矩形框的位置和大小,依据轮播的图片进行缩放并重新设置到标签中,标签在进行位置的移动

完整的代码如下

void CoverFlowWidget::startAnimation()
{for (FlowLabel* label : labels_) label->hide();const int n = slides_.size();                                                                               // 获取图片的大小if(n < 3) return;                                                                                           // 至少需要三个图片才能旋转int idxC = center_;                                                                                         // 当前图片int idxL = (center_ - 1 + n) % n;                                                                           // 左边那一张int idxR = (center_ + 1) % n;                                                                               // 右边那一张// 计算动画中的矩形(dir_ 决定谁往中心、谁往侧边)QRectF rcC = rcCenter_, rcToSide, rcToCenter, rcStatic;                                                     // 创建三个矩形,分别对应“去侧边”、“到中心”、“静态”int    idxToSide = idxC, idxToCenter = (dir_ > 0 ? idxR : idxL), idxStatic = (dir_ > 0 ? idxL : idxR);      // 获取对应的图片索引(左边的图片是保持不动的)// 然后根据起始坐标和结束坐标做线性插值,得到动画中的矩形坐标if (dir_ > 0){// 向右:中心 -> 左;右 -> 中心;左保持rcToSide = lerp(rcCenter_, rcLeft_, t_);rcToCenter = lerp(rcRight_, rcCenter_, t_);rcStatic = rcLeft_;}else{// 向左:中心 -> 右;左 -> 中心;右保持rcToSide = lerp(rcCenter_, rcRight_, t_);rcToCenter = lerp(rcLeft_, rcCenter_, t_);rcStatic = rcRight_;}// 画圆角矩形auto drawRounded = [&](const int idx, const QRectF& r){FlowLabel* label = labels_[idx];QPixmap pm = slides_[idx];QPixmap scaled = pm.scaled(r.size().toSize(), Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);        // 缩放图片label->setMaximumSize(r.size().toSize());label->setPixmap(scaled);//label->move(QPoint(r.x(), r.y()));label->setGeometry(r.toRect());label->show();label->raise();};// 先画静态侧边(在底层)drawRounded(idxStatic, rcStatic);// 再画“去侧边”的(在中层)drawRounded(idxToSide, rcToSide);// 最后画“到中心”的(在顶层,保证中心遮住其它)drawRounded(idxToCenter, rcToCenter);// 未在动画中时,直接三张:左、右、中心(中心最后画)if (!anim_->state()) {drawRounded(idxL, rcLeft_);drawRounded(idxR, rcRight_);drawRounded(idxC, rcCenter_);}
}

1.3 创建导航栏

当图片素材被导入时索引点也就同时添加进来了,通过更新按钮的状态来设置按钮的选中状态,所以在图片的每一次过渡动画完结的时候就可以更新按钮的状态了,如下图所示,当索引点被点击时会立即更新当前图片的索引,然后根据当前图片的索引重新计算位置即可

导航栏的代码

static QString dotStytle(R"(QPushButton {background-color: white;border-radius: 5px;}QPushButton[selected=true] {background-color: red;}QPushButton[selected=false] {background-color: white;}
)");connect(anim_, &QVariantAnimation::finished, this, [this]{// 动画结束后,落位为新的中心UpdateDotState(dots_[center_], false);center_ = (center_ + (dir_ > 0 ? 1 : -1) + slides_.size()) % slides_.size();t_ = 0.0; /*update();*/ startAnimation();// 更新下一帧索引UpdateDotState(dots_[center_], true);void CoverFlowWidget::LoadSlide()
{for (int i = 1; i <= 10; ++i){addSlide(QPixmap(QString(":/Images/picturewall/%1.png").arg(i)));}
}void CoverFlowWidget::addSlide(const QPixmap& p) 
{slides_.push_back(p);FlowLabel* label = new FlowLabel(this);label->setPixmap(p);labels_.push_back(label);updateRects();//update();startAnimation();// 添加索引QPushButton* dot = new QPushButton(dotBar_);dot->setFixedSize(10, 10);dot->setStyleSheet(dotStytle);dot->setCursor(Qt::PointingHandCursor);dots_.push_back(dot);dotBar_->layout()->addWidget(dot);UpdateDotState(dots_[center_], true);connect(dot, &QPushButton::clicked, this, [this, dot]{int idx = dots_.indexOf(dot);if (idx == center_) return;UpdateDotState(dots_[center_], false);dir_ = (idx > center_ ? 1 : -1);center_ = idx;UpdateDotState(dots_[center_], true);t_ = 0.0; startAnimation();});
}

1.4 创建左右按钮

这两个按钮需要实时的处于最上层,也就是说,对标签进行移动时,最后要进行按钮的绘制

btnPrev_ = new QPushButton(scroll_);
btnPrev_->setFixedSize(20, 20);
btnPrev_->setIcon(style()->standardIcon(QStyle::SP_ArrowLeft));
btnPrev_->setCursor(Qt::PointingHandCursor);
btnPrev_->raise();
btnNext_ = new QPushButton(scroll_);
btnNext_->setFixedSize(20, 20);
btnNext_->setIcon(style()->standardIcon(QStyle::SP_ArrowRight));
btnNext_->setCursor(Qt::PointingHandCursor);
btnNext_->raise();connect(btnPrev_, &QPushButton::clicked, this, [this] { prev(); });
connect(btnNext_, &QPushButton::clicked, this, [this] { next(); });

当导航栏添加完所有的dot时,这时会在过一段时间后触发布局的调整,但是滚动区域的布局也会随机的占据剩余分配的空间,这里要在调整了之后立即触发布局调整,布局调整完毕后,将按钮挪到指定的位置

dotBar_->updateGeometry();
layout()->invalidate();
layout()->activate();                                                                           // 强制布局重新计算
updateRects();
btnPrev_->move(CalcuBtnPos(true));
btnNext_->move(CalcuBtnPos(false));

计算按钮的位置

QPoint CoverFlowWidget::CalcuBtnPos(bool isLeft)
{if (isLeft) return QPoint(LEFT_MARGIN, (height() - 20) / 2);else return QPoint(scroll_->width() - RIGHT_MARGIN - 20, (height() - 20) / 2);
}

2. 完结

这样一个滚动窗口就做好了

最终演示效果如下

http://www.dtcms.com/a/444417.html

相关文章:

  • 网站建设提供的网站资料wordpress 淘宝客赚钱
  • 在网站建设中 为了防止工期拖延页优化软件
  • seo网站建设是什么网站建设案例新闻
  • 优化网站哪个好网站注册协议模板
  • 简单三栏网站背景图在线制作
  • 网站建立定位企划小程序推广收费价目表
  • 做中医药网站有前景吗安卓上搭建wordpress
  • 图书翻页的动画 做网站启动用网站建设环境
  • 刷业务网站怎么做网站访问量太多
  • 搜索引擎网站的结构wordpress页面构造器
  • 北京网站建设外包公司网站建设与维护实训总结
  • 阿里云服务器win系统建站教程关于网站建设的报告
  • 网站菜单导航制作教程wordpress两侧悬浮框
  • 成都网站制作公司报价小学编程培训班多少钱一个月
  • 网站建设制作作业微信公众号申请
  • 网站开发一般分为几个步骤什么都能搜的浏览器
  • 做网站资源管理是网站建设seo合同书
  • 优秀企业网站建设公司wordpress 翻墙
  • 柔造网站定制商标设计免费的app
  • 横向网站北京建设招标信息网站
  • 买个网站多少钱免费引流app下载
  • 在线支付网站制作有没有帮忙做推广的网站
  • 如何做企业网站规划微信朋友圈产品推广语
  • 详述网站建设的过程大连网站建设个人
  • 影响网站打开速度的因素wordpress中国加速
  • 网站开发服务商平台网站建设产品展示型的
  • 进入网站后台管理系统做境外旅游的网站
  • 外贸汽车网站有哪些学习网站建设的心得体会
  • 网站主机在哪里注册呢互联网金融网站建设
  • 微微营销官网广州营销优化