Android 自定義日歷控件

廢話不多說(shuō),先直接上最終的效果圖(完整代碼鏈接在底部)
日歷.png

實(shí)現(xiàn)思路

首先缤弦,我們將效果圖實(shí)現(xiàn)的過程坦冠,拆分:
1形耗,將整個(gè)布局進(jìn)行拆分,分別實(shí)現(xiàn)
2辙浑,用系統(tǒng)calendar類實(shí)現(xiàn)數(shù)據(jù)填充
3激涤,附屬數(shù)據(jù)的填充(比如日消費(fèi)什么的)

第一步,界面鋪設(shè)

瞄一眼判呕,就很容易得出該日歷由三個(gè)部分組成倦踢,
a.月份標(biāo)題
b.星期數(shù)
c.日歷數(shù)據(jù)
以下是我的實(shí)現(xiàn)布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="40dp">

        <ImageView
            android:id="@+id/btn_calendar_pre"
            android:layout_width="60dp"
            android:layout_height="30dp"
            android:layout_centerVertical="true"
            android:src="@mipmap/arrow_pre" />

        <TextView
            android:id="@+id/tv_calendar_date"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="5月18"
            android:textColor="#000000"
            android:textSize="20sp" />

        <ImageView
            android:id="@+id/btn_calendar_next"
            android:layout_width="60dp"
            android:layout_height="30dp"
            android:layout_alignParentRight="true"
            android:layout_centerVertical="true"
            android:src="@mipmap/arrow_next" />

    </RelativeLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:gravity="center_vertical"
        android:orientation="horizontal">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="30dp"
            android:layout_weight="1"
            android:gravity="center"
            android:text="日"
            android:textColor="#000"
            android:textSize="16sp" />

      //..........

    </LinearLayout>

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recy_calendar"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />

</LinearLayout>

效果如下,主要功能在日歷數(shù)據(jù)的展示上面侠草,我采用的是recycleview布局


布局.png

第二步辱挥,日歷數(shù)據(jù)的填充

 private void initData(Context context) {
        dateList.clear();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy - MM");
        //年月--設(shè)置標(biāo)題欄的數(shù)據(jù)
        String dateTitle = sdf.format(mCalendar.getTime());
        tvDateTitle.setText(dateTitle);

        //表格中的數(shù)據(jù)
        Calendar calendar = (Calendar) mCalendar.clone();
        calendar.set(Calendar.DAY_OF_MONTH, 1); //設(shè)置時(shí)間到當(dāng)前月份的第一天

        //1---代表周日  2---代表周一
        int firstDay = calendar.get(Calendar.DAY_OF_WEEK);//獲取日期的偏移量

        int preDays = firstDay - 1; //因?yàn)榻菢?biāo)是從0開始的
        //僅僅美觀操作,下面代碼可加可不加 效果參見pc系統(tǒng)的日歷月份調(diào)至  2018-4
        preDays = preDays == 0 ? 7 : preDays; //為了保證第一行一定是 上個(gè)月+這個(gè)月(可能沒有) 的數(shù)據(jù) ,
        //最后一行一定是 這個(gè)月(可能沒有)+下個(gè)月 的數(shù)據(jù)
        calendar.add(Calendar.DAY_OF_MONTH, -preDays);//將偏移量移至上個(gè)月边涕,把上個(gè)月的幾天添加到本月的日歷中

        int maxDays = 6 * 7;//直接寫死晤碘,6行7列,至于為什么功蜓,請(qǐng)參考pc右下角日歷
        ClendarInfo clendarInfo;
        Date time = null;
        sdf = new SimpleDateFormat("yyyy-MM-dd");
        boolean needDoThing = dataMap.size() > 0;  //表示當(dāng)月有數(shù)據(jù)
        for (int i = 0; i < maxDays; i++) {
            time = calendar.getTime();
            clendarInfo = new ClendarInfo();

//-------第三步----------添加附屬數(shù)據(jù)開始----------------------------
            String key = sdf.format(new Date(time.getYear(), time.getMonth() + 1, time.getDate()));
            if (needDoThing && dataMap.containsKey(key)) { //將本月需要做的事添加到集合中,而且的當(dāng)前月份
                String thing = dataMap.get(key);
                if (!TextUtils.isEmpty(thing))
                    clendarInfo.setDoThing(thing);
            }
//-------第三步----------添加附屬數(shù)據(jù)結(jié)束----------------------------
            clendarInfo.setDate(time);
            dateList.add(clendarInfo);
            calendar.add(Calendar.DAY_OF_MONTH, 1);
        }
        //  Log.i("TAG", "dataMap=" + dataMap.toString());
        //將日歷數(shù)據(jù)填充到recycleview中
        if (adapter == null) {
            adapter = new DateAdapter(context, R.layout.item_calendar_layout, dateList);
            adapter.setOnItemClickListener(this);
            recyclerView.setAdapter(adapter);

        } else {
            adapter.notifyDataSetChanged();
        }
    }

