Android超簡單實現(xiàn)自定義日歷

目錄

前言

由于只想單純的實現(xiàn)一個日歷藤巢,因此整體比較簡單竟纳,沒有過多的代碼撵溃,更方便捋清楚實現(xiàn)日歷的邏輯

效果展示

實現(xiàn)思路

首先日歷控件可以左右滑動因此我們選擇ViewPager來作為最外層容器,然后在頂上加上周日到周六的文字標題

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <TextView
            android:layout_weight="1"
            android:textSize="15sp"
            android:textColor="@color/black"
            android:padding="5dp"
            android:gravity="center"
            android:text="日"
            android:layout_width="0dp"
            android:layout_height="wrap_content"/>
        <TextView
            android:layout_weight="1"
            android:textSize="15sp"
            android:gravity="center"
            android:textColor="@color/black"
            android:padding="5dp"
            android:text="一"
            android:layout_width="0dp"
            android:layout_height="wrap_content"/>
        <TextView
            android:layout_weight="1"
            android:textSize="15sp"
            android:gravity="center"
            android:textColor="@color/black"
            android:padding="5dp"
            android:text="二"
            android:layout_width="0dp"
            android:layout_height="wrap_content"/>
        <TextView
            android:layout_weight="1"
            android:textSize="15sp"
            android:gravity="center"
            android:textColor="@color/black"
            android:padding="5dp"
            android:text="三"
            android:layout_width="0dp"
            android:layout_height="wrap_content"/>
        <TextView
            android:layout_weight="1"
            android:textSize="15sp"
            android:gravity="center"
            android:textColor="@color/black"
            android:padding="5dp"
            android:text="四"
            android:layout_width="0dp"
            android:layout_height="wrap_content"/>
        <TextView
            android:layout_weight="1"
            android:textSize="15sp"
            android:gravity="center"
            android:textColor="@color/black"
            android:padding="5dp"
            android:text="五"
            android:layout_width="0dp"
            android:layout_height="wrap_content"/>
        <TextView
            android:layout_weight="1"
            android:textSize="15sp"
            android:gravity="center"
            android:textColor="@color/black"
            android:padding="5dp"
            android:text="六"
            android:layout_width="0dp"
            android:layout_height="wrap_content"/>
    </LinearLayout>
    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/vpContainer"
        android:layout_width="match_parent"
        android:layout_height="330dp"/>
</LinearLayout>

然后展示具體日期的可以看做是一個七列多行的網(wǎng)格



因此我們可以使用GridView來展示日期锥累,這里我用的是自定義的自適應高度的GridView

class WrapGridView : GridView {
    constructor(context: Context?) : this(context, null)
    constructor(context: Context?, attrs: AttributeSet?) : this(context, attrs, 0)
    constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        val heightSpec = if (layoutParams.height == LayoutParams.WRAP_CONTENT) {
            MeasureSpec.makeMeasureSpec(Int.MAX_VALUE shr 2, MeasureSpec.AT_MOST)
        } else {
            heightMeasureSpec
        }
        // 這幾行代碼比較重要
        super.onMeasure(widthMeasureSpec, heightSpec)
    }
}

然后就是展示日期部分了缘挑,展示日期的時候我們只需要知道展示的月份有多少天和第一天是星期幾即可,每月前幾天的空白可以用空數(shù)據(jù)頂替


/**
     * 獲取第一天為星期幾
     */
    private fun getMonthOneDayWeek(): Int {
        val a: Calendar = Calendar.getInstance()
        a.set(Calendar.YEAR, year)
        a.set(Calendar.MONTH, month)
        a.set(Calendar.DATE, 1) //把日期設置為當月第一天
        return a.get(Calendar.DAY_OF_WEEK)
    }

    /**
     * 獲取當月有幾天
     */
    private fun getMonthMaxDay(): Int {
        val a: Calendar = Calendar.getInstance()
        a.set(Calendar.YEAR, year)
        a.set(Calendar.MONTH, month)
        return a.getActualMaximum(Calendar.DAY_OF_MONTH)
    }
 val data = ArrayList<DateBean>()
        //獲取第一天是星期幾然后計算出需要填充的空白數(shù)據(jù)桶略,這里使用0作為空白數(shù)據(jù)语淘,展示的時候判斷并顯示空
        repeat(getMonthOneDayWeek() - 1){
            //填充空白的
            data.add(DateBean(0,0,0))
        }
        //填充日期數(shù)據(jù)
        repeat(getMonthMaxDay()){
            data.add(DateBean(year,month,it + 1))
        }

這是日期實體類

data class DateBean(var year:Int,var month:Int,var day:Int)

最后的話就是關(guān)于添加多少頁展示數(shù)據(jù)的處理了,這里我設置的當前月之前會固定有200頁(也就是200個月)际歼,當前月之后默認有5頁(5個月)惶翻,當往后滑動頁面的時候會動態(tài)的添加新的頁面

