2010-09-18 57 views
22

我的頭髮試圖讓Android ListView做我想做的事。如何讓Android ListView項目選擇器使用state_checked

我想在單選模式下使用一個自定義行佈局,它具有用於選定,按下和檢查的不同背景顏色的ListView(即,選擇由顏色而不是複選標記顯示 - 這是我通常會稱爲「選擇」,但在android中的選擇似乎線我要選擇之前,我按它)

我想嘗試一個背景選擇器與三個國家在它。它適用於state_selected和state_pressed,但不是state_checked。所以我創建了一個CheckableRelativeLayout,它擴展了RelativeLayout並實現了Checkable並用於每行的視圖。

的簡化版本如下所示:

<my.package.CheckableRelativeLayout 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:background="@drawable/bkg_selector"> 
    > 

    <ImageView android:id="@+id/animage" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_alignParentLeft="true" 
    /> 
</my.package.CheckableRelativeLayout> 

bkg_selector看起來像

<?xml version="1.0" encoding="utf-8"?> 
<selector xmlns:android="http://schemas.android.com/apk/res/android"> 
    <item android:state_pressed="true" android:drawable="@drawable/purple" /> 
    <item android:state_checked="true" android:drawable="@drawable/red" /> 
    <item android:state_selected="true" android:drawable="@drawable/darkpurple" /> 
    <item android:drawable="@drawable/black" /> 
</selector> 

顏色是別處定義。

這仍然沒有工作。因此,在自定義ListAdapter中,我跟蹤了「checked」行並嘗試了(在getView中)

if(position == checkedPosition) ret.getBackground()。setState(CHECKED_STATE_SET);

它仍然不起作用。我怎樣才能做到我想要的?

回答

45

您需要在CheckableRelativeLayout中重寫onCreateDrawableState,併爲其設置Clickable =「true」。 我對的LinearLayout代碼:

public class CheckableLinearLayout extends LinearLayout implements Checkable { 
private boolean checked = false; 

public CheckableLinearLayout(Context context) { 
    super(context, null); 
} 

public CheckableLinearLayout(Context context, AttributeSet attrs) { 
    super(context, attrs);  
} 

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

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

public boolean isChecked() { 
    return checked; 
} 

public void toggle() { 
    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(); 
} 
+0

謝謝 - 我會盡力了這一點,看看它是否有效(挖掘出我的代碼以適應它!) – MrPurpleStreak 2011-02-13 18:32:08

+1

如果可以的話,我會加倍努力! – Gallal 2012-02-22 00:08:58

+2

比那還好,而不是設置點擊= TRUE,並覆蓋CheckableLinearLayout的performClick(),覆蓋此: @覆蓋 \t公共無效setChecked(布爾檢查){ \t \t mChecked =檢查; (Checkable c:mCheckableViews){ \t \t \t c。setChecked(選中); \t \t} \t \t refreshDrawableState(); \t} – 2012-05-24 19:03:13

10

比那還好,而不是設置點擊= TRUE,並覆蓋CheckableLinearLayout的performClick(),保持帕維爾的建議,對覆蓋onCreateDrawableState並通過以下替換CheckableLinearLayout的setChecked():

private final List<Checkable> mCheckableViews = new ArrayList<Checkable>(); 

@Override 
protected void onFinishInflate() { 
    super.onFinishInflate(); 
    final int childCount = getChildCount(); 
    findCheckableChildren(this); 
} 

private void findCheckableChildren(View v) { 
    if (v instanceof Checkable && v instanceof ViewGroup) { 
     mCheckableViews.add((Checkable) v); 
    } 
    if (v instanceof ViewGroup) { 
     final ViewGroup vg = (ViewGroup) v; 
     final int childCount = vg.getChildCount(); 
     for (int i = 0; i < childCount; ++i) { 
      findCheckableChildren(vg.getChildAt(i)); 
     } 
    } 
} 

    @Override 
    public void setChecked(boolean checked) { 
     mChecked = checked; 
     for (Checkable c : mCheckableViews) { 
      c.setChecked(checked); 
     } 
     refreshDrawableState(); 
    } 

它可以避免點擊和長按回調的問題。

+0

完美.. :)謝謝.. – 2012-05-28 22:46:53

+1

你從哪裏得到mCheckableViews? – 2012-11-29 05:36:34

+0

我更新了我的答案。 – 2012-11-30 12:45:38

0

恕我直言,它更容易使用自定義適配器:

class CustomAdapter extends ArrayAdapter<CustomRowItem> { 
    Context context; 

    public CustomAdapter(Context context, int resourceId, List<CustomRowItem> items) { 
     super(context, resourceId, items); 
     this.context = context; 
    } 

    private class ViewHolder { 
     TextView txt; 
     View layout; 
    } 

    public View getView(int position, View convertView, ViewGroup parent) { 
     ViewHolder holder = null; 
     CustomRowItem rowItem = getItem(position); 

     LayoutInflater mInflater = (LayoutInflater) context 
      .getSystemService(Activity.LAYOUT_INFLATER_SERVICE); 
     if (convertView == null) { 
      convertView = mInflater.inflate(R.layout.сustom_list, null); 
      holder = new ViewHolder(); 
      holder.txt = (TextView) convertView.findViewById(R.id.сustom_list_txt); 
      holder.layout = convertView.findViewById(R.id.сustom_list_layout); 
      convertView.setTag(holder); 
     } else 
      holder = (ViewHolder) convertView.getTag(); 

     holder.txt.setText(rowItem.getText()); 
     if(rowItem.isChecked()) 
      holder.layout.setBackgroundColor(-16720999); //color for checked 
     else 
      holder.layout.setBackgroundColor(0); //color for unchecked 

     return convertView; 
    } 

} 

class CustomRowItem { 
    private boolean value; 
    private String text; 

    public CustomRowItem(String text, boolean value) { 
     this.text = text; 
     this.value = value; 
    } 
    public boolean isChecked() { 
     return value; 
    } 
    public void setChecked(boolean checked) { 
     value = checked; 
    } 
    public String getText() { 
     return text; 
    } 
    void setText(String text) { 
     this.text = text; 
    } 
} 

сustom_list.xml:

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent" 
    android:padding="10dp" 
    android:id="@+id/сustom_list_layout" 
    android:orientation="vertical" > 
    <TextView 
     android:id="@+id/сustom_list_txt"   
     android:textSize="20sp" 
     android:layout_width="fill_parent"   
     android:layout_height="fill_parent"/> 
</LinearLayout> 

如何使用:

public class ExampleAct extends Activity { 

    final List<CustomRowItem> list = new ArrayList<CustomRowItem>(); 
    CustomAdapter adapter; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.example); 

     ListView listView=(ListView)findViewById(R.id.listView); 

     adapter = new CustomAdapter(this, R.layout.сustom_list, list); 
     listView.setAdapter(adapter); 

     list.add(new CustomRowItem("unchecked item",false)); 
     list.add(new CustomRowItem("checked item",true)); 

     adapter.notifyDataSetChanged(); 

     listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { //unchecked on click 
      @Override 
      public void onItemClick(AdapterView<?> parent, View itemClicked, int index, long id) { 
       if(list.get(index).isChecked()) { 
        list.get(index).setChecked(false); //uncheck 
        adapter.notifyDataSetChanged(); 
       } else { 
        // other actions 
       } 

     }); 

     listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { //checked on long click 
      @Override 
      public boolean onItemLongClick(AdapterView<?> parent, View itemClicked, int index, long id) { 
       list.get(index).setChecked(true); //check 
       adapter.notifyDataSetChanged(); 
       return true; // or false for calling context menu 
      } 
     }); 

    }