C#实现炫酷启动图-动态进度条效果

一、简述

最近接到一个新需求,让做一个动效进度条。

由于我们的产品比较大,在软件启动的时候会消耗比较长的时间,原生的进度条已经不能满足我们的需求,这里我们就需要一个会动的进度条,效果如下图所示。

光效进度条主要是做了一个进度动画,在已完成的部分上进行快速的迭代渲染,给用户一种直观感受,我们的软件一直努力加载,它还活着。

有了这个进度条之后,当我们的进度从40%到50%这个持续的过程中,界面再也不会出现假死的情况,是不是很完美呢。。。

下面我就来分析下这个动效进度条是怎么做的

二、动效进度条

如效果图所示,光效进度条不同于一般的进度条,他在基础的任务进度之上还添加了一层光效,主要是想告诉用户我们的软件一直在努力运行,请在耐心的等待一下下。

我自己在做功能的时候,往往喜欢先做一个测试demo,然后在把做好的功能集成在正式环境,这个功能也不列外,如第一节中展示的效果图,就是测试demo的样子,虽然很丑,但是基础功能是有的。

现在的很多软件,在进度展示上都有了比较绚丽的效果,比如压缩软件,解压文件的时候都会有动效进度条,用过的同学应该都知道长啥样,而我们的光效进度条跟这个效果差不多,除此之外我们还提供了另一种动效,延迟动效,他们两个在一定程度上都展示了更友好的进度效果。

在开始分析功能前,首先我们先来考虑下我们的需求:动效进度条,也就是说在原来的进度条基础上需要添加实时动画,让进度条看起来更炫酷一些,除了光效进度条以外,还有一种延迟到达进度条,也属于动态进度条。

延迟动效、说直白一点儿就是延迟到达,当我们设置了进度从10%到20%时,程序模拟了一个渐进的过程,使用一个时间段走完了这10%的进度。

下面我们分别来介绍这两种进度条的实现

实现炫酷的进度条我们可以从QWidget自定义开始写,也就是说从头开始写,但通常我们不这样干,因为这样可能会写出无穷无尽的bug,而且现有的轮子已经很稳定了,为什么还要造呢。

1、光效进度条

光效进度条我们使用了一个小技巧,采用一个简单的办法实现,我们的光效进度条控件继承自Qt原生进度条类QProgressBar,在新类中我们只需要在Qt绘制完原生进度条之后,补画动效即可。

a、paintEvent函数

paintEvent函数是Qt的绘制函数,当界面刷新的时候,这个接口函数就会被调用,因此我们需要重写这个接口,首先调用父窗口的绘制方法,然后我们在绘制我们自己的动效,代码如下所示

QProgressBar::paintEvent(event);
drawCache绘制动效

b、drawCache绘制动效

绘制动效的时候,我们需要知道动效的绘制区域,这个地方我们需要主动去解析qss的一些参数,Qt的style()->subElementRect这个接口刚好可以拿到我们需要的信息

下面简单描述下我们的实现流程

•首先我们获取进度条的几何大小和中间进度的几何大小,这样的话我们就可以计算出来各border的数值
•然后根据我们当前的value值就可以计算出进度条已经走过(就是值小于我们设定的区域)的几何大小
•我们的光效将是跑在第二步计算出来的区域上,一直循环迭代
•内存里我们维护一个cacheValue,这个值在每次界面刷新的时候递增,但是不能大于第二步的value值,cacheValue将是我们动效绘制的一个关键参数,他表示了动效绘制的长度
•构造一个渐变刷子,设置给QPainter
•绘制动效

上下大致描述了下绘制动效的一个流程,下面送上具体代码,由于篇幅原因,代码我进行了部分伪代码处理。

