2012年2月23日木曜日

Android DrawableState でリストアイテムの背景を変える ViewGroup を作る

アイテムを選択可能なリスト用として、 CheckedTextView を使った

android.R.layout.simple_list_item_single_choice

  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <!-- Copyright (C) 2008 The Android Open Source Project  
  3.   
  4.      Licensed under the Apache License, Version 2.0 (the "License");  
  5.      you may not use this file except in compliance with the License.  
  6.      You may obtain a copy of the License at  
  7.     
  8.           http://www.apache.org/licenses/LICENSE-2.0  
  9.     
  10.      Unless required by applicable law or agreed to in writing, software  
  11.      distributed under the License is distributed on an "AS IS" BASIS,  
  12.      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
  13.      See the License for the specific language governing permissions and  
  14.      limitations under the License.  
  15. -->  
  16.   
  17. <CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"  
  18.     android:id="@android:id/text1"  
  19.     android:layout_width="match_parent"  
  20.     android:layout_height="?android:attr/listPreferredItemHeightSmall"  
  21.     android:textAppearance="?android:attr/textAppearanceListItemSmall"  
  22.     android:gravity="center_vertical"  
  23.     android:checkMark="?android:attr/listChoiceIndicatorSingle"  
  24.     android:paddingLeft="?android:attr/listPreferredItemPaddingLeft"  
  25.     android:paddingRight="?android:attr/listPreferredItemPaddingRight"  
  26. />  




android.R.layout.simple_list_item_multiple_choice

  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <!-- Copyright (C) 2008 The Android Open Source Project  
  3.   
  4.      Licensed under the Apache License, Version 2.0 (the "License");  
  5.      you may not use this file except in compliance with the License.  
  6.      You may obtain a copy of the License at  
  7.     
  8.           http://www.apache.org/licenses/LICENSE-2.0  
  9.     
  10.      Unless required by applicable law or agreed to in writing, software  
  11.      distributed under the License is distributed on an "AS IS" BASIS,  
  12.      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
  13.      See the License for the specific language governing permissions and  
  14.      limitations under the License.  
  15. -->  
  16.   
  17. <CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"  
  18.     android:id="@android:id/text1"  
  19.     android:layout_width="match_parent"  
  20.     android:layout_height="?android:attr/listPreferredItemHeight"  
  21.     android:textAppearance="?android:attr/textAppearanceListItem"  
  22.     android:gravity="center_vertical"  
  23.     android:checkMark="?android:attr/listChoiceIndicatorMultiple"  
  24.     android:paddingLeft="8dip"  
  25.     android:paddingRight="8dip"  
  26. />  


が用意されていて

  1. public class MainActivity extends ListActivity {  
  2.   
  3.     @Override  
  4.     public void onCreate(Bundle savedInstanceState) {  
  5.         super.onCreate(savedInstanceState);  
  6.   
  7.         String[] data = { "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data",  
  8.                 "Data", "Data", "Data", "Data", };  
  9.   
  10.         ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_single_choice, android.R.id.text1, data);  
  11.         setListAdapter(adapter);  
  12.           
  13.         ListView lv = getListView();  
  14.         lv.setChoiceMode(ListView.CHOICE_MODE_SINGLE);  
  15.     }  
  16. }  


のように使うことで



のようにできます。


さて、

1行のレイアウトを複雑にしたい場合、内部に CheckBox を持ってその表示を変える方法に ついては Android Layout Cookbook に書きました。

CheckBox ではなく、単に1行の ViewGroup の背景色を変えて選択状態を変えたい場合は Checkable を implements した ViewGroup を作ります。

例えばリストの1行を LinearLayout にして、選択されたら背景を変えるようにするには、 このように LinearLayout を継承したクラスを作って Checkable を実装します。

