Animation between indices
This commit is contained in:
parent
98b6c44a47
commit
a76fa47768
@ -20,14 +20,19 @@ import android.content.Context;
|
|||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.widget.FrameLayout;
|
import android.view.animation.AlphaAnimation;
|
||||||
|
import android.view.animation.Animation;
|
||||||
|
import android.widget.ViewAnimator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by Phillip Hsu on 8/17/2016.
|
* Created by Phillip Hsu on 8/17/2016.
|
||||||
*
|
*
|
||||||
* A derivative of the AOSP datetimepicker RadialPickerLayout class.
|
* A derivative of the AOSP datetimepicker RadialPickerLayout class.
|
||||||
|
* The animations used here are taken from the DatePickerDialog class.
|
||||||
|
*
|
||||||
|
* A ViewAnimator is a subclass of FrameLayout.
|
||||||
*/
|
*/
|
||||||
public class GridSelectorLayout extends FrameLayout implements NumbersGrid.OnNumberSelectedListener {
|
public class GridSelectorLayout extends ViewAnimator implements NumbersGrid.OnNumberSelectedListener {
|
||||||
private static final String TAG = "GridSelectorLayout";
|
private static final String TAG = "GridSelectorLayout";
|
||||||
|
|
||||||
// Delay before auto-advancing the page, in ms.
|
// Delay before auto-advancing the page, in ms.
|
||||||
@ -35,6 +40,8 @@ public class GridSelectorLayout extends FrameLayout implements NumbersGrid.OnNum
|
|||||||
// my own logic, not ported from AOSP timepicker.
|
// my own logic, not ported from AOSP timepicker.
|
||||||
public static final int ADVANCE_PAGE_DELAY = 150;
|
public static final int ADVANCE_PAGE_DELAY = 150;
|
||||||
|
|
||||||
|
private static final int ANIMATION_DURATION = 300;
|
||||||
|
|
||||||
private static final int HOUR_INDEX = NumberGridTimePickerDialog.HOUR_INDEX;
|
private static final int HOUR_INDEX = NumberGridTimePickerDialog.HOUR_INDEX;
|
||||||
private static final int MINUTE_INDEX = NumberGridTimePickerDialog.MINUTE_INDEX;
|
private static final int MINUTE_INDEX = NumberGridTimePickerDialog.MINUTE_INDEX;
|
||||||
// TODO: Rename to HALF_DAY_INDEX?
|
// TODO: Rename to HALF_DAY_INDEX?
|
||||||
@ -54,12 +61,21 @@ public class GridSelectorLayout extends FrameLayout implements NumbersGrid.OnNum
|
|||||||
private MinutesGrid mMinutesGrid;
|
private MinutesGrid mMinutesGrid;
|
||||||
private final Handler mHandler = new Handler();
|
private final Handler mHandler = new Handler();
|
||||||
|
|
||||||
|
private final Animation mInAnimation;
|
||||||
|
private final Animation mOutAnimation;
|
||||||
|
|
||||||
public interface OnValueSelectedListener {
|
public interface OnValueSelectedListener {
|
||||||
void onValueSelected(int pickerIndex, int newValue, boolean autoAdvance);
|
void onValueSelected(int pickerIndex, int newValue, boolean autoAdvance);
|
||||||
}
|
}
|
||||||
|
|
||||||
public GridSelectorLayout(Context context, AttributeSet attrs) {
|
public GridSelectorLayout(Context context, AttributeSet attrs) {
|
||||||
super(context, attrs);
|
super(context, attrs);
|
||||||
|
// Taken from AOSP DatePickerDialog class
|
||||||
|
// TODO: They look terrible on our views. Create new animations.
|
||||||
|
mInAnimation = new AlphaAnimation(0.0f, 1.0f);
|
||||||
|
mInAnimation.setDuration(ANIMATION_DURATION);
|
||||||
|
mOutAnimation = new AlphaAnimation(1.0f, 0.0f);
|
||||||
|
mOutAnimation.setDuration(ANIMATION_DURATION);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Why do we need a Context param? RadialPickerLayout does it too.
|
// TODO: Why do we need a Context param? RadialPickerLayout does it too.
|
||||||
@ -69,6 +85,10 @@ public class GridSelectorLayout extends FrameLayout implements NumbersGrid.OnNum
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// *****************************************************************************************
|
||||||
|
// * TODO: Should we move this block to the Dialog class? This is pretty similar
|
||||||
|
// * to what AOSP's DatePickerDialog class does. I don't immediately see any
|
||||||
|
// * code that REALLY needs to be done in this class instead.
|
||||||
mIs24HourMode = is24HourMode;
|
mIs24HourMode = is24HourMode;
|
||||||
if (is24HourMode) {
|
if (is24HourMode) {
|
||||||
m24HoursGrid = new TwentyFourHoursGrid(context);
|
m24HoursGrid = new TwentyFourHoursGrid(context);
|
||||||
@ -81,6 +101,12 @@ public class GridSelectorLayout extends FrameLayout implements NumbersGrid.OnNum
|
|||||||
}
|
}
|
||||||
mMinutesGrid = new MinutesGrid(context);
|
mMinutesGrid = new MinutesGrid(context);
|
||||||
mMinutesGrid.initialize(this/*OnNumberSelectedListener*/);
|
mMinutesGrid.initialize(this/*OnNumberSelectedListener*/);
|
||||||
|
addView(mMinutesGrid);
|
||||||
|
|
||||||
|
setInAnimation(mInAnimation);
|
||||||
|
setOutAnimation(mOutAnimation);
|
||||||
|
|
||||||
|
// *****************************************************************************************
|
||||||
|
|
||||||
// Initialize the currently-selected hour and minute.
|
// Initialize the currently-selected hour and minute.
|
||||||
setValueForItem(HOUR_INDEX, initialHoursOfDay);
|
setValueForItem(HOUR_INDEX, initialHoursOfDay);
|
||||||
@ -165,11 +191,9 @@ public class GridSelectorLayout extends FrameLayout implements NumbersGrid.OnNum
|
|||||||
mCurrentItemShowing = index;
|
mCurrentItemShowing = index;
|
||||||
|
|
||||||
if (index != lastIndex) {
|
if (index != lastIndex) {
|
||||||
removeViewAt(0); // We could also call removeAllViews(), since we only have one child.
|
setInAnimation(animate? mInAnimation : null);
|
||||||
// We already verified that the index is either HOUR_INDEX or MINUTE_INDEX
|
setOutAnimation(animate? mOutAnimation : null);
|
||||||
addView(index == HOUR_INDEX ?
|
setDisplayedChild(index);
|
||||||
(mIs24HourMode ? m24HoursGrid : mHoursGrid)
|
|
||||||
: mMinutesGrid);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,6 +206,10 @@ public class GridSelectorLayout extends FrameLayout implements NumbersGrid.OnNum
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onNumberSelected(int number) {
|
public void onNumberSelected(int number) {
|
||||||
|
// Flag set to true if this onNumberSelected() event was caused by
|
||||||
|
// long clicking in a TwentyFourHoursGrid.
|
||||||
|
boolean fakeHourItemShowing = false;
|
||||||
|
|
||||||
if (getCurrentItemShowing() == HOUR_INDEX) {
|
if (getCurrentItemShowing() == HOUR_INDEX) {
|
||||||
if (!mIs24HourMode) {
|
if (!mIs24HourMode) {
|
||||||
// Change the value before passing it through the callback
|
// Change the value before passing it through the callback
|
||||||
@ -192,27 +220,32 @@ public class GridSelectorLayout extends FrameLayout implements NumbersGrid.OnNum
|
|||||||
number += 12;
|
number += 12;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Check if we would be changing half-days with the new value
|
// Check if we would be changing half-days with the new value.
|
||||||
|
// This can happen if this selection occurred with a long click.
|
||||||
if (mCurrentHoursOfDay < 12 && number >= 12 || mCurrentHoursOfDay >= 12 && number < 12) {
|
if (mCurrentHoursOfDay < 12 && number >= 12 || mCurrentHoursOfDay >= 12 && number < 12) {
|
||||||
int newHalfDay = getIsCurrentlyAmOrPm() == HALF_DAY_1 ? HALF_DAY_2 : HALF_DAY_1;
|
int newHalfDay = getIsCurrentlyAmOrPm() == HALF_DAY_1 ? HALF_DAY_2 : HALF_DAY_1;
|
||||||
|
// Update the half-day toggles states
|
||||||
mListener.onValueSelected(AMPM_INDEX, newHalfDay, false);
|
mListener.onValueSelected(AMPM_INDEX, newHalfDay, false);
|
||||||
|
// Advance the index prematurely to bypass the animation that would otherwise
|
||||||
|
// be forced on us if we let the listener autoAdvance us.
|
||||||
|
setCurrentItemShowing(MINUTE_INDEX, false/*animate?*/);
|
||||||
|
// We need to "trick" the listener to think we're still on HOUR_INDEX.
|
||||||
|
// When the listener gets the onValueSelected() callback,
|
||||||
|
// it needs to call our setCurrentItemShowing() with MINUTE_INDEX a second time,
|
||||||
|
// so it ends up doing nothing. (Recall that the new index must be different from the
|
||||||
|
// last index for setCurrentItemShowing() to actually change the current item
|
||||||
|
// showing.) This has the effect of "tricking" the listener to update its
|
||||||
|
// own states relevant to the HOUR_INDEX, without having it actually autoAdvance
|
||||||
|
// and forcing an animation on us.
|
||||||
|
fakeHourItemShowing = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// final int value = number;
|
final int currentItemShowing = fakeHourItemShowing? HOUR_INDEX : getCurrentItemShowing();
|
||||||
// mHandler.postDelayed(new Runnable() {
|
|
||||||
// @Override
|
setValueForItem(currentItemShowing, number);
|
||||||
// public void run() {
|
mListener.onValueSelected(currentItemShowing, number,
|
||||||
// mListener.onValueSelected(HOUR_INDEX, value, true);
|
|
||||||
// }
|
|
||||||
// }, ADVANCE_PAGE_DELAY);
|
|
||||||
// mListener.onValueSelected(HOUR_INDEX, value, true);
|
|
||||||
// } else {
|
|
||||||
// mListener.onValueSelected(getCurrentItemShowing(), number, false);
|
|
||||||
// }
|
|
||||||
setValueForItem(getCurrentItemShowing(), number);
|
|
||||||
mListener.onValueSelected(getCurrentItemShowing(), number,
|
|
||||||
true/*autoAdvance, not considered for MINUTE_INDEX*/);
|
true/*autoAdvance, not considered for MINUTE_INDEX*/);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user