LoginSignup
1
0

More than 5 years have passed since last update.

Spinnerの開閉タイミングをコントロールする

Posted at

はじめに

最近、案件でAndroidSpinnerクラスについてゴリゴリと実装をし、ある程度知見が溜まったのでメモ書きも含めてやりたいこととその実装例を画像+テキストベースで説明をしてみたいと思います。
(2019/02/25時点では開閉タイミングのみ)

TL;DR

  • Spinnerの開閉タイミングはSpinnerクラスをラップする必要がある。標準では不可能
  • Spinnerは思うようにコントロールしづらいので使用する際はUIなど細かい仕様にならないように調整する必要がある

Spinnerの開閉タイミングをハンドリングする

開閉タイミングをコントロールするには標準のSpinnerでは実現できません。Spinnerクラスをラップ(厳密にはAppCompatSpinnerクラス)し、以下のソースコードでオリジナルのSpinnerクラスを生成する必要があります。

使用タイミングとしては、閉じたときだけ(開いたときだけ)文字のサイズを変更したいやViewの画像部分などを非表示にしたいなどに対応できます。

ソースコード
public class CustomSpinner extends android.support.v7.widget.AppCompatSpinner {
    public CustomSpinner(Context context) {
        super(context);
    }

    public CustomSpinner(Context context, int mode) {
        super(context, mode);
    }

    public CustomSpinner(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public CustomSpinner(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public CustomSpinner(Context context, AttributeSet attrs, int defStyleAttr, int mode) {
        super(context, attrs, defStyleAttr, mode);
    }

    public CustomSpinner(Context context, AttributeSet attrs, int defStyleAttr, int mode, Resources.Theme popupTheme) {
        super(context, attrs, defStyleAttr, mode, popupTheme);
    }

    /**
     * An interface which a client of this Spinner could use to receive
     * open/closed events for this Spinner.
     */
    public interface OnSpinnerEventsListener {

        /**
         * Callback triggered when the spinner was opened.
         */
        void onSpinnerOpened(Spinner spinner);

        /**
         * Callback triggered when the spinner was closed.
         */
        void onSpinnerClosed(Spinner spinner);

    }

    private OnSpinnerEventsListener mListener;
    private boolean mOpenInitiated = false;

    // implement the Spinner constructors that you need

    @Override
    public boolean performClick() {
        // register that the Spinner was opened so we have a status
        // indicator for when the container holding this Spinner may lose focus
        mOpenInitiated = true;
        if (mListener != null) {
            mListener.onSpinnerOpened(this);
        }
        return super.performClick();
    }

    @Override
    public void onWindowFocusChanged (boolean hasFocus) {
        if (hasBeenOpened() && hasFocus) {
            performClosedEvent();
        }
    }

    /**
     * Register the listener which will listen for events.
     */
    public void setSpinnerEventsListener(OnSpinnerEventsListener onSpinnerEventsListener) {
        mListener = onSpinnerEventsListener;
    }

    /**
     * Propagate the closed Spinner event to the listener from outside if needed.
     */
    public void performClosedEvent() {
        mOpenInitiated = false;
        if (mListener != null) {
            mListener.onSpinnerClosed(this);
        }
    }

    /**
     * A boolean flag indicating that the Spinner triggered an open event.
     *
     * @return true for opened Spinner
     */
    public boolean hasBeenOpened() {
        return mOpenInitiated;
    }
}

使い方
CustomSpinner customSpinner = (CustomSpinner) findViewById(R.id.custom_spinner);
// adapterの設定は省略しています
customSpinner.setSpinnerEventsListener(new CustomSpinner.OnSpinnerEventsListener() {
    @Override
    public void onSpinnerOpened(Spinner spinner) {
        Log.v("opened!!");
    }

    @Override
    public void onSpinnerClosed(Spinner spinner) {
        Log.v("closed!!");
    }
});

注意点としては、AppCompatSpinnerクラスをラップしているので標準のSpinnerクラスのようなUIにはなりません。レイアウトにandroid:dropDownVerticalOffset="30dp"を追加するか、customSpinner.setDropDownVerticalOffset(30)を設定してドロップダウンの場所を調整する必要があります。

スクリーンショット 2019-02-25 17.27.16.png

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0