How do I create a ripple button effect in QML?

Viewed 1626

I'm using QtQuick/QML and I want to create a ripple effect when I click on a button. I do know that this is available in Material Style, but I think it's an inherent property when you change the theme and I don't want to change anything else in my project.

Is there a way to add ONLY the ripple effect onto my button, and change nothing else? If so, how do I do it?

3 Answers

As Kostia Hvorov said, QtQuick.Controls.Material.impl.Ripple is the easiest way to go. I would like to add my trick to handle rectangular background with radius:

import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Controls.Material.impl 2.12
import QtGraphicalEffects 1.12

Column
{
    spacing: 20
    
    Button
    {
        anchors.horizontalCenter: parent.horizontalCenter
        id: button
        text: "ripple demo"
    }
    
    Ripple {
        id: ripple
        anchors.horizontalCenter: parent.horizontalCenter
        clipRadius: 4
        width: 200
        height: 64
        pressed: button.pressed
        active: button.down || button.visualFocus || button.hovered
        color: "#20FFFFFF"
        layer.enabled: true
        layer.effect: OpacityMask {
            maskSource: Rectangle
            {
                width: ripple.width
                height: ripple.height
                radius: 4
            }
        }
    }
}   

Try it Online

I have made this with some PropertyAnimation. Here is how:

import QtQuick 2.15
import QtQuick.Controls 2.15

Button {
    id: control

    opacity: enabled ? 1.0 : 0.2

    property int tripleWidth: width * 3

    background: Rectangle {
        border.width: 1
        border.color: "black"
        radius: 3
        color: "white"

        clip: true

        Rectangle {
            id: ripple
            property int diameter: 0
            property int pressX: 0
            property int pressY: 0

            x: pressX - radius
            y: pressY - radius

            color: "green"
            radius: diameter / 2
            width: diameter
            height: diameter

            opacity: 1 - diameter / control.tripleWidth

            function animate(x, y, size) {
                pressX = x
                pressY = y
                diameter = size
            }

            Behavior on diameter {
                PropertyAnimation {
                    duration: 200
                    onRunningChanged: {
                        if(!running) {
                            duration = 0;
                            ripple.diameter = 0;
                            duration = 200;
                        }
                    }
                }
            }
        }
    }

    onClicked: {
        ripple.animate(pressX, pressY, control.tripleWidth)
    }

    contentItem: Item {
        implicitWidth: txt.implicitWidth
        implicitHeight: 20

        Text {
            id: txt
            anchors.centerIn: parent
            text: control.text
        }
    }
}

Easiest way to do it - using Ripple from QtQuick.Controls.Material.impl

So just add Ripple to your background Rect:

Ripple {
    clipRadius: height
    width: parent.width
    height: parent.height
    pressed: control.pressed
    anchor: control
    active: control.down || control.visualFocus || control.hovered
    color: control.flat && control.highlighted ?  control.Material.highlightedRippleColor : control.Material.rippleColor
}

You can replace "control.Material.rippleColor" or/and "control.Material.highlightedRippleColor" to any color and get any ripple color effect.

But there is one problem, it will work only with rectangular background(without round) otherwise it will be looking bad.

Related