Tuesday, September 16, 2014

Custom Calendar Demo in Android


Hi..Friends...Hope you all doing well..!!!
Today I am posting a useful post about how to make custom calendar in android using GridView and CustomAdapter,It looks great as compared to the default calendar of android system,So let's have a look the way to create it,

Our Calendar will look like this:



CalendarView




Now Lets have look at how actually make it with playing with code,Its really simple(if you follow the steps as per mentioned).


Step:1

Create new android Project from Eclipse IDE name it as u like.

Step:2

Now Go to "Layouts" folder into your project explorer and change your xml as per below code.

Calendar.xml








<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:background="#ffffff"

android:orientation="vertical" >



<RelativeLayout

android:id="@+id/header"
android:layout_width="fill_parent"
android:layout_height="70dp"
android:background="#D41016" >

<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:weightSum="7" >

<TextView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"
android:gravity="center"
android:text="Sun"
android:textColor="#ffffff"
android:textSize="12dp" />

<TextView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"
android:gravity="center"
android:text="Mon"
android:textColor="#ffffff"
android:textSize="12dp" />

<TextView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"
android:gravity="center"
android:text="Tue"
android:textColor="#ffffff"
android:textSize="12dp" />

<TextView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"
android:gravity="center"
android:text="Wed"
android:textColor="#ffffff"
android:textSize="12dp" />

<TextView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"
android:gravity="center"
android:text="Thu"
android:textColor="#ffffff"
android:textSize="12dp" />

<TextView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"
android:gravity="center"
android:text="Fri"
android:textColor="#ffffff"
android:textSize="12dp" />

<TextView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"
android:gravity="center"
android:text="Sat"
android:textColor="#ffffff"
android:textSize="12dp" />
</LinearLayout>

<RelativeLayout
android:id="@+id/previous"
android:layout_width="40dip"
android:layout_height="30dip"
android:layout_alignParentLeft="true" >

<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:background="@drawable/btn_back" />
</RelativeLayout>

<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="5dip"
android:textColor="#ffffff"
android:textSize="18dip"
android:textStyle="bold" />

<RelativeLayout
android:id="@+id/next"
android:layout_width="40dip"
android:layout_height="30dip"
android:layout_alignParentRight="true" >

<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:background="@drawable/btn_f" />
</RelativeLayout>
</RelativeLayout>

<GridView
android:id="@+id/gridview"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:listSelector="@android:color/transparent"
android:numColumns="7"
android:stretchMode="columnWidth" />

<RelativeLayout
android:id="@+id/rl_bottom"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:gravity="bottom"
android:padding="20dp" >

<TextView
android:id="@+id/tv_select"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginRight="10dp"
android:background="#D41016"
android:padding="10dp"
android:gravity="center"
android:text="@string/sel_date"
android:textColor="#ffffff"
android:textSize="16dp" />
</RelativeLayout>

</LinearLayout>


In this xml we have created a GridView ,In this gridView dates will be apear in each gridItem,Now let we move on to our next step of creating "GridItem".


Step:3

Upto here we have created frame for calendar,But what about if we want stylish date when selected and focused,So For that we will customize our gridView,So in this step we'll make a custom gridItem,to be inflated to our gridView using BaseAdapter,So go to layout and make a new android xml file,name it as "calendar_item.xml"
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@drawable/calendar_cell"
    android:gravity="center"
    android:orientation="vertical"
    android:padding="2dip" >

    <TextView
        android:id="@+id/date"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="#545454"
        android:textSize="16dip"
        android:textStyle="bold" >
    </TextView>

    <ImageView
        android:id="@+id/date_icon"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/dot"
     />

</LinearLayout>

Step:4


Uptill this step we have seen only the designing part,we have completed it,Now in this step we will discuss how to play with logic using java code to make it.go to your src folder,make a new java class and name it as CalendarAdapter



Change your adapter as per the code given below,

CalendarAdapter


package com.eps.blancatours.adapter;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Locale;

import android.content.Context;
import android.graphics.Color;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;

import com.eps.blancatours.R;

