Changed ProgressBar to SeekBar
This commit is contained in:
parent
85d78e566b
commit
b03c6123e9
@ -1,5 +1,6 @@
|
|||||||
package com.philliphsu.clock2.stopwatch;
|
package com.philliphsu.clock2.stopwatch;
|
||||||
|
|
||||||
|
import android.animation.Animator;
|
||||||
import android.animation.ObjectAnimator;
|
import android.animation.ObjectAnimator;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
@ -14,7 +15,7 @@ import android.util.Log;
|
|||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.ProgressBar;
|
import android.widget.SeekBar;
|
||||||
|
|
||||||
import com.philliphsu.clock2.R;
|
import com.philliphsu.clock2.R;
|
||||||
import com.philliphsu.clock2.RecyclerViewFragment;
|
import com.philliphsu.clock2.RecyclerViewFragment;
|
||||||
@ -53,7 +54,7 @@ public class StopwatchFragment extends RecyclerViewFragment<
|
|||||||
@Bind(R.id.chronometer) ChronometerWithMillis mChronometer;
|
@Bind(R.id.chronometer) ChronometerWithMillis mChronometer;
|
||||||
@Bind(R.id.new_lap) FloatingActionButton mNewLapButton;
|
@Bind(R.id.new_lap) FloatingActionButton mNewLapButton;
|
||||||
@Bind(R.id.stop) FloatingActionButton mStopButton;
|
@Bind(R.id.stop) FloatingActionButton mStopButton;
|
||||||
@Bind(R.id.progress_bar) ProgressBar mProgressBar;
|
@Bind(R.id.seek_bar) SeekBar mSeekBar;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is called only when a new instance of this Fragment is being created,
|
* This is called only when a new instance of this Fragment is being created,
|
||||||
@ -138,7 +139,7 @@ public class StopwatchFragment extends RecyclerViewFragment<
|
|||||||
mPreviousLap = data.getItem();
|
mPreviousLap = data.getItem();
|
||||||
Log.d(TAG, "Previous lap ID = " + mPreviousLap.getId());
|
Log.d(TAG, "Previous lap ID = " + mPreviousLap.getId());
|
||||||
}
|
}
|
||||||
if (mChronometer.isRunning() && mCurrentLap != null && mPreviousLap != null) {
|
if (mCurrentLap != null && mPreviousLap != null) {
|
||||||
// We really only want to start a new animator when the NEWLY RETRIEVED current
|
// We really only want to start a new animator when the NEWLY RETRIEVED current
|
||||||
// and previous laps are different (i.e. different laps, NOT merely different instances)
|
// and previous laps are different (i.e. different laps, NOT merely different instances)
|
||||||
// from the CURRENT current and previous laps, as referenced by mCurrentLap and mPreviousLap.
|
// from the CURRENT current and previous laps, as referenced by mCurrentLap and mPreviousLap.
|
||||||
@ -150,8 +151,16 @@ public class StopwatchFragment extends RecyclerViewFragment<
|
|||||||
// have different values for, e.g., t1 and pauseTime.
|
// have different values for, e.g., t1 and pauseTime.
|
||||||
//
|
//
|
||||||
// Therefore, we'll just always end the previous animator and start a new one.
|
// Therefore, we'll just always end the previous animator and start a new one.
|
||||||
// TODO: We may as well move the contents of this method here, since we're the only caller.
|
if (mChronometer.isRunning()) {
|
||||||
startNewProgressBarAnimator();
|
startNewProgressBarAnimator();
|
||||||
|
} else {
|
||||||
|
// I verified the bar was visible already without this, so we probably don't need this,
|
||||||
|
// but it's just a safety measure..
|
||||||
|
mSeekBar.setVisibility(View.VISIBLE);
|
||||||
|
ProgressBarUtils.setProgress(mSeekBar, getCurrentLapProgressRatio());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mSeekBar.setVisibility(View.INVISIBLE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -244,8 +253,12 @@ public class StopwatchFragment extends RecyclerViewFragment<
|
|||||||
void stop() {
|
void stop() {
|
||||||
mChronometer.stop();
|
mChronometer.stop();
|
||||||
mChronometer.setBase(SystemClock.elapsedRealtime());
|
mChronometer.setBase(SystemClock.elapsedRealtime());
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
// TOneverDO: Precede these with mProgressAnimator.end(), otherwise our
|
||||||
|
// Animator.onAnimationEnd() callback won't hide SeekBar in time.
|
||||||
mStartTime = 0;
|
mStartTime = 0;
|
||||||
mPauseTime = 0;
|
mPauseTime = 0;
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
mCurrentLap = null;
|
mCurrentLap = null;
|
||||||
mPreviousLap = null;
|
mPreviousLap = null;
|
||||||
mUpdateHandler.asyncClear(); // Clear laps
|
mUpdateHandler.asyncClear(); // Clear laps
|
||||||
@ -273,17 +286,67 @@ public class StopwatchFragment extends RecyclerViewFragment<
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void startNewProgressBarAnimator() {
|
private void startNewProgressBarAnimator() {
|
||||||
|
final long timeRemaining = remainingTimeBetweenLaps();
|
||||||
|
if (timeRemaining <= 0) {
|
||||||
|
mSeekBar.setVisibility(View.INVISIBLE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (mProgressAnimator != null) {
|
if (mProgressAnimator != null) {
|
||||||
mProgressAnimator.end();
|
mProgressAnimator.end();
|
||||||
}
|
}
|
||||||
long timeRemaining = mPreviousLap.elapsed() - mCurrentLap.elapsed();
|
// This can't go in the onAnimationStart() callback because the listener is added
|
||||||
if (timeRemaining <= 0)
|
// AFTER ProgressBarUtils.startNewAnimator() starts the animation.
|
||||||
return;
|
mSeekBar.setVisibility(View.VISIBLE);
|
||||||
|
mProgressAnimator = ProgressBarUtils.startNewAnimator(
|
||||||
|
mSeekBar, getCurrentLapProgressRatio(), timeRemaining);
|
||||||
|
mProgressAnimator.addListener(mAnimatorListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Animator.AnimatorListener mAnimatorListener = new Animator.AnimatorListener() {
|
||||||
|
private boolean cancelled;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAnimationStart(Animator animation) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAnimationEnd(Animator animation) {
|
||||||
|
// Pausing the stopwatch (and the current lap) uses Animator.cancel(), which will
|
||||||
|
// not only fire onAnimationCancel(Animator), but also onAnimationEnd(Animator).
|
||||||
|
// We should only let this call through when actually Animator.end() was called,
|
||||||
|
// and that happens when we stop() the stopwatch.
|
||||||
|
// If we didn't have this check, we'd be hiding the SeekBar every time we pause
|
||||||
|
// a lap.
|
||||||
|
if (!cancelled) {
|
||||||
|
mSeekBar.setVisibility(View.INVISIBLE);
|
||||||
|
}
|
||||||
|
cancelled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAnimationCancel(Animator animation) {
|
||||||
|
cancelled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAnimationRepeat(Animator animation) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private double getCurrentLapProgressRatio() {
|
||||||
|
if (mPreviousLap == null)
|
||||||
|
return 0;
|
||||||
// The cast is necessary, or else we'd have integer division between two longs and we'd
|
// The cast is necessary, or else we'd have integer division between two longs and we'd
|
||||||
// always get zero since the numerator will always be less than the denominator.
|
// always get zero since the numerator will always be less than the denominator.
|
||||||
double ratioTimeRemaining = timeRemaining / (double) mPreviousLap.elapsed();
|
return remainingTimeBetweenLaps() / (double) mPreviousLap.elapsed();
|
||||||
mProgressAnimator = ProgressBarUtils.startNewAnimator(
|
}
|
||||||
mProgressBar, ratioTimeRemaining, timeRemaining);
|
|
||||||
|
private long remainingTimeBetweenLaps() {
|
||||||
|
if (mCurrentLap == null || mPreviousLap == null)
|
||||||
|
return 0;
|
||||||
|
return mPreviousLap.elapsed() - mCurrentLap.elapsed();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void savePrefs() {
|
private void savePrefs() {
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import android.widget.ProgressBar;
|
|||||||
* Created by Phillip Hsu on 8/10/2016.
|
* Created by Phillip Hsu on 8/10/2016.
|
||||||
*/
|
*/
|
||||||
public class ProgressBarUtils {
|
public class ProgressBarUtils {
|
||||||
private static final int MAX_PROGRESS = 100000;
|
private static final int MAX_PROGRESS = 1000000;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs and starts a new countdown ObjectAnimator with the given properties.
|
* Constructs and starts a new countdown ObjectAnimator with the given properties.
|
||||||
@ -15,9 +15,9 @@ public class ProgressBarUtils {
|
|||||||
* by {@link #MAX_PROGRESS}. A ratio of 1 means the bar is full.
|
* by {@link #MAX_PROGRESS}. A ratio of 1 means the bar is full.
|
||||||
* @return the created ObjectAnimator for holding a reference to
|
* @return the created ObjectAnimator for holding a reference to
|
||||||
*/
|
*/
|
||||||
public static ObjectAnimator startNewAnimator(final ProgressBar bar, final double ratio, final long duration) {
|
public static ObjectAnimator startNewAnimator(ProgressBar bar, double ratio, long duration) {
|
||||||
bar.setMax(MAX_PROGRESS);
|
bar.setMax(MAX_PROGRESS);
|
||||||
final int progress = (int) (MAX_PROGRESS * ratio);
|
final int progress = scaleRatio(ratio);
|
||||||
ObjectAnimator animator = ObjectAnimator.ofInt(
|
ObjectAnimator animator = ObjectAnimator.ofInt(
|
||||||
// The object that has the property we wish to animate
|
// The object that has the property we wish to animate
|
||||||
bar,
|
bar,
|
||||||
@ -45,4 +45,17 @@ public class ProgressBarUtils {
|
|||||||
animator.start();
|
animator.start();
|
||||||
return animator;
|
return animator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper around {@link ProgressBar#setProgress(int) setProgress(int)} that keeps {@code bar}'s
|
||||||
|
* max in sync with the animation's progress scale factor.
|
||||||
|
*/
|
||||||
|
public static void setProgress(ProgressBar bar, double ratio) {
|
||||||
|
bar.setMax(MAX_PROGRESS);
|
||||||
|
bar.setProgress(scaleRatio(ratio));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int scaleRatio(double ratio) {
|
||||||
|
return (int) (MAX_PROGRESS * ratio);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,20 +18,22 @@
|
|||||||
android:background="@color/colorPrimary"
|
android:background="@color/colorPrimary"
|
||||||
android:gravity="center_horizontal"
|
android:gravity="center_horizontal"
|
||||||
android:textSize="@dimen/text_size_display_3"
|
android:textSize="@dimen/text_size_display_3"
|
||||||
style="@style/TextAppearance.AppCompat.Inverse"/>
|
style="@style/TextAppearance.AppCompat.Inverse"
|
||||||
|
android:layout_marginBottom="8dp"/>
|
||||||
|
|
||||||
<!-- RecyclerView -->
|
<!-- RecyclerView -->
|
||||||
<include layout="@layout/fragment_recycler_view"/>
|
<include layout="@layout/fragment_recycler_view"/>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<ProgressBar
|
<SeekBar
|
||||||
android:id="@+id/progress_bar"
|
android:id="@+id/seek_bar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:layout_anchor="@id/chronometer"
|
app:layout_anchor="@id/chronometer"
|
||||||
app:layout_anchorGravity="bottom"
|
app:layout_anchorGravity="bottom"
|
||||||
style="@style/Widget.AppCompat.ProgressBar.Horizontal"/>
|
android:paddingStart="0dp"
|
||||||
|
android:paddingEnd="0dp"/>
|
||||||
|
|
||||||
<!-- TODO: dimen resource for height -->
|
<!-- TODO: dimen resource for height -->
|
||||||
<android.support.v7.widget.GridLayout
|
<android.support.v7.widget.GridLayout
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user