summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--res/layout/date_picker_done_button.xml2
-rw-r--r--src/com/android/datetimepicker/Utils.java17
-rw-r--r--src/com/android/datetimepicker/date/MonthView.java223
-rw-r--r--src/com/android/datetimepicker/date/SimpleMonthView.java4
4 files changed, 207 insertions, 39 deletions
diff --git a/res/layout/date_picker_done_button.xml b/res/layout/date_picker_done_button.xml
index ebe24d3..1ca8239 100644
--- a/res/layout/date_picker_done_button.xml
+++ b/res/layout/date_picker_done_button.xml
@@ -22,10 +22,12 @@
<Button
android:id="@+id/done"
style="?android:attr/buttonBarButtonStyle"
+ android:padding="0dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="48dp"
android:text="@string/done_label"
android:textSize="@dimen/done_label_size"
android:textColor="@color/done_text_color" />
+
</LinearLayout>
diff --git a/src/com/android/datetimepicker/Utils.java b/src/com/android/datetimepicker/Utils.java
index 4a3110c..0b57f7c 100644
--- a/src/com/android/datetimepicker/Utils.java
+++ b/src/com/android/datetimepicker/Utils.java
@@ -25,6 +25,7 @@ import android.text.format.Time;
import android.view.View;
import java.util.Calendar;
+import java.util.Locale;
/**
* Utility helper functions for time and date pickers.
@@ -137,4 +138,20 @@ public class Utils {
return pulseAnimator;
}
+
+ /**
+ * Determines if the device's current default locale uses right-to-left written script
+ */
+ public static boolean isRtl() {
+ return isRtl(Locale.getDefault());
+ }
+
+ /**
+ * Determines if a particular locale uses right-to-left written script
+ */
+ public static boolean isRtl(Locale locale) {
+ final int directionality = Character.getDirectionality(locale.getDisplayName().charAt(0));
+ return directionality == Character.DIRECTIONALITY_RIGHT_TO_LEFT ||
+ directionality == Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC;
+ }
}
diff --git a/src/com/android/datetimepicker/date/MonthView.java b/src/com/android/datetimepicker/date/MonthView.java
index 00711f3..07df483 100644
--- a/src/com/android/datetimepicker/date/MonthView.java
+++ b/src/com/android/datetimepicker/date/MonthView.java
@@ -19,6 +19,7 @@ package com.android.datetimepicker.date;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
+import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.graphics.Paint.Style;
@@ -32,6 +33,7 @@ import android.text.format.DateFormat;
import android.text.format.DateUtils;
import android.text.format.Time;
import android.util.AttributeSet;
+import android.util.Pair;
import android.view.MotionEvent;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
@@ -54,6 +56,7 @@ import java.util.Locale;
*/
public abstract class MonthView extends View {
private static final String TAG = "MonthView";
+ private static final boolean DEBUG = false;
/**
* These params can be passed into the view to control how it appears.
@@ -99,6 +102,24 @@ public abstract class MonthView extends View {
*/
public static final String VIEW_PARAMS_SHOW_WK_NUM = "show_wk_num";
+
+ /**
+ * Configuration flags to customize the month view's look
+ * override parameters through {@link #customizeViewParameters}
+ */
+ public static final String CONFIG_EDGE_PADDING = "edge_padding";
+ public static final String CONFIG_HEADER_SIZE = "header_size";
+ public static final String CONFIG_MONTH_LABEL_TEXT_SIZE = "month_label_text_size";
+ public static final String CONFIG_MONTH_DAY_TEXT_SIZE = "month_day_text_size";
+ public static final String CONFIG_MONTH_HEADER_LABEL_FLAGS = "month_header_label_flags";
+ public static final String CONFIG_MONTH_ROW_HEIGHT = "month_row_height";
+ public static final String CONFIG_FILL_PARENT_CONTAINER = "fill_parent_container";
+ public static final String CONFIG_HEADER_TITLE_COLOR = "header_title_color";
+ public static final String CONFIG_DAY_SELECTED_CIRCLE_COLOR = "day_selected_circle_color";
+ public static final String CONFIG_DAY_SELECTED_CIRCLE_ALPHA = "day_selected_circle_alpha";
+ public static final String CONFIG_CURRENT_DAY_COLOR = "current_day_color";
+ public static final String CONFIG_HEADER_TITLE_OFFSET = "header_title_offset";
+
protected static int DEFAULT_HEIGHT = 32;
protected static int MIN_HEIGHT = 10;
protected static final int DEFAULT_SELECTED_DAY = -1;
@@ -109,18 +130,17 @@ public abstract class MonthView extends View {
protected static final int DEFAULT_NUM_ROWS = 6;
protected static final int MAX_NUM_ROWS = 6;
- private static final int SELECTED_CIRCLE_ALPHA = 60;
-
- protected static int DAY_SEPARATOR_WIDTH = 1;
- protected static int MINI_DAY_NUMBER_TEXT_SIZE;
- protected static int MONTH_LABEL_TEXT_SIZE;
- protected static int MONTH_DAY_LABEL_TEXT_SIZE;
- protected static int MONTH_HEADER_SIZE;
- protected static int DAY_SELECTED_CIRCLE_SIZE;
-
// used for scaling to the device density
protected static float mScale = 0;
+ private int mSelectedCircleAlpha = 60;
+ protected int mDaySeparatorWidth = 1;
+ protected int mMiniDayNumberTextSize;
+ protected int mMonthLabelTextSize;
+ protected int mMonthDayLabelTextSize;
+ protected int mMonthHeaderSize;
+ protected int mDaySelectedCircleSize;
+
protected DatePickerController mController;
// affects the padding on the sides of this view
@@ -134,6 +154,7 @@ public abstract class MonthView extends View {
protected Paint mMonthTitleBGPaint;
protected Paint mSelectedCirclePaint;
protected Paint mMonthDayLabelPaint;
+ protected Paint mLinePaint;
private final Formatter mFormatter;
private final StringBuilder mStringBuilder;
@@ -187,6 +208,14 @@ public abstract class MonthView extends View {
protected int mMonthTitleColor;
protected int mMonthTitleBGColor;
+ // default format for the header label
+ protected int mHeaderDateFlags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR
+ | DateUtils.FORMAT_NO_MONTH_DAY;
+ protected boolean mShouldFillParent;
+ protected int mHeaderTitleColor;
+ protected int mSelectedCircleColor;
+ protected int mHeaderTitleOffset;
+
public MonthView(Context context) {
this(context, null);
}
@@ -202,7 +231,9 @@ public abstract class MonthView extends View {
mMonthTitleTypeface = res.getString(R.string.sans_serif);
mDayTextColor = res.getColor(R.color.date_picker_text_normal);
+ mHeaderTitleColor = mDayTextColor;
mTodayNumberColor = res.getColor(R.color.blue);
+ mSelectedCircleColor = mTodayNumberColor;
mDisabledDayTextColor = res.getColor(R.color.date_picker_text_disabled);
mMonthTitleColor = res.getColor(android.R.color.white);
mMonthTitleBGColor = res.getColor(R.color.circle_background);
@@ -210,11 +241,11 @@ public abstract class MonthView extends View {
mStringBuilder = new StringBuilder(50);
mFormatter = new Formatter(mStringBuilder, Locale.getDefault());
- MINI_DAY_NUMBER_TEXT_SIZE = res.getDimensionPixelSize(R.dimen.day_number_size);
- MONTH_LABEL_TEXT_SIZE = res.getDimensionPixelSize(R.dimen.month_label_size);
- MONTH_DAY_LABEL_TEXT_SIZE = res.getDimensionPixelSize(R.dimen.month_day_label_text_size);
- MONTH_HEADER_SIZE = res.getDimensionPixelOffset(R.dimen.month_list_item_header_height);
- DAY_SELECTED_CIRCLE_SIZE = res
+ mMiniDayNumberTextSize = res.getDimensionPixelSize(R.dimen.day_number_size);
+ mMonthLabelTextSize = res.getDimensionPixelSize(R.dimen.month_label_size);
+ mMonthDayLabelTextSize = res.getDimensionPixelSize(R.dimen.month_day_label_text_size);
+ mMonthHeaderSize = res.getDimensionPixelOffset(R.dimen.month_list_item_header_height);
+ mDaySelectedCircleSize = res
.getDimensionPixelSize(R.dimen.day_number_select_circle_radius);
mRowHeight = (res.getDimensionPixelOffset(R.dimen.date_picker_view_animator_height)
@@ -281,9 +312,9 @@ public abstract class MonthView extends View {
mMonthTitlePaint = new Paint();
mMonthTitlePaint.setFakeBoldText(true);
mMonthTitlePaint.setAntiAlias(true);
- mMonthTitlePaint.setTextSize(MONTH_LABEL_TEXT_SIZE);
+ mMonthTitlePaint.setTextSize(mMonthLabelTextSize);
mMonthTitlePaint.setTypeface(Typeface.create(mMonthTitleTypeface, Typeface.BOLD));
- mMonthTitlePaint.setColor(mDayTextColor);
+ mMonthTitlePaint.setColor(mHeaderTitleColor);
mMonthTitlePaint.setTextAlign(Align.CENTER);
mMonthTitlePaint.setStyle(Style.FILL);
@@ -297,23 +328,28 @@ public abstract class MonthView extends View {
mSelectedCirclePaint = new Paint();
mSelectedCirclePaint.setFakeBoldText(true);
mSelectedCirclePaint.setAntiAlias(true);
- mSelectedCirclePaint.setColor(mTodayNumberColor);
+ mSelectedCirclePaint.setColor(mSelectedCircleColor);
mSelectedCirclePaint.setTextAlign(Align.CENTER);
mSelectedCirclePaint.setStyle(Style.FILL);
- mSelectedCirclePaint.setAlpha(SELECTED_CIRCLE_ALPHA);
+ mSelectedCirclePaint.setAlpha(mSelectedCircleAlpha);
mMonthDayLabelPaint = new Paint();
mMonthDayLabelPaint.setAntiAlias(true);
- mMonthDayLabelPaint.setTextSize(MONTH_DAY_LABEL_TEXT_SIZE);
+ mMonthDayLabelPaint.setTextSize(mMonthDayLabelTextSize);
mMonthDayLabelPaint.setColor(mDayTextColor);
mMonthDayLabelPaint.setTypeface(Typeface.create(mDayOfWeekTypeface, Typeface.NORMAL));
mMonthDayLabelPaint.setStyle(Style.FILL);
mMonthDayLabelPaint.setTextAlign(Align.CENTER);
mMonthDayLabelPaint.setFakeBoldText(true);
+ mLinePaint = new Paint();
+ mLinePaint.setAntiAlias(true);
+ mLinePaint.setStrokeWidth(0);
+ mLinePaint.setColor(Color.BLACK);
+
mMonthNumPaint = new Paint();
mMonthNumPaint.setAntiAlias(true);
- mMonthNumPaint.setTextSize(MINI_DAY_NUMBER_TEXT_SIZE);
+ mMonthNumPaint.setTextSize(mMiniDayNumberTextSize);
mMonthNumPaint.setStyle(Style.FILL);
mMonthNumPaint.setTextAlign(Align.CENTER);
mMonthNumPaint.setFakeBoldText(false);
@@ -329,6 +365,60 @@ public abstract class MonthView extends View {
private int mDayOfWeekStart = 0;
/**
+ * Override the default drawing parameters of the view
+ *
+ * @params is a dictionary of attributes (CONFIG_*) with their corresponding values in
+ * pixels
+ */
+ public void customizeViewParameters(HashMap<String, Integer> params) {
+ if (params == null) return;
+ for (String key : params.keySet()) {
+
+ int paramValue = params.get(key);
+ if (key.equals(CONFIG_MONTH_LABEL_TEXT_SIZE)) {
+ mMonthLabelTextSize = paramValue;
+
+ } else if (key.equals(CONFIG_HEADER_SIZE)) {
+ mMonthHeaderSize = paramValue;
+
+ } else if (key.equals(CONFIG_MONTH_DAY_TEXT_SIZE)) {
+ mMonthDayLabelTextSize = paramValue;
+ mMiniDayNumberTextSize = paramValue;
+
+ } else if (key.equals(CONFIG_MONTH_HEADER_LABEL_FLAGS)) {
+ mHeaderDateFlags = paramValue;
+
+ } else if (key.equals(CONFIG_MONTH_ROW_HEIGHT)) {
+ mRowHeight = paramValue;
+
+ } else if (key.equals(CONFIG_EDGE_PADDING)) {
+ mEdgePadding = paramValue;
+
+ } else if (key.equals(CONFIG_FILL_PARENT_CONTAINER)) {
+ mShouldFillParent = (paramValue == 1);
+
+ } else if (key.equals(CONFIG_HEADER_TITLE_COLOR)) {
+ mHeaderTitleColor = paramValue;
+
+ } else if (key.equals(CONFIG_CURRENT_DAY_COLOR)) {
+ mTodayNumberColor = paramValue;
+
+ } else if (key.equals(CONFIG_DAY_SELECTED_CIRCLE_ALPHA)) {
+ mSelectedCircleAlpha = paramValue;
+
+ } else if (key.equals(CONFIG_DAY_SELECTED_CIRCLE_COLOR)) {
+ mSelectedCircleColor = paramValue;
+
+ } else if (key.equals(CONFIG_HEADER_TITLE_OFFSET)) {
+ mHeaderTitleOffset = paramValue;
+ }
+ }
+
+ // reinitialize paints as some of their properties might have been overridden
+ initView();
+ }
+
+ /**
* Sets all the parameters for displaying this week. The only required
* parameter is the week number. Other parameters have a default value and
* will only update if a new value is included, except for focus month,
@@ -413,8 +503,13 @@ public abstract class MonthView extends View {
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), mRowHeight * mNumRows
- + getMonthHeaderSize());
+ if (mShouldFillParent) {
+ setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec),
+ MeasureSpec.getSize(heightMeasureSpec));
+ } else {
+ setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), mRowHeight * mNumRows
+ + getMonthHeaderSize());
+ }
}
@Override
@@ -437,35 +532,45 @@ public abstract class MonthView extends View {
* A wrapper to the MonthHeaderSize to allow override it in children
*/
protected int getMonthHeaderSize() {
- return MONTH_HEADER_SIZE;
+ return mMonthHeaderSize;
}
private String getMonthAndYearString() {
- int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR
- | DateUtils.FORMAT_NO_MONTH_DAY;
mStringBuilder.setLength(0);
long millis = mCalendar.getTimeInMillis();
- return DateUtils.formatDateRange(getContext(), mFormatter, millis, millis, flags,
+ return DateUtils.formatDateRange(getContext(), mFormatter, millis, millis, mHeaderDateFlags,
Time.getCurrentTimezone()).toString();
}
protected void drawMonthTitle(Canvas canvas) {
- int x = (mWidth + 2 * mEdgePadding) / 2;
- int y = (getMonthHeaderSize() - MONTH_DAY_LABEL_TEXT_SIZE) / 2 + (MONTH_LABEL_TEXT_SIZE / 3);
+ // the title is centered within the view
+ int x = mWidth / 2;
+ int y = (getMonthHeaderSize() - mMonthDayLabelTextSize) / 2 + (mMonthLabelTextSize / 3) +
+ mHeaderTitleOffset;
+
+ if (DEBUG) {
+ canvas.drawLine(0, 0, canvas.getWidth(), 0, mLinePaint);
+ canvas.drawLine(x, 0, x, mMonthHeaderSize, mLinePaint);
+ canvas.drawLine(0, mMonthHeaderSize, canvas.getWidth(), mMonthHeaderSize, mLinePaint);
+ }
canvas.drawText(getMonthAndYearString(), x, y, mMonthTitlePaint);
}
protected void drawMonthDayLabels(Canvas canvas) {
- int y = getMonthHeaderSize() - (MONTH_DAY_LABEL_TEXT_SIZE / 2);
+ int y = getMonthHeaderSize() - (mMonthDayLabelTextSize / 2);
int dayWidthHalf = (mWidth - mEdgePadding * 2) / (mNumDays * 2);
+ boolean isRtl = Utils.isRtl(); // current locale's written script direction
for (int i = 0; i < mNumDays; i++) {
int calendarDay = (i + mWeekStart) % mNumDays;
int x = (2 * i + 1) * dayWidthHalf + mEdgePadding;
+
mDayLabelCalendar.set(Calendar.DAY_OF_WEEK, calendarDay);
- canvas.drawText(mDayLabelCalendar.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.SHORT,
- Locale.getDefault()).toUpperCase(Locale.getDefault()), x, y,
- mMonthDayLabelPaint);
+ String dayDisplayName = mDayLabelCalendar.getDisplayName(Calendar.DAY_OF_WEEK,
+ Calendar.SHORT, Locale.getDefault()).toUpperCase(Locale.getDefault());
+
+ String dayLabel = generateDayLabel(dayDisplayName, isRtl);
+ canvas.drawText(dayLabel, x, y, mMonthDayLabelPaint);
}
}
@@ -476,14 +581,13 @@ public abstract class MonthView extends View {
* @param canvas The canvas to draw on
*/
protected void drawMonthNums(Canvas canvas) {
- int y = (((mRowHeight + MINI_DAY_NUMBER_TEXT_SIZE) / 2) - DAY_SEPARATOR_WIDTH)
+ int y = (((mRowHeight + mMiniDayNumberTextSize) / 2) - mDaySeparatorWidth)
+ getMonthHeaderSize();
final float dayWidthHalf = (mWidth - mEdgePadding * 2) / (mNumDays * 2.0f);
int j = findDayOffset();
for (int dayNumber = 1; dayNumber <= mNumCells; dayNumber++) {
final int x = (int)((2 * j + 1) * dayWidthHalf + mEdgePadding);
-
- int yRelativeToDay = (mRowHeight + MINI_DAY_NUMBER_TEXT_SIZE) / 2 - DAY_SEPARATOR_WIDTH;
+ int yRelativeToDay = (mRowHeight + mMiniDayNumberTextSize) / 2 - mDaySeparatorWidth;
final int startX = (int)(x - dayWidthHalf);
final int stopX = (int)(x + dayWidthHalf);
@@ -491,7 +595,6 @@ public abstract class MonthView extends View {
final int stopY = (int)(startY + mRowHeight);
drawMonthDay(canvas, mYear, mMonth, dayNumber, x, y, startX, stopX, startY, stopY);
-
j++;
if (j == mNumDays) {
j = 0;
@@ -560,6 +663,35 @@ public abstract class MonthView extends View {
}
/**
+ * Returns the text center of the nearest Day relative to an input set of coordinates
+ *
+ * The returned location is the center of day text. This is useful when you are trying to map a
+ * click to the nearest day or when implementing snap functionality.
+ *
+ * @param clickX input x-coordinate
+ * @param clickY input y-coordinate
+ * @return a Pair of coordinates (x,y) that are the closest to the input, or null if the input
+ * isn't valid or inside the header region
+ */
+ public Pair<Float, Float> mapToNearestDayCoordinates(float clickX, float clickY) {
+ // ensure the click maps to a valid 'clickable' region of the view
+ if (getDayFromLocation(clickX, clickY) == -1) return null;
+
+ // map the click to a row and column
+ int row = (int) (clickY - getMonthHeaderSize()) / mRowHeight;
+ int column = (int) ((clickX - mEdgePadding) * mNumDays / (mWidth - 2 * mEdgePadding));
+
+ // calculate the day text center drawn at a particular row and column
+ final float dayWidthHalf = (mWidth - mEdgePadding * 2) / (mNumDays * 2.0f);
+ float retX = (2 * column + 1) * dayWidthHalf + mEdgePadding;
+ int startY = (((mRowHeight + mMiniDayNumberTextSize) / 2) - mDaySeparatorWidth)
+ + getMonthHeaderSize();
+ float retY = startY + row * mRowHeight;
+
+ return new Pair<Float, Float>(retX, retY);
+ }
+
+ /**
* Called when the user clicks on a day. Handles callbacks to the
* {@link OnDayClickListener} if one is set.
* <p/>
@@ -812,4 +944,23 @@ public abstract class MonthView extends View {
public interface OnDayClickListener {
public void onDayClick(MonthView view, CalendarDay day);
}
+
+ /**
+ * Formats a given Day's display name into a single character label
+ *
+ * @param input display name of the day (Saturday, Monday .. etc)
+ * @param isRtl true if the input's written script is right-to-left
+ * @return
+ */
+ private String generateDayLabel(String input, boolean isRtl) {
+ Locale locale = Locale.getDefault();
+ // 'special-case'-ing Chinese languages as their Day labels are written right-to-left
+ if (isRtl || locale.equals(Locale.SIMPLIFIED_CHINESE) ||
+ locale.equals(Locale.TRADITIONAL_CHINESE) ||
+ locale.equals(new Locale("zh", "HK"))) {
+ return input.substring(input.length()-1);
+ } else {
+ return input.substring(0,1);
+ }
+ }
}
diff --git a/src/com/android/datetimepicker/date/SimpleMonthView.java b/src/com/android/datetimepicker/date/SimpleMonthView.java
index b416a45..d414d0a 100644
--- a/src/com/android/datetimepicker/date/SimpleMonthView.java
+++ b/src/com/android/datetimepicker/date/SimpleMonthView.java
@@ -19,8 +19,6 @@ package com.android.datetimepicker.date;
import android.content.Context;
import android.graphics.Canvas;
-import java.util.Calendar;
-
public class SimpleMonthView extends MonthView {
public SimpleMonthView(Context context) {
@@ -31,7 +29,7 @@ public class SimpleMonthView extends MonthView {
public void drawMonthDay(Canvas canvas, int year, int month, int day,
int x, int y, int startX, int stopX, int startY, int stopY) {
if (mSelectedDay == day) {
- canvas.drawCircle(x , y - (MINI_DAY_NUMBER_TEXT_SIZE / 3), DAY_SELECTED_CIRCLE_SIZE,
+ canvas.drawCircle(x , y - (mMiniDayNumberTextSize / 3), mDaySelectedCircleSize,
mSelectedCirclePaint);
}