✤ Feb 27, 2015 ✤
新年过后刚上班,略感无聊,然后手里玩着苹果的测试机,突然觉得苹果的开关按钮效果很惹人,遂打算实现一个。
我随便从网上找了一个苹果按钮的gif图,嗯,这个就是我想要实现的效果。
首先,从外观效果来分析一下吧。
大概观察了下,按钮好像差不多就这些属性。
恩,QtQuick 2.4
里,我记得好像是已经新添加了一个类似开关按钮的控件,本来是打算用那个控件重新设计style实现,不过后来我找了半天也没找到那个控件,忘记叫啥名字了。(已经记起名字叫做Switch。)于是,最后决定还是自己完全重新用Rectangle
画一个开关按钮粗来。
根据上面分析的结果,可以这样设计这个组件:整个组件分为3层,底下的背景层、上面的圆按钮、还有在背景层和按钮之间要有一层遮照层。背景、和按钮很好理解,至于为什么还要有一层遮照层呢,主要是因为按下按钮并快速拖动的时候,那个背景吞噬的效果并不是所有控件覆盖的,而是只是在未被拖过的背景才显示,=。=我是实在没啥好的解决办法了,所以才在加上了一层遮照层。
恩,感觉整个设计里面没有啥太大的难度,哦,就是有一点,不是在按下的过程中有吞噬的效果么,本来想可能需要再放一个Rectangle
实现。后来发现,其实我可以用背景矩形的边框做文章。于是,当按钮被按下的时候,背景矩形的边框越來越大越来越大,然后吞噬了整个面板~~嘿嘿
同样,在实现的时候,我还是将控件分为了control和style部分,所有行为的处理都在control里,而样式效果放在了style里。
代码如下:
这是control的代码
//RadioButton.qml
import QtQuick 2.4
import QtQuick.Controls 1.2
import QtQuick.Controls.Private 1.0
Control {
id:root
implicitWidth: 140
implicitHeight: 80
style: Qt.createComponent("RadioButtonStyle.qml", root)
/*! 是否被选中 */
property bool checked: false
/*! 是否被按下,按下并不一定选中 */
readonly property bool pressed: mousearea.pressed || upperma.pressed
MouseArea {
id: mousearea
anchors.fill: parent
onClicked: root.checked = !root.checked
}
Loader {
id: maskloader
property Component __mask //上层按钮
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: __style && __style.bkBorderWidth ? __style.bkBorderWidth : 0
anchors.rightMargin: parent.width-upperloader.x-upperloader.width
anchors.verticalCenter: parent.verticalCenter
sourceComponent: __style && __style.mask ? __style.mask : __mask
}
Loader {
id: upperloader
property Component __up //上层按钮
property real bkBorderWidth: __style && __style.bkBorderWidth ? __style.bkBorderWidth : 0
anchors.verticalCenter: parent.verticalCenter
sourceComponent: __style && __style.upper ? __style.upper : __up
x: root.checked ? root.width-width-bkBorderWidth : bkBorderWidth
onXChanged: {
if (x===root.width-width-bkBorderWidth) {
root.checked = true
}else if (x===bkBorderWidth) {
root.checked = false
}
}
MouseArea {
id:upperma
anchors.fill: parent
drag.target: parent
drag.axis: Drag.XAxis
drag.maximumX: root.width-upperloader.width-upperloader.bkBorderWidth
drag.minimumX: upperloader.bkBorderWidth
onClicked: root.checked = !root.checked
}
}
}
style的代码
//RadioButtonStyle.qml
import QtQuick 2.4
import QtQuick.Controls 1.2
import QtQuick.Controls.Private 1.0
Style {
id:style
property real bkBorderWidth: 2 //背景边框宽度
property real btnBorderWidth: 1 //按钮边框宽度
property color borderColor: "#B4B4B4" //边框颜色
property color checkedColor: "#4BD962" //选中颜色
property color defaultColor: "#FFFFFF" //未选中颜色
property Component upper: Rectangle {
height: control.height-style.bkBorderWidth*2
width: control.pressed ? 4/3*height : height
radius: height/2
color: style.defaultColor
border.width: style.btnBorderWidth
border.color: style.borderColor
Behavior on width {
PropertyAnimation {
}
}
}
property Component mask: Rectangle {
height: control.height-style.bkBorderWidth*2
width: parent.width
radius: height/2
color: control.checked ? style.checkedColor : style.borderColor
}
property Component background: Rectangle {
height: control.height
width: control.width
radius: height/2
color: style.defaultColor
border.width: control.checked || (control.pressed && !control.checked) ? height : style.bkBorderWidth
border.color: control.checked ? style.checkedColor : style.borderColor
Behavior on border.width {
PropertyAnimation {
duration: 350
}
}
}
//布局面板
property Component panel: Item {
anchors.fill: parent
Loader {
anchors.centerIn: parent
sourceComponent: background
}
}
}
运行截图:
未选:
选中:
按下的过程中:
最后,我有两个效果没有实现,被我放弃了。
QAQ谁有好方法,可以教教我~