仿安卓日历的效果(Flickable的使用)——QML

前言

之前博客就写过关于日历的基本功能,无论是用QWidgets还是用QML。然而我一直想要实现像安卓日历的那种如图效果:下拉展开、上滑收住这种效果,但是因为没思路就搁置了,直到我遇到了Flickable。

Flickable很好用,也很常用,比如列表ListView就基于Flickable,有了它,可以显示更多的内容,还携带者一些动画效果,用法也简单,我真的是要吹爆它。

 

效果图

我这个在电脑端调试的,还没在手机端试过,按理说应该没多大问题。

知识点和代码

Flickable的一些知识点

先透个底,我对Flickable的属性和方法,通过帮助文档有一定的了解,但是有些具体怎么结合着用,我还是不清楚,比如:flickDeceleration减速度,这个与谁结合发挥作用?是不是与方法flick(xVelocity, qreal yVelocity)?但是我速度 、减速度的公式忘记了。。。

算了先说我知道的吧,上面的问题,有人会,告诉我一声,不然,不然我也不能怎么样。

Flickable有四个属性是必须要知道的,

width height :这个Flickable的宽和高,就是可视的那个框框的大小
contentWidth 和 contentHeight:这个是内容的宽和高,就是内容条的大小

还有需要注意的是:Flickable里面的项包括它自己不能用id来anchor,而用parent代替,不然你将会看到偏离你设计的界面。如果你嫌弃用parent来锚布局(anchor)麻烦,你可以在Flickable外面包一层Item,上层的项用id 进行锚布局,Flickable可管不住。

上面四个属性够平时用了,不过我这次为了控制Flickable滑动的位置(使其固定停到某个位置),我还用到了另外一属性:
contentY:内容滑动到的Y的值,比如向下滑动100px,contentY将增加100。

代码实现

我将整体分为三部分:年月显示头(CalendarHeader)、当前选中周(WeekRow)显示和日历(calendarItem)显示。年月显示简单,只需要获取当前Date的年月就可以了;我们可以看到当日历收起来时,才会显示选中周的情况,所以这个要根据日历的行为进行显示或隐藏;日历怎需要根据手势的滑动,进行显示或隐藏。

现在思路捋顺了,代码也就出来了,日历部分的代码可参考之前的博客,当前选中周的代码我也不提供了(用ListView实现的,很简单),整体的逻辑界面如下:

import QtQuick 2.12


Item {
    id: myCal;
    property bool isHide:false;

    CalendarHeader{
        id:header;
        z:5;
        anchors{left: parent.left; top: parent.top;right: parent.right;}
    }
    WeekRow{
        id:weekRow;
        z:5;
        anchors{left: parent.left; right: parent.right; top:header.bottom;}
        height: myCal.isHide? 77:35;
        selectVisible: myCal.isHide;
    }
    Item{
        id: calendarItem;
        z:2;
        anchors{left: parent.left; right: parent.right; top: weekRow.bottom; bottom: parent.bottom;}
        Flickable{
            id:myflick;
            anchors.fill: parent;
            contentHeight: 1000;   contentWidth: parent.width;
            MyCalendarWidget{
                id:widget;
                anchors{left: parent.left; right: parent.right; top: parent.top;}
                onClicked: {
                    updateHeader();
                }
            }
            Rectangle{
                id:btn;
                anchors{left: parent.left; right: parent.right; top: parent.top;
                   topMargin: widget.height;}
                height: 10;
                color: "#00000000";
                property string downimg: "qrc:/res/down.png"
                property string img: "qrc:/res/zk.png"
                Image {
                    height: 15; width: 50;
                    anchors.centerIn: parent;
                    source: myCal.isHide ? btn.downimg : btn.img;
                }

            }
            onFlickStarted: {
                if(myCal.isHide)
                {
                    myflick.contentY=0;
                }
                else
                {
                    myflick.contentY=widget.height;
                    var data=packWeekData();
                    weekRow.updateSelectedWeek(data);
                }
                myCal.isHide=!myCal.isHide;

            }

        }
    }
    //将一周的数据以json的格式打包返回
    function packWeekData()
    {
        var selectedDay=widget.selectedDate.getDate();
        var arr=getWeekDateRangeByday();
        var arr1=new Array(7);
        for(var i=0; i<arr.length; i++)
        {
            var obj=new Object;
            obj.day=arr[i].toString();
            if(arr[i]===selectedDay)
                obj.selected=true;
            else
                obj.selected=false;
            arr1[i]=obj;
        }
        var jsonData=JSON.stringify(arr1);
        return jsonData;
    }
    //获取选中日期的一周数据 数组方式返回
    function getWeekDateRangeByday()
    {
        var myArray=new Array(7);
        var date=widget.selectedDate;
        var weekNum=date.getDay();
        var sunDate=new Date(date);
        sunDate.setDate(date.getDate()-weekNum);
        myArray[0]=sunDate.getDate();

        var dateVal=new Date(sunDate);
        for(var i=1; i<=6; i++)
        {
            dateVal.setDate(sunDate.getDate()+i);
            myArray[i]=dateVal.getDate();
        }
        return myArray;
    }
    function updateHeader()
    {
        var year=widget.selectedDate.getFullYear();
        var month=widget.selectedDate.getMonth()+1;
        header.yearTxt=year.toString();
        header.monthTxt=month.toString()+"月";
    }
    Component.onCompleted: {
        updateHeader();
    }


}

 

结束语

在这个日历控件做出后,如果后续写个待办事项,计划啥日历框,方便多了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值