public class CalendarAdapter extends BaseAdapter {
private Context mContext;

private java.util.Calendar month;
public GregorianCalendar pmonth; // calendar instance for previous month
/**
* calendar instance for previous month for getting complete view
*/
public GregorianCalendar pmonthmaxset;
private GregorianCalendar selectedDate;
int firstDay;
int maxWeeknumber;
int maxP;
int calMaxP;
int lastWeekDay;
int leftDays;
int mnthlength;
String itemvalue, curentDateString;
DateFormat df;

private ArrayList items;
public static List dayString;
private View previousView;

public CalendarAdapter(Context c, GregorianCalendar monthCalendar) {
CalendarAdapter.dayString = new ArrayList();
Locale.setDefault(Locale.US);
month = monthCalendar;
System.out.println(":::::::::::::::::::::MONTH CALENDAR:::::::::::::::"
+ monthCalendar);
selectedDate = (GregorianCalendar) monthCalendar.clone();
mContext = c;
month.set(GregorianCalendar.DAY_OF_MONTH, 1);

this.items = new ArrayList();
df = new SimpleDateFormat("yyyy-MM-dd", Locale.US);
curentDateString = df.format(selectedDate.getTime());
System.out
.println(":::::::::::::::::CURRENT DATE STRING::::::::::::::;"
+ curentDateString);
refreshDays();
}

public void setItems(ArrayList items) {
for (int i = 0; i != items.size(); i++) {
if (items.get(i).length() == 1) {
items.set(i, "0" + items.get(i));
}
}
this.items = items;
}

public int getCount() {
return dayString.size();
}

public Object getItem(int position) {
return dayString.get(position);
}

public long getItemId(int position) {
return 0;
}

// create a new view for each item referenced by the Adapter
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
TextView dayView;
if (convertView == null) { // if it's not recycled, initialize some
// attributes
LayoutInflater vi = (LayoutInflater) mContext
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.calendar_item, null);

}
dayView = (TextView) v.findViewById(R.id.date);
// separates daystring into parts.
String[] separatedTime = dayString.get(position).split("-");
// taking last part of date. ie; 2 from 2012-12-02
String gridvalue = separatedTime[2].replaceFirst("^0*", "");
System.out
.println(":::::::::::::::::::::::ADPTER SPLITTED MONTH:::::::::::::::::::::"
+ separatedTime[1]);
// checking whether the day is in current month or not.
if ((Integer.parseInt(gridvalue) > 1) && (position < firstDay)) {
// setting offdays to white color.
dayView.setTextColor(Color.parseColor("#CECECE"));
dayView.setClickable(false);
dayView.setFocusable(false);
} else if ((Integer.parseInt(gridvalue) < 7) && (position > 28)) {
dayView.setTextColor(Color.parseColor("#CECECE"));
dayView.setClickable(false);
dayView.setFocusable(false);
} else {
// setting curent month's days in blue color.
if (dayString.get(position).equals(curentDateString)) {
dayView.setTextColor(Color.parseColor("#CECECE"));
} else {
dayView.setTextColor(Color.parseColor("#D41016"));
}
}

if (dayString.get(position).equals(curentDateString)) {
setSelected(v);
previousView = v;
} else {
v.setBackgroundResource(R.drawable.list_item_background);
}
dayView.setText(gridvalue);

// create date string for comparison
String date = dayString.get(position);

if (date.length() == 1) {
date = "0" + date;
}

String monthStr = "" + (month.get(GregorianCalendar.MONTH));
if (monthStr.length() == 1) {
monthStr = "0" + monthStr;
}

// show icon if date is not empty and it exists in the items array
ImageView iw = (ImageView) v.findViewById(R.id.date_icon);
if (date.length() > 0 && items != null && items.contains(date)) {
iw.setVisibility(View.VISIBLE);
} else {
iw.setVisibility(View.INVISIBLE);
}
return v;
}

public View setSelected(View view) {
if (previousView != null) {
previousView.setBackgroundResource(R.drawable.list_item_background);
}
previousView = view;
view.setBackgroundResource(R.drawable.calendar_cel_selectl);
return view;
}

public void refreshDays() {
// clear items
items.clear();
dayString.clear();
Locale.setDefault(Locale.US);
pmonth = (GregorianCalendar) month.clone();
// month start day. ie; sun, mon, etc
firstDay = month.get(GregorianCalendar.DAY_OF_WEEK);
// finding number of weeks in current month.
maxWeeknumber = month.getActualMaximum(GregorianCalendar.WEEK_OF_MONTH);
// allocating maximum row number for the gridview.
mnthlength = maxWeeknumber * 7;
maxP = getMaxP(); // previous month maximum day 31,30....
calMaxP = maxP - (firstDay - 1);// calendar offday starting 24,25 ...
/**
* Calendar instance for getting a complete gridview including the three
* month's (previous,current,next) dates.
*/
pmonthmaxset = (GregorianCalendar) pmonth.clone();
/**
* setting the start date as previous month's required date.
*/
pmonthmaxset.set(GregorianCalendar.DAY_OF_MONTH, calMaxP);

/**
* filling calendar gridview.
*/
for (int n = 0; n < mnthlength; n++) {

itemvalue = df.format(pmonthmaxset.getTime());
pmonthmaxset.add(GregorianCalendar.DATE, 1);
dayString.add(itemvalue);

}
}

private int getMaxP() {
int maxP;
if (month.get(GregorianCalendar.MONTH) == month
.getActualMinimum(GregorianCalendar.MONTH)) {
pmonth.set((month.get(GregorianCalendar.YEAR) - 1),
month.getActualMaximum(GregorianCalendar.MONTH), 1);
} else {
pmonth.set(GregorianCalendar.MONTH,
month.get(GregorianCalendar.MONTH) - 1);
}
maxP = pmonth.getActualMaximum(GregorianCalendar.DAY_OF_MONTH);

return maxP;
}

}

Step:5

In this step we will set our calendar adapter to our grid View,So open your activity class from src folder from project explorere,And change its code as per below,

CalendarView.java

package com.examples.android.calendar;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.GregorianCalendar;
import java.util.Locale;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.GridView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;

