Is there an easy way to use a custom image for a checkbox? I'm looking to duplicate the "starred" behavior of gmail. So I want to have a checkbox that, when checked, is a filled in star. And when unchecked is an empty star. Do I have to use an imageview and do my own logic myself?
Create a drawable checkbox selector:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:drawable="#drawable/checkbox"
android:state_checked="false"/>
<item android:drawable="#drawable/checkboxselected"
android:state_checked="true"/>
<item android:drawable="#drawable/checkbox"/>
</selector>
Make sure your checkbox is like this android:button="#drawable/checkbox_selector"
<CheckBox
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:button="#drawable/checkbox_selector"
android:text="CheckBox"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textColor="#color/Black" />
Checkboxes being children of Button you can just give your checkbox a background image with several states as described here, under "Button style":
...and exemplified here:
Copy the btn_check.xml from android-sdk/platforms/android-#/data/res/drawable to your project's drawable folder and change the 'on' and 'off' image states to your custom images.
Then your xml will just need android:button="#drawable/btn_check"
<CheckBox
android:button="#drawable/btn_check"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true" />
If you want to use different default android icons, you can use android:button="#android:drawable/..."
res/drawable/day_selector.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:drawable="#drawable/dayselectionunselected"
android:state_checked="false"/>
<item android:drawable="#drawable/daysselectionselected"
android:state_checked="true"/>
<item android:drawable="#drawable/dayselectionunselected"/>
</selector>
res/layout/my_layout.xml
<CheckBox
android:id="#+id/check"
android:layout_width="39dp"
android:layout_height="39dp"
android:background="#drawable/day_selector"
android:button="#null"
android:gravity="center"
android:text="S"
android:textColor="#color/black"
android:textSize="12sp" />
If you have Android open source code, you can find the styles definition under:
src/frameworks/base/core/res/res/values
<style name="Widget.CompoundButton.CheckBox">
<item name="android:background">
#android:drawable/btn_check_label_background
</item>
<item name="android:button">
?android:attr/listChoiceIndicatorMultiple
</item>
</style>
Based on the Enselic and Rahul answers.
It works for me (before and after API 21):
<CheckBox
android:id="#+id/checkbox"
android:layout_width="40dp"
android:layout_height="40dp"
android:text=""
android:gravity="center"
android:background="#drawable/checkbox_selector"
android:button="#null"
app:buttonCompat="#null" />
Try it -
package com;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;
public class CheckBoxImageView extends ImageView implements View.OnClickListener {
boolean checked;
int defImageRes;
int checkedImageRes;
OnCheckedChangeListener onCheckedChangeListener;
public CheckBoxImageView(Context context, AttributeSet attr, int defStyle) {
super(context, attr, defStyle);
init(attr, defStyle);
}
public CheckBoxImageView(Context context, AttributeSet attr) {
super(context, attr);
init(attr, -1);
}
public CheckBoxImageView(Context context) {
super(context);
}
public boolean isChecked() {
return checked;
}
public void setChecked(boolean checked) {
this.checked = checked;
setImageResource(checked ? checkedImageRes : defImageRes);
}
private void init(AttributeSet attributeSet, int defStyle) {
TypedArray a = null;
if (defStyle != -1)
a = getContext().obtainStyledAttributes(attributeSet, R.styleable.CheckBoxImageView, defStyle, 0);
else
a = getContext().obtainStyledAttributes(attributeSet, R.styleable.CheckBoxImageView);
defImageRes = a.getResourceId(0, 0);
checkedImageRes = a.getResourceId(1, 0);
checked = a.getBoolean(2, false);
a.recycle();
setImageResource(checked ? checkedImageRes : defImageRes);
setOnClickListener(this);
}
#Override
public void onClick(View v) {
checked = !checked;
setImageResource(checked ? checkedImageRes : defImageRes);
onCheckedChangeListener.onCheckedChanged(this, checked);
}
public void setOnCheckedChangeListener(OnCheckedChangeListener onCheckedChangeListener) {
this.onCheckedChangeListener = onCheckedChangeListener;
}
public static interface OnCheckedChangeListener {
void onCheckedChanged(View buttonView, boolean isChecked);
}
}
Add this attrib -
<declare-styleable name="CheckBoxImageView">
<attr name="default_img" format="integer"/>
<attr name="checked_img" format="integer"/>
<attr name="checked" format="boolean"/>
</declare-styleable>
Use like -
<com.adonta.ziva.consumer.wrapper.CheckBoxImageView
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/checkBox"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:clickable="true"
android:padding="5dp"
app:checked_img="#drawable/check_box_checked"
app:default_img="#drawable/check_box" />
It will fix all your porblems.
Another option is to use a ToggleButton with null background and a custom button.
Bellow an example that includes a selector to the text color as well.
<ToggleButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:button="#drawable/toggle_selector"
android:background="#null"
android:paddingLeft="10dp"
android:layout_centerHorizontal="true"
android:gravity="center"
android:textColor="#drawable/toggle_text"
android:textOn="My on state"
android:textOff="My off state" />
toggle_selector.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:state_checked="true"
android:drawable="#drawable/state_on" />
<item
android:drawable="#drawable/state_off" />
</selector>
toggle_text.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:state_checked="true"
android:color="#color/app_color" />
<item
android:color="#android:color/darker_gray" />
</selector>
If you are using custom adapters than android:focusable="false" and android:focusableInTouchMode="false" are nessesury to make list items clickable while using checkbox.
<CheckBox
android:id="#+id/checkbox_fav"
android:focusable="false"
android:focusableInTouchMode="false"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:button="#drawable/checkbox_layout"/>
In drawable>checkbox_layout.xml
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:drawable="#drawable/uncked_checkbox"
android:state_checked="false"/>
<item android:drawable="#drawable/selected_checkbox"
android:state_checked="true"/>
<item android:drawable="#drawable/uncked_checkbox"/>
</selector>
If you use androidx.appcompat:appcompat and want a custom drawable (of type selector with android:state_checked) to work on old platform versions in addition to new platform versions, you need to use
<CheckBox
app:buttonCompat="#drawable/..."
instead of
<CheckBox
android:button="#drawable/..."
Adding custom drawable in the android:button did not work for me in Material Checkbox version-1.3.0 . I had to set android:drawable="#drawable/checkbox_selector" instead and also set android:button="#null" . You can also add android:drawablePadding to make it look good. However, this makes the entire checkbox clickable (along with the text).
Related
Use Selector as view's background, like following codes :
my_selector.xml:
<?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/cell_bg_e" />
<item android:state_checked="true" android:drawable="#drawable/cell_bg_e" />
<item android:state_selected="true" android:drawable="#drawable/cell_bg_e" />
<item android:drawable="#drawable/cell_bg_n_trans" />
</selector>
MyView.java
public class MyView extends LinearLayout
{
public MyView(Context context, CharSequence text, Drawable drawable) {
super(context);
setBackgroundResource(R.drawable.my_selector);
}
}
it works on all the devices except for some certain 800x480 resolution device(lick htc g12)
why ?
You should ensure the view you have set this selector drawable as a background of is clickable.
You can do this in code:
public MyView(Context context, CharSequence text, Drawable drawable) {
super(context);
setClickable(true);
setBackgroundResource(R.drawable.my_selector);
}
Alternatively in XML:
<MyView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/my_selector"
android:clickable="true"
android:orientation="horizontal"/>
If I change the background color of my EditText using the below code, it looks like the box is shrunken and it doesn't maintain the ICS theme of a blue bottom border that exists for a default EditText.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#99000000"
>
<EditText
android:id="#+id/id_nick_name"
android:layout_marginTop="80dip"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#ffffff"
/>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dip"
android:layout_marginLeft="20dip"
android:layout_marginRight="20dip"
android:orientation="horizontal"
android:layout_below="#+id/id_nick_name">
<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="add"
android:layout_weight="1"
/>
<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="cancel"
android:layout_weight="1"
/>
</LinearLayout>
</RelativeLayout>
Here is what it looks like:
one line of lazy code:
mEditText.getBackground().setColorFilter(Color.RED, PorterDuff.Mode.SRC_ATOP);
Here the best way
First : make new xml file in res/drawable name it rounded_edit_text then paste this:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" android:padding="10dp">
<solid android:color="#F9966B" />
<corners
android:bottomRightRadius="15dp"
android:bottomLeftRadius="15dp"
android:topLeftRadius="15dp"
android:topRightRadius="15dp" />
</shape>
Second: in res/layout copy and past following code (code of EditText)
<EditText
android:id="#+id/txtdoctor"
android:layout_width="match_parent"
android:layout_height="30dp"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:background="#drawable/rounded_edit_text"
android:ems="10" >
<requestFocus />
</EditText>
I create color.xml file, for naming my color name (black, white...)
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="white">#ffffff</color>
<color name="black">#000000</color>
</resources>
And in your EditText, set color
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="asdsadasdasd"
android:textColor="#color/black"
android:background="#color/white"
/>
or use style
in you style.xml:
<style name="EditTextStyleWhite" parent="android:style/Widget.EditText">
<item name="android:textColor">#color/black</item>
<item name="android:background">#color/white</item>
</style>
and add ctreated style to EditText:
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="asdsadasdasd"
style="#style/EditTextStyleWhite"
/>
What you should do is to create a 9 patch image for edittext and set that image as edit text background. You can create 9 patches using this website
I am attaching a sample 9 patch image for your reference.Use it as edittext background and you will get an idea.Right click the image and select "save image as". When you save the image dont forget to give its extension as "9.png"
The color you are using is white "#ffffff" is white so try a different one change in the values if you want until you get your need from this link Color Codes
and it should go fine
The simplest solution I have found is to change the background color programmatically. This does not require dealing with any 9-patch images:
((EditText) findViewById(R.id.id_nick_name)).getBackground()
.setColorFilter(Color.<your-desired-color>, PorterDuff.Mode.MULTIPLY);
Source: another answer
You should use style instead of background color. Try searching holoeverywhere then I think this one will help you solve your problem
Using holoeverywhere
just change some of the 9patch resources to customize the edittext look and feel.
For me this code it work
So put this code in XML file rounded_edit_text
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item>
<shape
android:shape="rectangle">
<stroke android:width="1dp" android:color="#3498db" />
<solid android:color="#00FFFFFF" />
<padding
android:left="5dp"
android:top="5dp"
android:right="5dp"
android:bottom="5dp" >
</padding>
</shape>
</item>
</layer-list>
I worked out a working solution to this problem after 2 days of struggle, below solution is perfect for them who want to change few edit text only, change/toggle color through java code, and want to overcome the problems of different behavior on OS versions due to use setColorFilter() method.
import android.content.Context;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.support.v4.content.ContextCompat;
import android.support.v7.widget.AppCompatDrawableManager;
import android.support.v7.widget.AppCompatEditText;
import android.util.AttributeSet;
import com.newco.cooltv.R;
public class RqubeErrorEditText extends AppCompatEditText {
private int errorUnderlineColor;
private boolean isErrorStateEnabled;
private boolean mHasReconstructedEditTextBackground;
public RqubeErrorEditText(Context context) {
super(context);
initColors();
}
public RqubeErrorEditText(Context context, AttributeSet attrs) {
super(context, attrs);
initColors();
}
public RqubeErrorEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initColors();
}
private void initColors() {
errorUnderlineColor = R.color.et_error_color_rule;
}
public void setErrorColor() {
ensureBackgroundDrawableStateWorkaround();
getBackground().setColorFilter(AppCompatDrawableManager.getPorterDuffColorFilter(
ContextCompat.getColor(getContext(), errorUnderlineColor), PorterDuff.Mode.SRC_IN));
}
private void ensureBackgroundDrawableStateWorkaround() {
final Drawable bg = getBackground();
if (bg == null) {
return;
}
if (!mHasReconstructedEditTextBackground) {
// This is gross. There is an issue in the platform which affects container Drawables
// where the first drawable retrieved from resources will propogate any changes
// (like color filter) to all instances from the cache. We'll try to workaround it...
final Drawable newBg = bg.getConstantState().newDrawable();
//if (bg instanceof DrawableContainer) {
// // If we have a Drawable container, we can try and set it's constant state via
// // reflection from the new Drawable
// mHasReconstructedEditTextBackground =
// DrawableUtils.setContainerConstantState(
// (DrawableContainer) bg, newBg.getConstantState());
//}
if (!mHasReconstructedEditTextBackground) {
// If we reach here then we just need to set a brand new instance of the Drawable
// as the background. This has the unfortunate side-effect of wiping out any
// user set padding, but I'd hope that use of custom padding on an EditText
// is limited.
setBackgroundDrawable(newBg);
mHasReconstructedEditTextBackground = true;
}
}
}
public boolean isErrorStateEnabled() {
return isErrorStateEnabled;
}
public void setErrorState(boolean isErrorStateEnabled) {
this.isErrorStateEnabled = isErrorStateEnabled;
if (isErrorStateEnabled) {
setErrorColor();
invalidate();
} else {
getBackground().mutate().clearColorFilter();
invalidate();
}
}
}
Uses in xml
<com.rqube.ui.widget.RqubeErrorEditText
android:id="#+id/f_signup_et_referral_code"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_toEndOf="#+id/referral_iv"
android:layout_toRightOf="#+id/referral_iv"
android:ems="10"
android:hint="#string/lbl_referral_code"
android:imeOptions="actionNext"
android:inputType="textEmailAddress"
android:textSize="#dimen/text_size_sp_16"
android:theme="#style/EditTextStyle"/>
Add lines in style
<style name="EditTextStyle" parent="android:Widget.EditText">
<item name="android:textColor">#color/txt_color_change</item>
<item name="android:textColorHint">#color/et_default_color_text</item>
<item name="colorControlNormal">#color/et_default_color_rule</item>
<item name="colorControlActivated">#color/et_engagged_color_rule</item>
</style>
java code to toggle color
myRqubeEditText.setErrorState(true);
myRqubeEditText.setErrorState(false);
This is my working solution
View view = new View(getApplicationContext());
view.setBackgroundResource(R.color.background);
myEditText.setBackground(view.getBackground());
I am using ListView and for every row I have row_item.xml and I inflate that in code
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<CheckBox
android:id="#+id/chk"
android:layout_alignParentLeft="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/txtChoice"
android:textColor="#FF0000"
android:text="TEST"
android:layout_toRightOf="#id/chk"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</RelativeLayout>
How to change that checkBox use another custom_1 image when is checked and another custom_2 image when is unchecked ?
Drawable customdrawablecheckbox.xml:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="false" android:drawable="#drawable/unchecked_drawable" />
<item android:state_checked="true" android:drawable="#drawable/checked_drawable" />
<item android:drawable="#drawable/unchecked_drawable" /> <!-- default state -->
</selector>
yourcheckbox xml:
<CheckBox
android:id="#+id/chk"
android:button="#drawable/customdrawablecheckbox"
android:layout_alignParentLeft="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
checkbox is a button, so you can provide your own drawable with check uncheck state and it as checkbox background. For instance
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="false" android:drawable="#drawable/yourdrawable1" />
<item android:state_checked="true" android:drawable="#drawable/yourdrawable2" />
<item android:drawable="#drawable/yourdrawable1" /> <!-- default -->
</selector>
and put this in a file.xml in your drawable folder. In your checkbox:
<CheckBox
android:button="#drawable/file"
android:id="#+id/chk"
android:layout_alignParentLeft="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
Its pretty easy :)
First you need to create a CustomCheckBox class which will extend CheckBox and override the onDraw(Canvas canvas) method:
public class CustomCheckBox extends CheckBox {
private final Drawable buttonDrawable;
public CustomCheckBox(Context context, AttributeSet set) {
super(context, set);
buttonDrawable = getResources().getDrawable(R.drawable.custom_check_box);
try {
setButtonDrawable(android.R.color.transparent);
} catch (Exception e) {
// DO NOTHING
}
setPadding(10, 5, 50, 5);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
buttonDrawable.setState(getDrawableState());
final int verticalGravity = getGravity() & Gravity.VERTICAL_GRAVITY_MASK;
final int height = buttonDrawable.getIntrinsicHeight();
if (buttonDrawable != null) {
int y = 0;
switch (verticalGravity) {
case Gravity.BOTTOM:
y = getHeight() - height;
break;
case Gravity.CENTER_VERTICAL:
y = (getHeight() - height) / 2;
break;
}
int buttonWidth = buttonDrawable.getIntrinsicWidth();
int buttonLeft = getWidth() - buttonWidth - 5;
buttonDrawable.setBounds(buttonLeft, y, buttonLeft + buttonWidth, y + height);
buttonDrawable.draw(canvas);
}
}
}
Also create your selector named custom_check_box in your drawable folder:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true" android:state_window_focused="false"
android:drawable="#drawable/btn_check_on" />
<item android:state_checked="false" android:state_window_focused="false"
android:drawable="#drawable/btn_check_off" />
<item android:state_checked="true" android:state_pressed="true"
android:drawable="#drawable/btn_check_on" />
<item android:state_checked="false" android:state_focused="true"
android:drawable="#drawable/btn_check_off" />
<item android:state_checked="false" android:drawable="#drawable/btn_check_off" />
<item android:state_checked="true" android:drawable="#drawable/btn_check_on" />
</selector>
And use your custom icons/imgs in the XML above for all three states (focused/pressed/default)
Use the custom component in your XML like this :
<*package + class path*.CustomCheckBox // example com.mypackage.ui.CustomCheckBox if your project is named "mypackage" and the class is in the "ui" folder
android:text="#string/text"
android:checked="false" android:layout_width="fill_parent"
android:id="#+id/myCheckbox" android:layout_height="wrap_content"/>
and java :
private CustomCheckBox mCheckbox;
mCheckbox = (CustomCheckBox) findviewbyid(R.id.myCheckbox);
It works because I used it both ways :) And with some tweaks it works for RadioButtons too the same way. Happy coding!
You can use selector in xml, which is used to change the image of checkbox dynamically according to its checked state.
For example:
<item android:drawable="#drawable/ic_linkedin" android:state_checked="true" />
<item android:drawable="#drawable/ic_linkedin_disabled" android:state_checked="false" />
In the following file, if the checkbox is checked, it will set the ic_linkedin icon and if the checkbox is unchecked, it will set the ic_linkedin_disabled icon.
I am using ListView and for every row I have row_item.xml and I inflate that in code
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<CheckBox
android:id="#+id/chk"
android:layout_alignParentLeft="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/txtChoice"
android:textColor="#FF0000"
android:text="TEST"
android:layout_toRightOf="#id/chk"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</RelativeLayout>
How to change that checkBox use another custom_1 image when is checked and another custom_2 image when is unchecked ?
Drawable customdrawablecheckbox.xml:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="false" android:drawable="#drawable/unchecked_drawable" />
<item android:state_checked="true" android:drawable="#drawable/checked_drawable" />
<item android:drawable="#drawable/unchecked_drawable" /> <!-- default state -->
</selector>
yourcheckbox xml:
<CheckBox
android:id="#+id/chk"
android:button="#drawable/customdrawablecheckbox"
android:layout_alignParentLeft="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
checkbox is a button, so you can provide your own drawable with check uncheck state and it as checkbox background. For instance
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="false" android:drawable="#drawable/yourdrawable1" />
<item android:state_checked="true" android:drawable="#drawable/yourdrawable2" />
<item android:drawable="#drawable/yourdrawable1" /> <!-- default -->
</selector>
and put this in a file.xml in your drawable folder. In your checkbox:
<CheckBox
android:button="#drawable/file"
android:id="#+id/chk"
android:layout_alignParentLeft="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
Its pretty easy :)
First you need to create a CustomCheckBox class which will extend CheckBox and override the onDraw(Canvas canvas) method:
public class CustomCheckBox extends CheckBox {
private final Drawable buttonDrawable;
public CustomCheckBox(Context context, AttributeSet set) {
super(context, set);
buttonDrawable = getResources().getDrawable(R.drawable.custom_check_box);
try {
setButtonDrawable(android.R.color.transparent);
} catch (Exception e) {
// DO NOTHING
}
setPadding(10, 5, 50, 5);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
buttonDrawable.setState(getDrawableState());
final int verticalGravity = getGravity() & Gravity.VERTICAL_GRAVITY_MASK;
final int height = buttonDrawable.getIntrinsicHeight();
if (buttonDrawable != null) {
int y = 0;
switch (verticalGravity) {
case Gravity.BOTTOM:
y = getHeight() - height;
break;
case Gravity.CENTER_VERTICAL:
y = (getHeight() - height) / 2;
break;
}
int buttonWidth = buttonDrawable.getIntrinsicWidth();
int buttonLeft = getWidth() - buttonWidth - 5;
buttonDrawable.setBounds(buttonLeft, y, buttonLeft + buttonWidth, y + height);
buttonDrawable.draw(canvas);
}
}
}
Also create your selector named custom_check_box in your drawable folder:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true" android:state_window_focused="false"
android:drawable="#drawable/btn_check_on" />
<item android:state_checked="false" android:state_window_focused="false"
android:drawable="#drawable/btn_check_off" />
<item android:state_checked="true" android:state_pressed="true"
android:drawable="#drawable/btn_check_on" />
<item android:state_checked="false" android:state_focused="true"
android:drawable="#drawable/btn_check_off" />
<item android:state_checked="false" android:drawable="#drawable/btn_check_off" />
<item android:state_checked="true" android:drawable="#drawable/btn_check_on" />
</selector>
And use your custom icons/imgs in the XML above for all three states (focused/pressed/default)
Use the custom component in your XML like this :
<*package + class path*.CustomCheckBox // example com.mypackage.ui.CustomCheckBox if your project is named "mypackage" and the class is in the "ui" folder
android:text="#string/text"
android:checked="false" android:layout_width="fill_parent"
android:id="#+id/myCheckbox" android:layout_height="wrap_content"/>
and java :
private CustomCheckBox mCheckbox;
mCheckbox = (CustomCheckBox) findviewbyid(R.id.myCheckbox);
It works because I used it both ways :) And with some tweaks it works for RadioButtons too the same way. Happy coding!
You can use selector in xml, which is used to change the image of checkbox dynamically according to its checked state.
For example:
<item android:drawable="#drawable/ic_linkedin" android:state_checked="true" />
<item android:drawable="#drawable/ic_linkedin_disabled" android:state_checked="false" />
In the following file, if the checkbox is checked, it will set the ic_linkedin icon and if the checkbox is unchecked, it will set the ic_linkedin_disabled icon.
So I have a ListView and I want to change the color of each items background and text. This ListView is inside a ListFragment. My code inflates the layout in the onCreateView and inflates the layout of each item in the newView.
The android:state_pressed="true" is working fine, whenever I press in one item the background changes to that color. But when selecting an item neither the bg color or text color changes, even though I've defined an item with android:state_selected="true" in the selector.
Edit: I'm using SDK level 11 (Android 3.0) and a Motorola Xoom.
The list fragment layout:
<?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:orientation="vertical">
<ListView
android:id="#android:id/list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
</LinearLayout>
The list item layout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="25dp"
android:background="#drawable/list_item_bg_selector">
<TextView android:id="#+id/form_title"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="#dimen/text_size_xlarge"
android:textStyle="bold"
android:textColor="#drawable/list_item_text_selector" />
<TextView android:id="#+id/form_subtitle"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="#dimen/text_size_medium"
android:textStyle="normal"
android:layout_marginTop="5dp"
android:textColor="#drawable/list_item_text_selector" />
</LinearLayout>
The background 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="#color/white" />
<item
android:state_selected="true"
android:drawable="#drawable/list_item_bg_selected" />
<item
android:drawable="#color/list_bg" />
</selector>
The text selector:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:state_selected="true"
android:drawable="#color/white" />
<item
android:drawable="#color/list_text_blue" />
</selector>
The answer is to use the android:state_activated="true" state, instead of the "selected" state. More on this here: ListFragment Item Selected Background
The best solution with support of all API levels is to implement Checkable feature for list item View which means that the top view of your list item layout has to implement Checkable interface (in my case it was TextView, but the same can be applied on ViewGroup classes like LinearLayout). When you click on a list item, the ListView call setChecked method and there we change the state of View to use android:state_checked="true" selector. Together with list view android:choiceMode="singleChoice" it will select only one item.
The trick is to override onCreateDrawableState method and set the checked state here for drawables. See example of SelectableTextView bellow. After the setChecked is called, the checked state is stored and called refreshDrawableState.
Example of SelectableTextView:
package com.example.widget.SelectableTextView;
import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.util.AttributeSet;
import android.widget.Checkable;
import android.widget.TextView;
public class SelectableTextView extends TextView implements Checkable {
private static final int[] CHECKED_STATE_SET = {
android.R.attr.state_checked
};
private boolean mChecked;
public SelectableTextView(Context context) {
super(context);
}
public SelectableTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SelectableTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public SelectableTextView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
#Override
public void setChecked(boolean checked) {
if (mChecked != checked) {
mChecked = checked;
refreshDrawableState();
}
}
#Override
public boolean isChecked() {
return mChecked;
}
#Override
public void toggle() {
setSelected(!mChecked);
}
#Override
protected int[] onCreateDrawableState(int extraSpace) {
final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
if (isChecked()) {
mergeDrawableStates(drawableState, CHECKED_STATE_SET);
}
return drawableState;
}
}
Example of selectable_list_item.xml layout:
<?xml version="1.0" encoding="utf-8"?>
<com.example.widget.SelectableTextView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#android:id/text1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textColor="#color/list_item_selector_foreground"
android:background="#drawable/list_item_selector_background"
tools:text="Item 1"/>
Example of list_item_selector_foreground.xml:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- checked -->
<item android:color="#color/list_item_text_active" android:state_checked="true"/>
<item android:color="#color/list_item_text"/>
</selector>
Example of list_item_selector_background.xml:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#color/list_item_background_selected" android:state_pressed="true"/>
<item android:drawable="#color/list_item_background_selected" android:state_focused="true"/>
<item android:drawable="#color/list_item_background_active" android:state_checked="true"/>
<item android:drawable="#color/list_item_background"/>
</selector>
Do not forget to set clickable="true" for the layout. This solved my problem.
List item layout:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/list_item_bg_selector"
android:clickable="true" >
<TextView
android:id="#+id/tvNewsPreviewTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxLines="3"
android:ellipsize="end"
android:textSize="#dimen/news_preview_title_textsize"
android:textStyle="bold" />
</RelativeLayout>
Background selector:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" >
<shape android:shape="rectangle">
<stroke android:width="1dp" android:color="#color/black" />
<gradient android:startColor="#color/white" android:endColor="#color/white" />
</shape>
</item>
<item>
<shape android:shape="rectangle">
<stroke android:width="1dp" android:color="#color/holo_gray_darker" />
<gradient android:startColor="#color/holo_gray_bright" android:endColor="#color/holo_gray_bright" />
</shape>
</item>
</selector>
#Andrew S: Along with using activated state in selector , activated state must be set to false for default case as shown in below selector code.
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="false"
android:state_activated="false"
android:color="#color/dark_text_blue"/>
<item android:state_pressed="true"
android:color="#color/red"/>
<item android:state_activated="true"
android:color="#color/red"/>
</selector>