Android Open Source - Langleo Number Picker






From Project

Back to project page Langleo.

License

The source code is released under:

Apache License

If you think the Android project Langleo listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/*
 * Copyright (C) 2008 The Android Open Source Project
 */*from   w w w . ja v a 2s  . c om*/
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.atteo.langleo_trial.views;

import android.content.Context;
import android.os.Handler;
import android.text.InputFilter;
import android.text.InputType;
import android.text.Spanned;
import android.text.method.NumberKeyListener;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnFocusChangeListener;
import android.view.View.OnLongClickListener;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.atteo.langleo_trial.R;

public class NumberPicker extends LinearLayout implements OnClickListener,
    OnFocusChangeListener, OnLongClickListener {

  public interface OnChangedListener {
    void onChanged(NumberPicker picker, int oldVal, int newVal);
  }

  public interface Formatter {
    String toString(int value);
  }

  /*
   * Use a custom NumberPicker formatting callback to use two-digit minutes
   * strings like "01". Keeping a static formatter etc. is the most efficient
   * way to do this; it avoids creating temporary objects on every call to
   * format().
   */
  public static final NumberPicker.Formatter TWO_DIGIT_FORMATTER = new NumberPicker.Formatter() {
    final StringBuilder mBuilder = new StringBuilder();
    final java.util.Formatter mFmt = new java.util.Formatter(mBuilder);
    final Object[] mArgs = new Object[1];

    public String toString(int value) {
      mArgs[0] = value;
      mBuilder.delete(0, mBuilder.length());
      mFmt.format("%02d", mArgs);
      return mFmt.toString();
    }
  };

  private final Handler mHandler;
  private final Runnable mRunnable = new Runnable() {
    public void run() {
      if (mIncrement) {
        changeCurrent(mCurrent + 1);
        mHandler.postDelayed(this, mSpeed);
      } else if (mDecrement) {
        changeCurrent(mCurrent - 1);
        mHandler.postDelayed(this, mSpeed);
      }
    }
  };

  private final EditText mText;
  private final InputFilter mNumberInputFilter;

  private String[] mDisplayedValues;
  private int mStart;
  private int mEnd;
  private int mCurrent;
  private int mPrevious;
  private OnChangedListener mListener;
  private Formatter mFormatter;
  private long mSpeed = 300;

  private boolean mIncrement;
  private boolean mDecrement;

  public NumberPicker(Context context) {
    this(context, null);
  }

  public NumberPicker(Context context, AttributeSet attrs) {
    this(context, attrs, 0);
  }

  public NumberPicker(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs);
    setOrientation(VERTICAL);
    LayoutInflater inflater = (LayoutInflater) context
        .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    inflater.inflate(R.layout.number_picker, this, true);
    mHandler = new Handler();
    InputFilter inputFilter = new NumberPickerInputFilter();
    mNumberInputFilter = new NumberRangeKeyListener();
    mIncrementButton = (NumberPickerButton) findViewById(R.id.increment);
    mIncrementButton.setOnClickListener(this);
    mIncrementButton.setOnLongClickListener(this);
    mIncrementButton.setNumberPicker(this);
    mDecrementButton = (NumberPickerButton) findViewById(R.id.decrement);
    mDecrementButton.setOnClickListener(this);
    mDecrementButton.setOnLongClickListener(this);
    mDecrementButton.setNumberPicker(this);

    mText = (EditText) findViewById(R.id.timepicker_input);
    mText.setOnFocusChangeListener(this);
    mText.setFilters(new InputFilter[] { inputFilter });
    mText.setRawInputType(InputType.TYPE_CLASS_NUMBER);

    if (!isEnabled()) {
      setEnabled(false);
    }
  }

  @Override
  public void setEnabled(boolean enabled) {
    super.setEnabled(enabled);
    mIncrementButton.setEnabled(enabled);
    mDecrementButton.setEnabled(enabled);
    mText.setEnabled(enabled);
  }

  public void setOnChangeListener(OnChangedListener listener) {
    mListener = listener;
  }

  public void setFormatter(Formatter formatter) {
    mFormatter = formatter;
  }

  /**
   * Set the range of numbers allowed for the number picker. The current value
   * will be automatically set to the start.
   * 
   * @param start
   *            the start of the range (inclusive)
   * @param end
   *            the end of the range (inclusive)
   */
  public void setRange(int start, int end) {
    mStart = start;
    mEnd = end;
    mCurrent = start;
    updateView();
  }

  /**
   * Set the range of numbers allowed for the number picker. The current value
   * will be automatically set to the start. Also provide a mapping for values
   * used to display to the user.
   * 
   * @param start
   *            the start of the range (inclusive)
   * @param end
   *            the end of the range (inclusive)
   * @param displayedValues
   *            the values displayed to the user.
   */
  public void setRange(int start, int end, String[] displayedValues) {
    mDisplayedValues = displayedValues;
    mStart = start;
    mEnd = end;
    mCurrent = start;
    updateView();
  }

  public void setCurrent(int current) {
    mCurrent = current;
    updateView();
  }

  /**
   * The speed (in milliseconds) at which the numbers will scroll when the the
   * +/- buttons are longpressed. Default is 300ms.
   */
  public void setSpeed(long speed) {
    mSpeed = speed;
  }

  public void onClick(View v) {
    validateInput(mText);
    if (!mText.hasFocus())
      mText.requestFocus();

    // now perform the increment/decrement
    if (R.id.increment == v.getId()) {
      changeCurrent(mCurrent + 1);
    } else if (R.id.decrement == v.getId()) {
      changeCurrent(mCurrent - 1);
    }
  }

  private String formatNumber(int value) {
    return (mFormatter != null) ? mFormatter.toString(value) : String
        .valueOf(value);
  }

  private void changeCurrent(int current) {

    // Wrap around the values if we go past the start or end
    if (current > mEnd) {
      current = mStart;
    } else if (current < mStart) {
      current = mEnd;
    }
    mPrevious = mCurrent;
    mCurrent = current;
    notifyChange();
    updateView();
  }

  private void notifyChange() {
    if (mListener != null) {
      mListener.onChanged(this, mPrevious, mCurrent);
    }
  }

  private void updateView() {

    /*
     * If we don't have displayed values then use the current number else
     * find the correct value in the displayed values for the current
     * number.
     */
    if (mDisplayedValues == null) {
      mText.setText(formatNumber(mCurrent));
    } else {
      mText.setText(mDisplayedValues[mCurrent - mStart]);
    }
    mText.setSelection(mText.getText().length());
  }

  private void validateCurrentView(CharSequence str) {
    int val = getSelectedPos(str.toString());
    if ((val >= mStart) && (val <= mEnd)) {
      mPrevious = mCurrent;
      mCurrent = val;
      notifyChange();
    }
    updateView();
  }

  public void onFocusChange(View v, boolean hasFocus) {

    /*
     * When focus is lost check that the text field has valid values.
     */
    if (!hasFocus) {
      validateInput(v);
    }
  }

  private void validateInput(View v) {
    String str = String.valueOf(((TextView) v).getText());
    if ("".equals(str)) {

      // Restore to the old value as we don't allow empty values
      updateView();
    } else {

      // Check the new value and ensure it's in range
      validateCurrentView(str);
    }
  }

  /**
   * We start the long click here but rely on the {@link NumberPickerButton}
   * to inform us when the long click has ended.
   */
  public boolean onLongClick(View v) {

    /*
     * The text view may still have focus so clear it's focus which will
     * trigger the on focus changed and any typed values to be pulled.
     */
    mText.clearFocus();

    if (R.id.increment == v.getId()) {
      mIncrement = true;
      mHandler.post(mRunnable);
    } else if (R.id.decrement == v.getId()) {
      mDecrement = true;
      mHandler.post(mRunnable);
    }
    return true;
  }

  public void cancelIncrement() {
    mIncrement = false;
  }

  public void cancelDecrement() {
    mDecrement = false;
  }

  private static final char[] DIGIT_CHARACTERS = new char[] { '0', '1', '2',
      '3', '4', '5', '6', '7', '8', '9' };

  private NumberPickerButton mIncrementButton;
  private NumberPickerButton mDecrementButton;

  private class NumberPickerInputFilter implements InputFilter {
    public CharSequence filter(CharSequence source, int start, int end,
        Spanned dest, int dstart, int dend) {
      if (mDisplayedValues == null) {
        return mNumberInputFilter.filter(source, start, end, dest,
            dstart, dend);
      }
      CharSequence filtered = String.valueOf(source.subSequence(start,
          end));
      String result = String.valueOf(dest.subSequence(0, dstart))
          + filtered + dest.subSequence(dend, dest.length());
      String str = String.valueOf(result).toLowerCase();
      for (String val : mDisplayedValues) {
        val = val.toLowerCase();
        if (val.startsWith(str)) {
          return filtered;
        }
      }
      return "";
    }
  }

  private class NumberRangeKeyListener extends NumberKeyListener {

    // XXX This doesn't allow for range limits when controlled by a
    // soft input method!
    public int getInputType() {
      return InputType.TYPE_CLASS_NUMBER;
    }

    @Override
    protected char[] getAcceptedChars() {
      return DIGIT_CHARACTERS;
    }

    @Override
    public CharSequence filter(CharSequence source, int start, int end,
        Spanned dest, int dstart, int dend) {

      CharSequence filtered = super.filter(source, start, end, dest,
          dstart, dend);
      if (filtered == null) {
        filtered = source.subSequence(start, end);
      }

      String result = String.valueOf(dest.subSequence(0, dstart))
          + filtered + dest.subSequence(dend, dest.length());

      if ("".equals(result)) {
        return result;
      }
      int val = getSelectedPos(result);

      /*
       * Ensure the user can't type in a value greater than the max
       * allowed. We have to allow less than min as the user might want to
       * delete some numbers and then type a new number.
       */
      if (val > mEnd) {
        return "";
      } else {
        return filtered;
      }
    }
  }

  private int getSelectedPos(String str) {
    if (mDisplayedValues == null) {
      return Integer.parseInt(str);
    } else {
      for (int i = 0; i < mDisplayedValues.length; i++) {

        /* Don't force the user to type in jan when ja will do */
        str = str.toLowerCase();
        if (mDisplayedValues[i].toLowerCase().startsWith(str)) {
          return mStart + i;
        }
      }

      /*
       * The user might have typed in a number into the month field i.e.
       * 10 instead of OCT so support that too.
       */
      try {
        return Integer.parseInt(str);
      } catch (NumberFormatException e) {

        /* Ignore as if it's not a number we don't care */
      }
    }
    return mStart;
  }

  /**
   * @return the current value.
   */
  public int getCurrent() {
    return mCurrent;
  }
}




