スマートフォン・ジン | Smartphone-Zine

引っ越し先→ https://smartphone-zine.com/

カスタムコンポーネントでCalendarViewを作成

AndroidではViewを自作することができます。独自に画面の描画を行った完全に新規のカスタムビューを作ることも、既存のViewを組み合わせたカスタムコンポーネントを作ることもできます。 今回は、既存のViewを組み合わせたカスタムコンポーネントを作成してみましょう。自前のCalendarViewを作成します。

まず、作成したビューは次のようにレイアウトファイルにクラス名で記述します。 [xml] <com.example.calendarsample.CalendarView android:id="@+id/Calendar1" android:layout_width="260dp" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_marginTop="49dp" > </com.example.calendarsample.CalendarView> [/xml] com.example.calendarsample.CalendarView.java を作成していきます。 カスタムコンポーネントを作成する場合、複数のViewを組み合わせることになると思いますので、ViewGroup(レイアウト)を継承しましょう。 今回のカスタムカレンダーコンポーネントでは縦に並べたいのでLinearLayoutを継承したクラスを作成します。

public class CalendarView extends LinearLayout {
    ....
}

コンストラクタを用意します。レイアウトXMLで使用する場合は、(Context context, AttributeSet attrs)をオーバーライドする必要があります。 [java] public CalendarView(Context context, AttributeSet attrs) { super(context, attrs); } [/java] コンストラクタ内部でビューを作成して、ビュー自身に追加していきます。カスタムコンポーネントの作成はこれだけです。実に簡単ですね! [java] private TextView mTitle; public CalendarView(Context context, AttributeSet attrs) { super(context, attrs); this.setOrientation(VERTICAL); mTitle = new TextView(context); addView(mTitle, new LinearLayout.LayoutParams( LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)); } [/java] では、カレンダーのカスタムコンポーネントを作成してみましょう。

  • カレンダーのタイトル用TextView
  • 週の文字列(日月火水木金土)用に7つのTextView
  • カレンダーの日付用に6×7=42マスのTextView

