Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Make RelativeLayout checkable

I try to write my own CheckBox using RelativeLayout with TextView and FrameLayout (with selector on background) inside.

I have setDuplicateParentStateEnabled(true) for FrameLayout that it take checkable status from parent, but why make RelativeLayout checkable I don't know.

public class MyCheckbox extends RelativeLayout implements OnClickListener, Checkable
{
private static final int ID_CHECKBOX = -1234411;
private static final int ID_TEXTVIEW = -1234412;
private static final int ID_PARENT = -1234413;

private TextView textView;
private FrameLayout checkBox;
private boolean isChecked;

public MyCheckbox(Context context)
{
    this(context, null);
}

public MyCheckbox(Context context, AttributeSet attrs)
{
    super(context, attrs);

    LayoutParams lp;

    setId(ID_PARENT);
    setOnClickListener(this);

    // checkBox
    checkBox = new FrameLayout(context);
    checkBox.setId(ID_CHECKBOX);
    checkBox.setDuplicateParentStateEnabled(true);

    // textView
    textView = new TextView(context);
    textView.setId(ID_TEXTVIEW);
    textView.setOnClickListener(this);


    boolean checkboxToRight = false;

    TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MaptrixCheckbox);

    for (int i = 0; i < a.getIndexCount(); i++)
    {
        int attr = a.getIndex(i);
        switch (attr)
        {
            case R.styleable.MyCheckbox_checkboxToRight:
                checkboxToRight = a.getBoolean(attr, false);
                break;

            case R.styleable.MyCheckbox_checkMark:
                checkBox.setBackgroundDrawable(a.getDrawable(attr));
                break;

            case R.styleable.MyCheckbox_text:
                textView.setText(a.getText(attr));
                break;
        }
    }
    a.recycle();

    if (checkboxToRight)
    {
        lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
        lp.addRule(ALIGN_PARENT_RIGHT);
        lp.addRule(CENTER_VERTICAL);
        lp.setMargins(margins, 0, margins, 0);
        addView(checkBox, lp);

        lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
        lp.addRule(CENTER_VERTICAL);
        lp.addRule(LEFT_OF, ID_CHECKBOX);
        addView(textView, lp);
    }
    else
    {
        lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
        lp.addRule(CENTER_VERTICAL);
        lp.setMargins(margins, 0, margins, 0);
        addView(checkBox, lp);

        lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
        lp.addRule(CENTER_VERTICAL);
        lp.addRule(RIGHT_OF, ID_CHECKBOX);
        addView(textView, lp);
    }

    refreshDrawableState();
}

@Override
public void onClick(View v)
{
    int id = v.getId();

    if (id == ID_PARENT || id == ID_TEXTVIEW) toggle();
}

public boolean isChecked()
{
    return isChecked;
}

public void setChecked(boolean chacked)
{
    isChecked = chacked;
    refreshDrawableState();
}

@Override
public void toggle()
{
    isChecked = !isChecked;
    refreshDrawableState();
}
}
like image 641
Nik Avatar asked Dec 04 '22 02:12

Nik


1 Answers

There seem to be two UI patterns for multi-select lists in Holo (in the context of ActionMode): using checkboxes or highlighting.

If all you need is highlighting, you can use this simpler method:

Make your list item layout use for the root a class like this one:

public class CheckableRelativeLayout extends RelativeLayout implements Checkable {
private static final int[] STATE_CHECKABLE = {R.attr.state_pressed};
boolean checked = false;

public void setChecked(boolean checked) {
    this.checked = checked;
    refreshDrawableState();
}

public boolean isChecked() {
    return checked;
}

public void toggle() {
    setChecked(!checked);
}

@Override
protected int[] onCreateDrawableState(int extraSpace) {
    int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
    if (checked) mergeDrawableStates(drawableState, STATE_CHECKABLE);

    return drawableState;
}
}

and make sure the root element in your list item layout uses

android:background="?android:attr/listChoiceBackgroundIndicator"

I know this is not really an answer to your question (you wanted an actual checkbox), but I haven't seen this documented anywhere.

The ListView uses the Checkable interface to determine whether it can rely on the list item element to display the checkable state or if it should try to display it itself.

like image 110
Pierre-Luc Paour Avatar answered Dec 31 '22 04:12

Pierre-Luc Paour