国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統(tǒng) > Android > 正文

android自定義view之實(shí)現(xiàn)日歷界面實(shí)例

2019-12-12 03:20:56
字體:
供稿:網(wǎng)友

現(xiàn)在網(wǎng)上有很多自定義view實(shí)現(xiàn)日歷的demo,今天講一講如何自己實(shí)現(xiàn)這個(gè)自定義view。

看一下最終效果圖:

在這個(gè)自定義view中,我使用了各種奇技淫巧的方法來實(shí)現(xiàn)這個(gè)日歷,真是費(fèi)盡心思。廢話少說,開始進(jìn)坑。

界面分析

頭部是一個(gè)textview,顯示年份和月份,然后下邊一行是星期幾,這兩行可以固定住,不隨月份切換而進(jìn)出屏幕。

再下邊就是我們自定義view 的主角,每個(gè)月的天數(shù)。目前規(guī)定是星期日為每星期第一天。上個(gè)月的天數(shù)填充滿第一行,下個(gè)月的前幾天填充完最后一行,顏色設(shè)置為灰色,本月日期中的周一至周五設(shè)置為紅色,周六周日設(shè)置為青色,特殊日期設(shè)置為綠色,并且在右上角填充特殊標(biāo)識(shí)符,用四分之三的圓弧包裹(上個(gè)月和下個(gè)月的日期沒有)。

此處還有個(gè)小細(xì)節(jié),每月的總行數(shù)會(huì)不斷改變,但是view的總高度并未改變,所以視覺效果會(huì)不一樣。

構(gòu)造方法

 public MyCalendar(Context context) {    super(context);  }  public MyCalendar(Context context, @Nullable AttributeSet attrs) {    super(context, attrs);  }

主要是實(shí)現(xiàn)上面兩個(gè)構(gòu)造方法,第一個(gè)是用來在java代碼中使用的,第二個(gè)是用來在xml布局文件中使用的。

暴露的接口

目前接口共有下面幾個(gè),setDate(CustomDate customDate),setWeekendHighLight(boolean b),setSpecialDay(int[] ints)

其中第一個(gè)是必須要設(shè)置的,否則是不會(huì)顯示任何東西,第二個(gè)設(shè)置的是否周末高亮,第三個(gè)設(shè)置的是特殊顯示的日期,第四個(gè)是設(shè)置是否可以點(diǎn)擊前一個(gè)月或者后一個(gè)月的日期,默認(rèn)為不設(shè)置,后期可以根據(jù)自己需求增加其他接口。

  /**   * 暴露接口,設(shè)置日期   *   * @param customDate   */  public void setDate(CustomDate customDate) {    Log.d(TAG, customDate.toString());    this.date = customDate;    firstDayOfWeek = date.getFirstDayOfWeek();    Log.d(TAG, (date.getMonth() + 1) + "月1號(hào)是星期" + firstDayOfWeek);    lastDayOfWeek = date.getLastDayOfWeek();    lineCount = calculateLineNum() + 1;    lastMonthTotalDays = date.getLastMonthDays();  }  /**   * 暴露接口,設(shè)置是否周末高亮   *   * @param b   */  public void setWeekendHighLight(boolean b) {    this.weekendHighlight = b;  }  public void setSpecialDay(int[] ints) {    this.specialDays = ints;  }  /**   * 暴露接口,設(shè)置是否可以點(diǎn)擊前一個(gè)月和后一個(gè)月的日期   *   * @param b   */  public void setCanClickNextOrPreMonth(boolean b) {    this.canClickNextOrPreMonth = b;  }

在這里說明一下計(jì)算顯示行數(shù)的方法,首先要注意我們獲取的星期數(shù)與實(shí)際的星期幾會(huì)有一個(gè)增加一天的問題,也就是當(dāng)前是星期4,那么你獲取的int將會(huì)是5.

 /**   * 獲得應(yīng)該設(shè)置為多少行   *   * @return   */  private int calculateLineNum() {    monthDaySum = date.getTotalDayOfMonth();    return (firstDayOfWeek - 1 + monthDaySum) / 7;  }

我們將第一天是星期幾減去一后加上這個(gè)月總共多少天,就可以獲得最后一天是在什么位置,然后除以七取商的整數(shù)部分,然后在進(jìn)一法即可獲得應(yīng)該顯示多少行。

onSizechanged方法

onSizechanged方法中已經(jīng)可以獲得顯示的尺寸了,此時(shí)我們需要做一些工作:

 protected void onSizeChanged(int w, int h, int oldw, int oldh) {    super.onSizeChanged(w, h, oldw, oldh);    this.viewWidth = w;    this.viewHeight = h;    Log.d(TAG, "onSizeChanged" + w + h);    cutGrid();    init();    setCellDay();  }

