キーリピートを実装する

Buttonクラスを拡張して、長押しされている場合クリック動作を呼び出すようにします。

RepeatButton.java
import android.content.Context;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnLongClickListener;
import android.widget.Button;

public class RepeatButton extends Button implements OnLongClickListener {

  /**
   * 連続してボタンを押す間隔(ms)
   */
  private static final int REPEAT_INTERVAL = 100;

  /**
   * 連打フラグ
   */
  private boolean isContinue = true;

  /**
   * ハンドラ
   */
  private Handler handler;

  public RepeatButton(Context context, AttributeSet attrs) {
    super(context, attrs);
    setOnLongClickListener(this);
    handler = new Handler();
  }

  @Override
  public boolean onTouchEvent(MotionEvent event) {
    super.onTouchEvent(event);

    // キーから指が離されたら連打をオフにする
    if (event.getAction() == MotionEvent.ACTION_UP) {
      isContinue = false;
    }

    return true;
  }

  @Override
  public boolean onLongClick(View v) {
    isContinue = true;

    // 長押しをきっかけに連打を開始する
    handler.post(repeatRunnable);

    return true;
  }

  Runnable repeatRunnable = new Runnable() {
    @Override
    public void run() {
      // 連打フラグをみて処理を続けるか判断する
      if (!isContinue) {
        return;
      }

      // クリック処理を実行する
      performClick();

      // 連打間隔を過ぎた後に、再び自分を呼び出す
      handler.postDelayed(this, REPEAT_INTERVAL);
    }
  };
}

使用例

こんな感じで使えばNumberPicker的に使えます

イメージ

MainActivity.java
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.TextView;

public class MainActivity extends Activity implements OnClickListener {

  private TextView txtNumber;

  private RepeatButton btnIncrement;

  private RepeatButton btnDecrement;

  private int number = 0;

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    txtNumber = (TextView)findViewById(R.id.txtNumber);
    txtNumber.setText(String.valueOf(number));
    btnIncrement = (RepeatButton)findViewById(R.id.btnIncrement);
    btnIncrement.setOnClickListener(this);
    btnDecrement = (RepeatButton)findViewById(R.id.btnDecrement);
    btnDecrement.setOnClickListener(this);
  }

  @Override
  public void onClick(View v) {
    switch (v.getId()) {
      case R.id.btnIncrement: {
        increment();
        break;
      }
      case R.id.btnDecrement: {
        decrement();
        break;
      }
    }
  }

  private void increment() {
    number++;
    txtNumber.setText(String.valueOf(number));
  }

  private void decrement() {
    number--;
    txtNumber.setText(String.valueOf(number));
  }
}
main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:gravity="center_vertical|center_horizontal"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent">
  <view
    class="jp.tomorrowkey.android.repeatpushbutton.RepeatButton"
    android:id="@+id/btnIncrement"
    android:text="Increment"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />
  <TextView
    android:id="@+id/txtNumber"
    android:text="0"
    android:textSize="32sp"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />
  <view
    class="jp.tomorrowkey.android.repeatpushbutton.RepeatButton"
    android:id="@+id/btnDecrement"
    android:text="Decrement"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />
</LinearLayout>

独自Viewの定義の仕方

独自ViewのXMLの定義の仕方は2つあります

viewタグを使う場合
<view
  class="jp.tomorrowkey.android.repeatpushbutton.RepeatButton"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content" />
クラス名でタグを書く場合
<jp.tomorrowkey.android.repeatpushbutton.RepeatButton
  android:layout_width="wrap_content"
  android:layout_height="wrap_content" />

サンプルソースではクラス名をタグに書くパターンをよく見ます。
2つの違いはというと
viewタグを使う場合ではviewのもっている属性名(android:layout_widthやandroid:idなど)を補完してくれます。
機能的に違いはないのでviewタグを使った方がコーディングは楽です。