Help us understand the problem. What is going on with this article?

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

More than 1 year has passed since last update.

はじめに

最近、案件で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

yoshiki-0428
心理的安全性を求めるフリーランスエンジニア。SI企業1年、Webベンチャー企業を2年間上流から下流のリードエンジニアを経て独立。主にJavaの記事、たまにネイティブアプリの記事も書きます。気軽にいいねよろしくお願いします。
https://yoshikiohashi.dev
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away