首先是將寬和高引入進(jìn)來,方便后邊使用。

cutGrid()方法是將區(qū)域分割為行X列的格式。

init()方法初始化了一些畫筆。

setCellDay()方法將每月的天對(duì)應(yīng)過到坐標(biāo)上。

首先看一下cutGrid()方法:

 /**   * 切分為每天   */  private void cutGrid() {    cellWidth = (float) viewWidth / ROW_COUNT;    cellHeight = (float) viewHeight / lineCount;    this.radius = Math.min(cellWidth / 2, cellHeight / 2);    for (int i = 0; i < lineCount; i++) {      for (int j = 0; j < ROW_COUNT; j++) {        points.add(new PointF(cellWidth * j + cellWidth / 2, cellHeight * i + cellHeight / 2));      }    }  }

cellWidth是每天的寬度,其中ROW_COUNT是一個(gè)常量7,表示每周7天;cellHeight是每行的高度,linecount是一個(gè)變量,需要我們根據(jù)日期計(jì)算,后邊會(huì)說到;radius是我們繪制區(qū)域的半徑,這個(gè)值是我們?nèi)挾群透叨戎休^小的值的一半。然后我們將每個(gè)方格中心坐標(biāo)點(diǎn)利用雙重循環(huán)放入一個(gè)List<Point> points中。

整個(gè)view被分割為如上的形狀。

下面來看一下init()方法:

private void init() {    circlePaint = new Paint();    circlePaint.setStyle(Paint.Style.STROKE);    circlePaint.setAntiAlias(true);    circlePaint.setColor(Color.BLUE);    textPaint = new Paint();    textPaint.setAntiAlias(true);    textPaint.setColor(Color.BLACK);    textPaint.setTextSize(radius / 2);    selectPaint = new Paint();    selectPaint.setColor(Color.YELLOW);    selectPaint.setAlpha(10);    selectPaint.setAntiAlias(true);    selectPaint.setStyle(Paint.Style.FILL);    selectTextPaint = new Paint();    selectTextPaint.setColor(Color.WHITE);    selectTextPaint.setAntiAlias(true);    selectTextPaint.setTextSize(radius / 2);    selectTextPaint.setStyle(Paint.Style.FILL);  }

基本都是畫筆工具。

