资讯动态

Qt自绘电池进度条:paintEvent实战与避坑指南

发布时间:2026/10/15 11:07:01 来源:尧图企业网站定制
简介一套面向Qt初学者的自定义控件示例聚焦重写paintEvent实现电池进度条覆盖QPainter基本绘制、电量比例计算、状态颜色切换与QPropertyAnimation动画驱动适合需要掌握Qt绘图和控件封装的开发者。压缩包共8个文件含3个cpp源文件、2个h头文件、1个pro工程文件、1个ui界面文件及1个工程配置user文件从源码实现、类声明到可视化布局和构建配置均有体现仅7KB体积结构清晰便于逐文件拆解学习。已有498人学习使用。示例逐层绘制电池外壳与电量内芯并以80%、20%为阈值切换正常色、警示色与过渡色直观呈现电量状态同时演示QPropertyAnimation驱动电量变化触发动态更新以及避免在paintEvent中重复计算、分离绘制逻辑与动画逻辑等优化手法。读者可借此快速熟悉Qt自定义控件从绘图到动画的完整实现链路是入门Qt图形界面设计的实用参考。1. 用paintEvent自绘电池别用三个QLabel拼出一个假电池要做一个带百分比数字的电池进度条很多人的第一反应是拼控件一个外框 QLabel、一个填充 QProgressBar、再加一个文字 QLabel。这个方案在小窗口里看着还行一旦放到状态栏、DPI 变化或者窗口拉伸三个控件的对齐就开始互相打架——圆角的弧度对不上、文字偏移两三个像素、电量填充的边距忽宽忽窄。用 paintEvent 自绘电池就是让外框、电量填充、刻度、文字共用同一套坐标在一次重绘里全部画完。这篇笔记围绕 Qt 绘制电池进度条paintEvent实现里最难拿捏的几个点展开重绘触发机制、坐标系规划、绘制顺序、动画刷新以及我踩过的几个真实坑。适合会用 QWidget、但还没系统梳理过自绘控件的开发者照着代码走一遍就能落地使用。2. 电池控件的底座paintEvent 的触发机制与坐标规划自绘控件的第一步不是画而是搞清楚 paintEvent 什么时候会被调用、每次调用要干什么。很多新手把绘制逻辑写在业务槽函数里数据一变就调 repaint()结果界面又卡又闪。这一章先把「谁在叫 paintEvent」讲清楚再给出一套坐标计算方案这两件事理顺了后续画出来的东西才是稳的。2.1 重绘从哪来update()、repaint() 与系统事件paintEvent 由事件系统驱动不是想调就能调的。最常见的触发源有三类窗口系统事件窗口被遮挡、移动、resize、显式调用 update()、显式调用 repaint()。窗口系统事件不受我们控制但后两个可以控制。一个典型的电池控件骨架长这样class BatteryWidget : public QWidget { Q_OBJECT public: explicit BatteryWidget(QWidget *parent nullptr); void setValue(int percent); int value() const { return m_percent; } protected: void paintEvent(QPaintEvent *event) override; private: int m_percent 62; // 默认显示 62% 电量 };setValue 的写法是整个控件的关键入口void BatteryWidget::setValue(int percent) { percent qBound(0, percent, 100); // 把电量强制限制在 0~100 之间 if (m_percent percent) return; // 值没变直接返回避免无谓重绘 m_percent percent; update(); // 异步请求一次重绘 }这里的逻辑有必要拆开说。qBound 保证了数据合法性外界传入 120 或 -5 都不会把控件画崩提前 return 处理了「连续 setValue 同一个值」的重复重绘问题最后的 update() 才是重绘的实际入口。update() 是异步的它只标记当前控件需要重绘然后回到事件循环里统一派发 paintEvent所以连续两次 setValue 只会触发一次重绘。这一点对动画场景尤其重要充电动画里每秒要刷新 30 次如果用 repaint() 同步重绘界面会明显掉帧。repaint() 与 update() 的区别在于它是同步的调用 repaint() 会立即执行 paintEvent不等事件循环。常规 UI 场景我几乎不用 repaint()只有一种情况例外——必须在某一帧里立刻把最新状态画出来比如视频播放器直接把帧数据贴到控件上。画一个电池进度条用 update() 就够了。还有一点值得注意paintEvent 每次被调用时整个控件区域都会被重绘。事件对象里带了需要更新的 region 信息但绝大多数场景直接用 event-rect() 或者干脆不理会事件参数整块重绘。局部重绘优化只在控件特别复杂时才需要考虑电池控件只有几行绘制整块重绘的成本可以忽略。写自定义控件时推荐在构造函数里设置两个属性BatteryWidget::BatteryWidget(QWidget *parent) : QWidget(parent) { setAttribute(Qt::WA_OpaquePaintEvent, true); setAttribute(Qt::WA_NoSystemBackground, false); }WA_OpaquePaintEvent 告诉 Qt 这个控件会画满整个区域不用先做背景清除直接省掉一次清屏操作WA_NoSystemBackground 也是类似的语义。如果控件有透明区域这两个属性就不要开否则会出现拖影。2.2 先算坐标再动笔外壳、壳体、内胆的尺寸分层画电池最忌在 paintEvent 里写一堆魔法数字比如 drawRect(10, 10, 80, 20)。控件一旦 resize这些数字就全废了。我的习惯是先把电池拆成三层外壳、壳体、内胆每个层次单独用一个函数计算坐标绘制代码只消费计算结果。QRectF BatteryWidget::shellRect() const { const qreal tipWidth 12; // 正极凸起占用的宽度 const qreal margin 2; // 与外边界的间距 return QRectF(margin, margin, width() - tipWidth - margin, height() - 2 * margin); } QRectF BatteryWidget::innerRect() const { QRectF shell shellRect(); return shell.adjusted(4, 4, -4, -4); // 壳体内边距 4px }这里把正极凸起放进了坐标规划而不是画的时候临时加偏移。原因是后续的刻度线、文字、电量填充都要以外壳左边界为参照正极凸起的宽度在 shellRect 里被提前扣除后所有子元素都能天然对齐。两个函数返回的都是 QRectF 而不是 QRect是有意为之。QRect 用整数坐标在 DPI 缩放或圆角矩形的浮点边界下容易产生 1px 的误差累积QRectF 在计算阶段保留小数哪怕最终绘制时像素会取整误差也被均匀分摊到边缘视觉上更干净。为什么要给电量填充留 4px 内边距一是视觉上让电量「泡在」壳体里更贴近真实电池二是当电量百分比特别低时填充矩形变窄如果紧贴外壳圆角矩形在窄条状态下会画出怪异的形状留出内边距后仍然能保持对称。刻度线则画在外壳和内胆之间的夹层区域这个细节到了第 3 章再展开。坐标规划做完后绘制顺序也必须钉死。我固定用五步先画外框再画内胆背景然后画电量填充接着画高光与刻度最后写文字。顺序不能乱——先写文字再画填充文字会被盖住把高光放在最后高光会把填充边缘盖掉看起来像电池缺了一块。颜色方案上我踩过坑后面避坑章会有详细记录。3. 绘制电池外观圆角外框、渐变高光与分段电量到了真正动笔的环节。这一章的代码量是全文最多的部分建议直接照抄后改参数跑一遍再根据视觉效果微调颜色。我给出的是一套比较通用的灰白配色深浅两套主题下都能看清。3.1 外框与正极凸起圆角半径怎么定电池外壳用圆角矩形画半径和尺寸比例直接相关。高度 30px 左右的控件圆角半径 6px 是合适范围半径再大电池就会变成胶囊形状不像电池。正极凸起是一个小长条矩形高约 8px圆角半径 2px与外壳中心线对齐。void BatteryWidget::paintEvent(QPaintEvent *event) { Q_UNUSED(event); QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing, true); QRectF shell shellRect(); QRectF tip(shell.right() 3, shell.center().y() - 4, 8, 8); // 正极凸起宽 8 高 8 QPen framePen(QColor(0x88, 0x8e, 0x99)); framePen.setWidthF(1.5); painter.setPen(framePen); painter.setBrush(Qt::NoBrush); painter.drawRoundedRect(shell, 6, 6); painter.drawRoundedRect(tip, 2, 2); }代码逻辑先用 shellRect 拿到外壳矩形tip 的 x 坐标接在外壳右边界之后y 方向手动偏移半高来实现垂直居中。画笔宽度 1.5px 比默认的 1px 略粗外框轮廓更清晰又不会像 2px 那样在小尺寸下吃掉太多内部空间。setBrush(Qt::NoBrush) 是这一小段里最容易漏掉的语句漏掉的后果第 5 章会单独讲。外框画完后内部还是透明的。要做真实感需要在壳体内画一层浅灰背景模拟空电池的暗腔painter.setPen(Qt::NoPen); painter.setBrush(QColor(0xee, 0xf0, 0xf3)); painter.drawRoundedRect(shell.adjusted(1, 1, -1, -1), 5, 5);这层底色的意义在于无论电量多低视觉上都能看出电池内部不是空的。adjusted(1,1,-1,-1) 让底色比外壳小一圈避免灰色背景在圆角处溢出外壳边缘。接下来是外壳顶部的高光。真实电池的外壳是光滑塑料上边缘会形成一条白色反光带。这个效果用 QLinearGradient 就能实现成本极低但观感提升明显QLinearGradient gloss(shell.topLeft(), shell.bottomLeft()); gloss.setColorAt(0.0, QColor(255, 255, 255, 180)); gloss.setColorAt(0.12, QColor(255, 255, 255, 40)); gloss.setColorAt(1.0, QColor(255, 255, 255, 0)); painter.setPen(Qt::NoPen); painter.setBrush(gloss); painter.drawRoundedRect(shell, 6, 6);渐变沿垂直方向展开顶部是半透明白色到 12% 高度处迅速衰减到接近透明整条高光只占外壳高度很少的一部分不喧宾夺主。如果不需要高光把这段删掉不影响功能。3.2 电量填充纯色、渐变与低电量分色策略电量填充是控件的灵魂。最简单的实现是纯色矩形但真实设备在满电和低电量时视觉反馈差异很大所以把颜色按电量分段更实用QColor BatteryWidget::fillColor() const { if (m_percent 60) return QColor(0x2e, 0xcc, 0x71); // 健康段绿色 if (m_percent 20) return QColor(0xf3, 0x9c, 0x12); // 警戒段橙色 return QColor(0xe7, 0x4c, 0x3c); // 危险段红色 }60/20 是移动设备常见的电量分割点。如果你的场景是工业设备要求 40% 就进入警戒直接改阈值和颜色即可。注意不要在 paintEvent 里临时计算三个颜色再比较把颜色决策抽成单独函数后期调色只改一个地方。填充的绘制核心在于宽度计算和圆角处理QRectF inner innerRect(); qreal fillWidth inner.width() * m_percent / 100.0; QPainterPath innerClip; innerClip.addRoundedRect(inner, 4, 4); painter.save(); painter.setClipPath(innerClip); // 限定绘制范围到内胆圆角 QColor fill fillColor(); painter.setPen(Qt::NoPen); painter.setBrush(fill); painter.drawRect(QRectF(inner.left(), inner.top(), fillWidth, inner.height())); painter.restore();fillWidth 把百分比线性映射到内胆宽度这个公式保证控件 resize 后填充比例依旧正确。为什么不用 drawRoundedRect 画填充因为当 fillWidth 只有 5px 而圆角半径写 4px 时Qt 会把矩形强行画成接近胶囊的形状中间直线几乎消失。用 clipPath 限定绘制范围后填充矩形即使越界也会被圆角剪裁得整整齐齐这是替代「窄条圆角矩形」最稳的方案。clip 路径的半径要与内胆圆角一致否则左边上下角会露直角。如果追求更精致的液面观感可以加垂直渐变QLinearGradient liquid(fillRect.topLeft(), fillRect.bottomLeft()); liquid.setColorAt(0.0, fill.lighter(120)); liquid.setColorAt(1.0, fill.darker(115)); painter.setBrush(liquid); painter.drawRect(fillRect);lighter(120) 把当前颜色提亮 20%darker(115) 压暗 15%渐变方向自上而下模拟光从液体上层进入的立体感。个人经验渐变只适合宽条填充fillWidth 很窄时亮暗过渡会显得杂乱此时直接退回纯色更好。3.3 刻度线与充电状态边框最后一步是给电池加刻度线增加精细感。刻度线画在壳体底部像真实电池的凹槽标注每段长约 4px 就够位置在内胆下边缘与外壳之间painter.setPen(QPen(QColor(0xbb, 0xc0, 0xc8), 1)); for (int i 1; i 5; i) { qreal x inner.left() inner.width() * i / 5.0; painter.drawLine(QPointF(x, shell.bottom() - 6), QPointF(x, shell.bottom() - 3)); }循环从 1 到 4把内胆宽度等分成五段四条刻度线均匀分布。x 坐标完全基于内胆计算控件拉伸成任何比例刻度都跟随壳体走。颜色选比外框浅一个层次的灰不抢戏。充电状态的外框变色逻辑可以放在这里一并处理通过一个 bool 标志位切换边框颜色让外框从灰色变为绿色视觉上立刻识别出「正在充电」。静态电池绘制到这里闭环了。把 BatteryWidget 放进窗口 setFixedSize(100, 36)编译运行你会看到一个灰白外壳、绿色填充、底部带四条刻度的小电池。如果没有达到预期多半是坐标计算或绘制顺序的问题对着代码逐段比对即可。4. 让电池会说话文字基线、充电动画与呼吸灯稳定的电池只能算半成品工程落地还需要百分比文字、电量变化的动画过渡、充电状态的视觉提示。这一章的内容来自我在设备状态栏项目里的实际实现算是把电池控件从「能看」变成「会用」的关键。4.1 百分比居中把 QFontMetrics 的基线算对很多开发者会在 paintEvent 里这样写文字painter.drawText(innerRect(), Qt::AlignCenter, QString::number(m_percent) %);这段代码表面看没问题实际运行时会发现文字整体偏上或偏下 1~2px换一种字体偏移量又不一致。原因在于 drawText 的矩形对齐以「行盒」为基准而视觉中心其实是字体的 x-height 中心两者有偏移。想让百分比在内胆里真正视觉居中必须手动算基线位置QString text QString::number(m_percent) %; QFont font painter.font(); font.setPixelSize(14); font.setBold(true); painter.setFont(font); QFontMetricsF fm(font); QRectF textRect innerRect(); qreal textWidth fm.horizontalAdvance(text); qreal baseline textRect.center().y() (fm.ascent() - fm.descent()) / 2.0; painter.setPen(QColor(0x33, 0x33, 0x33)); painter.drawText(QPointF(textRect.center().x() - textWidth / 2.0, baseline), text);baseline 的公式逻辑字体绘制时文字主体的真实高度是 ascent descentcenter 位置应该在 baseline 上方 descent 一半处。所以从矩形中心向下挪 (ascent - descent) / 2文字主体就会真正居中。这个公式可以原样套到任何文字自绘控件建议存成工具函数复用。文字颜色也要斟酌。电量 35% 时绿色背景配白字没问题电量 90% 时背景是亮绿色白字就几乎看不清了。所以我在电量高于 80% 时切换到深色文字if (m_percent 80) painter.setPen(QColor(0x1f, 0x2d, 0x3d)); else painter.setPen(QColor(0xff, 0xff, 0xff));这个细节看起来不值一提但满电状态时深灰字和低电量时白字可读性差距非常明显。我第一次只用了白字结果满电时数字糊成一团后来才补上这个分支判断。4.2 QPropertyAnimation 驱动的电量过渡动画电量从 20% 跳到 85%界面直接刷新会显得很生硬。真实设备充电时电量是渐进增长的用 QPropertyAnimation 插值一个 m_visualPercent 是最贴近真实观感的做法。先让控件暴露可动画属性class BatteryWidget : public QWidget { Q_OBJECT Q_PROPERTY(int visualPercent READ visualPercent WRITE setVisualPercent) public: int visualPercent() const { return m_visualPercent; } void setVisualPercent(int value) { m_visualPercent value; update(); } void animateSetValue(int targetPercent); private: int m_visualPercent 62; QPropertyAnimation *m_animation nullptr; };animateSetValue 创建并启动动画void BatteryWidget::animateSetValue(int targetPercent) { if (m_animation) { m_animation-stop(); m_animation-deleteLater(); } m_animation new QPropertyAnimation(this, visualPercent, this); m_animation-setDuration(500); m_animation-setStartValue(m_visualPercent); m_animation-setEndValue(targetPercent); m_animation-setEasingCurve(QEasingCurve::OutCubic); m_animation-start(); }Q_PROPERTY 这一行是整个动画能跑起来的前提。QPropertyAnimation 通过属性名查找 setter如果类没有声明 Q_PROPERTY动画会直接报错停止。动画时长 500ms 比较平衡太短像瞬移太长让用户觉得电量刷新迟钝OutCubic 让动画先快后慢接近真实电量的爬升手感。还有一个容易忽略的点动画插值过程中 setVisualPercent 被调用多次每次都触发 update()500ms 的动画大概会触发 30~60 次重绘。单个控件完全没问题但如果同时有 20 个电池控件做动画就得考虑让所有电池共享一个 100ms 的公共 QTimer 统一刷新。我后来的仪表盘项目就是让所有电池共享刷新定时器动画只更新数值重绘频率由外部控制。4.3 充电状态闪电符号与呼吸效果充电中的电池应该有区别于普通状态的外观。我的做法是外框改色加呼吸效果。呼吸效果需要一个随时间变化的 alpha 值用 QTimer 累加相位后触发重绘QTimer *breathTimer new QTimer(this); connect(breathTimer, QTimer::timeout, this, [this]() { m_breathePhase 0.15; if (m_breathePhase 2 * M_PI) m_breathePhase 0; update(); }); breathTimer-start(60);绘制时把外框颜色按正弦做透明度变化qreal breatheAlpha 0.55 * (1 sin(m_breathePhase)); QColor breathColor QColor(0x26, 0x9a, 0x5c, int(120 130 * breatheAlpha)); QPen breathPen(breathColor); breathPen.setWidthF(2.5); painter.setPen(breathPen); painter.drawRoundedRect(shell, 6, 6);呼吸的本质是 alpha 在 120 到 250 之间平滑摆动绿色边框像「透出」又「隐入」。定时器 60ms 一帧配上正弦波形观感足够流畅。呼吸只改变描边颜色不重新计算坐标绘制开销和静态时几乎一样。闪电符号用 QPainterPath 画折线放在内胆中央QPainterPath bolt; qreal cx inner.center().x(); qreal cy inner.center().y(); bolt.moveTo(cx 5, inner.top() 2); bolt.lineTo(cx - 4, cy); bolt.lineTo(cx 1, cy); bolt.lineTo(cx - 5, inner.bottom() - 2); bolt.lineTo(cx 4, cy - 1); painter.setPen(QPen(QColor(0xff, 0xff, 0xff), 2)); painter.drawPath(bolt);路径把闪电画成上下两折白色描边配合绿色边框视觉上像是真有一个小闪电嵌在电池里。路径坐标全部基于 inner 中心偏移无论控件尺寸如何变化闪电始终居中。5. 电池自绘的避坑指南五条血泪排查记录这一章整理的是我在实际项目里踩过、以及帮同事排查过的典型问题每条按「现象 → 原因 → 解决」的结构写。问题单独看都不大但排查起来往往要花掉一个下午。5.1 现象拖动窗口时电池区域疯狂闪烁、CPU 占用飙升原因绝大多数是 paintEvent 里做了耗时操作比如每次重绘都读取并缩放图片、创建字体或 QPixmap 对象。闪烁的根源是重绘频率过高且每次重绘都要重新分配资源Qt 的自动擦除背景和绘制叠加就成了肉眼可见的撕裂。解决把所有耗时资源创建移出 paintEvent在构造函数里预创建paintEvent 里只做绘制。如果控件有半透明叠加需求启用 Qt::WA_NoSystemBackground 并自行负责背景清除。再检查代码里是否误用了 repaint()——改成 update()让 Qt 合并重绘请求闪烁通常立刻缓解大半。5.2 现象圆角矩形边缘出现一圈锯齿白边放大看还有缺口原因绘制时没开抗锯齿或者内胆填充与外框圆角用了不同半径的圆角矩形叠加导致局部像素覆盖不均。白边是外壳底色与填充色之间的缝隙在设备像素上取整产生的。解决paintEvent 开头先执行 painter.setRenderHint(QPainter::Antialiasing, true)内胆 clip 路径的圆角半径与内胆保持一致再检查内胆与外框间距是否落在整数像素上。1.5px 画笔在高 DPI 下会产生半像素偏移必要时将画笔宽度调整为整数。5.3 现象百分比文字总是偏上两三个像素换字体后偏移量还变原因用 drawText(rect, Qt::AlignCenter) 时 Qt 按行盒垂直居中不同字体的 ascent/descent 比例不同行盒中心与视觉中心不重合。解决弃用矩形对齐改用 4.1 节的基线公式。先取字体度量算 baseline再用 drawText(QPointF, text) 定点绘制。这个方法对任何文字自绘控件通用抽成工具函数后到处复用。5.4 现象想画空心外框结果画成了实心圆角块原因画笔与画刷混淆。上一段代码里给 painter 设置了内部背景画刷画外框时忘了恢复为 Qt::NoBrushdrawRoundedRect 就同时用了画刷填充整个圆角矩形。解决养成习惯每次绘制前统一设置画笔和画刷painter.setPen(framePen); painter.setBrush(Qt::NoBrush); painter.drawRoundedRect(shell, 6, 6);同一段代码里既有填充又有描边时用 painter.save() 与 painter.restore() 把状态包起来避免后续绘制污染。5.5 现象调了 setValue 界面却长时间不更新甚至完全不更新原因常见三种——setValue 里忘了调用 update()百分比值没变被早退拦截用了 QPropertyAnimation 但类没声明 Q_PROPERTY动画直接失败数值停在旧值。第三种最隐蔽代码不报错只有运行时才发现数值纹丝不动。解决先确认 setValue 末尾有 update()再在 setValue 里 qDebug 打印当前值确认没走进「值没变就 return」分支最后检查 Q_PROPERTY 声明是否完整READ 和 WRITE 两个方法名拼写一致。三处排查完更新问题基本能定位。提示排坑时开着 Qt 调试输出很多自绘问题在 debug 版会打印 QPainter 警告这些警告往往直接指向问题根因。6. 把电池控件嵌进状态栏尺寸策略、高DPI适配与一次性能实测自绘控件最终要放回真实界面。我自己的常态场景是把电池放在状态栏右侧偶尔也塞进标题栏。这两类场景对控件的要求完全不同状态栏高度固定不允许控件自行撑大标题栏则要求电池跟随窗口缩放。6.1 状态栏尺寸策略高度跟随而非写死状态栏高度通常在 30px 左右直接 setFixedSize(100, 30) 在大多数系统下能用但状态栏高度并非完全一致写死高度会在某些主题下溢出 1~2px。稳妥做法是宽度固定、高度留弹性battery-setFixedWidth(100); battery-setMinimumHeight(statusBar()-height() - 6); battery-setMaximumHeight(statusBar()-height() - 2);宽度固定 100px 保证电池长宽比不变高度跟随状态栏实际高度收缩 2~6px。电池既不会顶到状态栏上下边界也不破坏整体视觉比例。高度变化时 paintEvent 里的坐标函数基于 height() 实时计算电池外形自动适配无需额外代码。6.2 高DPI适配别手动乘 devicePixelRatio高 DPI 下有个隐藏很深的坑不少开发者以为 QPainter 不会自动处理缩放于是手动乘 devicePixelRatio 再绘制。结果在 150% 缩放下电池变成原来一倍半大所有坐标错位。真相是——Qt6 启动时检测到系统缩放比例后QWidget 的 width() 返回的已经是逻辑像素值QPainter 在 paintEvent 内默认把逻辑坐标映射到设备像素。代码里不需要乘任何东西也不需要调用 painter.scale()。只要满足两点坐标全部基于控件的 width()/height() 计算绘制时开启抗锯齿。本章之前的代码全部满足同样的代码放到 4K 屏下电池依然清晰且比例正确。最后做一次性能实测。我用 QElapsedTimer 测过单个电池控件的 paintEvent 耗时绘制外框、内胆、填充、文字和刻度约 0.15ms加上呼吸动画的 alpha 计算约 0.2ms。状态栏同时放 10 个电池控件总耗时约 2ms完全不用做额外缓冲优化。如果仪表盘要同时画 50 个电池建议把所有电池的呼吸定时器合并成一个公共定时器统一驱动 alpha 相位这样能把重绘次数从 50 次降到 1 次。把电池控件接到大项目时建议把坐标规划、绘制、动画三层拆成独立文件避免一个类越写越大。我后来接自绘控件项目都固定走这套流程先独立窗口调好静态绘制再接进状态栏验证尺寸最后才加动画和充电逻辑。每次改动都强制走一遍「改代码 → 编译 → 看效果」的最小循环省掉了大量反复调整尺寸和颜色的时间。这套带完整源码的电池控件方案打包好了下载后直接编译就能跑剩下的微调交给你自己的配色偏好。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