void GMPProgressBar::drawCache()
{
 QStyleOptionProgressBarV2 opt;
 QRect outerRect = style()->subElementRect(QStyle::SE_ProgressBarGroove, &opt, this);
 QRect innerRect = style()->subElementRect(QStyle::SE_ProgressBarContents, &opt, this);
 QMargins borders(构造一个QMargins);

QRectF rect(动效绘制区域);

 if (m_iCacheValue != 0)
 {
  QPainter painter(this);
  QLinearGradient gradient(构造绘图刷子);
  painter.setBrush(gradient);
  painter.drawRoundedRect(rect, 2, 2);
 }
}

c、定时刷新

由于我们的动效是需要主动去刷新的,因此我们需要声明一个定时器,然后定时去刷新,实现代码可能像下面这样

connect(m_pCacheTimer, &QTimer::timeout, this, [this]{
  if (TM_CACHE == m_mode)
  {
   ++m_iCacheValue;
   repaint();
  }else
  {
   m_pCacheTimer->stop();
  }
 });

定时器只需要在我们第一次设置进度条值的时候启动,或者当我们设置一个新的值,而定时器没有启动,我们就需要去激活定时器。

TM_CACHE模式即是我们的动效模式,TM_SMOOTH模式则是我们的延迟到达模式

connect(this, &QProgressBar::valueChanged, [this](int value){//TM_CACHE模式下 启动动画时机
  if (!m_pCacheTimer->isActive() && value != 0 && TM_CACHE == m_mode)
  {
   m_pCacheTimer->start(m_iRefreshleveling);
  }
 });

动效进度条效果如下图所示

2、延迟到达进度条

动效进度条可能更适用于启动界面,但是也有一些时候,我们可能需要更平缓的一个加载曲线,例如安装软件、卸载软件的时候。

a、setValue

延迟到达进度条和动效进度条的实现方式就有所差别了,对于实现延迟到达进度条,我们这里重写了setValue函数,当外部调用该接口设置value值时,我们并没有立即去设置当前值,而是使用了一个时间段去完成这个值得刷新。

•外部调用setValue时,我们首先计算出我们应该绘制的最大宽度PixelMax、当前已经绘制到的最大宽度cacheValue和我们的步长
•设置定时器刷新频率,并重启定时器
•定时器刷新时,cacheValue自增我们的步长
•调用父类的QProgressBar::setValue接口设置值

b、定时器

延迟达到功能的的定时器和之前我们什么的动效定时器可以混用一个,我们定时器刷新的时候,针对不同的动画模式,我们执行不同的的代码即可,实现代码可能像下面这样

connect(m_pCacheTimer, &QTimer::timeout, this, [this]{
 if (TM_CACHE == m_mode)
 {
  ++m_iCacheValue;
  repaint();
 }
 else if (TM_SMOOTH == m_mode)
 {
  changeSmooth();
 }
 else
 {
  m_pCacheTimer->stop();
 }
});

延迟到达进度条效果如下图所示

3、接口说明

光效进度条类对外只暴露了3个接口,分别是设置动画模式、动画时长和刷新频率

特别需要注意的是,我们这里重写了父类的setValue接口,这意味着我们不能使用多态来操作这个接口

void setTransitionMode(TransitionMode mode);//设置动画模式
void setSmoothDuration(int duration);//设置刷新总时长 模式为TM_SMOOTH时有效
void setRefreshleveling(int rate);//设置刷新频率 每次更改TransitionMode之后会变为默认值

a、修改动画模式

修改动画模式的时候,我们需要清空内存中的所有数据,并把value值设为0。

void GMPProgressBar::setTransitionMode(TransitionMode mode)
{
 if (m_mode == mode)
 {
  return;
 }
 m_mode = mode;
 clearData();
 QProgressBar::setValue(0);
}

b、其他接口

设置刷新时长和频率接口都比较简单,不做特别说明

特别注意:这个3个接口最好是在动画启动前设置,动画开始后尽量不要去调用

三、启动图

第二节我们主要是讲述了怎么做一个动效进度条,这一节我们来做一个启动图页面,把这个动效使用进去。

