// Copyright 2015 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. package org.chromium.chrome.browser.widget; import android.animation.Animator; import android.animation.ObjectAnimator; import android.content.Context; import android.util.AttributeSet; import android.util.Property; import android.widget.FrameLayout; import android.widget.TextView; import org.chromium.chrome.R; import org.chromium.ui.interpolators.BakedBezierInterpolator; import java.text.NumberFormat; /** * View that shows an integer number. It provides a smooth roll animation on changing the * number. */ public class NumberRollView extends FrameLayout { private TextView mUpNumber; private TextView mDownNumber; private float mNumber; private Animator mLastRollAnimator; private int mContentDescriptionStringId; /** * A Property wrapper around the <code>number</code> functionality handled by the * {@link NumberRollView#setNumberRoll(float)} and {@link NumberRollView#getNumberRoll()} * methods. */ public static final Property<NumberRollView, Float> NUMBER_PROPERTY = new Property<NumberRollView, Float>(Float.class, "") { @Override public void set(NumberRollView view, Float value) { view.setNumberRoll(value); } @Override public Float get(NumberRollView view) { return view.getNumberRoll(); } }; /** * Constructor for inflating from XML. */ public NumberRollView(Context context, AttributeSet attrs) { super(context, attrs); } @Override protected void onFinishInflate() { super.onFinishInflate(); mUpNumber = (TextView) findViewById(R.id.up); mDownNumber = (TextView) findViewById(R.id.down); assert mUpNumber != null; assert mDownNumber != null; setNumberRoll(mNumber); } /** * Sets a number to display. * @param animate Whether it should smoothly animate to the number. */ public void setNumber(int number, boolean animate) { if (mLastRollAnimator != null) mLastRollAnimator.cancel(); if (animate) { Animator rollAnimator = ObjectAnimator.ofFloat(this, NUMBER_PROPERTY, number); rollAnimator.setInterpolator(BakedBezierInterpolator.TRANSFORM_CURVE); rollAnimator.start(); mLastRollAnimator = rollAnimator; } else { setNumberRoll(number); } } /** * @param pluralStringId The id of the string to use for the content description. The string * must be a plural that has one placeholder for a quantity. */ public void setContentDescriptionString(int pluralStringId) { mContentDescriptionStringId = pluralStringId; } /** * Gets the current number roll position. */ private float getNumberRoll() { return mNumber; } /** * Sets the number roll position. */ private void setNumberRoll(float number) { mNumber = number; int downNumber = (int) number; int upNumber = downNumber + 1; NumberFormat numberFormatter = NumberFormat.getIntegerInstance(); String newString = numberFormatter.format(upNumber); if (!newString.equals(mUpNumber.getText().toString())) { mUpNumber.setText(newString); if (mContentDescriptionStringId != 0) { mUpNumber.setContentDescription(getResources().getQuantityString( mContentDescriptionStringId, upNumber, upNumber)); } } newString = numberFormatter.format(downNumber); if (!newString.equals(mDownNumber.getText().toString())) { mDownNumber.setText(newString); if (mContentDescriptionStringId != 0) { mDownNumber.setContentDescription(getResources().getQuantityString( mContentDescriptionStringId, downNumber, downNumber)); } } float offset = number % 1.0f; mUpNumber.setTranslationY(mUpNumber.getHeight() * (offset - 1.0f)); mDownNumber.setTranslationY(mDownNumber.getHeight() * offset); mUpNumber.setAlpha(offset); mDownNumber.setAlpha(1.0f - offset); } }