然后是setAllDays()方法:

 /**   * 設(shè)置總共顯示多少天,每天的狀態(tài)   */  private void setCellDay() {    cellDays = new CellDay[lineCount * ROW_COUNT];    for (int i = 0, length = cellDays.length; i < length; i++) {      cellDays[i] = new CellDay();      cellDays[i].setPointX(points.get(i).x);      cellDays[i].setPointY(points.get(i).y);      if (firstDayOfWeek > 1 && i < firstDayOfWeek - 1) {        cellDays[i].setDayState(DayState.LASTMONTH);        cellDays[i].setDate(String.valueOf(lastMonthTotalDays - firstDayOfWeek + i + 2));        cellDays[i].setCustomDate(new CustomDate(            date.getYear(), date.getMonth() - 1, lastMonthTotalDays - firstDayOfWeek + i + 2));      }      if (i >= firstDayOfWeek - 1 && i < monthDaySum + firstDayOfWeek - 1) {        cellDays[i].setDayState(CURRENTMONTH);        cellDays[i].setDate(String.valueOf(i + 2 - firstDayOfWeek));        cellDays[i].setCustomDate(new CustomDate(            date.getYear(), date.getMonth(), i - firstDayOfWeek + 2));        //設(shè)置周末高亮        if (weekendHighlight) {          if (i % 7 == 0 || i % 7 == 6) {            cellDays[i].setDayState(WEEKEND);          }        }      }      if (i >= monthDaySum + firstDayOfWeek - 1) {        cellDays[i].setDayState(NEXTMONTH);        cellDays[i].setDate(String.valueOf(i - monthDaySum - firstDayOfWeek + 2));        cellDays[i].setCustomDate(new CustomDate(            date.getYear(), date.getMonth() + 1, i - monthDaySum - firstDayOfWeek + 2));      }      for (int j = 0, s = specialDays.length; j < s; j++) {        if (specialDays[j] + firstDayOfWeek - 2 == i) {          cellDays[i].setDayState(SPECIALDAY);        }      }    }  }

在這里我們用到了一個(gè)自定的類-CellDay。

CellDay有以下幾個(gè)字段

    private String date;    private DayState dayState;    private CustomDate customDate;    private float pointX;    private float pointY;    private boolean isSelected;

1、String date表示當(dāng)前的日期。

2、dayState是一個(gè)美劇類型,定義了天的狀態(tài)值。

  • LASTMONTH:上個(gè)月的日期
  • CURRENTMONTH:本月的日期
  • NEXTMONTH: 下個(gè)月的日期
  • CURRENTDAY: 今天的日期
  • WEEKEND:周末的日期
  • SPECIALDAY:用戶自定義的可以設(shè)置狀態(tài)的日期

其中可以設(shè)置多種狀態(tài),用法和SPECIALDAY基本一樣。

  1. cusomedate是我們自己定義的一個(gè)工具類,包含項(xiàng)目中需要用到的一系列方法。
  2. pointX是橫坐標(biāo)。
  3. pointY是縱坐標(biāo)。
  4. isSelceted表示有沒有被選中。

CustomDate工具

public class CustomDate {  private Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT+8"));  private int year;  private int month;  private int day;  private int dayOfWeek;  public CustomDate() {  }  /**   * 獲取當(dāng)前的日期   * @return   */  public CustomDate getCurrentDate() {    this.year = calendar.get(Calendar.YEAR);    this.month = calendar.get(Calendar.MONTH);    this.day = calendar.get(Calendar.DAY_OF_MONTH);    this.dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);    return new CustomDate(year, month, day);  }  public CustomDate(int year, int month, int day) {    this.year = year;    this.month = month;    this.day = day;    calendar.set(year, month, day);    dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);  }  /**   * 獲取上個(gè)月的天數(shù)   * @return   */  public int getLastMonthDays() {    return this.getDaysOfMonth(this.year, this.month - 1);  }  /**   * 獲取第一天是星期幾   *   * @return   */  public int getFirstDayOfWeek() {    calendar.set(this.year, this.month, 1);    return calendar.get(Calendar.DAY_OF_WEEK);  }  /**   * 獲取最后一天是星期幾   *   * @return   */  public int getLastDayOfWeek() {    calendar.set(this.year, this.month, getTotalDayOfMonth());    return calendar.get(Calendar.DAY_OF_WEEK);  }  /**   * 獲取這個(gè)月總共的天數(shù)   * @return   */  public int getTotalDayOfMonth() {    return this.getDaysOfMonth(year, month);  }  public int getTotalWeekOfMonth() {    return calendar.getMaximum(Calendar.WEEK_OF_MONTH);  }  public int getYear() {    return year;  }  public void setYear(int year) {    this.year = year;  }  public int getMonth() {    return month;  }  public void setMonth(int month) {    this.month = month;  }  public int getDay() {    return day;  }  public void setDay(int day) {    this.day = day;  }  public int getDayOfWeek() {    return dayOfWeek;  }  public void setDayOfWeek(int dayOfWeek) {    this.dayOfWeek = dayOfWeek;  }  @Override  public String toString() {    return "CustomDate{" +        "year=" + year +        ", month=" + (getMonth() + 1) +        ", day=" + day +        ", dayOfWeek=" + dayOfWeek +        '}';  }  /**   * 獲取年中每月的天數(shù)   * @param year   * @param month   * @return   */  private int getDaysOfMonth(int year, int month) {    if (month > 11) {      month = 0;      year += 1;    } else if (month < 0) {      month = 11;      year -= 1;    }    int[] arr = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};    int daysOfMonth = 0;    if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) {      arr[1] = 29;    }    daysOfMonth = arr[month];    return daysOfMonth;  }}

注釋中對(duì)每個(gè)方法的說明已經(jīng)非常清晰了。

int getLastMonthDays()

獲取上個(gè)月的天數(shù)是用來計(jì)算上個(gè)月最后一天是星期幾,然后以此推導(dǎo)出上個(gè)月在本月中顯示的天數(shù)和對(duì)應(yīng)的星期。

getFirstDayOfWeek()

獲取本月第一天是星期幾,然后排序本月的天數(shù)與對(duì)應(yīng)的星期。

int getTotalDayOfMonth()

獲取本月總共多少天。配合第一天是星期幾用來計(jì)算總共分為幾行,也就是確定linenumber。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持武林網(wǎng)。

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 泗阳县| 富川| 当雄县| 卢氏县| 两当县| 沿河| 苍梧县| 巴南区| 镇远县| 五台县| 衡南县| 吴旗县| 花莲市| 辽源市| 巴林左旗| 新田县| 太谷县| 喀喇沁旗| 思茅市| 邵武市| 深水埗区| 济宁市| 西安市| 蓝田县| 紫阳县| 玛纳斯县| 光泽县| 南康市| 随州市| 谢通门县| 江都市| 新源县| 武邑县| 塔城市| 汕尾市| 牙克石市| 焦作市| 祥云县| 基隆市| 吉木萨尔县| 南宁市|