LoginSignup
18
19

More than 5 years have passed since last update.

【Android】キーボード出現時にListViewを自動スクロールさせる

Posted at

エディットテキストのフォーカス等でキーボードが出現した際に、ListViewを任意の場所(アイテム)に自動スクロールさせる方法です。

わかりづらいですが完成形はこんな感じ。

  s_qiita_2_1.png  s_qiita_2_2.png

キーボード出現を検知する

View#onSizeChangedをフックし、このメソッドが取得するViewのサイズ変更をキーボード出現とみなす方法をとります。
サイズ変更をActivityやFragmentでハンドリングできるようにするために、まずはListViewを拡張したクラスをつくります。
以下ではonSizeChangedがコールバックされたらリスナーのonKeyboadAppearedを呼び出すようにしています。

CustomListView.java

package com.example.scrollsample;

import android.content.Context;
import android.util.AttributeSet;
import android.widget.ListView;

public class CustomListView  extends ListView{

    //ActivityまたはFragmentが実装するインターフェース
    public interface OnKeyboardAppearedListener {
        public void onKeyboardAppeared(boolean isChange);
    }
    private OnKeyboardAppearedListener listener;


    public CustomListView(Context context) {
        super(context);
    }

    //このコンストラクタが無いとXMLからインフレートできないので注意
    public  CustomListView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public  CustomListView(Context context, AttributeSet attrs,
            int defStyle) {
        super(context, attrs, defStyle);
    }

    //リスナー登録のメソッド
    public void setListener(OnKeyboardAppearedListener listener) {
        this.listener = listener;
    }

    //Viewのサイズが変化した時に呼ばれるメソッド
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w,h,oldw,oldh);

        //キーボード出現時(Viewのサイズが小さくなった場合)のみ
        if(h < oldh){
            //インターフェースを実装したリスナー(Activity、Fragment)のメソッドを呼ぶ
            listener.onKeyboardAppeared(true);          
        }       
    }
}

任意の場所にスクロールさせる

ActivityやFragmentでOnKeyboardAppearedListenerをimplementsし、onKeyboardAppearedメソッドをオーバーライドすれば、キーボード出現(Viewのサイズ変更)をハンドリングできます。

スクロールにはListView#smoothScrollToPositionを使っています。
Viewのサイズ変更が完了しきってないと上手く動作しないので、Handler#postDelayedを使ってタイミングを遅らせています。(もっと良い方法があれば是非。。)
なお、スクロールアニメーションが要らない場合は、ListView#setSelectionでOKです。

smoothScrollToPositionの引数にはposition(アイテム番号)を指定するので、ここではアイテム総数から1を引いた番号、つまり一番最後のアイテムまでスクロールさせています。

main.fragment

public class MainFragment extends Fragment implements OnKeyboardAppearedListener{

    private CustomListView listView;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        View view = inflater.inflate(R.layout.fragment_main, container, false);

        //CustomListView
        listView = (CustomListView) view.findViewById(R.id.listView);
        //リスナー登録
        listView.setListener(this);

        //ダミーのitemをCustomListViewにセット
        String[] memnuStrings = { "item0","item1","item2","item3","item4","item5","item6","item7","item8","item9","item10","item11","item12", "item13","item14","item15","item16","item17","item18","item19","item20"};
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, memnuStrings);
        listView.setAdapter(adapter);

        return view;
    }

    @Override
    public void onKeyboardAppeared(boolean isChange) {

        //ListView生成済、且つサイズ変更した(キーボードが出現した)場合
        if(isChange){

            //リストアイテムの総数-1(0番目から始まって最後のアイテム)にスクロールさせる           
            Handler handler = new Handler();
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    //リストアイテムの総数-1(0番目から始まって最後のアイテム)にフォーカスさせる
                    listView.smoothScrollToPosition(listView.getCount()-1);
                }
            };
            handler.postDelayed(runnable, 500);

            //スクロールアニメーションが要らない場合はこれでOK
            //listView.setSelection(listView.getCount()-1);
        }
    }   
}

レイアウト定義

ちなみにCustomListViewはレイアウトのxmlファイルで組み込んでます。

fragment_main
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <!-- カスタムリストビュー -->
    <com.example.scrollsample.CustomListView
        android:id="@+id/listView"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:scrollingCache="false" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#CCC"
        android:orientation="horizontal"
        android:padding="6dp" >

        <EditText
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:background="#FFF"
            android:focusableInTouchMode="true"
            android:inputType="textMultiLine"
            android:maxLength="200"
            android:padding="6dp"
            android:textSize="18sp" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="6dp"
            android:text="Button"
            android:textSize="12sp" />
    </LinearLayout>

</LinearLayout>

おわりに

正直使いどころが微妙ですが、チャットUIや入力フォームがある設定画面をListViewで作りたい場合とかにつかえる、、、かも?

18
19
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
18
19