From b612bb9493d006667f767c59278f8d0925dbd9f6 Mon Sep 17 00:00:00 2001 From: Sam Blitzstein Date: Tue, 9 Apr 2013 20:34:59 -0700 Subject: Add pulsating effect to header label when switching view. Bug: 8570362 Change-Id: Ie8534f5be227605ee17d14e558f3398f9d7c6ed7 --- src/com/android/datetimepicker/Utils.java | 25 ++++++++++++++++ .../datetimepicker/time/TimePickerDialog.java | 34 +++++++++++++++++----- 2 files changed, 52 insertions(+), 7 deletions(-) (limited to 'src/com/android') diff --git a/src/com/android/datetimepicker/Utils.java b/src/com/android/datetimepicker/Utils.java index 9bc5952..ae3087b 100644 --- a/src/com/android/datetimepicker/Utils.java +++ b/src/com/android/datetimepicker/Utils.java @@ -16,8 +16,12 @@ package com.android.datetimepicker; +import android.animation.Keyframe; +import android.animation.ObjectAnimator; +import android.animation.PropertyValuesHolder; import android.os.Build; import android.text.format.Time; +import android.view.View; import java.util.Calendar; @@ -27,6 +31,7 @@ import java.util.Calendar; public class Utils { public static final int MONDAY_BEFORE_JULIAN_EPOCH = Time.EPOCH_JULIAN_DAY - 3; + public static final int PULSE_ANIMATOR_DURATION = 600; static final String SHARED_PREFS_NAME = "com.android.calendar_preferences"; @@ -92,4 +97,24 @@ public class Utils { int refDay = Time.EPOCH_JULIAN_DAY - diff; return (julianDay - refDay) / 7; } + + /** + * Render an animator to pulsate a view in place. + * @param labelToAnimate the view to pulsate. + * @return The animator object. Use .start() to begin. + */ + public static ObjectAnimator getPulseAnimator(View labelToAnimate) { + Keyframe k0 = Keyframe.ofFloat(0f, 1f); + Keyframe k1 = Keyframe.ofFloat(0.25f, 0.85f); + Keyframe k2 = Keyframe.ofFloat(0.625f, 1.1f); + Keyframe k3 = Keyframe.ofFloat(1f, 1f); + + PropertyValuesHolder scaleX = PropertyValuesHolder.ofKeyframe("scaleX", k0, k1, k2, k3); + PropertyValuesHolder scaleY = PropertyValuesHolder.ofKeyframe("scaleY", k0, k1, k2, k3); + ObjectAnimator pulseAnimator = + ObjectAnimator.ofPropertyValuesHolder(labelToAnimate, scaleX, scaleY); + pulseAnimator.setDuration(PULSE_ANIMATOR_DURATION); + + return pulseAnimator; + } } diff --git a/src/com/android/datetimepicker/time/TimePickerDialog.java b/src/com/android/datetimepicker/time/TimePickerDialog.java index 57ce93a..a5ef395 100644 --- a/src/com/android/datetimepicker/time/TimePickerDialog.java +++ b/src/com/android/datetimepicker/time/TimePickerDialog.java @@ -16,6 +16,7 @@ package com.android.datetimepicker.time; +import android.animation.ObjectAnimator; import android.annotation.SuppressLint; import android.app.ActionBar.LayoutParams; import android.app.DialogFragment; @@ -65,11 +66,16 @@ public class TimePickerDialog extends DialogFragment implements OnValueSelectedL public static final int AM = 0; public static final int PM = 1; + // Delay before starting the pulse animation, in ms. + private static final int PULSE_ANIMATOR_DELAY = 300; + private OnTimeSetListener mCallback; private TextView mDoneButton; private TextView mHourView; + private TextView mHourSpaceView; private TextView mMinuteView; + private TextView mMinuteSpaceView; private TextView mAmPmTextView; private View mAmPmHitspace; private RadialPickerLayout mTimePicker; @@ -181,6 +187,8 @@ public class TimePickerDialog extends DialogFragment implements OnValueSelectedL mHourView = (TextView) view.findViewById(R.id.hours); mHourView.setOnKeyListener(keyboardListener); + mHourSpaceView = (TextView) view.findViewById(R.id.hour_space); + mMinuteSpaceView = (TextView) view.findViewById(R.id.minutes_space); mMinuteView = (TextView) view.findViewById(R.id.minutes); mMinuteView.setOnKeyListener(keyboardListener); mAmPmTextView = (TextView) view.findViewById(R.id.ampm_label); @@ -198,20 +206,20 @@ public class TimePickerDialog extends DialogFragment implements OnValueSelectedL savedInstanceState.containsKey(KEY_CURRENT_ITEM_SHOWING)) { currentItemShowing = savedInstanceState.getInt(KEY_CURRENT_ITEM_SHOWING); } - setCurrentItemShowing(currentItemShowing, false, true); + setCurrentItemShowing(currentItemShowing, false, true, true); mTimePicker.invalidate(); mHourView.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { - setCurrentItemShowing(HOUR_INDEX, true, true); + setCurrentItemShowing(HOUR_INDEX, true, false, true); mTimePicker.tryVibrate(); } }); mMinuteView.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { - setCurrentItemShowing(MINUTE_INDEX, true, true); + setCurrentItemShowing(MINUTE_INDEX, true, false, true); mTimePicker.tryVibrate(); } }); @@ -320,7 +328,7 @@ public class TimePickerDialog extends DialogFragment implements OnValueSelectedL setHour(newValue, false); String announcement = String.format("%d", newValue); if (mAllowAutoAdvance && autoAdvance) { - setCurrentItemShowing(MINUTE_INDEX, true, false); + setCurrentItemShowing(MINUTE_INDEX, true, true, false); announcement += ". " + mSelectMinutes; } tryAccessibilityAnnounce(announcement); @@ -350,6 +358,7 @@ public class TimePickerDialog extends DialogFragment implements OnValueSelectedL CharSequence text = String.format(format, value); mHourView.setText(text); + mHourSpaceView.setText(text); if (announce) { tryAccessibilityAnnounce(text); } @@ -362,12 +371,15 @@ public class TimePickerDialog extends DialogFragment implements OnValueSelectedL CharSequence text = String.format(Locale.getDefault(), "%02d", value); tryAccessibilityAnnounce(text); mMinuteView.setText(text); + mMinuteSpaceView.setText(text); } // Show either Hours or Minutes. - private void setCurrentItemShowing(int index, boolean animate, boolean announce) { - mTimePicker.setCurrentItemShowing(index, animate); + private void setCurrentItemShowing(int index, boolean animateCircle, boolean delayLabelAnimate, + boolean announce) { + mTimePicker.setCurrentItemShowing(index, animateCircle); + TextView labelToAnimate; if (index == HOUR_INDEX) { int hours = mTimePicker.getHours(); if (!mIs24HourMode) { @@ -377,18 +389,26 @@ public class TimePickerDialog extends DialogFragment implements OnValueSelectedL if (announce) { tryAccessibilityAnnounce(mSelectHours); } + labelToAnimate = mHourView; } else { int minutes = mTimePicker.getMinutes(); mTimePicker.setContentDescription(mMinutePickerDescription+": "+minutes); if (announce) { tryAccessibilityAnnounce(mSelectMinutes); } + labelToAnimate = mMinuteView; } int hourColor = (index == HOUR_INDEX)? mBlue : mBlack; int minuteColor = (index == MINUTE_INDEX)? mBlue : mBlack; mHourView.setTextColor(hourColor); mMinuteView.setTextColor(minuteColor); + + ObjectAnimator pulseAnimator = Utils.getPulseAnimator(labelToAnimate); + if (delayLabelAnimate) { + pulseAnimator.setStartDelay(PULSE_ANIMATOR_DELAY); + } + pulseAnimator.start(); } /** @@ -581,7 +601,7 @@ public class TimePickerDialog extends DialogFragment implements OnValueSelectedL if (!mIs24HourMode) { updateAmPmDisplay(hour < 12? AM : PM); } - setCurrentItemShowing(mTimePicker.getCurrentItemShowing(), true, true); + setCurrentItemShowing(mTimePicker.getCurrentItemShowing(), true, true, true); mDoneButton.setEnabled(true); } else { Boolean[] enteredZeros = {false, false}; -- cgit v1.2.3