2011-07-08 10 views
6

StateListDrawableをバックグラウンドとして使用すると、非常に奇妙なListView動作が発生します。私はthisポストへの答えに従おうとしましたが、私はstate_checked状態を動作させていませんでしたが、今ListViewが狂っています。ListView項目と状態セレクタのバックグラウンドdrawableの奇妙な動作

アイテムをクリックすると、すぐにセレクタのstate_checkedアイテムに色が変わることはありません。しかし少しでもクリックした後、多くのビューが突然state_checked背景に切り替わります。一見ランダムです。ここで

私の状態セレクタのXMLコードです:

<?xml version="1.0" encoding="utf-8"?> 
<selector 
    xmlns:android="http://schemas.android.com/apk/res/android"> 

    <item android:state_pressed="true" > 
     <shape> 
      <gradient 
       android:startColor="@color/grey" 
       android:endColor="@color/darkgrey" 
       android:angle="270" /> 
      <stroke 
       android:width="0dp" 
       android:color="@color/grey05" /> 
      <corners 
       android:radius="0dp" /> 
      <padding 
       android:left="10sp" 
       android:top="10sp" 
       android:right="10sp" 
       android:bottom="10sp" /> 
     </shape> 
    </item> 

    <item android:state_focused="true" > 
     <shape> 
      <gradient 
       android:endColor="@color/orange4" 
       android:startColor="@color/orange5" 
       android:angle="270" /> 
      <stroke 
       android:width="0dp" 
       android:color="@color/grey05" /> 
      <corners 
       android:radius="0dp" /> 
      <padding 
       android:left="10sp" 
       android:top="10sp" 
       android:right="10sp" 
       android:bottom="10sp" /> 
     </shape> 
    </item> 

    <item android:state_checked="true"> 
     <shape> 
      <gradient 
       android:endColor="@color/brown2" 
       android:startColor="@color/brown1" 
       android:angle="270" /> 
      <stroke 
       android:width="0dp" 
       android:color="@color/grey05" /> 
      <corners 
       android:radius="0dp" /> 
      <padding 
       android:left="10sp" 
       android:top="10sp" 
       android:right="10sp" 
       android:bottom="10sp" /> 
     </shape> 
    </item> 

    <item android:state_selected="true"> 
     <shape> 
      <gradient 
       android:endColor="@color/brown2" 
       android:startColor="@color/brown1" 
       android:angle="270" /> 
      <stroke 
       android:width="0dp" 
       android:color="@color/grey05" /> 
      <corners 
       android:radius="0dp" /> 
      <padding 
       android:left="10sp" 
       android:top="10sp" 
       android:right="10sp" 
       android:bottom="10sp" /> 
     </shape> 
    </item> 

    <item>   
     <shape> 
      <gradient 
       android:startColor="@color/white" 
       android:endColor="@color/white2" 
       android:angle="270" /> 
      <stroke 
       android:width="0dp" 
       android:color="@color/grey05" /> 
      <corners 
       android:radius="0dp" /> 
      <padding 
       android:left="10sp" 
       android:top="10sp" 
       android:right="10sp" 
       android:bottom="10sp" /> 
     </shape> 
    </item> 

</selector> 

そしてここでは、チェック可能に実装する私のカスタムビューのための私の.javaクラスです:

public class Entry extends LinearLayout implements Checkable { 

    public Entry(Context context) { 
     super(context, null); 

     // Inflate this view 
     LayoutInflater temp = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
     temp.inflate(R.layout.entry, this, true); 

     initViews(); 
    } 

    private static final int[] CheckedStateSet = { 
     android.R.attr.state_checked 
    }; 

    private void initViews() { 
     this.setBackgroundResource(R.drawable.listview_row); 
    } 

    public boolean isChecked() { 
     return _checked; 
    } 

    public void toggle() { 
     _checked = !_checked; 
    } 

    public void setChecked(boolean checked) { 
     _checked = checked; 
    } 

    @Override 
    protected int[] onCreateDrawableState(int extraSpace) { 
     final int[] drawableState = super.onCreateDrawableState(extraSpace + 1); 
     if (isChecked()) { 
      mergeDrawableStates(drawableState, CheckedStateSet); 
     } 
     return drawableState; 
    } 

