Reputation: 11
I am trying to create a simple calendar for android. It is supposed to show one month at a time and list associated events according to a selected day. I am stuck now on the implementation of the calendar UI since it doesn't list february 2016 and following months correctly.
instead of 29 days it lists 28 and also the listing of february starts on sunday instead of monday. can someone please take a look at my program and help me?
I suspect the error in the following lines:
// init temporary calendar to monday, first day of displayed month
Calendar calx= getCalendar(year, month, 1);
// get WEEK_OF_YEAR of first Day of Month
int firstWeek = calx.get(Calendar.WEEK_OF_YEAR);
// Set DAY_OF_WEEK to Monday
cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
// Set WEEK_OF_YEAR to first week the month is part of
cal.set(Calendar.WEEK_OF_YEAR, firstWeek);
I hope not to offend anyone by posting my complete program, but i am really unsure where the bug is crawling........
drawable/circle_today.xml:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#ffff00" />
<corners
android:topLeftRadius="30dp"
android:topRightRadius="30dp"
android:bottomLeftRadius="30dp"
android:bottomRightRadius="30dp"
/>
</shape>
drawable/circle_selected.xml:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#00ff00" />
<corners
android:topLeftRadius="30dp"
android:topRightRadius="30dp"
android:bottomLeftRadius="30dp"
android:bottomRightRadius="30dp"
/>
</shape>
layout/activity_main.xml:
<RelativeLayout 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" android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">
<TableLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:id="@+id/tableLayout"></TableLayout>
<ListView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/listView"
android:layout_below="@+id/tableLayout"
android:layout_centerHorizontal="true" />
</RelativeLayout>
MainActivity.java:
import android.content.Intent;
import android.graphics.Color;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentActivity;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.AppCompatActivity;
import android.view.Gravity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
public class MainActivity extends AppCompatActivity {
// TableLayout which holds the calendar matrix
private TableLayout calendarTable;
// list for future use as list of events of selected day
private ListView dayList;
//LIST OF ARRAY STRINGS WHICH WILL SERVE AS LIST ITEMS
ArrayList<String> listItems=new ArrayList<String>();
//DEFINING A STRING ADAPTER WHICH WILL HANDLE THE DATA OF THE LISTVIEW
ArrayAdapter<String> adapter;
// today stays today for the complete lifecycle of MainActivity
private int today;
// thisMonth stays thisMonth for the complete lifecycle of MainActivity
private int thisMonth;
// selectedDay changes onClick
private int selectedDay;
// month changes onClick on day of other month
private int month;
// year changes when other month either is january or december of different year
private int year;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// get calendar whith parameters of now
Calendar calendar = getCalendar();
// initiate global variables
selectedDay = today = calendar.get(Calendar.DAY_OF_MONTH);
thisMonth = month = calendar.get(Calendar.MONTH);
year = calendar.get(Calendar.YEAR);
// set up TableLayout which holds the calendar matrix
calendarTable = (TableLayout) findViewById(R.id.tableLayout);
// set up list for future use as list of events of selected day
dayList = (ListView) findViewById(R.id.listView);
adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, listItems);
dayList.setAdapter(adapter);
// sanity test
testCalendar();
// build calendar table
updateCalendar();
}
// function to test Calendar behaviour, as expected the output is
// Week: 8 Day: 27 Month: 1
// Week: 8 Day: 28 Month: 1
// Week: 9 Day: 29 Month: 1
// Week: 9 Day: 1 Month: 2
// contrary to UI behaviour which lists 2016-2-1 as sunday and lists only 28 days
private final void testCalendar() {
Calendar c = getCalendar(2016, 1, 27);
for (int i = 0; i < 4; i++) {
System.out.println("Week: " +c.get(Calendar.WEEK_OF_YEAR) + " Day: " +
c.get(Calendar.DAY_OF_MONTH) + " Month: " + c.get(Calendar.MONTH));
c.add(Calendar.DAY_OF_MONTH, 1);
}
}
// function to ensure correct configuration of Calendar
private final Calendar getCalendar() {
Calendar gc = new GregorianCalendar();
gc.setFirstDayOfWeek(Calendar.MONDAY);
gc.setMinimalDaysInFirstWeek(4);
return gc;
}
// function to ensure correct configuration of Calendar
private final Calendar getCalendar(int year, int month, int day) {
Calendar gc = new GregorianCalendar(year, month, day);
gc.setFirstDayOfWeek(Calendar.MONDAY);
gc.setMinimalDaysInFirstWeek(4);
return gc;
}
private void updateCalendar() {
// reset table
calendarTable.removeAllViews();
// init calendar used by this function
Calendar cal = getCalendar();
// init temporary calendar to monday, first day of displayed month
Calendar calx= getCalendar(year, month, 1);
// get WEEK_OF_YEAR of first Day of Month
int firstWeek = calx.get(Calendar.WEEK_OF_YEAR);
// Set DAY_OF_WEEK to Monday
cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
// Set WEEK_OF_YEAR to first week the month is part of
cal.set(Calendar.WEEK_OF_YEAR, firstWeek);
// init reusable vars
TableRow row = null;
TextView tv = null;
int paddingNormal = 35;
//outer loop, rows
for (int i = 0; i < 7; i++) {
// init row
row = new TableRow(this);
// stretch row
// code to stretch row width to parent view, took no effect
/*row.setLayoutParams(new TableRow.LayoutParams(TableRow.LayoutParams.MATCH_PARENT,
TableRow.LayoutParams.WRAP_CONTENT));*/
// inner loop, fields
for (int j = 0; j < 8; j++) {
// init
tv = new TextView(this);
// center day labels
tv.setGravity(Gravity.CENTER_VERTICAL | Gravity.CENTER_HORIZONTAL);
// code to stretch row width to parent view, took no effect
/*tv.setLayoutParams(new TableRow.LayoutParams(TableRow.LayoutParams.WRAP_CONTENT,
TableRow.LayoutParams.WRAP_CONTENT));*/
// first row, headers
if (i == 0) {
tv.setPadding(paddingNormal, paddingNormal, paddingNormal, paddingNormal);
tv.setBackgroundColor(Color.rgb(213, 213, 213));
switch (j) {
case 0:
break;
case 1:
tv.setText("MO");
break;
case 2:
tv.setText("DI");
break;
case 3:
tv.setText("MI");
break;
case 4:
tv.setText("DO");
break;
case 5:
tv.setText("FR");
break;
case 6:
tv.setText("SA");
break;
case 7:
tv.setText("SO");
break;
}
}
else if (j == 0) {
// week no
tv.setPadding(paddingNormal, paddingNormal, paddingNormal, paddingNormal);
tv.setBackgroundColor(Color.rgb(213, 213, 213));
tv.setText(""+cal.get(Calendar.WEEK_OF_YEAR));
} else {
// days
tv.setPadding(paddingNormal, paddingNormal, paddingNormal, paddingNormal);
tv.setText("" + cal.get(Calendar.DAY_OF_MONTH));
// mark days of different month
if ((cal.get(Calendar.MONTH) != month)) {
tv.setTextColor(Color.rgb(213, 213, 213));
// switch to previous or next month
tv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// set selectedDay of different month
selectedDay = Integer.parseInt(((TextView) v).getText() + "");
// if selectedDay is bigger 15 it is part of previous month
if (selectedDay > 15) {
// if month is january
if (month == Calendar.JANUARY) {
// month is reset to december
month = Calendar.DECEMBER;
// and year decremented to previous year
year = year - 1;
} else {
// else month is decremented
month = month - 1;
}
// else selectedDay is part of next month
} else {
// if month is december
if (month == Calendar.DECEMBER) {
// month is reset to january
month = Calendar.JANUARY;
// and year is incremented
year = year + 1;
} else {
// else only month is incremented
month = month + 1;
}
}
// updateCalendar to display different month
updateCalendar();
}
});
} else {
// mark today with yellow circle
if ((cal.get(Calendar.DAY_OF_MONTH) == today) && month == thisMonth) {
tv.setBackgroundResource(R.drawable.circle_today);
}
// mark selected day with green circle
if ((cal.get(Calendar.DAY_OF_MONTH) == selectedDay)) {
tv.setBackgroundResource(R.drawable.circle_selected);
}
// setOnclickListener to updateCalendar and display the new selection and dayList
tv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// set selectedDay before rebuilding table
selectedDay = Integer.parseInt(((TextView) v).getText() + "");
// rebuild table
updateCalendar();
}
});
}
// increment calendar DAY_OF_MONTH field by 1
cal.add(Calendar.DAY_OF_MONTH, 1);
}
// add TextView to row
row.addView(tv);
}
// add row to TableLayout
calendarTable.addView(row);
}
// Set ActionBar Title to "*month* *year*"
String title ="";
switch(month)
{
case Calendar.JANUARY:
title = "Jänner " + year;
break;
case Calendar.FEBRUARY:
title = "Februar " + year;
break;
case Calendar.MARCH:
title = "März " + year;
break;
case Calendar.APRIL:
title = "April " + year;
break;
case Calendar.MAY:
title = "Mai " + year;
break;
case Calendar.JUNE:
title = "Juni " + year;
break;
case Calendar.JULY:
title = "Juli " + year;
break;
case Calendar.AUGUST:
title = "August " + year;
break;
case Calendar.SEPTEMBER:
title = "September " + year;
break;
case Calendar.OCTOBER:
title = "Oktober " + year;
break;
case Calendar.NOVEMBER:
title = "November " + year;
break;
case Calendar.DECEMBER:
title = "Dezember " + year;
break;
}
setTitle(title);
// list events of selected day
updateDayList();
}
private void updateDayList() {
// TODO implement...
adapter.clear();
adapter.add(selectedDay + "/" + month + "/" + year);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
Upvotes: 1
Views: 93
Reputation: 11
Do not use old Java time classes, use Joda Time or the new Java time classes introduced in JDK 1.8 .
Upvotes: 0
Reputation: 159135
Remember that DAY_OF_WEEK
uses 0=Sunday, 1=Monday, ...
and so on. Don't know if locale makes a difference, but in US
the week starts on Sunday.
Feb 1, 2015 is a Sunday. WEEK_OF_YEAR
is 6.
Setting DAY_OF_WEEK
to 1=Monday
will get you Monday, Feb 2, 2015.
I don't think that is what you were after.
Upvotes: 1