private fun initListener(){
        vpContainer.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
            override fun onPageSelected(position: Int) {
                currentPos = position
                fragments[currentPos].arguments?.let {
                    val currentPageYear = it.getInt(CalendarFragment.YEAR) //當前頁的年
                    val currentPageMonth = it.getInt(CalendarFragment.MONTH) //當前頁的月
                    //展示的月需要加1(因為系統(tǒng)中的月是從0開始的)
                    onPageChangedCallBack?.onPageChanged(currentPageYear,currentPageMonth + 1)
                }
                //刷新下當前的數(shù)據(jù)
                fragments[currentPos].refreshData()
                if(currentPos + 3 > fragments.size){
                    addNextFragment()
                }
            }
        })
    }

    /**
     * 動態(tài)添加后面的日歷
     */
    private fun addNextFragment() {
        fragments[fragments.size-1].arguments?.let {
            //獲取展示的最小的年和月
            val minYear = it.getInt(CalendarFragment.YEAR)
            val minMonth = it.getInt(CalendarFragment.MONTH)
            //動態(tài)加兩個
            for(i in minMonth + 1 until minMonth + 2){
                var month = i
                var year = minYear
                if(i > 11){
                    month = i - 12
                    year = minYear + 1
                }
                val fragment = CalendarFragment(object :OnDateSelectCallBack{
                    override fun onDateSelect(year: Int, month: Int, day: Int) {
                        onDateSelectCallBack?.onDateSelect(year,month,day)
                    }
                })
                val arguments = Bundle()
                arguments.putInt(CalendarFragment.YEAR,year)
                arguments.putInt(CalendarFragment.MONTH,month)
                fragment.arguments = arguments
                fragments.add(fragment)
            }
            fragmentAdapter?.notifyDataSetChanged()
        }
    }

更加詳細的代碼請參考源碼

案例源碼

https://gitee.com/itfitness/calendar-view

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市鹅心,隨后出現(xiàn)的幾起案子吕粗,更是在濱河造成了極大的恐慌,老刑警劉巖旭愧,帶你破解...
    沈念sama閱讀 216,744評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件颅筋,死亡現(xiàn)場離奇詭異宙暇,居然都是意外死亡,警方通過查閱死者的電腦和手機议泵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,505評論 3 392
  • 文/潘曉璐 我一進店門占贫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人肢簿,你說我怎么就攤上這事靶剑。” “怎么了池充?”我有些...
    開封第一講書人閱讀 163,105評論 0 353
  • 文/不壞的土叔 我叫張陵桩引,是天一觀的道長。 經(jīng)常有香客問我收夸,道長坑匠,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,242評論 1 292
  • 正文 為了忘掉前任卧惜,我火速辦了婚禮厘灼,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘咽瓷。我一直安慰自己设凹,他們只是感情好,可當我...
    茶點故事閱讀 67,269評論 6 389
  • 文/花漫 我一把揭開白布茅姜。 她就那樣靜靜地躺著闪朱,像睡著了一般。 火紅的嫁衣襯著肌膚如雪钻洒。 梳的紋絲不亂的頭發(fā)上奋姿,一...
    開封第一講書人閱讀 51,215評論 1 299
  • 那天,我揣著相機與錄音素标,去河邊找鬼称诗。 笑死,一個胖子當著我的面吹牛头遭,可吹牛的內(nèi)容都是我干的寓免。 我是一名探鬼主播,決...
    沈念sama閱讀 40,096評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼计维,長吁一口氣:“原來是場噩夢啊……” “哼袜香!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起享潜,我...
    開封第一講書人閱讀 38,939評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎嗅蔬,沒想到半個月后剑按,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體疾就,經(jīng)...
    沈念sama閱讀 45,354評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,573評論 2 333
  • 正文 我和宋清朗相戀三年艺蝴,在試婚紗的時候發(fā)現(xiàn)自己被綠了猬腰。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,745評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡猜敢,死狀恐怖姑荷,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情缩擂,我是刑警寧澤鼠冕,帶...
    沈念sama閱讀 35,448評論 5 344
  • 正文 年R本政府宣布,位于F島的核電站胯盯,受9級特大地震影響懈费,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜博脑,卻給世界環(huán)境...
    茶點故事閱讀 41,048評論 3 327
  • 文/蒙蒙 一憎乙、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧叉趣,春花似錦泞边、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,683評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至乡数,卻和暖如春椭蹄,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背净赴。 一陣腳步聲響...
    開封第一講書人閱讀 32,838評論 1 269
  • 我被黑心中介騙來泰國打工绳矩, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人玖翅。 一個月前我還...
    沈念sama閱讀 47,776評論 2 369
  • 正文 我出身青樓翼馆,卻偏偏與公主長得像,于是被迫代替她去往敵國和親金度。 傳聞我的和親對象是個殘疾皇子应媚,可洞房花燭夜當晚...
    茶點故事閱讀 44,652評論 2 354

推薦閱讀更多精彩內(nèi)容