第二步中园爷,主要的要注意的地方是:
a.星期天的角標(biāo)是0,
b.一月份的角標(biāo)是0
c.Calendar.add(Calendar.DAY_OF_MONTH, 1);可以理解為在月份中式撼,參數(shù) 1 表示日期往后挪一天童社,-1 表示往前面挪一天。
Calendar.add(Calendar.MONTH, +1); //當(dāng)前月加1端衰,即下個(gè)月
Calendar.add(Calendar.MONTH, -1);//當(dāng)前月減1,即上個(gè)月
以上方法就是生成日歷數(shù)據(jù)的核心代碼了。代碼的注釋也寫的很詳細(xì)甘改,如果還不清楚旅东,可在文末將完整代碼復(fù)制下來(lái),或者在文本末十艾,下載該博客的demo

第三步抵代,添加附屬數(shù)據(jù)

實(shí)現(xiàn)的主要方法,就是步驟二中的代碼中注釋掉的部分了忘嫉。
至于荤牍,不是當(dāng)前月的日期顯示灰色,當(dāng)天日期標(biāo)紅庆冕,當(dāng)前月黑色顯示康吵,就是在recycleview的adapter中實(shí)現(xiàn)了,這些都很簡(jiǎn)單访递,就寫出來(lái)了晦嵌。

      Map<String, String> dataMap = new HashMap<>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        dataMap.put(sdf.format(new Date(2018-1900, 5, 1)), "吃飯");
        dataMap.put(sdf.format(new Date(2018-1900, 5, 11)), "睡覺");
        dataMap.put(sdf.format(new Date(2018-1900, 5, 16)), "打豆豆");
        dataMap.put(sdf.format(new Date(2018-1900, 5, 21)), "繼續(xù)睡覺");
        dataMap.put(sdf.format(new Date(2018-1900, 5, 9)), "來(lái)啊,繼續(xù)浪");
        dataMap.put(sdf.format(new Date(2018-1900, 5, 30)), "打豆豆");
        
        clendarView.setDataMap(dataMap);

上面這段代碼是從activity中傳入的附屬數(shù)據(jù),具體情況惭载,要按照需求來(lái)決定旱函,僅僅作為參考。最后附上demo地址

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末描滔,一起剝皮案震驚了整個(gè)濱河市棒妨,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌含长,老刑警劉巖券腔,帶你破解...
    沈念sama閱讀 217,657評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異茎芋,居然都是意外死亡颅眶,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門田弥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)涛酗,“玉大人,你說(shuō)我怎么就攤上這事偷厦∩烫荆” “怎么了?”我有些...
    開封第一講書人閱讀 164,057評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵只泼,是天一觀的道長(zhǎng)剖笙。 經(jīng)常有香客問我,道長(zhǎng)请唱,這世上最難降的妖魔是什么弥咪? 我笑而不...
    開封第一講書人閱讀 58,509評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮十绑,結(jié)果婚禮上聚至,老公的妹妹穿的比我還像新娘。我一直安慰自己本橙,他們只是感情好扳躬,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,562評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著甚亭,像睡著了一般贷币。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上亏狰,一...
    開封第一講書人閱讀 51,443評(píng)論 1 302
  • 那天役纹,我揣著相機(jī)與錄音,去河邊找鬼暇唾。 笑死字管,一個(gè)胖子當(dāng)著我的面吹牛啰挪,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播嘲叔,決...
    沈念sama閱讀 40,251評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼亡呵,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了硫戈?” 一聲冷哼從身側(cè)響起锰什,我...
    開封第一講書人閱讀 39,129評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎丁逝,沒想到半個(gè)月后汁胆,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,561評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡霜幼,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,779評(píng)論 3 335
  • 正文 我和宋清朗相戀三年嫩码,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片罪既。...
    茶點(diǎn)故事閱讀 39,902評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡铸题,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出琢感,到底是詐尸還是另有隱情丢间,我是刑警寧澤,帶...
    沈念sama閱讀 35,621評(píng)論 5 345
  • 正文 年R本政府宣布驹针,位于F島的核電站烘挫,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏柬甥。R本人自食惡果不足惜饮六,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,220評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望苛蒲。 院中可真熱鬧卤橄,春花似錦、人聲如沸撤防。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)寄月。三九已至,卻和暖如春无牵,著一層夾襖步出監(jiān)牢的瞬間漾肮,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工茎毁, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留克懊,地道東北人忱辅。 一個(gè)月前我還...
    沈念sama閱讀 48,025評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像谭溉,于是被迫代替她去往敵國(guó)和親墙懂。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,843評(píng)論 2 354

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