    @Override 
    public boolean performClick() { 
     toggle(); 
     return super.performClick(); 
    } 
} 

私がしようとして数時間の周りつついてきましたそれを理解するために、残念ながら助けを求めることには容認しなければならない。誰かが上記のコードで何か間違って見えることができますListViewは、アイテム上で変な挙動を引き起こすでしょうか?必要に応じて、より多くのコードを投稿することもできます。

+0

私はあなたがView Wrapperクラス – Nitin

答えて

21

ListViewで作業する場合、常にビューがプレゼンテーションとアダプタがデータモデルであることを心に留めておくことが非常に重要です。

これは、すべての状態が、ビュー内のではなく、のアダプタにあることを意味します。

私はあなたのコードを伝えることができるものから、あなたがチェック状態を示しているビューがあり、その状態がアダプタビューではないです。つまり、ユーザーがリスト内のその項目をクリックすると、その項目を表示するために使用されているビューには、内部チェック状態が変更され、ユーザーに表示されている内容が切り替わります。

しかし、ビューはデータモデルではないため、ここで再生しているこの状態は一時的なものであり、実際にクリックされたアダプターアイテムには関連付けられていません。

この原因の最も顕著な問題は、ビューのリサイクルにあります。 ListViewをスクロールすると、アイテムが最後までスクロールされ、新しいアイテムが下に表示されると、古いアイテムを表示するために使用されたビューが新しいアイテムを表示するために再利用されます。これは、新しい項目が表示されるたびに新しい項目ビュー階層を拡張する必要がある場合よりもはるかに効率的です。

ビューに状態があるため、このリサイクルが発生したときにビューの状態が新しいアイテムにランダムに再関連付けされます。これは、スクロールだけでなく、多くの場合に発生する可能性があります。

この問題を解決するには、アダプターにチェック状態を設定して、アダプターに現在ある状態に基づいてビューのチェック状態を設定するように実装します(Adapter.getView())。これにより、ビューがリサイクルされるたびに(新しいデータ行をバインドするために呼び出されるgetView())、表示されている新しいデータに正しく従うようにチェック状態を更新します。

+0

ohhhhはい私は今参照してください使用する必要がありますと思う。だから今、私のアダプターは、データベースからデータを取得します(「クリックされた」列はありません)。現在チェックされているアイテムの状態をアダプタのコレクションの中に保存することをお勧めしますか?また、 'ListView.setItemChecked()'メソッドを使用すると、アダプタの項目もチェックされますか? –

+0

ListViewのチェック状態の使い方を検討してください。これは、単一選択または複数選択を行うことができます。これは、各行id(行インデックスではなく、データベース内のデータが変更された場合に変更される可能性があるため)に関連付けられている状態を追跡します。リスト項目のトップレベルビューでCheckableを実装することで、この状態を表示するには、UIをリストビューと正しく対話させる必要があります。これのサンプルはApiDemosにあります。 – hackbod

+0

おかげさまでhackbodが、私はこれが本当に私がやっていることが主な理由から、これは実際に私がさらに混乱していると思います。私のListViewのトップレベルのリストアイテムビューは、上記のコードを投稿したチェック可能なエントリクラスです。以前はperformclick()メソッドをオーバーライドすることは避けていましたが、リストビューのインスタンスでListView.setItemChecked()メソッドを使用していました。しかし、これはうまくいかず、ビューは自分のstate_checked項目の背景に変更されません(他の状態が正しく表示されているにもかかわらず)。これは別の問題ですか、それとも関連していますか? –

3

私は上記のコードから問題が発生しているとは思わない。私はこれまでにこの問題を抱えていました。リストビューのビューをリサイクルする必要がありました。あなたのリストが画面外に出ている場合は、これが当てはまるかもしれません。このような場合は、項目の状態をリストに保存して、作成したリストの状態を基にしておくことができます。ビューのリサイクルの詳細については、thisthisをご覧ください。

0

かなり複雑なListViewのセットに似たようなことをすると、アダプタに余分なリストが追加され、クリックされたアイテムの位置が追加されました。 getView(...)はビューを膨張/再利用し、終了する直前にアイテムの状態をチェックし、内部アダプタの状態によってどのバックグラウンドを適用するかを決定します。

また、現在セレクタが表示されているので、背景を透明にするように状態リストのXMLファイルを設定しています。