启动图不是我们主要分析的内容,这个我就简单说下这个类的实现方式和一些借口说明

1、实现思路

Qt已经给我们提供了一个QSplashScreen,但是使用起来还是特别有限,因此这里我把Qt的源码直接进行了二次开发

•首先Qt的原生实现方式基本都被移植了出来
•启动图使用了简单的上下布局,上面是一张我自绘制的图片,放在了一个QLabel上,下面是动效进度条
•自绘制的图片上包括了,产品名称、logo、背景图等等

2、背景图切换

当我们调用setPixmap设置背景图时,如果我们指定了多张图,我将会启动一个定时器,在指定时长后重新构造一张大的背景图,并添加到启动窗口上

这里主要说明下背景图是怎么构造出来的,代码如下所示

a、根据背景图构造启动图大小,并移动到屏幕中间

m_currentPixmap = m_lstPixmaps.at(m_iCurrentIndex);
QRect size(QPoint(), m_currentPixmap.size() / m_currentPixmap.devicePixelRatio());
size.setHeight(size.height() + StatusBarHeight);
setFixedSize(size.size());
m_pProgressBar->setFixedWidth(size.width() / 8 * 3);
move(QApplication::desktop()->screenGeometry().center() - size.center());

b、绘制程序logo

QPainter painter(&m_currentPixmap);
painter.drawPixmap(m_startPos, m_logo);

c、绘制标题栏

painter.save();
painter.setFont(m_titleFont);
QFontMetrics fontMetrics(m_titleFont);
int textWidth = fontMetrics.width(m_strWindowTitle);
int textHegith = m_logo.height();
QRect textTect = QRect(m_startPos + QPoint(13 + m_logo.width(), 0), QSize(textWidth, textHegith));
painter.drawText(textTect, m_strWindowTitle, QTextOption(Qt::AlignCenter));
painter.restore();

d、设置给QLabel背景图

m_pWindowBackground->setPixmap(m_currentPixmap);

启动图的效果这里就不在贴图了,第三节上的两个gif图都是最终的启动图效果

四、测试

最后就是测试代码了,主要是模拟了程序的一个加载过程

1、构造启动图

首先我们构造一个启动图对象,并设置程序logo和动画模式

GMPSplashScreen * screen = new GMPSplashScreen(QPixmap(":/splashScreen/start.png"));
screen->show();
screen->setLogo(QIcon("logo.ico").pixmap(48, 48));
screen->setTransitionMode(GMPProgressBar::TM_CACHE);

2、背景图

设置背景图,并设置背景图更换时间间隔

QList<QPixmap> lstPixmap;
lstPixmap.append(QPixmap(":/splashScreen/start.png"));
lstPixmap.append(QPixmap(":/splashScreen/start.jpg"));
screen->setPixmap(lstPixmap, 2000);

3、其他信息

设置程序的提示信息和标题栏

screen->showMessage("Established connections", 0);
screen->setTitle(QStringLiteral("广联达BIM土建计量GTJ2018"));

4、事件循环

这里写了一个死循环,主要是为了模拟程序的一个加载过程,每隔10ms处理下界面刷新事件

a.processEvents();
while (1)
{
 QTest::qSleep(10);
 a.processEvents();
}
splashScreen w;
w.show();
screen->finish(&w);

总结

以上所述是小编给大家介绍的C#实现炫酷启动图-动态进度条效果,希望对大家有所帮助,如果大家有任何疑问欢迎给我留言,小编会及时回复大家的!

(0)