Java Source Code List

com.atteo.langleo_trial.CollectionProgress.java
com.atteo.langleo_trial.ImportData.java
com.atteo.langleo_trial.ImportFile.java
com.atteo.langleo_trial.Langleo.java
com.atteo.langleo_trial.LearningAlgorithm.java
com.atteo.langleo_trial.TaskInfo.java
com.atteo.langleo_trial.TaskManager.java
com.atteo.langleo_trial.activities.Collections.java
com.atteo.langleo_trial.activities.Download.java
com.atteo.langleo_trial.activities.EditCollection.java
com.atteo.langleo_trial.activities.EditList.java
com.atteo.langleo_trial.activities.EditWord.java
com.atteo.langleo_trial.activities.Help.java
com.atteo.langleo_trial.activities.ImportFromFile.java
com.atteo.langleo_trial.activities.Lists.java
com.atteo.langleo_trial.activities.Main.java
com.atteo.langleo_trial.activities.Preferences.java
com.atteo.langleo_trial.activities.SelectFile.java
com.atteo.langleo_trial.activities.SelectList.java
com.atteo.langleo_trial.activities.StackDetails.java
com.atteo.langleo_trial.activities.Study.java
com.atteo.langleo_trial.activities.Updates.java
com.atteo.langleo_trial.activities.Words.java
com.atteo.langleo_trial.algorithms.Olli.java
com.atteo.langleo_trial.models.Collection.java
com.atteo.langleo_trial.models.Language.java
com.atteo.langleo_trial.models.List.java
com.atteo.langleo_trial.models.OlliAnswer.java
com.atteo.langleo_trial.models.OlliFactor.java
com.atteo.langleo_trial.models.Question.java
com.atteo.langleo_trial.models.StudyDay.java
com.atteo.langleo_trial.models.StudySession.java
com.atteo.langleo_trial.models.Word.java
com.atteo.langleo_trial.util.BetterAsyncTask.java
com.atteo.langleo_trial.util.ProgressHandler.java
com.atteo.langleo_trial.views.MainMenuButton.java
com.atteo.langleo_trial.views.NumberPickerButton.java
com.atteo.langleo_trial.views.NumberPicker.java
com.atteo.langleo_trial.views.SelectLimitDialog.java