Androidで長押し可能なカスタムViewを作る
能書き
ノリでAndroid開発を始めて二日目。
それっぽい挙動をするViewを作れたので記録しておく。
コードだけコピりたい人はこちら: Holdable button sample. · GitHub
なお、ド素人が書いたコードであると免責しておく。*1*2
.javaファイル
public class HoldableButton extends AppCompatButton {
private int delayMsec;
private int intervalMsec;
private MainTask mainTask;
private final Handler handler = new Handler();
private Runnable runnableCode;
//
//
public HoldableButton(Context context) {
this(context, null);
}
public HoldableButton(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public HoldableButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initAttrs(
context.obtainStyledAttributes(
attrs, R.styleable.HoldableButton, defStyleAttr, 0
)
);
setMainTask(() -> {});
}
private void initAttrs(TypedArray typedArray) {
delayMsec = typedArray.getInteger(
R.styleable.HoldableButton_delay_msec, 400
);
intervalMsec = typedArray.getInteger(
R.styleable.HoldableButton_interval_msec, 100
);
typedArray.recycle();
}
private void initListener() {
setOnClickListener(view -> mainTask.doTask());
//
runnableCode = () -> {
mainTask.doTask();
handler.postDelayed(runnableCode, intervalMsec);
};
setOnTouchListener(
(view, motionEvent) -> {
switch(motionEvent.getAction()) {
case MotionEvent.ACTION_DOWN:
handler.postDelayed(runnableCode, delayMsec);
break;
case MotionEvent.ACTION_UP:
handler.removeCallbacks(runnableCode);
view.performClick();
break;
default:
break;
}
return true;
}
);
}
//
public void setMainTask(MainTask mainTask) {
this.mainTask = mainTask;
initListener();
}
//
//
@FunctionalInterface
public interface MainTask {
void doTask();
}
}
果たすべきメインタスクを文字通りmainTaskとして保持している。
- タップが短いとき → mainTask.doTaskを一度だけ呼び出す。
- タップが長いとき → mainTask.doTaskをintervalMsecおきに呼び出す。
そしてタップが『長い』と判断する閾値がdelayMsecなのである。
これらのパラメータを扱いやすくするため、属性とすることにした。
.xmlファイル
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="HoldableButton">
<attr name="delay_msec" format="integer" />
<attr name="interval_msec" format="integer" />
</declare-styleable>
</resources>
正直今の段階では『なんとなく感』が強いので解説は避ける。
また、このままだとボタンが潰れて表示される。
三時間粘った末、解決策が発見できた。
You should explicitly setandroid:theme
. That theme should be derived fromWidget.AppCompat.Button
theme.
先人は偉大だ。
むすび
試行錯誤しながら、主に次のリンク先の情報を元に完成させることが出来た。
背景 View上で長押しを判定したい時、通常はGestureDetectorクラスのOnGestureListenerをimplementsしてonLongPressを実装する。 [中略] しかしonLongPressは長押し判定の時間を指定できない。