Calendar Dialog - Tutorial (source code download)

Updated: 07 April 2013

Tested in:
HTC desire S (android 2.3.5), Samsung Galaxy Ace (android 2.3.4), Samsung Galaxy Tab P3100 (android 4.0.4)

Base on:
Eclipse Indigo build in 20120216-1857, Java 1.6, Android 4.1.2

Download Source code:
DemoDialogCalendar20130407.rar

Description:
Open calendar in dialog and select date.

Screen shot:


Tutorial:
1. Create Calendar layouts:
   calendar_day_gridcell.xml: layout for days.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
 xmlns:android="http://schemas.android.com/apk/res/android"
 android:orientation="vertical"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:background="@drawable/calendar_button_selector">

 <Button
  android:id="@+id/calendar_day_gridcell"
  android:layout_gravity="center"
  android:textColor="#FFFFFF"
  android:background="@drawable/calendar_button_selector"
  android:textAppearance="?android:attr/textAppearanceMedium"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content">
 </Button>
 
 <TextView
  android:id="@+id/num_events_per_day"
  style="@style/calendar_event_style"
  android:layout_gravity="right"
  android:layout_width="10dip"
  android:layout_height="10dip">
 </TextView>
 
</RelativeLayout>

   simple_calendar_view.xml: layout for calendar dialog.

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

 <LinearLayout
  android:orientation="horizontal"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content">

  <ImageView
   android:id="@+id/prevMonth"
   android:src="@drawable/calendar_left_arrow_selector"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content">
  </ImageView>
  <Button
   android:id="@+id/currentMonth"
   android:layout_weight="0.6"
   android:textColor="#FFFFFF"
   android:textAppearance="?android:attr/textAppearanceMedium"
   android:background="@drawable/calendar_bar"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content">
  </Button>
  <ImageView
   android:id="@+id/nextMonth"
   android:src="@drawable/calendar_right_arrow_selector"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content">
  </ImageView>
 </LinearLayout>

 <LinearLayout
  android:layout_gravity="center"
  android:layout_marginTop="2dp"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content">
  <ImageView
   android:id="@+id/calendarheader"
   android:src="@drawable/blue_bg_with_text"
   android:layout_gravity="center"
   android:layout_width="fill_parent"
   android:layout_height="wrap_content">
  </ImageView>
 </LinearLayout>


 <GridView
  android:id="@+id/calendar"
  android:numColumns="7"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content">
 </GridView>

</LinearLayout>

2. Create class for calendar controller:

public class GridCellAdapter extends BaseAdapter implements OnClickListener {
  private static final String tag = "GridCellAdapter";
  private final Context _context;

  private final List<String> list;
  private static final int DAY_OFFSET = 1;
  private final String[] weekdays = new String[] { "Sun", "Mon", "Tue",
    "Wed", "Thu", "Fri", "Sat" };
  private final String[] months = {
    getResources().getString(R.string.calendar_month_jan),
    getResources().getString(R.string.calendar_month_feb),
    getResources().getString(R.string.calendar_month_mar),
    getResources().getString(R.string.calendar_month_apr),
    getResources().getString(R.string.calendar_month_may),
    getResources().getString(R.string.calendar_month_jun),
    getResources().getString(R.string.calendar_month_jul),
    getResources().getString(R.string.calendar_month_aug),
    getResources().getString(R.string.calendar_month_sep),
    getResources().getString(R.string.calendar_month_oct),
    getResources().getString(R.string.calendar_month_nov),
    getResources().getString(R.string.calendar_month_dec) };
  
  private final int[] daysOfMonth = { 31, 28, 31, 30, 31, 30, 31, 31, 30,
    31, 30, 31 };
  private final int month, year;
  private int daysInMonth, prevMonthDays;
  private int currentDayOfMonth;
  private int currentWeekDay;
  private Button gridcell;
  private TextView num_events_per_day;
  private final HashMap eventsPerMonthMap;
  private final SimpleDateFormat dateFormatter = new SimpleDateFormat(
    "dd-MMM-yyyy");

