In Android, I have a GridView - each cell in the GridView is an ImageView. When a user clicks on a cell, I would like that cell to be "selected" (have its background turn blue), and all other cells to "unselect" (have their backgrounds turn white).
I have implemented the following background drawable, but it only changes the background while the cell is pressed:
<?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/iconborder_selected" /> <!-- pressed -->
<item android:drawable="#drawable/iconborder_unselected" /> <!-- default -->
</selector>
EDIT: Here is my adapter code for the GridView.
class IconAdapter extends BaseAdapter {
private Context context = null;
private List<Drawable> icons = new ArrayList<Drawable>();
public IconAdapter(Context context) {
this.context = context;
for (Field f : R.drawable.class.getFields()) {
String path = f.getName();
if (path.contains("icon_")) {
int id = context.getResources().getIdentifier(path, "drawable",
context.getPackageName());
Drawable drawable = context.getResources().getDrawable(id);
icons.add(drawable);
}
}
}
#Override
public int getCount() {
return icons.size();
}
#Override
public Object getItem(int position) {
return icons.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ImageView iv = new ImageView(context);
iv.setImageDrawable(icons.get(position));
iv.setBackgroundResource(R.drawable.iconborder);
return iv;
}
}
You should add state_selected too:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true"
android:drawable="#drawable/iconborder_selected" /> <!-- selected -->
<item android:state_pressed="true"
android:drawable="#drawable/iconborder_pressed" /> <!-- pressed -->
<item android:state_pressed="false"
android:drawable="#drawable/iconborder_unselected" /> <!-- default -->
</selector>
Try in the XML declaration of the GridView to put these lines:
<GridView
<!-- Some stuff here, like id, width, e.t.c. -->
android:drawSelectorOnTop="true"
android:listSelector="path_to_your_selector"
/>
And your selector should contain something like this:
<item android:state_pressed="true">
<shape>
<!-- Or a drawable here -->
</shape>
</item>
<item android:state_focused="true">
<shape>
<!-- Or a drawable here -->
</shape>
</item>
<item android:drawable="#android:color/transparent" />
Related
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>
How to make ListView Item Selection remain stable ?
<ListView
android:id="#+id/list_slidermenu"
android:layout_height="0dp"
android:layout_width="match_parent"
android:layout_weight="8"
android:layout_gravity="start"
android:scrollbars="none"
android:fastScrollEnabled="true"
android:choiceMode="singleChoice"
/>
You've to make getSelectedIndex() and setSelectedIndex() method in your adapter.
private int selectedIndex;
public int getSelectedIndex() {
return selectedIndex;
}
public void setSelectedIndex(int index) {
this.selectedIndex = index;
// Re-draw the list by informing the view of the changes
notifyDataSetChanged();
}
and then
#Override
public View getView(int position, View convertView, ViewGroup parent) {
.......
// Highlight the selected item in the list
if (selectedIndex != -1 && selectedIndex == position) {
v.setBackgroundResource(R.color.yourColor);
}
return v;
}
and used from onListItemClick(....)
adapter.setSelectedIndex(position);
Another way as #Sun said
Used gradient to make list selection remain stable
gradient_bg.xml:-
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:startColor="#7ecce8"
android:centerColor="#7ecce8"
android:endColor="#7ecce8"
/>
</shape>
gradient_bg_hover.xml:-
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:startColor="#7ecce8"
android:centerColor="#7ecce8"
android:endColor="#7ecce8"
/>
</shape>
list_selector.xml:-
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:state_selected="false"
android:state_pressed="false"
android:drawable="#drawable/gradient_bg" />
<item android:state_pressed="true"
android:drawable="#drawable/gradient_bg_hover" />
<item android:state_selected="true"
android:state_pressed="false"
android:drawable="#drawable/gradient_bg_hover" />
</selector>
finally in ListView, use listSelector property like below:
android:listSelector="#drawable/list_selector"
I have used gradient to make list selection remain stable
gradient_bg.xml:-
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:startColor="#7ecce8"
android:centerColor="#7ecce8"
android:endColor="#7ecce8"
/>
</shape>
gradient_bg_hover.xml:-
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:startColor="#7ecce8"
android:centerColor="#7ecce8"
android:endColor="#7ecce8"
/>
</shape>
list_selector.xml:-
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:state_selected="false"
android:state_pressed="false"
android:drawable="#drawable/gradient_bg" />
<item android:state_pressed="true"
android:drawable="#drawable/gradient_bg_hover" />
<item android:state_selected="true"
android:state_pressed="false"
android:drawable="#drawable/gradient_bg_hover" />
</selector>
finally in ListView, use listSelector property like below:
android:listSelector="#drawable/list_selector"
You need to keep track of selected item and accordingly change the background of the list row.
1.Change the selected item's position in item click :
#Override
public void onItemSelected(AdapterView<?> arg0, View arg1,int position, long arg3) {
adapter.setSelectedItem(position);
}
2.Get selected item and set background :
public class AudioAdapter extends ArrayAdapter<Audio> {
Integer selected_position = -1;
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// Your Code
if (position == selected_position) {
// set selected color
v.setBackgroundResource(R.color.yourSelectedColor);
} else {
// set default color
v.setBackgroundResource(R.color.yourDefaultColor);
}
}
public int getSelectedItem() {
return selected_position;
}
public void setSelectedItem(int index) {
this.selected_position = index;
}
}
Hope it helps ツ
I have a ListView and I have a Drawable for each item in the ListView to highlight each row when it's selected/pressed. I also have a custom adapter where I'm programatically setting the background color of each row (I want to have alternating background colors). This is a new feature I added and before adding the code the rows would highlight blue, but after they do not highlight. Not sure how to fix it. Here is what I have:
ListView item layout
<?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:orientation="vertical"
android:paddingLeft="5dip"
android:paddingRight="5dip"
android:paddingTop="8dip"
android:paddingBottom="8dip"
android:background="#drawable/app_selector"
>
<TextView
android:id="#+id/text"
style="#style/ListingTitle"
android:layout_alignParentTop="true"
android:paddingBottom="2dip"
/>
</RelativeLayout>
Drawable
<?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/light_blue" />
<item android:state_selected="true" android:state_pressed="false" android:drawable="#color/light_blue" />
<item android:state_activated="true" android:state_selected="false" android:state_pressed="false" android:drawable="#color/light_blue" />
<item android:state_selected="false" android:state_pressed="false" android:drawable="#android:color/transparent" />
</selector>
Fragment
public class ListingFragment extends SherlockListFragment
{
public void onActivityCreated(final Bundle icicle)
{
ListView lv = getListView();
mListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
mListView.setMultiChoiceModeListener(new MultiChoiceModeListener() {
#Override
public void onItemCheckedStateChanged(android.view.ActionMode mode, int position, long id, boolean checked) {
}
#Override
public boolean onActionItemClicked(android.view.ActionMode mode, android.view.MenuItem item) {
}
}
}
/* ADAPTER */
private class CustomAdapter extends BaseAdapter
{
#Override
public View getView(final int position, View convertView, final ViewGroup parent)
{
final ViewHolder holder;
if (convertView == null)
{
holder = new ViewHolder();
convertView = mInflater.inflate(R.layout.item, parent, false);
}
else
{
holder = (ViewHolder)convertView.getTag();
}
if (position % 2 == 0)
convertView.setBackgroundColor(Color.GRAY);
else
convertView.setBackgroundColor(Color.TRANSPARENT);
return(convertView);
}
}
}
Expanding on dum's answer, you don't need to do all that work in code.
Drawable A
<?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/light_blue" />
<item android:state_selected="true" android:state_pressed="false" android:drawable="#color/light_blue" />
<item android:state_activated="true" android:state_selected="false" android:state_pressed="false" android:drawable="#color/light_blue" />
<item android:state_selected="false" android:state_pressed="false" android:drawable="#android:color/transparent" />
</selector>
Drawable B
<?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/light_blue" />
<item android:state_selected="true" android:state_pressed="false" android:drawable="#color/light_blue" />
<item android:state_activated="true" android:state_selected="false" android:state_pressed="false" android:drawable="#color/light_blue" />
<item android:state_selected="false" android:state_pressed="false" android:drawable="#android:color/gray" />
</selector>
In your Adapter:
if (position % 2 == 0) {
convertView.setBackgroundResource(R.drawable.A);
} else {
convertView.setBackgroundResource(R.drawable.B);
}
instead of changing the drawable with plain color, first create a new drawable programmatically and set the states just like in your xml and then set colors for each state. then try replacing your background with your programmatically created drwable.
Normally when I create a ListView in simple ArrayAdapter. It got this highlight feature automatically without additional setup. However, when I create this ListView with my custom CursorAdapter this feature seem to be missing and I cannot find a way to solve it.
Here is my custom CursorAdapter
public class RecentCallAdapter extends CursorAdapter {
private final String tag = this.getClass().getSimpleName();
public RecentCallAdapter(Context context, Cursor c, int flags) {
super(context, c, flags);
// TODO Auto-generated constructor stub
}
private static class ViewHolder {
TextView name;
TextView date;
int nameCol;
int dateCol;
int numberCol;
Calendar cal;
}
#Override
public void bindView(View v, Context context, Cursor cursor) {
// TODO Auto-generated method stub
ViewHolder holder = (ViewHolder) v.getTag();
if (holder == null) {
holder = new ViewHolder();
holder.name = (TextView) v.findViewById(R.id.recentcall_item_name);
holder.date = (TextView) v.findViewById(R.id.recentcall_item_date);
holder.nameCol = cursor.getColumnIndex(Calls.CACHED_NAME);
holder.dateCol = cursor.getColumnIndex(Calls.DATE);
holder.numberCol = cursor.getColumnIndex(Calls.NUMBER);
holder.cal = Calendar.getInstance();
v.setTag(holder);
}
String name = cursor.getString(holder.nameCol);
if(name == null){
name = cursor.getString(holder.numberCol);
}
holder.name.setText(name);
holder.cal.setTimeInMillis(Long.valueOf(cursor.getString(holder.dateCol)));
holder.date.setText(Utility.calculateTimePass(holder.cal.getTime()));
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
// TODO Auto-generated method stub
LayoutInflater inflater = LayoutInflater.from(context);
View v = inflater.inflate(R.layout.recentcall_item, parent, false);
bindView(v, context, cursor);
return v;
}
Any way to solve this?
Thank.
use selector same following
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:state_focused="true" android:drawable="#android:drawable/list_selector_background">
</item>
<item android:state_focused="true" android:state_selected="true" android:drawable="#android:drawable/list_selector_background">
</item>
</selector>
and use this code in listview tag for set selector
android:drawSelectorOnTop="true"
android:listSelector="#drawable/selector"
I will give you an example which is working for me.
To hold the color of listview item when you press it, include the following line in your
listview layout:
android:background="#drawable/bg_key"
Then define bg_key.xml in drawable folder like this:
<?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/pressed_color"/>
<item
android:drawable="#color/default_color" />
</selector>
Finally, include this in your listview onClickListener:
listView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,long arg3) {
view.setSelected(true);
...
}
}
This way, only one item will be color-selected at any time. You can define your color values in res/values/colors.xml with something like this:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="pressed_color">#4d90fe</color>
<color name="default_color">#ffffff</color>
</resources>
In your custom layout set the background as android:background="#drawable/bkg"
bkg.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/pressed" />
<item android:state_focused="false"
android:drawable="#drawable/normal" />
</selector>
normal.xml
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#10EB0A"/>
<stroke android:width="3dp"
android:color="#0FECFF" />
</shape>
pressed.xml
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#FF1A47"/>
<stroke android:width="3dp"
android:color="#0FECFF"/>
</shape>
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>