How to customize list preference radio button - android

I have customized all the radioButtons in my application but the radioButtons in the listPreference does not get customized.
I have used this xml named btn_radio.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true" android:state_window_focused="false"
android:drawable="#drawable/radio_selected" />
<item android:state_checked="false" android:state_window_focused="false"
android:drawable="#drawable/radio_unselected" />
<item android:state_checked="true" android:state_pressed="true"
android:drawable="#drawable/radio_selected" />
<item android:state_checked="false" android:state_pressed="true"
android:drawable="#drawable/radio_unselected" />
<item android:state_checked="true" android:state_focused="true"
android:drawable="#drawable/radio_selected" />
<item android:state_checked="false" android:state_focused="true"
android:drawable="#drawable/radio_unselected" />
<item android:state_checked="false" android:drawable="#drawable/radio_unselected" />
<item android:state_checked="true" android:drawable="#drawable/radio_selected" />
</selector>
This is the customRadioButton which extends the android custom radio button
<style name="CustomRadioButton" Parent="#android:style/Widget.CompoundButton.RadioButton">
<item name="android:button">#drawable/btn_radio</item>
</style>
in the theme of my application I have done this changes
<item name="android:radioButtonStyle">#style/CustomRadioButton</item>
<item name="android:listChoiceIndicatorSingle">#style/CustomRadioButton</item>
This changes customize all the radioButtons in my application except radioButtons in my ListPreference

Styling the ListPreference from XML is not directly possible. The problem is that ListPreference (through DialogPreference) calls AlertDialog.Builder(Context) to build its Dialog, rather than AlertDialog.Builder(Context context, int themeResourceId). While the latter allows for providing a theme, the former does not, causing it to fall back to a default Android theme.
For a project, I needed a ListPreference with a custom title-color, a custom radiobutton-style and a custom ListView-selector (basically, Holo in a different color). I solved this by extending ListPreference and overriding onPrepareDialogBuilder(Builder) and OnCreateDialogView() so I could use a custom ListView with a simple ArrayAdapter, rather than Dialog's built-in ListView (which doesn't have support for styling). I also had to override onDialogClosed() in order to set the right value to the preference.
In order to use it, all you have to do is replace the classname of the preference in your preferences.xml rom ListPreference to com.your.packagename.ThemedListPreference. Other than that, the implementation is identical to ListPreference.
public class ThemedListPreference extends ListPreference implements OnItemClickListener {
public static final String TAG = "ThemedListPreference";
private int mClickedDialogEntryIndex;
private CharSequence mDialogTitle;
public ThemedListPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ThemedListPreference(Context context) {
super(context);
}
#Override
protected View onCreateDialogView() {
// inflate custom layout with custom title & listview
View view = View.inflate(getContext(), R.layout.dialog_settings_updatetime, null);
mDialogTitle = getDialogTitle();
if(mDialogTitle == null) mDialogTitle = getTitle();
((TextView) view.findViewById(R.id.dialog_title)).setText(mDialogTitle);
ListView list = (ListView) view.findViewById(android.R.id.list);
// note the layout we're providing for the ListView entries
ArrayAdapter<CharSequence> adapter = new ArrayAdapter<CharSequence>(
getContext(), R.layout.btn_radio,
getEntries());
list.setAdapter(adapter);
list.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
list.setItemChecked(findIndexOfValue(getValue()), true);
list.setOnItemClickListener(this);
return view;
}
#Override
protected void onPrepareDialogBuilder(Builder builder) {
// adapted from ListPreference
if (getEntries() == null || getEntryValues() == null) {
// throws exception
super.onPrepareDialogBuilder(builder);
return;
}
mClickedDialogEntryIndex = findIndexOfValue(getValue());
// .setTitle(null) to prevent default (blue)
// title+divider from showing up
builder.setTitle(null);
builder.setPositiveButton(null, null);
}
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
mClickedDialogEntryIndex = position;
ThemedListPreference.this.onClick(getDialog(), DialogInterface.BUTTON_POSITIVE);
getDialog().dismiss();
}
#Override
protected void onDialogClosed(boolean positiveResult) {
// adapted from ListPreference
super.onDialogClosed(positiveResult);
if (positiveResult && mClickedDialogEntryIndex >= 0
&& getEntryValues() != null) {
String value = getEntryValues()[mClickedDialogEntryIndex]
.toString();
if (callChangeListener(value)) {
setValue(value);
}
}
}
}
For my ListView items I used the layout below. Note that drawable/btn_radio_holo_light is an XML-drawable like the one in your android-sdk/platforms/android-x/data/res/drawable folder, only with references to different drawables.
<?xml version="1.0" encoding="utf-8"?>
<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/text1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:checkMark="#drawable/btn_radio_holo_light"
android:gravity="center_vertical"
android:minHeight="#dimen/list_item_minheight"
android:paddingLeft="#dimen/list_item_paddingLeft"
android:paddingRight="#dimen/list_item_paddingLeft" />
For my Dialog layout (onCreateDialogView()), I used the following:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="#+id/dialog_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:textColor="#color/title_color"
android:textSize="22sp" />
<View
android:layout_width="match_parent"
android:layout_height="2dp"
android:background="#color/divider_color" />
<ListView
android:id="#android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:listSelector="#drawable/list_selector" />
</LinearLayout>