を作成しましょう。 また、今週は背景をグレーにして、今日の日付は赤色で表示するようにします。 ソースは次のようになります。 [java] package com.example.calendarsample; import android.content.Context; import android.graphics.Color; import android.graphics.Typeface; import android.util.AttributeSet; import android.util.Log; import android.view.Gravity; import android.widget.LinearLayout; import android.widget.TextView; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; public class CalendarView extends LinearLayout { private static final int WEEK_7 = 7; private static final int MAX_WEEK = 6; public CalendarView(Context context, AttributeSet attrs) { super(context, attrs); this.setOrientation(VERTICAL); // dp-->px 変換用の値 final float scale = context.getResources().getDisplayMetrics().density; // パディング final int padding = (int) (scale * 5); // 右パディング final int paddingR = (int) (scale * 15); // タイトルとのパディング final int paddintT = (int) (scale * 20); titleFontPx = scale * 30; // 本日の日付を保持 mToday = Calendar.getInstance(); // タイトル部 年月表示 Log.v("CalendarView", "タイトル部 年月表示"); mTitle = new TextView(context); mTitle.setGravity(Gravity.CENTER_HORIZONTAL); // 中央に表示 mTitle.setTypeface(null, Typeface.BOLD); // 太字 mTitle.setText("DEBUG"); mTitle.setPadding(0, 0, 0, paddintT); addView(mTitle, new LinearLayout.LayoutParams( LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)); dayFontPx = mTitle.getTextSize(); // 現在のフォントサイズを保持 defaultColor = mTitle.getTextColors().getDefaultColor(); // 週表示部 日月火水木金土 Log.v("CalendarView", "週表示部 日月火水木金土"); mWeekLayout = new LinearLayout(context); // 週表示レイアウト Calendar cal = Calendar.getInstance(); cal.set(Calendar.DAY_OF_WEEK, beginningWeek); // 週の頭をセット SimpleDateFormat formatter = new SimpleDateFormat("E"); // 曜日を取得するフォーマッタ for (int i = 0; i < WEEK_7; i++) { TextView textView = new TextView(context); textView.setText(formatter.format(cal.getTime())); // テキストに曜日を表示 textView.setGravity(Gravity.CENTER_HORIZONTAL); // 中央に表示 LinearLayout.LayoutParams llp = new LinearLayout.LayoutParams( 0, LayoutParams.WRAP_CONTENT); llp.weight = 1; mWeekLayout.addView(textView, llp); cal.add(Calendar.DAY_OF_MONTH, 1); } addView(mWeekLayout, new LinearLayout.LayoutParams( LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)); // カレンダー部 最大6行必要 Log.v("CalendarView", "カレンダー部 最大6行必要"); for (int i = 0; i < MAX_WEEK; i++) { LinearLayout weekLine = new LinearLayout(context); mWeeks.add(weekLine); // 1週間分の日付ビュー作成 for (int j = 0; j < WEEK_7; j++) { TextView dayView = new TextView(context); dayView.setText(String.valueOf*1; } init(mToday.get(Calendar.YEAR), mToday.get(Calendar.MONTH)); } // 表示設定 public void init(int year, int month) { Calendar cal = Calendar.getInstance(); cal.clear(); // まずクリアしてからセットしないといけない cal.set(Calendar.YEAR, year); cal.set(Calendar.MONTH, month); cal.set(Calendar.DAY_OF_MONTH, 1); int todayYear = mToday.get(Calendar.YEAR); int todayMonth = mToday.get(Calendar.MONTH); int todayDay = mToday.get(Calendar.DAY_OF_MONTH); // タイトル 年月 設定 String formatString = mTitle.getContext().getString(R.string.format_month_year); // 年月フォーマット文字列 mTitle.setTextSize(titleFontPx); // 年月を取得するフォーマッタ SimpleDateFormat formatter = new SimpleDateFormat(formatString); mTitle.setText(formatter.format(cal.getTime())); // 週表示部 日月火水木金土 Log.v("CalendarView", "週表示部 日月火水木金土"); Calendar week = Calendar.getInstance(); week.set(Calendar.DAY_OF_WEEK, beginningWeek); // 週の頭をセット SimpleDateFormat weekFormatter = new SimpleDateFormat("E"); // 曜日を取得するフォーマッタ for (int i = 0; i < WEEK_7; i++) { TextView textView = (TextView) mWeekLayout.getChildAt(i); textView.setText(weekFormatter.format(week.getTime())); // テキストに曜日を表示 week.add(Calendar.DAY_OF_MONTH, 1); } // カレンダーの最初の空白の個数を求める。 int skipCount; // 空白の個数 int firstDayMonthWeek = cal.get(Calendar.DAY_OF_WEEK); // 1日の曜日 if (beginningWeek > firstDayMonthWeek) { skipCount = firstDayMonthWeek - beginningWeek + WEEK_7; } else { skipCount = firstDayMonthWeek - beginningWeek; } int lastDay = cal.getActualMaximum(Calendar.DATE); // 月の最終日 // 日付を生成する。 int dayCounter = 1; for (int i = 0; i < MAX_WEEK; i++) { LinearLayout weekLayout = mWeeks.get(i); weekLayout.setBackgroundColor(defaultBackgroundColor); for (int j = 0; j < WEEK_7; j++) { TextView dayView = (TextView) weekLayout.getChildAt(j); if (i == 0 && skipCount > 0) { dayView.setText(" "); skipCount--; } else if (dayCounter <= lastDay) { dayView.setText(String.valueOf(dayCounter)); // 今日の日付を赤文字にする if (todayYear == year && todayMonth == month && todayDay == dayCounter) { dayView .setTextColor(todayColor); // 赤文字 dayView.setTypeface(null, Typeface.BOLD); // 太字 weekLayout .setBackgroundColor(todayBackgroundColor); // 週の背景グレー } else { dayView.setTextColor(defaultColor); dayView.setTypeface(null, Typeface.NORMAL); } dayCounter++; } else { dayView.setText(" "); } } } } / 週の始まりの曜日を保持する */ public int beginningWeek = Calendar.SUNDAY; / 今日のフォント色 / public int todayColor = Color.RED; /** 今週の背景色 / public int todayBackgroundColor = Color.LTGRAY; / 通常の背景色 */ public int defaultBackgroundColor = Color.TRANSPARENT; / 通常のフォント色 / public int defaultColor; /** 年月のフォントサイズ / public float titleFontPx; /* 日付のフォントサイズ / public float dayFontPx; private TextView mTitle; // 年月表示部分 private LinearLayout mWeekLayout; private ArrayList mWeeks = new ArrayList(); private Calendar mToday; } [/java] 実行するときは、標示したい年月をinit(year,month)に渡せばOKです。 [java] CalendarView cal = (CalendarView) findViewById(R.id.Calendar1); cal.beginningWeek = Calendar.SUNDAY; // 週の開始曜日を指定 cal.init(2012, 9-1); // 2012年9月のカレンダーを表示 [/java] 以上で、カスタムカレンダーを作成することができました。

*1:i * WEEK_7) + (j + 1))); // TODO:DEBUG dayView.setGravity(Gravity.RIGHT); // 右寄せで表示 dayView.setPadding(0, padding, paddingR, padding); LinearLayout.LayoutParams llp = new LinearLayout.LayoutParams( 0, LayoutParams.WRAP_CONTENT); llp.weight = 1; weekLine.addView(dayView, llp); } this.addView(weekLine, new LinearLayout.LayoutParams( LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT