2012年10月18日木曜日

Android ListPopupWindow で折り返し表示させる

ListPopupWindow の1行のレイアウトに android.R.layout.simple_list_item_1 を指定すると、TextView に表示する文字列が1行の幅より長い場合に折り返さずに切れてしまいます。



android.R.layout.simple_list_item_1
<?xml version="1.0" encoding="utf-8"?> <!-- Copyright (C) 2006 The Android Open Source Project Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@android:id/text1" android:layout_width="match_parent" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceListItemSmall" android:gravity="center_vertical" android:paddingLeft="?android:attr/listPreferredItemPaddingLeft" android:paddingRight="?android:attr/listPreferredItemPaddingRight" android:minHeight="?android:attr/listPreferredItemHeightSmall" />

protected void showListPopup(View anchor) { ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, android.R.id.text1, new String[] { "test", "test2test2test2test2test2test2test2test2test2", "test3", "test4" }); ListPopupWindow popup = new ListPopupWindow(this); popup.setAdapter(adapter); popup.setAnchorView(anchor); popup.show(); }

android.R.layout.simple_dropdown_item_1line.xml のように singleLine や ellipsize を指定しているならわかりますが、そうではないのにどうしてなのか調べてみました。

android.R.layout.simple_dropdown_item_1line
<?xml version="1.0" encoding="utf-8"?> <!-- /* //device/apps/common/assets/res/any/layout/simple_spinner_item.xml ** ** Copyright 2008, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. ** You may obtain a copy of the License at ** ** http://www.apache.org/licenses/LICENSE-2.0 ** ** Unless required by applicable law or agreed to in writing, software ** distributed under the License is distributed on an "AS IS" BASIS, ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ** See the License for the specific language governing permissions and ** limitations under the License. */ --> <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@android:id/text1" style="?android:attr/dropDownItemStyle" android:textAppearance="?android:attr/textAppearanceLargePopupMenu" android:singleLine="true" android:layout_width="match_parent" android:layout_height="?android:attr/listPreferredItemHeight" android:ellipsize="marquee" />

ListPopupWindow では、内部で持っている PopupWindow に ListView ではなく、ListView を継承した DropDownListView をセットしています。
この DropDownListView で次のように obtainView() を Override して、そこで1行の View が TextView だったら setHorizontallyScrolling(true) をセットしています。

http://tools.oesf.biz/android-4.0.1_r1.0/xref/frameworks/base/core/java/android/widget/ListPopupWindow.java#1110
1110 private static class DropDownListView extends ListView { ... 1159 /** 1160 * <p>Avoids jarring scrolling effect by ensuring that list elements 1161 * made of a text view fit on a single line.</p> 1162 * 1163 * @param position the item index in the list to get a view for 1164 * @return the view for the specified item 1165 */ 1166 @Override 1167 View obtainView(int position, boolean[] isScrap) { 1168 View view = super.obtainView(position, isScrap); 1169 1170 if (view instanceof TextView) { 1171 ((TextView) view).setHorizontallyScrolling(true); 1172 } 1173 1174 return view; 1175 }

コメントに書いてありますが、「TextView を1行に固定する事でスクロール時にガタガタ動いてしまう状態を避ける」ためだそうです。

setHorizontallyScrolilng() は TextView のメソッドです。TextView の setSingleLine() 内で呼ばれる applySingleLine() から呼ばれていることからもわかるように、文字を1行にするかどうかに関わるメソッドです。

1行の View が TextView のときだけ setHorizontallyScrolilng() を呼ぶようになっているので、次のようになんらかの ViewGroup に入れてしまえば複数行で表示されます。

R.layout.row
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_vertical" android:minHeight="?android:attr/listPreferredItemHeightSmall" android:orientation="vertical" android:paddingLeft="?android:attr/listPreferredItemPaddingLeft" android:paddingRight="?android:attr/listPreferredItemPaddingRight" > <TextView android:id="@android:id/text1" android:layout_width="match_parent" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceListItemSmall" /> </LinearLayout>

protected void showListPopup(View anchor) { ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.row, android.R.id.text1, new String[] { "test", "test2test2test2test2test2test2test2test2test2", "test3", "test4" }); ListPopupWindow popup = new ListPopupWindow(this); popup.setAdapter(adapter); popup.setAnchorView(anchor); popup.show(); }







0 件のコメント:

コメントを投稿