在用QtQuick来编写时间滚动控件有两种方式,一种是用PathView设置路径点,另一种则用用ListView。本次采用ListView来制作时间滚动控件。
ListView可以直接驱动鼠标滚轮和触屏点击,非常有效。Hightlight控件在delegate控件的下面,如果delegate控件的
纯文字,那么文字会显示在Highlight控件的上面,展示出文字和选中的背景。如果delegate同样为一个不透明的控件,那
么hightlight将被覆盖,不会显示,并且滚动时上下边界有弹动效果不是很协调,可以通过调整z值和透明度解决(弹动效果不
能解决).
这里用的做法便是像下面这样,在底层加一个背景控件设置颜色,delegate设置为透明文字控件,hightlight就可
以显示了,文字和背景都能显示,并且顶部和底部的弹动效果,也会消失(因为delegate为纯文字)。当拖动时view会在顶部和
底部多一个item,可设置clip去掉。如下写了一个滚动并且在下下加了渐变设置
新建文件Spanner.qml
import QtQuick 2.7
Item{
id: spannerRoot
width: 30
height: titleText.height + viewRect.height
property int itemCount: 3
property int viewModel: 0
property int viewModelBase: 0
property int dataLength: 0
property string title: ""
property string currentText: view.currentItem.text
signal movementEnded
Text{
id: titleText
width: parent.width
height: 20
color: "white"
text: title
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
Item{
id: viewRect
anchors.top: titleText.bottom
width: parent.width
height: itemCount * 30
ListView{
id: view
anchors.fill: parent
clip: true //去除在拖动时顶部和底部多显示的一个item
preferredHighlightBegin: highlightItem.height
preferredHighlightEnd: 2 * highlightItem.height
highlightRangeMode: ListView.StrictlyEnforceRange
model: viewModel
delegate: Text{
width: parent.width
height: 30
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
//设置不够位数左边用0补齐
text: (new Array(dataLength).join('0') + (viewModelBase + index)).slice(-dataLength)
color: "white"
}
highlight: Rectangle{
color: "lightgreen"
}
onMovementEnded: spannerRoot.movementEnded(); //当滚动结束时将信号导出
}
//添加一个渐变色
Rectangle{
anchors.fill: parent
gradient: Gradient {
GradientStop {
position: 0.00;
color: "transparent";
}
GradientStop {
position: 0.329;
color: "red";
}
GradientStop {
position: 0.33;
color: "transparent";
}
GradientStop {
position: 0.67;
color: "transparent";
}
GradientStop {
position: 0.671;
color: "red";
}
GradientStop {
position: 1.00;
color: "transparent";
}
}
}
}
//根据index设置ListView的当前item
function setCurrentIndex(index){
view.currentIndex = index;
}
}
这样就可以生成一个滚动滚件,参数由外部设置;要生成日期滚动控件,我们需要复制三个,并做一些逻辑判断
新建文件DateEdit.qml
import QtQuick 2.0
Item {
width: dateEditRow.width
height: dateEditRow.height
property var dataLengthArray: [4,2,2]
property var titleArray: ["年","月","日"]
property var modelArray: [14,12,31] //显示model范围
property var modelBaseArray: [year_base(modelArray[0]) + 1,1,1]//显示起点
property string curDate: ""
Row{
id: dateEditRow
spacing: 3
Repeater{
id: spannerRepeater
model: 3
Spanner{
itemCount: 3 //显示的item个数
dataLength: dataLengthArray[index]//数据是几位,不够的用0在左边补齐
title: titleArray[index] //上面的标题
viewModel: modelArray[index] //总共可滚动的项目数
viewModelBase: modelBaseArray[index] //从哪里开始
}
onItemAdded: {
item.movementEnded.connect(autoCorrectDate); //绑定滚动结束的函数
}
}
}
Component.onCompleted: {
//初始化显示当前日期
var currentDate = new Date();
spannerRepeater.itemAt(0).setCurrentIndex(modelArray[0] - 1);
spannerRepeater.itemAt(1).setCurrentIndex(currentDate.getMonth());
spannerRepeater.itemAt(2).setCurrentIndex(currentDate.getDate() - 1);
}
function year_base(modelCount){
var curDate = new Date();
var yearBase;
if(modelArray && modelArray.length > 0)
yearBase = curDate.getFullYear() - modelCount;
else
yearBase = curDate.getFullYear() - 10;
return yearBase;
}
function autoCorrectDate(){
var year = Number(spannerRepeater.itemAt(0).currentText);
var month = Number(spannerRepeater.itemAt(1).currentText);
var day = Number(spannerRepeater.itemAt(2).currentText);
var monthType = month_type(month);
switch (monthType){
case 1:
break;
case 2:
if(is_runnian(year)){
if(day > 29)
spannerRepeater.itemAt(2).setCurrentIndex(modelArray[2] - 3); //最大31天润年2月最大29天,31-29+1=3
}else{
if(day > 28)
spannerRepeater.itemAt(2).setCurrentIndex(modelArray[2] - 4); //最大31天平年2月最大28天,31-28+1=4
}
break;
case 3:
if(day > 30){
spannerRepeater.itemAt(2).setCurrentIndex(modelArray[2] - 2); //最大31天小月30天,31-30+1=2
}
}
curDate = spannerRepeater.itemAt(0).currentText + '-' + spannerRepeater.itemAt(1).currentText + '-' + spannerRepeater.itemAt(2).currentText;
}
function is_runnian(year){
var cond1 = year % 4 == 0; //条件1:年份必须要能被4整除
var cond2 = year % 100 != 0; //条件2:年份不能是整百数
var cond3 = year % 400 ==0; //条件3:年份是400的倍数
//当条件1和条件2同时成立时,就肯定是闰年,所以条件1和条件2之间为“与”的关系。
//如果条件1和条件2不能同时成立,但如果条件3能成立,则仍然是闰年。所以条件3与前2项为“或”的关系。
//所以得出判断闰年的表达式:
var cond = cond1 && cond2 || cond3;
if(cond) {
return true;
} else {
return false;
}
}
function month_type(month){
if(month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12)
return 1;
else if(month == 2)
return 2;
else
return 3;
}
}