  // Days in Current Month
  public GridCellAdapter(Context context, int textViewResourceId,
    int month, int year) {
   super();
   this._context = context;
   this.list = new ArrayList<String>();
   this.month = month;
   this.year = year;

   Calendar calendar = Calendar.getInstance();
   setCurrentDayOfMonth(calendar.get(Calendar.DAY_OF_MONTH));
   setCurrentWeekDay(calendar.get(Calendar.DAY_OF_WEEK));
   Log.d(tag, "New Calendar:= " + calendar.getTime().toString());
   Log.d(tag, "CurrentDayOfWeek :" + getCurrentWeekDay());
   Log.d(tag, "CurrentDayOfMonth :" + getCurrentDayOfMonth());

   // Print Month
   printMonth(month, year);

   // Find Number of Events
   eventsPerMonthMap = findNumberOfEventsPerMonth(year, month);
  }

  private String getMonthAsString(int i) {
   return months[i];
  }

  private String getWeekDayAsString(int i) {
   return weekdays[i];
  }

  private int getNumberOfDaysOfMonth(int i) {
   return daysOfMonth[i];
  }

  public String getItem(int position) {
   return list.get(position);
  }

  @Override
  public int getCount() {
   return list.size();
  }

  private void printMonth(int mm, int yy) {
   Log.d(tag, "==> printMonth: mm: " + mm + " " + "yy: " + yy);
   // The number of days to leave blank at
   // the start of this month.
   int trailingSpaces = 0;
   int leadSpaces = 0;
   int daysInPrevMonth = 0;
   int prevMonth = 0;
   int prevYear = 0;
   int nextMonth = 0;
   int nextYear = 0;

   int currentMonth = mm - 1;
   String currentMonthName = getMonthAsString(currentMonth);
   daysInMonth = getNumberOfDaysOfMonth(currentMonth);

   Log.d(tag, "Current Month: " + " " + currentMonthName + " having "
     + daysInMonth + " days.");

   // Gregorian Calendar : MINUS 1, set to FIRST OF MONTH
   GregorianCalendar cal = new GregorianCalendar(yy, currentMonth, 1);
   Log.d(tag, "Gregorian Calendar:= " + cal.getTime().toString());

   if (currentMonth == 11) {
    prevMonth = currentMonth - 1;
    daysInPrevMonth = getNumberOfDaysOfMonth(prevMonth);
    nextMonth = 0;
    prevYear = yy;
    nextYear = yy + 1;
    Log.d(tag, "*->PrevYear: " + prevYear + " PrevMonth:"
      + prevMonth + " NextMonth: " + nextMonth
      + " NextYear: " + nextYear);
   } else if (currentMonth == 0) {
    prevMonth = 11;
    prevYear = yy - 1;
    nextYear = yy;
    daysInPrevMonth = getNumberOfDaysOfMonth(prevMonth);
    nextMonth = 1;
    Log.d(tag, "**--> PrevYear: " + prevYear + " PrevMonth:"
      + prevMonth + " NextMonth: " + nextMonth
      + " NextYear: " + nextYear);
   } else {
    prevMonth = currentMonth - 1;
    nextMonth = currentMonth + 1;
    nextYear = yy;
    prevYear = yy;
    daysInPrevMonth = getNumberOfDaysOfMonth(prevMonth);
    Log.d(tag, "***---> PrevYear: " + prevYear + " PrevMonth:"
      + prevMonth + " NextMonth: " + nextMonth
      + " NextYear: " + nextYear);
   }

   // Compute how much to leave before before the first day of the
   // month.
   // getDay() returns 0 for Sunday.
   int currentWeekDay = cal.get(Calendar.DAY_OF_WEEK) - 1;
   trailingSpaces = currentWeekDay;

   Log.d(tag, "Week Day:" + currentWeekDay + " is "
     + getWeekDayAsString(currentWeekDay));
   Log.d(tag, "No. Trailing space to Add: " + trailingSpaces);
   Log.d(tag, "No. of Days in Previous Month: " + daysInPrevMonth);

   if (cal.isLeapYear(cal.get(Calendar.YEAR)) && mm == 2) {
    ++daysInMonth;
   }

   // Trailing Month days
   for (int i = 0; i < trailingSpaces; i++) {
    Log.d(tag,
      "PREV MONTH:= "
        + prevMonth
        + " => "
        + getMonthAsString(prevMonth)
        + " "
        + String.valueOf((daysInPrevMonth
          - trailingSpaces + DAY_OFFSET)
          + i));
    list.add(String
      .valueOf((daysInPrevMonth - trailingSpaces + DAY_OFFSET)
        + i)
      + "-GREY"
      + "-"
      + getMonthAsString(prevMonth)
      + "-"
      + prevYear);
   }

   // Current Month Days
   for (int i = 1; i <= daysInMonth; i++) {
    Log.d(currentMonthName, String.valueOf(i) + " "
      + getMonthAsString(currentMonth) + " " + yy);
    if (i == getCurrentDayOfMonth()
      && (currentMonth == _calendar.get(Calendar.MONTH))
      && (year == _calendar.get(Calendar.YEAR))) {
     list.add(String.valueOf(i) + "-BLUE" + "-"
       + getMonthAsString(currentMonth) + "-" + yy);
    } else {
     list.add(String.valueOf(i) + "-WHITE" + "-"
       + getMonthAsString(currentMonth) + "-" + yy);
    }
   }

   // Leading Month days
   for (int i = 0; i < list.size() % 7; i++) {
    Log.d(tag, "NEXT MONTH:= " + getMonthAsString(nextMonth));
    list.add(String.valueOf(i + 1) + "-GREY" + "-"
      + getMonthAsString(nextMonth) + "-" + nextYear);
   }
  }