相关推荐

  • C# Winform下载文件并显示进度条的实现代码

    方法一: 效果如下图所示: 代码如下: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; namespace WinShowDown { public partial class F

  • C#实现带百分比的进度条功能示例

    本文实例讲述了C#实现带百分比的进度条功能.分享给大家供大家参考,具体如下: 功能需求: 如果程序中会执行一个耗时的计算过程,我想在用户点击按钮后,弹出一个进度条窗口,显示正在执行的进度(最好能带有百分比),执行完成后,进度条窗口关闭,回到主程序窗口. 在关闭子窗口之前父窗体不能点击操作. 实现方法: 先设计Form2进度条窗体,在Form2中央上放ProgressBar控件progressBar1和Label控件label1,代码: public partial class Form2 : F

  • C#中常使用进度条的代码

    复制代码 代码如下: using System; using System.Drawing; using System.Collections; using System.ComponentModel; using System.Windows.Forms; using System.Data; using System.Diagnostics; using System.Threading; namespace WindowsApplication2 { /// <summary> /// 

  • c#根据文件大小显示文件复制进度条实例

    初学者,照着书上的抄袭制作,但已经理解了里面的意思和应用,并且进行了稍微改善和异常捕捉.这里记录下,以防以后用到这方面的知识点. 窗体设计: code: 复制代码 代码如下: using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.

  • c#进度条 progressBar 使用方法的小例子

    复制代码 代码如下: using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Text;using System.Windows.Forms;using Mes.Core; namespace HCMDoImport{    public partial class ProcessBarForm : B

  • asp.net(c#)开发中的文件上传组件uploadify的使用方法(带进度条)

    在Web开发中,有很多可以上传的组件模块,利用HTML的File控件的上传也是一种办法,不过这种方式,需要处理的细节比较多,而且只能支持单文件的操作.在目前Web开发中用的比较多的,可能uploadify(参考http://www.uploadify.com/)也算一个吧,不过这个版本一直在变化,他们的脚本调用也有很大的不同,甚至调用及参数都一直在变化,很早的时候,那个Flash的按钮文字还没法变化,本篇随笔主要根据项目实际,介绍一下3.1版本的uploadify的控件使用,这版本目前还是最新的

  • C#实现带进度条的ListView

    推荐阅读:ListView 百分比进度条(delphi版) 对于已经有的组件,可以直接添加进来,添加后要先运行一下,然后会在工具箱内找到相应控件. 1.首先编写组件,然后将组件添加到工具箱内 编写代码如下: public partial class ListViewEx : System.Windows.Forms.ListView { public ListViewEx() { InitializeComponent(); } //C# listview进度条显示 private Color

  • C#自定义音乐播放器进度条

    有些时候我们做的程序需要进度条,而vs提供的控件不是我们想要的.先看效果图: 进度条闪烁动画,当然背景可设为Transparent 之前想手绘进度条线条的,结果控件运行时会闪烁,所以直接用了panel控件 源码: [DefaultEvent("ProgressClick")] [ToolboxBitmap(typeof(TrackBar))] public partial class ProcessBar : UserControl { public ProcessBar() { //

  • C#实现炫酷启动图-动态进度条效果

    一.简述 最近接到一个新需求,让做一个动效进度条. 由于我们的产品比较大,在软件启动的时候会消耗比较长的时间,原生的进度条已经不能满足我们的需求,这里我们就需要一个会动的进度条,效果如下图所示. 光效进度条主要是做了一个进度动画,在已完成的部分上进行快速的迭代渲染,给用户一种直观感受,我们的软件一直努力加载,它还活着. 有了这个进度条之后,当我们的进度从40%到50%这个持续的过程中,界面再也不会出现假死的情况,是不是很完美呢... 下面我就来分析下这个动效进度条是怎么做的 二.动效进度条 如效

  • Qt实现炫酷启动图动态进度条效果

    目录 一.简述 二.动效进度条 1.光效进度条 2.延迟到达进度条 3.接口说明 三.启动图 1.实现思路 2.背景图切换 四.测试 1.构造启动图 2.背景图 3.其他信息 4.事件循环 五.源码 一.简述 最近接到一个新需求,让做一个动效进度条. 由于我们的产品比较大,在软件启动的时候会消耗比较长的时间,原生的进度条已经不能满足我们的需求,这里我们就需要一个会动的进度条,效果如下图所示. 光效进度条主要是做了一个进度动画,在已完成的部分上进行快速的迭代渲染,给用户一种直观感受,我们的软件一直

  • JavaScript实现简单动态进度条效果

    本文实例为大家分享了js实现动态进度条效果的具体代码,供大家参考,具体内容如下 1.效果 2.源码 <html> <head> <script type="text/javascript"> window.onload = function () { var myProgress = document.getElementById("myProgress"); var mySpan = document.getElementByI

  • vue实现动态进度条效果

    本文实例为大家分享了vue实现动态进度条效果的具体代码,供大家参考,具体内容如下 演示效果: 结构 progress/index.js const controller = { init: require('./controllers/html'), speed: require('./controllers/speed') } exports.init = controller.init exports.speed = controller.speed progress/controllers

  • bootstrap实现动态进度条效果

    Bootstrap的动态进度条: html: 创建一个modal   这里使用fade先将modal隐藏起来,然后modal里面嵌入progress 代码很简单 <div class="modal fade" data-backdrop="static" tabindex="-1" id="progressbar"> <!--窗口声明:--> <div class="modal-dial

  • Android打造炫酷进度条效果

    本文实例为大家分享了Android炫酷进度条效果的具体代码,供大家参考,具体内容如下 学习:视频地址 HorizontalProgressbarWithProgress的代码 import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Paint; import android.os.Build; imp

  • Android view自定义实现动态进度条

    Android  自定义view实现动态进度条 效果图: 这个是看了梁肖的demo,根据他的思路自己写了一个,但是我写的这个貌似计算还是有些问题,从上面的图就可以看出来,左侧.顶部.右侧的线会有被截掉的部分,有懂得希望能给说一下,改进一下,这个过程还是有点曲折的,不过还是觉得收获挺多的.比如通动画来进行动态的展示(之前做的都是通过Handler进行更新的所以现在换一种思路觉得特别好),还有圆弧的起止角度,矩形区域的计算等!关于绘制我们可以循序渐进,比如最开始先画圆,然后再画周围的线,最后设置动画

  • bootstrap+jQuery实现的动态进度条功能示例

    本文实例讲述了bootstrap+jQuery实现的动态进度条功能.分享给大家供大家参考,具体如下: 此款进度条实现的功能: 1.利用了bootstrap的进度条组件. a.在最外层的<div>中加入class .progress,在里层<div>加入class .progress-bar从而实现基本的进度条. b.在外层<div>中加入class .progress-striped实现条纹进度条. c.在内层<div>加入class .progress-b

  • 基于 D3.js 绘制动态进度条的实例详解

    D3 是什么 D3 的全称是(Data-Driven Documents),顾名思义可以知道是一个被数据驱动的文档.听名字有点抽象,说简单一点,其实就是一个 JavaScript 的函数库,使用它主要是用来做数据可视化的.如果你不知道什么是 JavaScript ,请先学习一下 JavaScript,推荐阮一峰老师的教程. JavaScript 文件的后缀名通常为 .js,故 D3 也常使用 D3.js 称呼.D3 提供了各种简单易用的函数,大大简化了 JavaScript 操作数据的难度.由于

  • Android  view自定义实现动态进度条

    Android  自定义view实现动态进度条 效果图: 这个是看了梁肖的demo,根据他的思路自己写了一个,但是我写的这个貌似计算还是有些问题,从上面的图就可以看出来,左侧.顶部.右侧的线会有被截掉的部分,有懂得希望能给说一下,改进一下,这个过程还是有点曲折的,不过还是觉得收获挺多的.比如通动画来进行动态的展示(之前做的都是通过Handler进行更新的所以现在换一种思路觉得特别好),还有圆弧的起止角度,矩形区域的计算等!关于绘制我们可以循序渐进,比如最开始先画圆,然后再画周围的线,最后设置动画

随机推荐