2010-09-18 2 views
22

Вырвать мои волосы, пытаясь получить Android ListView, чтобы делать то, что я хочу.Как получить селектор элементов списка android ListView для использования state_checked

Я хочу иметь ListView в режиме одиночного выбора с настраиваемой строкой строки, которая имеет другой цвет фона для выбранных, нажатых и отмеченных (т. Е. Выбор отображается цветом, а не галочкой - это то, что я как правило, называют «выбор», но выбор в андроиде кажется строкой, которую я собираюсь выбрать до того, как я ее нажму)

Я думал о попытке выбора фона с тремя состояниями в нем. Он отлично работает для 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);

И это STILL не работает. Как я могу заставить его делать то, что я хочу?

ответ

45

Вам необходимо переопределить onCreateDrawableState в вашем CheckableRelativeLayout и установить для него 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

+1

Я бы поднял больше, если бы мог! – Gallal

+2

лучше, чем это, вместо того, чтобы интерактивными = истина и переопределение performClick CheckableLinearLayout в(), переопределить: @Override \t общественного недействительными setChecked (булево проверено) { \t \t mChecked = проверяется; \t \t для: (см. C: m Проверяемые виды) { \t \t \t c.setChecked (проверено); \t \t} \t \t refreshDrawableState(); \t} –

10

Лучше, чем это, вместо того, чтобы интерактивные = истина и переопределение performClick CheckableLinearLayout в(), держать предложение Павла для подмены onCreateDrawableState и заменить setChecked CheckableLinearLayout в() следующий:

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

perfect .. :) спасибо .. –

+1

Откуда вы получаете mCheckableViews? –

+0

Я обновил свой ответ. –

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 
      } 
     }); 

    } 
Смежные вопросы