在 Qt 中实现变色的图标(tintColor)

响应状态的按钮图标

很多时候,设计要求当按钮的状态变化时(比如 hover、按下,禁用),按钮的背景、文字、图标能够改变颜色,以反馈按钮的当前状态。如下图:

改变文字、背景的颜色很容易,但是改变图标颜色就比较麻烦了。早期的方案,是提供一整套不同颜色图片,分别设置给不同的状态。

比如 iOS 上的 UIButton:

func setImage(UIImage?, for: UIControl.State)
// Sets the image to use for the specified state.

再比如 Android 上的 Drawable selector:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- pressed -->
    <item android:drawable="@drawable/button_1_selected" android:state_pressed="true"/>
    <!-- focused -->
    <item android:drawable="@drawable/button_1_normal" android:state_focused="true"/>
    <!-- default -->
    <item android:drawable="@drawable/button_1_normal"/>
</selector>

所有一旦要新加或者改变一个图标,都要设计提供一组图片文件,开发一个个的加到代码项目中,再添加一组设置图片的代码,是特别的麻烦。

后来,一些平台提供了相关的解决方案,就是 tintColor。有了 tintColor, 只要一张图片就可以了,通过代码就可以改变图标的颜色。

这里我们主要针对 Qt 框架,对其他平台的 tintColor 有兴趣的话,可以查看下面给出的文档:

Apple Developer Documentation

ImageView  |  Android Developers

给 Qml Image 增加 tintColor

在 Qt 中,目前并不支持 tintColor,所有还需要我们自己造轮子。

不过我们只打算在 Qml 中支持,如果你使用 QWidget,也可以参考我们的思路自己动手实现一个。

先看一下最终给使用者的控件:

import QtQuick 2.12
import QtQuick.Controls 2.5

Image {

    property url originSource
    property string tintColor

    source: {
        if (Qt.colorEqual(tintColor, "transparent"))
            return originSource
        return "image://EffectSync/tint/")
                + encodeURIComponent(originSource)
                + "?tintColor=" + tintColor
    }
}

使用者只需要设置 originSource 和 tintColor 就可以了。

实现 QQuickImageProvider

上面的关键是 "image://" 开头的 url,是通过 ImageProvider 实现的。

如何实现 QQuickImageProvider,在我的另一篇文章中有进过,所以不再重复了。

实现 tintColor 效果

在 QQuickImageProvider 中,拿到原始图片 image 后,我们直接就地修改 image 的像素,将所有颜色,替换为 tintColor 的 r、g、b 值:

    auto size = image.bytesPerLine();
    auto a = tintColor_.alpha();
    auto r = tintColor_.red() * a / 255;
    auto g = tintColor_.green() * a / 255;
    auto b = tintColor_.blue() * a / 255;
    for (int i = 0; i < image.height(); ++i) {
        auto bytes = image.scanLine(i);
        auto end = bytes + size;
        while (bytes < end) {
            if (bytes[3]) {
                a = bytes[3];
                if (a == 255) {
                    bytes[0] = b;
                    bytes[1] = g;
                    bytes[2] = r;
                } else {
                    bytes[0] = b * a / 255;
                    bytes[1] = g * a / 255;
                    bytes[2] = r * a / 255;
                }
            }
            bytes += 4;
        }
    }

注意,QImage 图片的像素一般是 premultiplied ,所以要乘以原始像素的 alpha 值。但是如果原始像素 alpha 为 0,可以不修改改像素,优化性能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Fighting Horse

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值