Please, see my answer here, maybe it helps.
It's a much easier way to solve the problem.

Related

How to make a View looks like it is being selected programmatically, if background is ?android:attr/selectableItemBackground (ListView in AlertDialog)

I pretty like the selector behavior generated in navigation drawer.
It has ripple effect.
Its ImageView and TextView has proper color, when being selected.
In my dialog, I try to achieve the same effect, by using the following layout.
label_array_adapter.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:background="?android:attr/selectableItemBackground"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal">
<ImageView
android:duplicateParentState="true"
android:id="#+id/image_view"
android:paddingStart="24dp"
android:paddingLeft="24dp"
android:paddingEnd="16dp"
android:paddingRight="16dp"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:src="?attr/labelIconSelector" />
<TextView
android:duplicateParentState="true"
android:textSize="16sp"
android:id="#+id/text_view"
android:layout_width="0dp"
android:width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:textColor="?attr/labelTextViewColorSelector" />
</LinearLayout>
labelIconSelector
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true">
<bitmap android:src="#drawable/ic_label_white_24dp"
android:tint="#color/colorPrimaryBrown" />
</item>
<item>
<bitmap android:src="#drawable/ic_label_white_24dp"
android:tint="#ff757575" />
</item>
</selector>
labelTextViewColorSelector
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true" android:color="#color/colorPrimaryBrown" />
<item android:color="#color/primaryTextColorLight" />
</selector>
In my ArrayAdapter, I try to programmatically select the 1st item via view.setSelected(true)
public class LabelArrayAdapter extends ArrayAdapter<TabInfo> {
private static class ViewHolder {
public final ImageView imageView;
public final TextView textView;
public ViewHolder(View view) {
imageView = view.findViewById(R.id.image_view);
textView = view.findViewById(R.id.text_view);
Utils.setCustomTypeFace(textView, Utils.ROBOTO_REGULAR_TYPE_FACE);
}
}
public LabelArrayAdapter(#NonNull Context context, List<TabInfo> tabInfos) {
super(context, R.layout.label_array_adapter, tabInfos);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = null;
if (convertView == null) {
LayoutInflater inflator = LayoutInflater.from(this.getContext());
view = inflator.inflate(R.layout.label_array_adapter, null);
final ViewHolder viewHolder = new ViewHolder(view);
view.setTag(viewHolder);
// Not sure why this is required.
view.setLayoutParams(new AbsListView.LayoutParams(AbsListView.LayoutParams.MATCH_PARENT, Utils.dpToPixel(48)));
} else {
view = convertView;
}
ViewHolder holder = (ViewHolder) view.getTag();
TabInfo tabInfo = getItem(position);
if (tabInfo == null) {
holder.imageView.setVisibility(View.INVISIBLE);
holder.textView.setText("(No label)");
} else {
holder.imageView.setVisibility(View.VISIBLE);
holder.textView.setText(tabInfo.getName());
}
if (position == 0) {
view.setSelected(true);
} else {
view.setSelected(false);
}
return view;
}
}
This is how I try to show Dialog via DialogFragment.
return new AlertDialog.Builder(getActivity())
.setTitle("Move to")
.setAdapter(new LabelArrayAdapter(this.getContext(), customTabInfos), (dialog, which) -> {
})
.create();
However, it doesn't work as you can see in the following screenshot. The 1st item doesn't look like it is being selected.
May I know, is there anything I had missed out?
How to make a View looks like it is being selected programmatically, if its background is ?android:attr/selectableItemBackground (ListView in AlertDialog)
Update
Using
alertDialog.getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
alertDialog.getListView().setSelection(position);
wouldn't help either.
Here is an approach using a layer list drawable as the background for the view group that represents the item being selected.
First, for API 21+, we define a layer list drawable that displays the selected color when the item is selected. A call to View#setSelected() must be made for this to have an effect.
layer_list.xml (v21)
color/selected is #2000ffe5 for the demos.
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<selector>
<item
android:drawable="#color/selected"
android:state_selected="true" />
</selector>
</item>
<item
android:id="#+id/selectableBackground"
android:drawable="?android:selectableItemBackground" />
</layer-list>
For API < 21, we cannot use android:drawable="?android:selectableItemBackground" in the layer list, so we will fall back to an alternate but similar visual cue.
layer_list < API 21
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<selector android:exitFadeDuration="#android:integer/config_shortAnimTime">
<item
android:drawable="#color/selected"
android:state_pressed="false"
android:state_selected="true" />
<item
android:drawable="#color/selectable_background"
android:state_pressed="true" />
</selector>
</item>
</layer-list>

