エディットテキストのフォーカス等でキーボードが出現した際に、ListViewを任意の場所(アイテム)に自動スクロールさせる方法です。
わかりづらいですが完成形はこんな感じ。
キーボード出現を検知する
View#onSizeChangedをフックし、このメソッドが取得するViewのサイズ変更をキーボード出現とみなす方法をとります。
サイズ変更をActivityやFragmentでハンドリングできるようにするために、まずはListViewを拡張したクラスをつくります。
以下ではonSizeChangedがコールバックされたらリスナーのonKeyboadAppearedを呼び出すようにしています。
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を引いた番号、つまり一番最後のアイテムまでスクロールさせています。
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ファイルで組み込んでます。
<?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で作りたい場合とかにつかえる、、、かも?