How to Create Custom Calendar in Android Example? In this tutorial, we will create a custom calendar that you can build in Android Studio using Linear Layouts and add an onClickListener to selected a Date.
Need some career advice or prepping for an Android developer interview? Hit me up on Topmate.io, and let's chat!
Our calendar widget will contain 7 columns for the week and 7 rows for month dates. Here is an image of what we will build:
This project is a fork from Github, link here.
How to Create Custom Calendar in Android Example
Getting Started
Create a new Empty MainActivity project in Android Studio with xml layout activity_main.xml.
To create a layout as shown in the image above, we will create a need layout resource file in res > layout named simple_calendar.xml.
For calendar layout, we need LinearLayout inside which using TextViews and other nested LinearLayout we will create the calendar. Here is the XML code of the same.
<?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="wrap_content"
android:background="@android:color/white"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:orientation="horizontal">
<TextView
android:id="@+id/current_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/green"
android:textSize="28sp" />
<TextView
android:id="@+id/current_month"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="10dp"
android:textColor="@color/green"
android:textSize="28sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:weightSum="7">
<Button
android:id="@+id/button5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@android:color/transparent"
android:text="S"
android:textColor="@color/green"
android:textSize="16sp" />
<Button
android:id="@+id/button4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@android:color/transparent"
android:text="S"
android:textColor="@color/green"
android:textSize="16sp" />
<Button
android:id="@+id/button10"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@android:color/transparent"
android:text="M"
android:textColor="@color/green"
android:textSize="16sp" />
<Button
android:id="@+id/button9"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@android:color/transparent"
android:text="T"
android:textColor="@color/green"
android:textSize="16sp" />
<Button
android:id="@+id/button8"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@android:color/transparent"
android:text="W"
android:textColor="@color/green"
android:textSize="16sp" />
<Button
android:id="@+id/button7"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@android:color/transparent"
android:text="T"
android:textColor="@color/green"
android:textSize="16sp" />
<Button
android:id="@+id/button6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@android:color/transparent"
android:text="F"
android:textColor="@color/green"
android:textSize="16sp" />
</LinearLayout>
<LinearLayout
android:id="@+id/calendar_week_1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:weightSum="7" />
<LinearLayout
android:id="@+id/calendar_week_2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:weightSum="7" />
<LinearLayout
android:id="@+id/calendar_week_3"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:weightSum="7" />
<LinearLayout
android:id="@+id/calendar_week_4"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:weightSum="7" />
<LinearLayout
android:id="@+id/calendar_week_5"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:weightSum="7" />
<LinearLayout
android:id="@+id/calendar_week_6"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:weightSum="7" />
</LinearLayout>
Now create a java file named SimpleCalendar.java which extends LinearLayout. Here is the code for the same:
package com.example.customcalendar;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
import java.util.Calendar;
public class SimpleCalendar extends LinearLayout {
private static final String CUSTOM_GREY = "#a0a0a0";
private static final String[] ENG_MONTH_NAMES = {"January", "February", "March", "April",
"May", "June", "July", "August",
"September", "October", "November", "December"};
private Button selectedDayButton;
private Button[] days;
LinearLayout weekOneLayout;
LinearLayout weekTwoLayout;
LinearLayout weekThreeLayout;
LinearLayout weekFourLayout;
LinearLayout weekFiveLayout;
LinearLayout weekSixLayout;
private LinearLayout[] weeks;
private int currentDateDay, chosenDateDay, currentDateMonth,
chosenDateMonth, currentDateYear, chosenDateYear,
pickedDateDay, pickedDateMonth, pickedDateYear;
int userMonth, userYear;
private DayClickListener mListener;
private Calendar calendar;
LinearLayout.LayoutParams defaultButtonParams;
private LinearLayout.LayoutParams userButtonParams;
public SimpleCalendar(Context context) {
super(context);
init(context);
}
public SimpleCalendar(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public SimpleCalendar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public SimpleCalendar(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context);
}
@SuppressLint("SetTextI18n")
private void init(Context context) {
DisplayMetrics metrics = getResources().getDisplayMetrics();
View view = LayoutInflater.from(context).inflate(R.layout.simple_calendar, this, true);
calendar = Calendar.getInstance();
weekOneLayout = view.findViewById(R.id.calendar_week_1);
weekTwoLayout = view.findViewById(R.id.calendar_week_2);
weekThreeLayout = view.findViewById(R.id.calendar_week_3);
weekFourLayout = view.findViewById(R.id.calendar_week_4);
weekFiveLayout = view.findViewById(R.id.calendar_week_5);
weekSixLayout = view.findViewById(R.id.calendar_week_6);
TextView currentDate = view.findViewById(R.id.current_date);
TextView currentMonth = view.findViewById(R.id.current_month);
currentDateDay = chosenDateDay = calendar.get(Calendar.DAY_OF_MONTH);
if (userMonth != 0 && userYear != 0) {
currentDateMonth = chosenDateMonth = userMonth;
currentDateYear = chosenDateYear = userYear;
} else {
currentDateMonth = chosenDateMonth = calendar.get(Calendar.MONTH);
currentDateYear = chosenDateYear = calendar.get(Calendar.YEAR);
}
currentDate.setText("" + currentDateDay);
currentMonth.setText(ENG_MONTH_NAMES[currentDateMonth]);
initializeDaysWeeks();
if (userButtonParams != null) {
defaultButtonParams = userButtonParams;
} else {
defaultButtonParams = getdaysLayoutParams();
}
addDaysinCalendar(defaultButtonParams, context, metrics);
initCalendarWithDate(chosenDateYear, chosenDateMonth, chosenDateDay);
}
private void initializeDaysWeeks() {
weeks = new LinearLayout[6];
days = new Button[6 * 7];
weeks[0] = weekOneLayout;
weeks[1] = weekTwoLayout;
weeks[2] = weekThreeLayout;
weeks[3] = weekFourLayout;
weeks[4] = weekFiveLayout;
weeks[5] = weekSixLayout;
}
private void initCalendarWithDate(int year, int month, int day) {
if (calendar == null)
calendar = Calendar.getInstance();
calendar.set(year, month, day);
int daysInCurrentMonth = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
chosenDateYear = year;
chosenDateMonth = month;
chosenDateDay = day;
calendar.set(year, month, 1);
int firstDayOfCurrentMonth = calendar.get(Calendar.DAY_OF_WEEK);
calendar.set(year, month, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
int dayNumber = 1;
int daysLeftInFirstWeek;
int indexOfDayAfterLastDayOfMonth;
if (firstDayOfCurrentMonth != 1) {
daysLeftInFirstWeek = firstDayOfCurrentMonth;
indexOfDayAfterLastDayOfMonth = daysLeftInFirstWeek + daysInCurrentMonth;
for (int i = firstDayOfCurrentMonth; i < firstDayOfCurrentMonth + daysInCurrentMonth; ++i) {
if (currentDateMonth == chosenDateMonth
&& currentDateYear == chosenDateYear
&& dayNumber == currentDateDay) {
days[i].setBackgroundColor(getResources().getColor(R.color.pink));
days[i].setTextColor(Color.WHITE);
} else {
days[i].setTextColor(Color.BLACK);
days[i].setBackgroundColor(Color.TRANSPARENT);
}
int[] dateArr = new int[3];
dateArr[0] = dayNumber;
dateArr[1] = chosenDateMonth;
dateArr[2] = chosenDateYear;
days[i].setTag(dateArr);
days[i].setText(String.valueOf(dayNumber));
days[i].setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onDayClick(v);
}
});
++dayNumber;
}
} else {
daysLeftInFirstWeek = 8;
indexOfDayAfterLastDayOfMonth = daysLeftInFirstWeek + daysInCurrentMonth;
for (int i = 8; i < 8 + daysInCurrentMonth; ++i) {
if (currentDateMonth == chosenDateMonth
&& currentDateYear == chosenDateYear
&& dayNumber == currentDateDay) {
days[i].setBackgroundColor(getResources().getColor(R.color.pink));
days[i].setTextColor(Color.WHITE);
} else {
days[i].setTextColor(Color.BLACK);
days[i].setBackgroundColor(Color.TRANSPARENT);
}
int[] dateArr = new int[3];
dateArr[0] = dayNumber;
dateArr[1] = chosenDateMonth;
dateArr[2] = chosenDateYear;
days[i].setTag(dateArr);
days[i].setText(String.valueOf(dayNumber));
days[i].setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onDayClick(v);
}
});
++dayNumber;
}
}
if (month > 0)
calendar.set(year, month - 1, 1);
else
calendar.set(year - 1, 11, 1);
int daysInPreviousMonth = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
for (int i = daysLeftInFirstWeek - 1; i >= 0; --i) {
int[] dateArr = new int[3];
if (chosenDateMonth > 0) {
if (currentDateMonth != chosenDateMonth - 1
|| currentDateYear != chosenDateYear
|| daysInPreviousMonth != currentDateDay) {
days[i].setBackgroundColor(Color.TRANSPARENT);
}
dateArr[0] = daysInPreviousMonth;
dateArr[1] = chosenDateMonth - 1;
dateArr[2] = chosenDateYear;
} else {
if (currentDateMonth != 11
|| currentDateYear != chosenDateYear - 1
|| daysInPreviousMonth != currentDateDay) {
days[i].setBackgroundColor(Color.TRANSPARENT);
}
dateArr[0] = daysInPreviousMonth;
dateArr[1] = 11;
dateArr[2] = chosenDateYear - 1;
}
days[i].setTag(dateArr);
days[i].setText(String.valueOf(daysInPreviousMonth--));
days[i].setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onDayClick(v);
}
});
}
int nextMonthDaysCounter = 1;
for (int i = indexOfDayAfterLastDayOfMonth; i < days.length; ++i) {
int[] dateArr = new int[3];
if (chosenDateMonth < 11) {
if (currentDateMonth == chosenDateMonth + 1
&& currentDateYear == chosenDateYear
&& nextMonthDaysCounter == currentDateDay) {
days[i].setBackgroundColor(getResources().getColor(R.color.pink));
} else {
days[i].setBackgroundColor(Color.TRANSPARENT);
}
dateArr[0] = nextMonthDaysCounter;
dateArr[1] = chosenDateMonth + 1;
dateArr[2] = chosenDateYear;
} else {
if (currentDateMonth == 0
&& currentDateYear == chosenDateYear + 1
&& nextMonthDaysCounter == currentDateDay) {
days[i].setBackgroundColor(getResources().getColor(R.color.pink));
} else {
days[i].setBackgroundColor(Color.TRANSPARENT);
}
dateArr[0] = nextMonthDaysCounter;
dateArr[1] = 0;
dateArr[2] = chosenDateYear + 1;
}
days[i].setTag(dateArr);
days[i].setTextColor(Color.parseColor(CUSTOM_GREY));
days[i].setText(String.valueOf(nextMonthDaysCounter++));
days[i].setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onDayClick(v);
}
});
}
calendar.set(chosenDateYear, chosenDateMonth, chosenDateDay);
}
public void onDayClick(View view) {
mListener.onDayClick(view);
if (selectedDayButton != null) {
if (chosenDateYear == currentDateYear
&& chosenDateMonth == currentDateMonth
&& pickedDateDay == currentDateDay) {
selectedDayButton.setBackgroundColor(getResources().getColor(R.color.pink));
selectedDayButton.setTextColor(Color.WHITE);
} else {
selectedDayButton.setBackgroundColor(Color.TRANSPARENT);
if (selectedDayButton.getCurrentTextColor() != Color.RED) {
selectedDayButton.setTextColor(getResources()
.getColor(R.color.calendar_number));
}
}
}
selectedDayButton = (Button) view;
if (selectedDayButton.getTag() != null) {
int[] dateArray = (int[]) selectedDayButton.getTag();
pickedDateDay = dateArray[0];
pickedDateMonth = dateArray[1];
pickedDateYear = dateArray[2];
}
if (pickedDateYear == currentDateYear
&& pickedDateMonth == currentDateMonth
&& pickedDateDay == currentDateDay) {
selectedDayButton.setBackgroundColor(getResources().getColor(R.color.pink));
selectedDayButton.setTextColor(Color.WHITE);
} else {
selectedDayButton.setBackgroundColor(getResources().getColor(R.color.grey));
if (selectedDayButton.getCurrentTextColor() != Color.RED) {
selectedDayButton.setTextColor(Color.WHITE);
}
}
}
private void addDaysinCalendar(LayoutParams buttonParams, Context context,
DisplayMetrics metrics) {
int engDaysArrayCounter = 0;
for (int weekNumber = 0; weekNumber < 6; ++weekNumber) {
for (int dayInWeek = 0; dayInWeek < 7; ++dayInWeek) {
final Button day = new Button(context);
day.setTextColor(Color.parseColor(CUSTOM_GREY));
day.setBackgroundColor(Color.TRANSPARENT);
day.setLayoutParams(buttonParams);
day.setTextSize((int) metrics.density * 8);
day.setSingleLine();
days[engDaysArrayCounter] = day;
weeks[weekNumber].addView(day);
++engDaysArrayCounter;
}
}
}
private LayoutParams getdaysLayoutParams() {
LinearLayout.LayoutParams buttonParams = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);
buttonParams.weight = 1;
return buttonParams;
}
public void setUserDaysLayoutParams(LinearLayout.LayoutParams userButtonParams) {
this.userButtonParams = userButtonParams;
}
public void setUserCurrentMonthYear(int userMonth, int userYear) {
this.userMonth = userMonth;
this.userYear = userYear;
}
public void setDayBackground(Drawable userDrawable) {
Drawable userDrawable1 = userDrawable;
}
public interface DayClickListener {
void onDayClick(View view);
}
public void setCallBack(DayClickListener mListener) {
this.mListener = mListener;
}
}
Now in activity_main.xml you can easily create a SimpleCalendar widget. Set its height and width as they are the required attributes. Here is the code for the same.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:orientation="horizontal">
<com.example.customcalendar.SimpleCalendar
android:id="@+id/square_day"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
Now in MainActivity.java, create SimpleCalendar object and using findViewByID link it with the XML widget . Here is the code for the same:
package com.example.customcalendar;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import java.util.Calendar;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SimpleCalendar simpleCalendar = findViewById(R.id.square_day);
Calendar calendar = Calendar.getInstance();
// Get current month
int month = calendar.get(Calendar.MONTH);
//Get current Year
int year = calendar.get(Calendar.YEAR);
simpleCalendar.setUserCurrentMonthYear(month,year);
simpleCalendar.setCallBack(new SimpleCalendar.DayClickListener() {
@Override
public void onDayClick(View view) {
// Create on Click event here.
}
});
}
}
Interested in implementing calendar library built by other android developers, see Top 20 Android Calendar Library here.
Interested in implementing Rating feature in your app, see here: Android Rate App feature implementation.
View Comments (0)