Change background color of the selected item in Android Spinner

I am working on an android app and using Spinner at many places in my app.
What I want is to change the background color of the selected item of spinner, so that one can easily identify which item is currently selected.
I have already checked this link Setting background color for Spinner Item on selection but doing so will change the selected textview background color but do not change its color in dropdown list and I want to change the background color of the selected textview when I will see the dropdown list.
I want to change the color of selected item in list not on spinner, please see the image below.
How can I do this? Please, can someone help me here?.
Thanks a lot in advanced.
You need to implement below method in your adapter class:
It will help you:
int selectedItem = -1;
ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, list) {
#Override
public View getDropDownView(int position, View convertView, ViewGroup parent)
{
View v = null;
v = super.getDropDownView(position, null, parent);
// If this is the selected item position
if (position == selectedItem) {
v.setBackgroundColor(Color.BLUE);
}
else {
// for other views
v.setBackgroundColor(Color.WHITE);
}
return v;
}
};
dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mySpinner.setAdapter(dataAdapter);
Now on item selected in spinner put below
selectedItem = position;
Here is solution via XML:
Spinner looks like:
<Spinner
android:id="#+id/settingsSleepingTimePicker"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/spinner_main_button"
android:popupBackground="#color/colorPrimary"
android:textColor="#android:color/white"
android:textSize="20sp"/>
While creating spinner set setDropDownViewResource as custom layout:
adapter.setDropDownViewResource(R.layout.spinner_item);
And spinner_item.xml looks like:
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#android:id/text1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/spinner"
android:textColor="#ffffff"
android:textSize="20sp" />
And finally we set #drawable/spinner like this:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#color/colorPrimaryLight" android:state_hovered="true" />
<item android:drawable="#color/colorPrimaryLight" android:state_selected="true" />
</selector>
Hope my answer will be helpfull!
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">#color/colorPrimary</item>
<item name="colorPrimaryDark">#color/colorPrimaryDark</item>
<item name="colorAccent">#color/colorAccent</item>
<item name="colorControlNormal">#color/spinner_background</item>
</style>
Define Spinner_background color in color folder..
Try creating a selector in the drawable, something like,
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="false" android:drawable="#color/colorPrimary" />
<item android:drawable="#android:color/transparent" />
</selector>
And set the spinner background as
android:background="#drawable/spinner_selector"
I've searched the internet for a proper solution to do this without hardcoding the background behaviour in java code.
You can achieve this (setting the selected item background color) using drawables.
What you need to do it set the dropdownViewResource to a custom layout. That layout should look something like this:
<?xml version="1.0" encoding="utf-8"?>
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/spinner_item_background"
android:gravity="left"
android:padding="8dp" />
In spinner_item_background.xml, you can define a background for each item state. For example, if you want to have a ripple effect on press, but a solid effect when selected, you can try this:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Activated state is the selected item -->
<item android:state_activated="true" android:drawable="#00ff00"/>
<!-- Pressed state is the one the user is interacting with -->
<item android:state_pressed="true" android:drawable="#00ff00"/>
<!-- The rest of the items -->
<item android:drawable="#ffffff"/>
</selector>
Create an int variable public static int posOfItemSpinnerSelected in your Activity:
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
posOfItemSpinnerSelected=position;
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
and in your adapter insert this code
if(position== YourActivity.posOfItemSpinnerSelected){
textView.setBackgroundColor(ContextCompat.getColor(mActivity,R.color.item_spinner_selected));
} else {
textView.setBackgroundColor(ContextCompat.getColor(mActivity,R.color.white));
}