  /**
   * NOTE: YOU NEED TO IMPLEMENT THIS PART Given the YEAR, MONTH, retrieve
   * ALL entries from a SQLite database for that month. Iterate over the
   * List of All entries, and get the dateCreated, which is converted into
   * day.
   * 
   * @param year
   * @param month
   * @return
   */
  private HashMap findNumberOfEventsPerMonth(int year, int month) {
   HashMap map = new HashMap<String, Integer>();
   return map;
  }

  @Override
  public long getItemId(int position) {
   return position;
  }

  @Override
  public View getView(int position, View convertView, ViewGroup parent) {
   View row = convertView;
   if (row == null) {
    LayoutInflater inflater = (LayoutInflater) _context
      .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    row = inflater.inflate(R.layout.calendar_day_gridcell, parent,
      false);
   }

   // Get a reference to the Day gridcell
   gridcell = (Button) row.findViewById(R.id.calendar_day_gridcell);
   gridcell.setOnClickListener(this);

   // ACCOUNT FOR SPACING

   Log.d(tag, "Current Day: " + getCurrentDayOfMonth());
   String[] day_color = list.get(position).split("-");
   String theday = day_color[0];
   String themonth = day_color[2];
   String theyear = day_color[3];
   if ((!eventsPerMonthMap.isEmpty()) && (eventsPerMonthMap != null)) {
    if (eventsPerMonthMap.containsKey(theday)) {
     num_events_per_day = (TextView) row
       .findViewById(R.id.num_events_per_day);
     Integer numEvents = (Integer) eventsPerMonthMap.get(theday);
     num_events_per_day.setText(numEvents.toString());
    }
   }

   // Set the Day GridCell
   gridcell.setText(theday);
   gridcell.setTag(theday + "-" + themonth + "-" + theyear);
   Log.d(tag, "Setting GridCell " + theday + "-" + themonth + "-"
     + theyear);

   if (day_color[1].equals("GREY")) {
    gridcell.setTextColor(Color.DKGRAY);
   }
   if (day_color[1].equals("WHITE")) {
    gridcell.setTextColor(Color.WHITE);
   }
   if (day_color[1].equals("BLUE")) {
    gridcell.setTextColor(Color.YELLOW);
    // gridcell.setTextColor(getResources().getColor(
    // R.color.static_text_color));
   }
   return row;
  }

  @Override
  public void onClick(View view) {
   String date_month_year = (String) view.getTag();
   // selectedDayMonthYearButton.setText("Selected: " +
   // date_month_year);
   setSelectedDate(date_month_year);
   try {
    Date parsedDate = dateFormatter.parse(date_month_year);
    Log.d(tag, "Parsed Date: " + parsedDate.toString());
    setSelectedDate(date_month_year);

   } catch (ParseException e) {
    e.printStackTrace();
   }
  }

  public int getCurrentDayOfMonth() {
   return currentDayOfMonth;
  }

  private void setCurrentDayOfMonth(int currentDayOfMonth) {
   this.currentDayOfMonth = currentDayOfMonth;
  }

  public void setCurrentWeekDay(int currentWeekDay) {
   this.currentWeekDay = currentWeekDay;
  }

  public int getCurrentWeekDay() {
   return currentWeekDay;
  }
 }

References:
developer.android.com/reference/android/app/Dialog.html
developer.android.com/reference/java/util/Calendar.html

Leave a Reply

Powered by Blogger.