How to get a android ListView item selector to use state_checked

前端 未结 3 974
攒了一身酷
攒了一身酷 2020-12-13 10:27

Tearing my hair out trying to get an Android ListView to do what I want.

I want to have a ListView in single choice mode with a custom row layout that has a differe

相关标签:
3条回答
  • 2020-12-13 10:34

    Better than that, instead of setting clickable=true and overriding CheckableLinearLayout's performClick(), keep Pavel's suggestion for overriding onCreateDrawableState and replace CheckableLinearLayout's setChecked() by the following:

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

    It'll avoid problems on click and long click callbacks.

    0 讨论(0)
  • 2020-12-13 10:58

    You need to override onCreateDrawableState in your CheckableRelativeLayout and set Clickable="true" for it. My code for 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 讨论(0)
  • 2020-12-13 10:59

    IMHO, it's easier to use a custom adapter:

    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>
    

    How use:

    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
                }
            });
    
        }
    
    0 讨论(0)
提交回复
热议问题