Navigation Drawer item background colour for selected item

I used Android Studio to implement the Navigation Drawer and I can't get the blue colour that is used to show which section we're currently in to change.
I've tried numerous things, I'm currently using a listSelector which looks like:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_activated="true" android:drawable="#color/selected" />
<item android:state_pressed="true" android:drawable="#color/highlight" />
</selector>
I've also tried state_checked. state_pressed works in this situation but the currently selected item is still blue.
EDIT:
I've been examining this more and when the adapter is created the context that is passed is getActionBar().getThemedContext() so I'm thinking if I can find the right attribute to assign to my actionbar style I can change it from there. I've tried a few different attributes with no luck. Does anyone know the exact attribute?
I've also realised if I put
<item name="android:activatedBackgroundIndicator">#drawable/nav_listview_selector</item>
in the main part of my theme and change getActionBar().getThemedContext() for getActivity.getBaseContext then I can change the color but I don't think this is the correct way. I think the themed context should be used. So if anyone knows where the activatedBackgroundIndicator could be put so that it would be used in getActionBar.getThemedContext()
EDIT2:
So the text view used for the listview is one within the SDK it looks like this:
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#android:id/text1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceListItemSmall"
android:gravity="center_vertical"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:background="?android:attr/activatedBackgroundIndicator"
android:minHeight="?android:attr/listPreferredItemHeightSmall"
/>
So I tried modifying the "?android:attr/activatedBackgroundIndicator" at the theme level but it has no effect for checked/selected/activated but it does for pressed. Does anyone know why this is? And how I can change it?
To solve this problem:
1- You don't need android:listSelector under your ListView.
2- Open (or Create) styles.xml under (res/values).
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="android:activatedBackgroundIndicator">#drawable/drawer_list_selector</item>
</style>
3- Under res/drawable folder create drawer_list_selector.xml file
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:drawable="#drawable/light_gray_color" />
<item android:state_activated="true" android:drawable="#drawable/red_color" />
<item android:drawable="#android:color/transparent" />
</selector>
4- Under res/drawable create red_color.xml / light_gray_color.xml (or any other name) and add your desired Hex color:
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#C8FF0000"/>
</shape>
5- Open your project AndroidManifest.xml and add android:theme tag (if not exist)
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
Reference / Credit: Changing Navigation Drawer Selected Item Color from default blue
To change the "Navigation Drawer item background colour for selected item" you could do it with the attribut:
colorControlHighlight
In your "styles.xml" it could look like this:
<style name="YourStyleNameFor.NavigationDrawer" parent="ThemeOverlay.AppCompat.Light">
<item name="colorControlHighlight">#color/your_highlight_color</item>
</style>
Don't forget to apply your Style in the tag:
android.support.design.widget.NavigationView
For example in your activity_main.xml it could look like this:
<android.support.design.widget.NavigationView
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="#layout/navigationdrawer_header"
<!-- the following line referes to your style -->
app:theme="#style/YourThemeNameFor.NavigationDrawer"
<!-- the following two lines are maybe also interesting for you -->
app:itemIconTint="#color/gray3"
app:itemTextColor="#color/gray3"
app:menu="#menu/navigationdrawer_main" />
This is working for me:
First define a drawable item_bg.xml as:
<?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/nav_menu_bg" />
</selector>
Then use this drawable in navigation_main_layout.xml as:
<android.support.design.widget.NavigationView
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:itemBackground="#drawable/item_bg"
android:fitsSystemWindows="true"
app:headerLayout="#layout/nav_header_navigation"
app:menu="#menu/navigation_main_layout_drawer" />
here is how i have done and it is working, the brief concept is maintain the position of selected item in adapter and call notifyDataSetChanged on calling notifyDatasetChanged the getView method is called again and in get view check the position on the selected position change the background view. Here is the code :
Adapter of NavigationDrawer List View
public class MenuAdapter extends BaseAdapter {
private static final int TYPE_HEADER = 0;
private static final int TYPE_ITEM = 1;
private Context mContext;
private String name;
private int profile;
private int mIcons[];
private int selectedPosition = 0;
private String mNavTitles[];
private LayoutInflater mInflater;
public MenuAdapter(String titles[], int icon[], String Name, int profile) {
mNavTitles = titles;
mIcons = icon;
name = Name;
this.profile = profile;
}
public MenuAdapter(String Titles[], int Icons[], Context mContext) {
mNavTitles = Titles;
mIcons = Icons;
this.mContext = mContext;
mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public int getCount() {
return mNavTitles.length;
}
#Override
public Object getItem(int position) {
return position;
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
convertView = mInflater.inflate(R.layout.item_row, parent, false);
TextView textView = (TextView) convertView.findViewById(R.id.rowText);
ImageView imageView = (ImageView) convertView.findViewById(R.id.rowIcon);
final LinearLayout layout = (LinearLayout) convertView.findViewById(R.id.outerLayout);
imageView.setImageResource(mIcons[position]);
textView.setText(mNavTitles[position]);
if (position == selectedPosition)
layout.setBackgroundColor(mContext.getResources().getColor(R.color.app_bg));
else
layout.setBackgroundColor(mContext.getResources().getColor(R.color.normal_bg));
return convertView;
}
public void setSelectedPosition(int position) {
this.selectedPosition = position;
}
}
in your activity do this
private class DrawerItemClickListener implements ListView.OnItemClickListener {
#Override
public void onItemClick(AdapterView parent, View view, int position, long id) {
mMenuAdapter.setSelectedPosition(position - 1);
mMenuAdapter.notifyDataSetChanged();
}
}
if anyone still face any difficulty, feel free to ask.
I have implement drawer menu with custom adapter class. May be it will help someone Drawer List
<ListView
android:id="#+id/listview_drawer"
android:layout_width="260dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="#color/menu_item_color"
android:choiceMode="singleChoice"
android:divider="#android:color/transparent"
android:dividerHeight="0dp"
android:fadingEdge="none"
/>
drawer_list_item.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/menu_selector"
>
<ImageView
android:id="#+id/imgIcon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="12dp"
android:layout_marginRight="12dp"
android:src="#drawable/ic_menu_home" />
<TextView
android:id="#+id/lblName"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_centerVertical="true"
android:gravity="center_vertical"
android:layout_toRightOf="#+id/imgIcon"
android:minHeight="48dp"
android:textColor="#color/menu_txt_color" />
menu_selector.xml
<selector xmlns:android="http://schemas.android.com/apk/res/android" android:exitFadeDuration="#android:integer/config_mediumAnimTime">
<!-- selected -->
<item android:drawable="#color/menu_item_active_color" android:state_focused="true" android:state_pressed="false"/>
<item android:drawable="#color/menu_item_active_color" android:state_pressed="true"/>
<item android:drawable="#color/menu_item_active_color" android:state_activated="true"/>
<item android:drawable="#color/menu_item_active_color" android:state_checked="true"/>
<item android:drawable="#color/menu_item_active_color" android:state_selected="true"/>
<item android:drawable="#color/menu_item_color" android:state_activated="false"/>
Add this on item click listner of listview
yourlistview.setItemChecked(position, true);
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#color/list_item_back_pressed" android:state_pressed="true" />
<item android:state_activated="true"><color android:color="#color/primary_blue"/></item>
<item android:drawable="#color/list_item_back_normal"/>
</selector>
In addition to providing a custom selector drawable for the listSelector, you should also set the background resource of the list item to a similar selector drawable that has different drawables for the different states.
I usually use my custom adapter that has an int selection field, and a setSelection(int) function. And in the getView function I set the background of the view according to position == selection.
Still not sure why it is that it doesn't work. But the way I found around it is to use my own simple_list_item_activated layout to be passed to the ArrayAdapter which was basically the same except for setting the text colour to white. I then replaced getActionBar().getThemedContext() with getActivity().getBaseContext() and it now has an effect.
This may not be the correct way and may have repercussions in the future, but for now I have it working the way I want it to.
I know its too late but I have solved this issue in my app.
Pls dont think it is silly, just simply change the position of "state_pressed" to top.
<item android:drawable="#drawable/list_item_bg_pressed" android:state_pressed="true"/>
<item android:drawable="#drawable/list_item_bg_normal" android:state_activated="false"/>
<item android:drawable="#drawable/list_item_bg_selected" android:state_activated="true"/>
In Future if anyone comes here using, Navigation Drawer Activity (provided by Studio in Activity Prompt window)
The answer is -
Use this before OnCreate() in MainActivity
int[][] state = new int[][] {
new int[] {android.R.attr.state_checked}, // checked
new int[] {-android.R.attr.state_checked}
};
int[] color = new int[] {
Color.rgb(255,46,84),
(Color.BLACK)
};
ColorStateList csl = new ColorStateList(state, color);
int[][] state2 = new int[][] {
new int[] {android.R.attr.state_checked}, // checked
new int[] {-android.R.attr.state_checked}
};
int[] color2 = new int[] {
Color.rgb(255,46,84),
(Color.GRAY)
};
ColorStateList csl2 = new ColorStateList(state2, color2);
and use this in onNavigationItemSelected() in MainActivity (you dont need to Write this function if you use Navigation Drawer activity, it will be added in MainActivity).
NavigationView nav = (NavigationView) findViewById(R.id.nav_view);
nav.setItemTextColor(csl);
nav.setItemIconTintList(csl2);
nav.setItemBackgroundResource(R.color.white);
Tip - add this code before If else Condition in onNavigationItemSelected()
This worked for me :
implemented menu drawer not by populating the navigation view with list, but with menu items.
created a drawable like this :
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#color/drawer_menu_selector_color" android:state_checked="true"></item>
<item android:drawable="#color/drawer_menu_selector_color" android:state_activated="true"></item>
and in onCreate method , set the id of the menu item which corresponds to selected activity as checked.
and implement the drawable selector file to your navigation drawer like this
app:itemBackground="#drawable/drawer_menu_selector"
fyi : need to define your 'app' namespace.
I searched for solution on this issue, tried everything, and only this solution worked for me.
You can find it on this link https://tuchangwei.github.io/2016/07/18/The-solution-that-the-menu-item-of-Navigation-View-can-t-change-its-background-When-it-is-selected-checked/
All the credit to https://tuchangwei.github.io/

Highlight selected item in ListView on Android

I have been making an application that works with ListViews in Android, and I can't make it so that the selected (chacked) item has a different background. I'm using CHOICE_MODE_SINGLE. This is how my code looks so far:
The ListView that I use:
(inside layout.xml)
<ListView
android:id="#+id/listView"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:choiceMode="singleChoice"
android:listSelector="#drawable/selector_test" >
</ListView>
The TextView layout I use in the adapter:
(listItem.xml)
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/listItem"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="23sp"
android:textStyle="bold" />
This is where I add the adapter:
mListAdapter = new ArrayAdapter<String>(this, R.layout.listItem, mList);
mListView = (ListView) findViewById(R.id.listView);
mListView.setAdapter(mAuthorAdapter);
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int position, long arg3) {
String selected = mList.get(position);
// ...
mListView.setItemChecked(position, true);
}
});
I'm sure that the proper item is checked on click, because when I call getCheckedItemPosition(), it returns the proper value.
And now, the two things I tried in order to highlight the checked item:
Selector drawable:
(selector_test.xml)
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" android:enterFadeDuration="#android:integer/config_longAnimTime">
<item android:state_checked="true"><shape>
<solid android:color="#color/red" />
</shape></item>
<item android:state_selected="true"><shape>
<solid android:color="#color/blue" />
</shape></item>
<item android:state_pressed="true"><shape>
<solid android:color="#color/green" />
</shape></item>
</selector>
I add it to .xml with:
android:listSelector="#drawable/selector_test"
Background drawable:
(background_test.xml)
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#color/red" android:state_checked="true"/>
<item android:drawable="#color/blue" android:state_selected="true"/>
<item android:drawable="#color/green"/>
</selector>
I add it to .xml with:
android:background="#drawable/background_test"
I've tried adding the selector and the background to both listView.xml and listItem.xml, but the only thing that changes is the default background color, and the color of the selector when the item is pressed (or held).
android:state_checked="true" and android:state_selected="true" seem to do nothing.
I can change the background by overriding the getView() method in ArrayAdapter and invoking setBackgroundColor() in it if the view is selected, and it does change the background, but also gets rid of the selector entirely. Also, I don't really like to override classes just to change one line of code, especially if that same thing can be achieved in a different way.
So what I'm asking is, is there a way to highlight checked item in ListView by adding a selector or background drawable to it, and I am just doing it wrong, or will I have to make it work some other way.
Thanks in advance! :)
add this line in onStart of your activity
lv.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
where lv is instance of listView
then override this method and add the following lines to it.
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
// Set the item as checked to be highlighted
lv.setItemChecked(position, true);
v.setBackgroundColor(Color.BLUE);
conversationAdapter.notifyDataSetChanged();
}
and then change the color of previous selected item's background back to normal in getView method of your custom adapter
Try this:
listViewDay.setItemChecked(position, true);
listViewDay.setSelection(position);
listitem.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="40dp"
android:background="#drawable/list_day_selector" >
<TextView
android:id="#+id/txtItemDay"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center_vertical|center_horizontal"
android:text="22"
android:textColor="#android:color/white"
android:textSize="22sp" />
</LinearLayout>
list_selector.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#drawable/list_item_bg_normal" android:state_activated="false"/>
<item android:drawable="#drawable/bg_with_left_arrow" android:state_pressed="true"/>
<item android:drawable="#drawable/bg_with_left_arrow" android:state_activated="true"/>
</selector>
Programmatically, use setSelector. For example:
lv.setSelector(R.color.abc_background_cache_hint_selector_material_dark);
After some hours of encountering one glitch after another (including the selector leaving a dirty stripe), I decided to do it myself:
class MyListAdapter extends ArrayAdapter<MyData> {
// !!! access to the current selection
int mSelected = 0;
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = super.getView(position, convertView, parent);
// !!! this is where the selected item is highlighted
v.findViewById(R.id.selectionSign).setVisibility(position == mSelected ? View.VISIBLE : View.INVISIBLE);
return v;
}
public CommandListAdapter(Context context, List<MyData> objects) {
super(context, R.layout.mylistitem, R.id.mytext, objects);
}
}
with the OnItemClickListener:
mMyListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
setSelectionPosNoUpd(position);
update();
}
});
and the functions defined as:
void setSelectionPosNoUpd(int n) {
mCommandListAdapter.mSelected = n;
//update();
}
void update() {
mListViewOfCommands.smoothScrollToPosition(getSelectionPos());
mCommandListAdapter.notifyDataSetChanged();
}
and the list item XML (res/layout/mylistitem.xml) is:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="#+id/mytext"
/>
</LinearLayout>
<View
android:id="#+id/selectionSign"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#10ff5000"
android:visibility="invisible"
/>
</FrameLayout>
The downside is that after changing the selection I have to update(): there is no easy way to unhighlight the previously highlighted view.
Set item state in selector like this:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_activated="true"
android:color="#color/XXX/>
</selector>
I don't know why state_checked not working. At first I thought it must be a Checkableview then I tried CheckedTextView. Still not working.
Anyway, state_activated will solve the problem.
I think you cann't use mListView inside anonymous class. You must use AdapterView arg0
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View view,
int position, long id) {
AnyObject obj=(AnyObject)arg0.getItemAtPosition(position);
........
.........
.........
}
});
This post has worked out for me: http://www.mynewsfeed.x10.mx/articles/index.php?id=14
The ListView (inside layout.xml):
<ListView
android:id="#+id/list"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:background="#drawable/list_custom"
android:choiceMode="singleChoice"/>
Selector drawable(list_custom.xml):
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:drawable="#color/orange"/>
<item android:state_activated="true" android:drawable="#color/blue" />
<item android:drawable="#color/green" />
</selector>
Color.xml in values folder:
<resources>
<item name="blue" type="color">#FF33B5E5</item>
<item name="green" type="color">#FF99CC00</item>
<item name="orange" type="color">#FFFFBB33</item>
</resources>