public class CalendarView extends Activity {

public GregorianCalendar month, itemmonth;// calendar instances.

public CalendarAdapter adapter;// adapter instance
public Handler handler;// for grabbing some event values for showing the dot
// marker.
public ArrayList items; // container to store calendar items which
// needs showing the event marker

public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.calendar);
Locale.setDefault( Locale.US );
month = (GregorianCalendar) GregorianCalendar.getInstance();
itemmonth = (GregorianCalendar) month.clone();

items = new ArrayList();
adapter = new CalendarAdapter(this, month);

GridView gridview = (GridView) findViewById(R.id.gridview);
gridview.setAdapter(adapter);

handler = new Handler();
handler.post(calendarUpdater);

TextView title = (TextView) findViewById(R.id.title);
title.setText(android.text.format.DateFormat.format("MMMM yyyy", month));

RelativeLayout previous = (RelativeLayout) findViewById(R.id.previous);

previous.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {
setPreviousMonth();
refreshCalendar();
}
});

RelativeLayout next = (RelativeLayout) findViewById(R.id.next);
next.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {
setNextMonth();
refreshCalendar();

}
});

gridview.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView parent, View v,
int position, long id) {

((CalendarAdapter) parent.getAdapter()).setSelected(v);
String selectedGridDate = CalendarAdapter.dayString
.get(position);
String[] separatedTime = selectedGridDate.split("-");
String gridvalueString = separatedTime[2].replaceFirst("^0*",
"");// taking last part of date. ie; 2 from 2012-12-02.
int gridvalue = Integer.parseInt(gridvalueString);
// navigate to next or previous month on clicking offdays.
if ((gridvalue > 10) && (position < 8)) {
setPreviousMonth();
refreshCalendar();
} else if ((gridvalue < 7) && (position > 28)) {
setNextMonth();
refreshCalendar();
}
((CalendarAdapter) parent.getAdapter()).setSelected(v);

showToast(selectedGridDate);

}
});
}

protected void setNextMonth() {
if (month.get(GregorianCalendar.MONTH) == month
.getActualMaximum(GregorianCalendar.MONTH)) {
month.set((month.get(GregorianCalendar.YEAR) + 1),
month.getActualMinimum(GregorianCalendar.MONTH), 1);
} else {
month.set(GregorianCalendar.MONTH,
month.get(GregorianCalendar.MONTH) + 1);
}

}

protected void setPreviousMonth() {
if (month.get(GregorianCalendar.MONTH) == month
.getActualMinimum(GregorianCalendar.MONTH)) {
month.set((month.get(GregorianCalendar.YEAR) - 1),
month.getActualMaximum(GregorianCalendar.MONTH), 1);
} else {
month.set(GregorianCalendar.MONTH,
month.get(GregorianCalendar.MONTH) - 1);
}

}

protected void showToast(String string) {
Toast.makeText(this, string, Toast.LENGTH_SHORT).show();

}

public void refreshCalendar() {
TextView title = (TextView) findViewById(R.id.title);

adapter.refreshDays();
adapter.notifyDataSetChanged();
handler.post(calendarUpdater); // generate some calendar items

title.setText(android.text.format.DateFormat.format("MMMM yyyy", month));
}

public Runnable calendarUpdater = new Runnable() {

@Override
public void run() {
items.clear();

// Print dates of the current week
DateFormat df = new SimpleDateFormat("yyyy-MM-dd",Locale.US);
String itemvalue;
for (int i = 0; i < 7; i++) {
itemvalue = df.format(itemmonth.getTime());
itemmonth.add(GregorianCalendar.DATE, 1);
items.add("2012-09-12");
items.add("2012-10-07");
items.add("2012-10-15");
items.add("2012-10-20");
items.add("2012-11-30");
items.add("2012-11-28");
}

adapter.setItems(items);
adapter.notifyDataSetChanged();
}
};
}

In this code we have set our custom calendarAdapter to our GridView,Which will make calendar,So here coding is over,Now once go to your Manifest.xml file and make sure thiat your activity is registered in that or not,If not Please change your manifest file as per below,

Manifest.xml



    package="com.examples.android.calendar"
    android:versionCode="1"
    
    android:versionName="1.0" >

   
        android:minSdkVersion="8"
        android:targetSdkVersion="10" />

   
        android:icon="@drawable/appicon"
        android:label="@string/app_name" >
       
            android:name="com.examples.android.calendar.CalendarView"
            android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen" >
           
               

               
           
       
   


Now Clean and build your project and run it..It will Display as below,


Please comment for any issue or query ,Happy  to help ever..Thank you happy coding friends...!!



5 comments:

  1. Can you plz share the code base.. Because few resource are missing

    ReplyDelete
  2. Can you please send you source code to kelsrathod@gmail.com

    ReplyDelete
  3. sorry i'm a newbie android programmer... now i want to learn so can you share the source code to maju3634@yahoo.com? Thankyou

    ReplyDelete
  4. please send your source code "s.selimmiah@gmail.com"

    ReplyDelete

Time is money so...make more n more mony so u can get more tym of ur lyf...:-P