I am looking to implement a navigation drawer selector which shows the currently selected item at all times when the drawer is opened and that is retained even when the drawer is closed. Something like this:
I have used something like this but it only shows the selector when I click on the list item. This is in my res folder:
<?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/list_activated_holo" />
</selector>
How do i attain the above shown implementation?Which state do i need to implement? Thanks
Have resolved same issue by setting color in getView() of ArrayAdapter that populates my list in NavigationDrawer:
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = LayoutInflater.from(getActivity()).inflate(
R.layout.side_menu_list_item,
parent,
false);
holder = new ViewHolder();
holder.title = (TextView) convertView.findViewById(R.id.text1);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
if (mCurrentSelectedPosition == position) {
holder.title.setBackgroundResource(R.color.menu_list_separator_line);
} else {
holder.title.setBackgroundResource(R.color.app_background_light);
}
holder.title.setText(menuItems[position]);
return convertView;
}
There's another state, "android:state_selected", that you must use. Use a state drawable for the background of your list item, and use a different state drawable for listSelector of your list:
list_row_layout.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="?android:attr/listPreferredItemHeight"
android:background="#drawable/listitem_background"
>
...
</LinearLayout>
listitem_background.xml:
<?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/android:transparent" />
<item android:drawable="#drawable/listitem_normal" />
</selector>
layout.xml that includes the ListView:
...
<ListView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:listSelector="#drawable/listitem_selector"
/>
...
listitem_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/listitem_pressed" />
<item android:state_focused="true" android:drawable="#drawable/listitem_selected" />
</selector>
Related
I want to change my navigation drawer list item's background colour to be changed when i click on it.
Also it should change the text and icon colour of that item as well.
Thanks in advance..
This is quite simple and is similar to changing the background of any view that you use. You can simply create a method and write all the change code into it. Pass the view as a parameter in the method.
Whenever you click on any of the navigation drawer items, pass your view on the method.
For instance, check this method
private boolean viewSelected(View view) {
ViewHolder currentViewHolder = (ViewHolder) view.getTag();
KTextView yourtextView = currentViewHolder.yourtextView;
view.setBackgroundColor(ResourceUtil.getInstance().getColor(R.color.colorSideMenuSelectedBackground));
currentViewHolder.viewSelector.setVisibility(View.VISIBLE);
yourtextView.setTypeface(yourtextView.getContext(), ResourceUtil.getInstance().getString(R.string.yourFontName));
if (lastSelectedView == null) {
lastSelectedView = view;
return true;
}
if (lastSelectedView != view) {
ViewHolder oldViewHolder = (ViewHolder) lastSelectedView.getTag();
oldViewHolder.viewSelector.setVisibility(View.GONE);
lastSelectedView.setBackgroundColor(ResourceUtil.getInstance().getColor(android.R.color.white));
KTextView newTextView = oldViewHolder.yourtextView;
newTextView.setTypeface(yourtextView.getContext(), ResourceUtil.getInstance().getString(R.string.yourfontname));
lastSelectedView = view;
return true;
}
return false;
}
This method will simply change the background, font and color of the views.
Hope this helps!
This can be done using https://developer.android.com/guide/topics/resources/color-list-resource.
Create two drawable files :
1.drawer_background
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="checked_background_color" android:state_checked="true" />
<item android:color="default_background_color" />
</selector>
2.drawer_text_background
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="checked_text_color" android:state_checked="true" />
<item android:color="default_text_color" />
</selector>
And add these two properties to your NavigationView ie
app:itemIconTint="#drawable/drawer_background"
app:itemTextColor="#color/drawer_text_background"
one more if some color is overlapping with some other color
app:itemBackground="#android:color/transparent"
Now, All you have to do is to set an item as checked on Click listener of that item to change background and text color. You can do it programmatically.
I solved it setting this attribute to my NavigationView app:itemBackground="#drawable/drawer_selector"
and my drawer_selector is as below
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:drawable="#color/white" />
<item android:state_focused="true" android:drawable="#color/white" />
<item android:state_activated="true" android:drawable="#color/white" />
<item android:drawable="#color/orange" />
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>
Does anyone have an idea why the setItemChecked() function doesn't work for my below example:
private class DrawerItemClickListener implements
ListView.OnItemClickListener {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
int pos = position;
...
default:
break;
}
listView.setItemChecked(pos, true);
setTitle(titles[pos]);
drawerLayout.closeDrawer(listviewLayout);
}
}
In all examples I've seen so far, the setItemChecked is done inside the DrawerItemClickListener method. But for some reason it does not want to work. I've tried to put it inside onCreate() or onResume(), but still no result.
I tested for simple listView, and it seems it doesn't work there either. Any suggestions ?
Code for my adapter:
public View getView(int position, View convertView, ViewGroup parent) {
Account account = this.items.get(position);
ViewHolder viewHolder;
if (convertView == null) {
viewHolder = new ViewHolder();
LayoutInflater inflater = LayoutInflater.from(getContext());
convertView = inflater.inflate(layoutResID, parent, false);
viewHolder.textViewTitle = (TextView) convertView
.findViewById(R.id.textViewTitle);
viewHolder.imageViewImage = (ImageView) convertView
.findViewById(R.id.imageView);
convertView.setTag(viewHolder);
} else
viewHolder = (ViewHolder) convertView.getTag();
return convertView;
}
It almost doesn't matter where you call setItemChecked(). Are you using custom ListView views?
If your answer is yes, you have to specify selectors for ListView items.
This might be your drawer's ListView item:
<TextView
android:id="#+id/drawer_item_text_view"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/drawer_list_item_background"/>
Your item's background (R.drawable.drawer_list_item_background) must be specified as selector:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#drawable/bg_menu_active" android:state_checked="true"/>
<item android:drawable="#drawable/bg_menu_active" android:state_selected="true"/>
<item android:drawable="#drawable/bg_menu_active" android:state_activated="true"/>
<item android:drawable="#drawable/bg_menu_normal" android:state_checked="false"/>
</selector>
R.drawable.bg_menu_active:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<stroke android:width="1dp" android:color="#color/white"/>
</shape>
R.drawable.bg_menu_normal:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<solid android:color="#android:color/black"/>
</shape>
After this done, you are able to set chosen item as checked and highlight it somehow.
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>
I have the following list adapter that uses an inflater, I've tried adding the color change here but it changes every item not just the one clicked.
private class ListAdapter extends ArrayAdapter<jsonData>{
private List<jsonData> jList;
public ListAdapter(Context context, int resource,List<jsonData> jList) {
super(context, resource, jList);
this.jList = jList;
}
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.listviewact_layout, null);
v.setBackgroundResource(R.layout.list_selector);
}
jsonData jd = jList.get(position);
if (jd != null) {
TextView name = (TextView) v.findViewById(R.id.memberName);
TextView dateJoined = (TextView) v.findViewById(R.id.dateJoined);
if (name != null) {
name.setText("Member Name: " + jd.name);
}
if (dateJoined != null) {
dateJoined.setText("Joined: " + getNewDate(jd.joined));
}
}
return v;
}
I am able to get the item position also, most of it works fine except the colors. I also tried adding a resource file for the selector, but I get the same result.
UPDATE: This seems to work. I have a glitch though when I scroll the item colors go crazy.
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
if(selectedItemPosition != position){
//Resets old item to original color
parent.getChildAt(selectedItemPosition).setBackgroundColor(Color.BLACK);
view.setBackgroundColor(Color.BLUE);
selectedItemPosition = position;
}
}
use android:listSelector not android:background for adding selector xml file to ur listview
<ListView
android:id="#+id/list"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:listSelector="#drawable/list_selector">
</ListView>
Try this selector xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:state_enabled="true"
android:state_pressed="true" android:drawable="#color/android:blue" />
<item android:state_enabled="true"
android:state_focused="true" android:drawable="#color/android:transparent" />
<item
android:drawable="#color/android:black" />
view.setbackground();
Changes the background of entire list .since your view points to that list not a field in that list.
try this
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="true" android:drawable="#color/black" /> <!-- focused -->
<item android:state_focused="true" android:state_pressed="true" android:drawable="#color/black" /> <!-- focused and pressed-->
<item android:state_pressed="true" android:drawable="#color/green" /> <!-- pressed -->
<item android:drawable="#color/black" /> <!-- default -->
</selector>