Android: custom selector state never gets "true"

I'm struggling with this already from hours and I cannot find a solution, I hope someone can help me.
I have a ListView with a custom adapter extending BaseAdapter and each element of the list extends a LinearLayout containing only a TextView. I started basically from How to add a custom button state.
This is the list_item.xml layout file of the list element:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res/com.example.mypackage"
android:id="#+id/newItem"
app:state_playing="true"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/item_selector"
android:orientation="horizontal" >
<TextView
android:id="#+id/textview"
style="#style/Text_View_Style_White"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:duplicateParentState="true"
android:ellipsize="marquee"
android:focusableInTouchMode="true"
android:marqueeRepeatLimit="marquee_forever"
android:padding="3dp"
android:scrollHorizontally="true"
android:singleLine="true"
android:textColor="#drawable/item_text_selector" />
</LinearLayout>
Here is the relevant code of the BaseAdapter:
class AlbumListAdapter extends BaseAdapter implements Checkable {
private Context mContext;
public AlbumListAdapter(Context context) {
mContext = context;
}
#Override
public int getCount() {
return listSize; // is a variable
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
AlbumViewHolder albumHolder = null;
if (convertView == null) {
// Inflate the layout
LayoutInflater li = getActivity().getLayoutInflater();
convertView = li.inflate(R.layout.list_item, null);
albumHolder = new AlbumViewHolder(mContext, null);
albumHolder.albumTitle = (TextView) convertView
.findViewById(R.id.textview);
convertView.setTag(albumHolder);
} else {
albumHolder = (AlbumViewHolder) convertView.getTag();
}
albumHolder.albumTitle.setText("Some text in the TextView");
albumHolder.albumTitle.setSelected(true);
if (myBooleanCondition)
{
albumHolder.setPlaying(true);
albumHolder.refreshDrawableState();
for (int i = 0; i < albumHolder.getDrawableState().length; i++) {
if (albumHolder.getDrawableState()[i] != 0)
System.out.println(TAG + " State i = "
+ i + " -> " + getResources().getResourceEntryName(albumHolder.getDrawableState()[i]));
}
}
return convertView;
}
}
and here the list element class extending the LinearLayout:
static class AlbumViewHolder extends LinearLayout {
private static final int[] STATE_PLAYING_SET = { R.attr.state_playing };
private boolean mIsPlaying = false;
TextView albumTitle;
public AlbumViewHolder(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void setPlaying(boolean isPlaying) {
mIsPlaying = isPlaying;
}
#Override
protected int[] onCreateDrawableState(int extraSpace) {
final int[] drawableState = super
.onCreateDrawableState(extraSpace + 1);
if (mIsPlaying) {
System.out.println(TAG
+ " - onCreateDrawableState() -> mIsPlaying = "
+ mIsPlaying);
mergeDrawableStates(drawableState, STATE_PLAYING_SET);
}
return drawableState;
}
}
Here is the attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="music">
<attr name="state_playing" format="boolean" />
<attr name="playing" format="boolean" />
</declare-styleable>
</resources>
and here the 2 selectors trying to use the selector state state_playing, one for the background of the LinearLayout of each element (item_selector.xml):
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res/com.example.mypackage">
<item android:drawable="#color/blue_fluo3" app:state_playing="true"/>
<item android:drawable="#color/orange_fluo" android:state_pressed="true" app:state_playing="false"/>
<item android:drawable="#color/orange_fluo" android:state_activated="true" app:state_playing="false"/>
<item android:drawable="#android:color/transparent" app:state_playing="false"/>
</selector>
and one for the textColor of the TextView (item_text_selector.xml):
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res/com.example.mypackage">
<item app:state_playing="true" android:color="#color/orange_fluo"/>
<item android:state_pressed="true" app:state_playing="false" android:color="#color/black"/>
<item android:state_activated="true" app:state_playing="false" android:color="#color/black"/>
<item app:state_playing="false" android:color="#android:color/white"/>
</selector>
The result is the same for both: the state_playing seems to work but only in state "false", because if I add a line at the beginning of the selector state list with <item app:state_playing="false" android:color="#color/yellow"/> for the text selector and <item android:drawable="#color/red" app:state_playing="false"/> for the background selector everything is working as expected, I can see the LinearLayout with red background and the text with yellow text!
I really don't know what to try anymore... (even if I set the property by default to the objects (app:state_playing="true") in the xml layout it doesn't work!
Any help, hint or experience sharing is extremely appreciated!
It looks okay to me,but I'd suggest setting duplicateParentState in the container layout as below. I have a vague memory of having issues along those lines myself...
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res/com.example.mypackage"
android:id="#+id/newItem"
android:duplicateParentState="true"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/item_selector"
android:orientation="horizontal" >
<TextView
android:id="#+id/textview"
style="#style/Text_View_Style_White"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:duplicateParentState="true"
android:ellipsize="marquee"
android:focusableInTouchMode="true"
android:marqueeRepeatLimit="marquee_forever"
android:padding="3dp"
android:scrollHorizontally="true"
android:singleLine="true"
android:textColor="#drawable/item_text_selector" />

Categories

Resources