CheckedLinearLayout.java
  1. public class CheckedLinearLayout extends LinearLayout implements Checkable {  
  2.     private boolean mChecked;  
  3.   
  4.     private static final int[] CHECKED_STATE_SET = { android.R.attr.state_checked };  
  5.   
  6.     public CheckedLinearLayout(Context context) {  
  7.         this(context, null);  
  8.     }  
  9.   
  10.     public CheckedLinearLayout(Context context, AttributeSet attrs) {  
  11.         this(context, attrs, 0);  
  12.     }  
  13.   
  14.     public CheckedLinearLayout(Context context, AttributeSet attrs, int defStyle) {  
  15.         super(context, attrs, defStyle);  
  16.     }  
  17.   
  18.     @Override  
  19.     public void toggle() {  
  20.         setChecked(!mChecked);  
  21.     }  
  22.   
  23.     @Override  
  24.     public boolean isChecked() {  
  25.         return mChecked;  
  26.     }  
  27.   
  28.     @Override  
  29.     public void setChecked(boolean checked) {  
  30.         if (mChecked != checked) {  
  31.             mChecked = checked;  
  32.             refreshDrawableState();  
  33.         }  
  34.     }  
  35.   
  36.     @Override  
  37.     protected int[] onCreateDrawableState(int extraSpace) {  
  38.         final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);  
  39.         if (isChecked()) {  
  40.             mergeDrawableStates(drawableState, CHECKED_STATE_SET);  
  41.         }  
  42.         return drawableState;  
  43.     }  
  44. }  


Checkable インタフェースのメソッドは toggle(), isChecked(), setChecked() だけなのですが、 これを実装するだけでは背景は変わってくれません。
キモは onCreateDrawableState() で、ここで super.onCreateDrawableState() で LinearLayout の drawableState を取得し、それにチェック状態の state を mergeDrawableStates() で追加したものを返す必要があります。

MainActivity.java
  1. public class MainActivity extends ListActivity {  
  2.   
  3.     @Override  
  4.     public void onCreate(Bundle savedInstanceState) {  
  5.         super.onCreate(savedInstanceState);  
  6.   
  7.         String[] data = { "Data""Data""Data""Data""Data""Data""Data""Data""Data""Data""Data",  
  8.                 "Data""Data""Data""Data", };  
  9.   
  10.         ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.list_item, android.R.id.text1, data);  
  11.         setListAdapter(adapter);  
  12.           
  13.         ListView lv = getListView();  
  14.         lv.setChoiceMode(ListView.CHOICE_MODE_SINGLE);  
  15.     }  
  16. }  


list_item.xml
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <yanzm.example.drawablestatesample.CheckedLinearLayout   
  3.     xmlns:android="http://schemas.android.com/apk/res/android"  
  4.     android:layout_width="match_parent"  
  5.     android:layout_height="wrap_content"  
  6.     android:background="@drawable/list_item_bg"  
  7.     android:gravity="center_vertical"  
  8.     android:orientation="vertical"  
  9.     android:padding="8dip" >  
  10.   
  11.     <TextView  
  12.         android:id="@android:id/text1"  
  13.         android:layout_width="wrap_content"  
  14.         android:layout_height="wrap_content"  
  15.         android:textAppearance="?android:attr/textAppearanceListItem" />  
  16.   
  17.     <TextView  
  18.         android:layout_width="wrap_content"  
  19.         android:layout_height="wrap_content"  
  20.         android:text="sub text"  
  21.         android:textAppearance="?android:attr/textAppearanceListItemSmall" />  
  22.   
  23. </yanzm.example.drawablestatesample.CheckedLinearLayout>  


list_item.bg
  1. <selector xmlns:android="http://schemas.android.com/apk/res/android">  
  2.   
  3.     <item android:state_checked="true">  
  4.         <shape>  
  5.             <solid android:color="#666666" />  
  6.         </shape></item>  
  7.     <item>  
  8.         <shape>  
  9.             <solid android:color="#00000000" />  
  10.         </shape>  
  11.     </item>  
  12.   
  13. </selector>  


こんな感じにタップした行の背景が変わるようになります。





0 件のコメント:

コメントを投稿