I need to disable the second element in my navigation drawer until a certain task is finished. Here is how I disable the second element:
nav_item_selector.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#color/dark_green"
android:state_pressed="true" />
<item android:drawable="#android:color/transparent"
android:state_enabled="true" />
<item android:drawable="#android:color/darker_gray"
android:state_enabled="false" />
</selector>
nav_fragment.xml (wrapped in a DrawerLayout)
<ListView
android:id="#+id/left_drawer"
android:layout_width="#dimen/nav_drawer_width"
android:layout_height="match_parent"
android:layout_gravity="start"
android:cacheColorHint="#0000"
android:background="#drawable/gradient_radial_backround"
android:choiceMode="singleChoice"
android:divider="#color/green_light"
android:dividerHeight="1dp" />
nav_list_item.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/nav_list_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/nav_item_selector"
android:orientation="horizontal"
android:padding="#dimen/standard_padding">
<ImageView
android:id="#+id/nav_list_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="#null"
android:src="#drawable/ic_launcher" />
<TextView
android:id="#+id/nav_list_text"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fontFamily="sans-serif-light"
android:gravity="center_vertical"
android:minHeight="#dimen/listPreferredItemHeightSmall"
android:paddingLeft="#dimen/activity_horizontal_small_margin"
android:text="List Item"
android:textSize="#dimen/text_nav_list_entry"
android:textColor="#color/dark_green" />
</LinearLayout>
Activity:
public class NavItemAdapter extends ArrayAdapter<String> {
LayoutInflater inflater;
private String[] listItems;
public NavItemAdapter(Context context, int textViewResourceId, String[] listItems) {
super(context, textViewResourceId, listItems);
this.listItems = listItems;
inflater = LayoutInflater.from(context);
}
#Override
public boolean isEnabled(int position)
{
if(position == 1)
return false;
else
return true;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null)
convertView = new NavItemView(getContext());
NavItemView navItemView = (NavItemView) convertView;
switch (position) {
case 0:
navItemView.setUpItem(R.drawable.ic_nav_1_checked, listItems[position], R.drawable.ic_nav_1);
break;
case 1:
navItemView.setUpItem(R.drawable.ic_nav_2_checked, listItems[position], R.drawable.ic_nav_2);
break;
case 2:
navItemView.setUpItem(R.drawable.ic_nav_3_checked, listItems[position], R.drawable.ic_nav_3);
break;
case 3:
navItemView.setUpItem(R.drawable.ic_nav_4_checked, listItems[position], R.drawable.ic_nav_4);
break;
case 4:
navItemView.setUpItem(R.drawable.ic_nav_5_checked, listItems[position], R.drawable.ic_nav_5);
break;
case 5:
navItemView.setUpItem(R.drawable.ic_nav_6_checked, listItems[position], R.drawable.ic_nav_6);
break;
}
return convertView;
}
}
class NavItemView extends LinearLayout implements Checkable {
private View v;
private ImageView iconView;
private TextView textView;
private Boolean checked = false;
private int mImageChecked;
private int mImage;
public NavItemView(Context context) {
super(context);
LayoutInflater inflater = LayoutInflater.from(context);
v = inflater.inflate(R.layout.list_item_navdrawer, this, true);
assert v != null;
iconView = (ImageView) v.findViewById(R.id.nav_list_icon);
textView = (TextView) v.findViewById(R.id.nav_list_text);
}
#Override
public boolean isChecked() {
return checked;
}
#Override
public void setChecked(boolean checked) {
this.checked = checked;
if (isChecked()) {
setBackgroundColor(getResources().getColor(R.color.transparent));
textView.setTextColor(getResources().getColor(R.color.light_pink));
iconView.setImageResource(mImageChecked);
} else {
//Reset to default
setBackgroundColor(getResources().getColor(R.color.transparent));
textView.setTextColor(getResources().getColor(R.color.green_lighter));
iconView.setImageResource(mImage);
}
}
#Override
public void toggle() {
checked = !checked;
}
private void setUpItem(int imageChecked, String title, int image) {
mImageChecked = imageChecked;
mImage = image;
textView.setText(title);
iconView.setImageResource(image);
}
}
What happens is the item is disabled, but the selector does not kick in (it stays the same colour). Not only that but that item's divider disappears which is even worse! What is happening here?
I actually can't believe this but the only solution seems to be a bit of a weird hack. There are several threads on this question but the only solid answer I've found is from user Jason Lin located here.
It seems there were two pieces of the puzzle missing, the first is that returning false for the item I want to disable in isEnabled() merely makes the item unclickable and unfocusable. To actually disable it I need to perform the same check in getView() and call setEnabled(false) on the item...
if(position == 1)
convertView.setEnabled(false);
AND
Set android:duplicateParentState="true" on the linear layout of the row.
This was the most important part as obviously I tried to called setEnabled(false) in getView() first of all, but it took me all day to learn I need the combination of all 3 of these things - returning false in isEnabled(), setting enabled to false in getView(), and setting duplicateParentState to true :)
Related
I have a Todo project in Android using a ListView. Each item of my listview have one switch in order to delete the task, one TextView and one ImageView. The problem is when I check a switch of a specific task, the task is deleted (desired behavior) but it checks the following one too (without deleting it) .
Here is the code of my Adapter:
public class Adapter extends BaseAdapter {
private List<Tache> lesTaches;
private Context context;
private LayoutInflater inflater;
public Adapter(Context context, List<Tache> list) {
this.context = context;
lesTaches = list;
inflater = LayoutInflater.from(context);
}
#Override
public int getCount() {
return lesTaches.size();
}
#Override
public Object getItem(int position) {
return lesTaches.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
View view;
if(convertView == null) {
view = (View) inflater.inflate(R.layout.tache_item, parent, false);
} else {
view = (View) convertView;
}
TextView intitule = (TextView) view.findViewById(R.id.intitule);
intitule.setText(lesTaches.get(position).getIntitule());
final Switch switch1 = (Switch) view.findViewById(R.id.switch1);
switch1.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if(buttonView.isPressed()) {
if(isChecked) {
remove(lesTaches.get(position));
}
}
}
});
return view;
}
public void remove(Tache toDel) {
lesTaches.remove(toDel);
notifyDataSetChanged();
}
public void addItem(Tache toAdd) {
lesTaches.add(toAdd);
notifyDataSetChanged();
}}
And here is my tache_item.xml :
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Switch
android:id="#+id/switch1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="false"
android:layout_marginHorizontal="5dp"
android:focusable="false" />
<TextView
android:id="#+id/intitule"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toEndOf="#+id/switch1"
android:layout_toRightOf="#+id/switch1" />
<ImageView
android:id="#+id/icon_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_weight="1"
android:layout_marginHorizontal="5dp"
app:srcCompat="#drawable/ic_info_black" />
</RelativeLayout>
Here is a screen of my app showing the problem (I deleted the first task so we do not see it but the second one get checked):
Image showing the problem:
I already search on the net and test to replace the setOnCheckedChangeListener by an onClickListener but the same problem appear.
This question already has answers here:
How to customize a Spinner in Android
(6 answers)
Closed 5 years ago.
I'm trying to remove the default highlight effect for Spinner item's onClick. I have my own specific spinner background which have radius in its corners. When I applied the new background, it still has its default background under my custom background. I've tried styling like this:
<style name="ExternalPSpinnerTheme" parent="Widget.AppCompat.Spinner.DropDown">
<item name="android:listSelector">#color/transparent</item>
<item name="android:listChoiceBackgroundIndicator">#color/transparent</item>
<item name="android:listChoiceIndicatorSingle">#color/transparent</item>
<item name="android:selectableItemBackground">#color/transparent</item>
<item name="android:background">#drawable/spinner_sortfriend_background</item>
<item name="android:cacheColorHint">#android:color/transparent</item>
<item name="android:popupBackground">#drawable/spinner_sortfriend_background</item>
<item name="android:dropDownSelector">#color/transparent</item>
</style>
I've tried changing the parent to Widget.AppCompat.Spinner but it didn't work.. PopupBackground and background works tho.
The other question is questioning on how to hide dividers and add its own spinner custom implementation, mine is asking about how to remove the default onClick highlight effect on the background. How did I try to achieve it? This is how:
if (position > 0 &&
(position + 1) < mDataset.size()){
divider.setVisibility(View.VISIBLE);
convertView.setBackground(ContextCompat.getDrawable(context, R.drawable.spinner_dropdown_background_middle_white_to_migrey));
} else if (position == 0){
divider.setVisibility(View.VISIBLE);
convertView.setBackground(ContextCompat.getDrawable(context, R.drawable.spinner_dropdown_background_top_white_to_migrey));
} else if (position + 1 == mDataset.size()){
divider.setVisibility(View.GONE);
convertView.setBackground(ContextCompat.getDrawable(context, R.drawable.spinner_dropdown_background_bottom_white_to_migrey));
}
And I still didn't get the right answer, I even tried the solution in the other question. I just realized something tho, only the background on the first item overlaps with my custom background click effect, but the one at the end of the list doesn't get overlapped.. Weird..
Any solution?
Create custom Spinner Layout in your xml as follows
<RelativeLayout
android:id="#+id/relativeLayout_multiChoiceDropDown"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/drawable_border_profile">
<TextView
android:id="#+id/textView_multiChoiceDropDownText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:layout_marginBottom="#dimen/margin_5dp"
android:layout_marginEnd="#dimen/margin_5dp"
android:layout_marginStart="#dimen/margin_5dp"
android:layout_marginTop="#dimen/margin_5dp"
android:layout_toStartOf="#+id/button_multiChoiceDropDownArrow"
android:padding="#dimen/margin_5dp"
android:text="Select Item"
android:textColor="#color/black"
android:textSize="#dimen/text_size_16"/>
<Button
android:id="#+id/button_multiChoiceDropDownArrow"
android:layout_width="#dimen/profile_multi_choice_width"
android:layout_height="#dimen/profile_multi_choice_height"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:layout_margin="#dimen/margin_5dp"
android:background="#drawable/dropdownarrow"/>
</RelativeLayout>
drawable_border_profile.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#80FFFFFF"/>
<stroke
android:width="0.5dp"
android:color="#color/light_gray"/>
<padding
android:bottom="1dp"
android:left="1dp"
android:right="1dp"
android:top="1dp"/>
</shape>
Then Set OnClickListener on RelativeLayout. On that You can open Popup Window
LayoutInflater inflater = (LayoutInflater)parentActivity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
LinearLayout layout = (LinearLayout) inflater.inflate(R.layout.pop_up_window, null);
RelativeLayout layout1 = holder.relativeLayout_multiChoiceDropDown;
pw = new PopupWindow(layout, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT, true);
pw.setBackgroundDrawable(new BitmapDrawable());
pw.setTouchable(true);
pw.setOutsideTouchable(true);
pw.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
pw.setTouchInterceptor(new View.OnTouchListener()
{
public boolean onTouch(View v, MotionEvent event)
{
if (event.getAction() == MotionEvent.ACTION_OUTSIDE)
{
pw.dismiss();
return true;
}
return false;
}
});
pw.setContentView(layout);
pw.showAsDropDown(layout1, -5, 0);
final ListView list = (ListView) layout.findViewById(R.id.dropDownList);
Adapter_DropDown adapter = new Adapter_DropDown(parentActivity, items);
list.setAdapter(adapter);
pop_up_window.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout android:id="#+id/PopUpView"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/qatool_basic_info_dropdown"
android:orientation="vertical">
<ListView
android:id="#+id/dropDownList"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:divider="#000"
android:dividerHeight="0.5dp">
</ListView>
You can use customArray Adapter
public class Adapter_Spinner extends ArrayAdapter
{
Context context;
List<Response_IdDesc> dataArray;
public Adapter_Spinner(Context context, int textViewResourceId, List<Response_IdDesc> dataArray)
{
super(context, textViewResourceId, dataArray);
this.dataArray = dataArray;
this.context = context;
}
#Override public Response_IdDesc getItem(int position)
{
return dataArray.get(position);
}
#Override public int getCount()
{
return dataArray.size();
}
#Override public int getPosition(Object item)
{
return dataArray.indexOf(item);
}
#Override
public View getDropDownView(int position, View convertView, ViewGroup parent)
{
return getCustomView(position, convertView, parent);
}
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
return getCustomView(position, convertView, parent);
}
public View getCustomView(int position, View convertView, ViewGroup parent)
{
LayoutInflater inflater = LayoutInflater.from(context);
View view = inflater.inflate(R.layout.rowitem_spinner_profile, parent, false);
TextView label = (TextView) view.findViewById(R.id.textview_spinner);
label.setText(dataArray.get(position).DESC);
return view;
}
}
Then set your spinner adapter like this
Adapter_Spinner adapter_spinner = new Adapter_Spinner(parentActivity, R.layout.rowitem_spinner, list);
spinner.setAdapter(adapter_spinner);
I am new to android and I have just started programming a simple app to try different things out.
I was programming a ListView (and, in the same way a GridView) but there is something I got wrong. Each item is a couple of an image and a text field.
| img | __text__ |
I want to be able to choose any number of list items, keeping them enlightened for all the selection process, before passing the selected items to the next activity. If I want to
de-select one of them, I simply have to re-click on the item to have the selection disappear. For this purpose I use a custom selector so that when the item is pressed it changes colours.
If the items are all contained in a screen, everything is ok. But as soon as they grow in number and recycling kicks in, the enlightening of selected items which get out of the screen is lost. I have debugged the state of items and those whose enlightening is lost are still correctly selected, so I think it’s just a problem on how the graphic reloads when an item is restored after it went out of the device screen.
Here’s the code of the activity layout:
<!-- items_selection.xml -->
<?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"
android:background="#color/Background">
<ListView
android:id="#+id/item_list"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:divider="#color/divider"
android:dividerHeight="3dp"
android:choiceMode="multipleChoice"
android:listSelector="#drawable/list_selector">
</ListView>
</LinearLayout>
This is the Row Item layout:
<!-- list_row.xml -->
<?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="wrap_content"
android:background="#drawable/list_selector"
android:orientation="horizontal"
android:padding="5dip" >
<LinearLayout
android:id="#+id/item_list_item"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_marginRight="5dip"
android:padding="3dip" >
<ImageView
android:id="#+id/item_image"
android:layout_width="#dimen/img_side"
android:layout_height="#dimen/img_side" />
</LinearLayout>
<TextView
android:id="#+id/item_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="#+id/item_list_item"
android:layout_centerVertical="true"
android:textColor="#color/black"
android:textSize="#dimen/textnorm"
/>
</RelativeLayout>
This is the selector I used:
<!-- 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/rect" />
<item
android:state_pressed="true"
android:drawable="#drawable/rect_sel" />
<item
android:state_selected="true"
android:state_pressed="false"
android:drawable="#drawable/rect_sel" />
</selector>
<!-- rect.xml -->
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:startColor="#D5DDE0"
android:centerColor="#e7e7e8"
android:endColor="#CFCFCF"
android:angle="270" />
</shape>
<!-- rect_sel.xml -->
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:startColor="#78DDFF"
android:centerColor="#16cedb"
android:endColor="#09adb9"
android:angle="270" />
</shape>
This is the code of the Activity:
public class ItemSelection extends AppCompatActivity {
private int numitems;
private ListView listview;
private ArrayList<Item> items = new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.items_selection);
numitems = 15;
build_list();
listview = (ListView) findViewById(R.id.item_list);
listview.setAdapter(new ListAdapter(this, items));
}
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.next_btn, menu);
return true;
}
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
switch(id){
case R.id.next_btn:
Intent intent = new Intent (this, nextActivity.class);
intent.putStringArrayListExtra("items", Chosen_Items());
startActivity(intent);
return true;
default:
Toast.makeText(getApplicationContext(), "ERROR", Toast.LENGTH_SHORT).show();
return super.onOptionsItemSelected(item);
}
}
private void build_list() {
//Populates the item list with more items than the screen can support.
}
private ArrayList<String> Chosen_Items(){
ArrayList<String> selitems = new ArrayList<>();
for (int i=0; i<numitems; i++){
if (items.get(i).isSelected()){
selitems.add(items.get(i).getName());
}
}
return selitems;
}
This is the code of the listAdapter:
public class ListAdapter extends BaseAdapter {
private ArrayList <Item> items;
private Activity sActivity;
public ListAdapter(Activity sActivity, ArrayList<Item> items) {
this.sActivity = sActivity;
this.items = items;
}
#Override
public int getCount() {
return items.size();
}
#Override
public Object getItem(int position) {
return items.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
public View getView(final int position, View convertView, ViewGroup parent) {
View view = convertView;
ViewHolder holder;
if(view == null) {
LayoutInflater li = sActivity.getLayoutInflater();
view = li.inflate(R.layout.list_row, null);
holder = new ViewHolder();
holder.text = (TextView)view.findViewById(R.id.item_name);
holder.img = (ImageView)view.findViewById(R.id.item_image);
view.setTag(holder);
}
else {
holder = (ViewHolder)view.getTag();
}
holder.text.setText(items.get(position).getName());
holder.img.setImageResource(items.get(position).getImage());
view.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View viewitem) {
if (!viewitem.isSelected() && !items.get(position).isSelected()) {
viewitem.setSelected(true);
items.get(position).setSelected(true);
}
else {
viewitem.setSelected(false);
items.get(position).setSelected(false);
}
}
});
return view;
}
private static class ViewHolder{
public TextView text;
public ImageView img;
}
}
I have already tried to manually set the background color of the items re-entering the screen (by using
view.setBackgroundResource(R.drawable.rect_sel)
in the adapter, before the click handler) but the problem remains. Can anyone help me solving the problem?
~~~~~~~~~~~~~~~~~~~ SOLUTION ~~~~~~~~~~~~~~~~~~
It seems the selector doesn't follow the recycle of the items and their views.There has to be a better and more elegant solution taking advantage of a selector in this situation. But out of all the attempts i made, none has worked. This solution is the best workaround and does not use the selector.
public View getView(final int position, View convertView, ViewGroup parent) {
View view = convertView;
ViewHolder holder;
if(view == null) {
LayoutInflater li = sActivity.getLayoutInflater();
view = li.inflate(R.layout.list_row, null);
holder = new ViewHolder();
holder.text = (TextView)view.findViewById(R.id.item_name);
holder.img = (ImageView)view.findViewById(R.id.item_image);
view.setTag(holder);
}
else {
holder = (ViewHolder)view.getTag();
}
holder.text.setText(items.get(position).getName());
holder.img.setImageResource(items.get(position).getImage());
if(items.get(position).isSelected()){
view.setBackgroundResource(R.drawable.rect_sel);
}else{
view.setBackgroundResource(R.drawable.rect);
}
view.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View viewitem) {
if (!viewitem.isSelected() && !items.get(position).isSelected()) {
viewitem.setBackgroundResource(R.drawable.rect_sel);
viewitem.setSelected(true);
items.get(position).setSelected(true);
}
else {
viewitem.setBackgroundResource(R.drawable.rect);
viewitem.setSelected(false);
items.get(position).setSelected(false);
}
}
});
return view;
}
private static class ViewHolder{
public TextView text;
public ImageView img;
}
While in the list_row.xml file, the following line can be just deleted:
android:background="#drawable/list_selector"
In your getView() method just add this test:
if (items.get(position).isSelected()){
view.setBackgroundResource(R.drawable.rect_sel);
} else {
view.setBackgroundResource(R.drawable.rect);
}
Or just view.setSelected(items.get(position).isSelected());. While you already have a selector for your list item.
You must define the current selection state of view inside getView method.
Add this line:
viewitem.setSelected(items.get(position).isSelected());
after viewholder has been created like:
holder.img.setImageResource(items.get(position).getImage());
viewitem.setSelected(items.get(position).isSelected());
I think you should set the id for your RelativeLayout then add it to ViewHolder
private static class ViewHolder{
public TextView text;
public ImageView img;
RelativeLayout rl;
}
After that you handle event when click RelativeLayout then change background for RelativeLayout
public View getView(...)
...
...
// you should update the state of relative layout first
if (items.get(position).isSelected()) {
holder.setBackgroundColor(Color.parseColor("#ffff00"));
}else{
holder.setBackgroundColor(Color.parseColor("#ff0000"));
}
holder.rl.setOnClickListener(new View.OnClickListener(){ //remmember it is rl.setOnClick... not view.setOnClick...
public void onClick(View v) {
if (!items.get(position).isSelected()) {
items.get(position).setSelected(true);
holder.setBackgroundColor(Color.parseColor("#ffff00"));
}else {
items.get(position).setSelected(false);
holder.setBackgroundColor(Color.parseColor("#ff0000"));
}
}
});
}
Suggestion
You should modify your row layout like this (I have removed LinearLayout but the new layout still good)
<!-- list_row.xml -->
<?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="wrap_content"
android:background="#drawable/list_selector"
android:orientation="horizontal"
android:padding="5dip" >
<ImageView
android:id="#+id/item_image"
android:layout_marginRight="5dip"
android:padding="3dip"
android:layout_alignParentLeft="true"
android:layout_width="#dimen/img_side"
android:layout_height="#dimen/img_side" />
<TextView
android:id="#+id/item_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="#+id/item_image"
android:layout_centerVertical="true"
android:textColor="#color/black"
android:textSize="#dimen/textnorm"
/>
</RelativeLayout>
Remember that your list row layout is more simple then your listview will scroll faster, smooth and prevent some annoying bug.
Hope this help
I have this items.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal" android:layout_width="match_parent"
android:focusable="true"
android:clickable="true"
android:background="?android:attr/selectableItemBackground"
android:layout_height="wrap_content">
<ImageView
android:layout_width="match_parent"
android:layout_height="60dp"
android:id="#+id/colorPreview" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:textAppearance="#android:style/TextAppearance.Large"
android:textColor="#android:color/white"
android:id="#+id/colorName" />
</RelativeLayout>
When I use it separately, the selectableItemBackground animates when I click the view. But when I use it for the items in a RecyclerView, the effect on click does not happen anymore. How can I fix this?
PS: this is the listener on the RecyclerView, if it is relevant:
public ColorListOnItemTouchListener(Context context, OnItemClickListener clickListener) {
mClickListener = clickListener;
mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
#Override
public boolean onDown(MotionEvent e) {
return true;
}
#Override
public void onLongPress(MotionEvent e) {
if(childView != null && mClickListener != null) {
mClickListener.onItemLongPress(childView, index);
}
}
#Override
public boolean onSingleTapUp(MotionEvent e) {
if(childView != null && mClickListener != null) {
mClickListener.onItemClick(childView, index);
}
return true;
}
#Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
return false;
}
});
}
Thank you!
Edit:
public class ColorsCursorAdapter extends RecyclerView.Adapter<ColorsCursorAdapter.ViewHolder> {
private static final int layout = R.layout.color_item;
private Cursor mCursor;
public ColorsCursorAdapter(Cursor c) {
super();
this.mCursor = c;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(layout, parent, false);
TextView name = (TextView) v.findViewById(R.id.colorName);
ImageView image = (ImageView) v.findViewById(R.id.colorPreview);
return new ViewHolder(v, name, image);
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
mCursor.moveToPosition(position);
int color = mCursor.getInt(mCursor.getColumnIndex(ColorItem.COLUMN_COLOR));
holder.colorName.setText(Utils.getColorString(color));
holder.colorPreview.setImageDrawable(new ColorDrawable(color));
}
#Override
public int getItemCount() {
if(mCursor != null) {
return mCursor.getCount();
}
return 0;
}
public void swapCursor(Cursor c) {
mCursor = c;
notifyDataSetChanged();
}
public Cursor getCursor() {
return mCursor;
}
public static class ViewHolder extends RecyclerView.ViewHolder {
public TextView colorName;
public ImageView colorPreview;
public ViewHolder(View root, TextView colorName, ImageView colorPreview) {
super(root);
root.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//
}
});
this.colorName = colorName;
this.colorPreview = colorPreview;
}
}
}
And the adapter is created with:
colorList.setLayoutManager(new LinearLayoutManager(this));
adapter = new ColorsCursorAdapter(null);
colorList.setAdapter(adapter);
Something that was not mentioned in other answers: setting android:clickable="true" is required in order to make the animations work when there is no OnClickListener attached to the view.
Instead of setting it as background, I set it as foreground, it works. Hope it would helpful.
android:foreground="?attr/selectableItemBackground"
In your items.xml, set FrameLayout as the root layout and set selectableItemBackground for FrameLayout. It works for me, but I do not know why.
<?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="wrap_content"
android:foreground="?android:selectableItemBackground">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!-- your code -->
</RelativeLayout>
</FrameLayout>
View that you want to have ripple effect has to be clickable. You can either do that by specifying android:clickable="true" in XML file or setting onClickListener programmatically. When you are using this on item inside RecyclerView and you are using Kotlin set onClickListener on "itemView" from ViewHolder class.
I have seen the same behavior. On my side it was related to the fact that when I clicked a list item within a fragment and directly replacing that fragment with another, the animation hadn't no time to be shown. As soon as I removed the fragment replacement, I could see the animation.
#Override
public boolean onSingleTapUp(MotionEvent e) {
if(childView != null && mClickListener != null) {
mClickListener.onItemClick(childView, index);
}
return true;
}
Return false might fix this issue. For me, I was overriding onTouch on my button and returning true at the end. Returning false enabled the touch animation to happen from setting:
android:background="?attr/selectableItemBackground"
In my case the problem was caused by DividerItemDecoration. As soon as I got rid of that, it started to work. I suggest to put a line at the end of xml file for each item in RecyclerView, it's much easier to customize and you won't run into these kinds of problems.
No one of the previous solutions worked for me.
Finally I had to implement my own drawable for that, and its work like the provided by Android.
Create a new drawable:
res/drawable/selectable_item_background.xml
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#color/colorAccent">
<item
android:id="#android:id/mask"
android:drawable="#android:color/white" />
</ripple>
Use it in you cell:
Just like you used the Android drawable
android:background="#drawable/selectable_item_background"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/selectable_item_background"
android:clickable="true"
android:orientation="vertical">
...
For more info, or implementation for versions before API 21. Take a look to this post.
I have this xml code for a list view:
<ListView
android:id="#android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#+id/searchView"
android:background="#drawable/list_selector"
android:choiceMode="singleChoice" />
This is the list_selector drawable:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"
android:exitFadeDuration="#android:integer/config_shortAnimTime">
<item android:drawable="#drawable/button_pressed" android:state_activated="true"/>
</selector>
And the list_view has a checkedTextView as each item as follows:
<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/checkList"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:checkMark="?android:attr/listChoiceIndicatorMultiple"
android:gravity="center_vertical"
android:orientation="vertical"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="#color/white"
android:paddingLeft="6dip" />
There are two problems with this setup.
1.) I can check the box next to each item but I cant uncheck it.
2.) Before I implemented the checkbox, the list selector makes the item go bluish when you select it, now when you select the item, the list_selector doesnt do anything, only the checkbox becomes ticked.
So is there anyway to be able to solve 1. and make it so as, I have to click just the checkbox to tick/untick it and when I click anywhere else within the listview item, list_selector comes into play?
EDIT: My custom adapter: Also, I have solved the marking/unmarking. It Works. The only problem now is 2.) as above!
public class ContactsAdapter extends BaseAdapter {
private List<Contact> mData;
private LayoutInflater mInflater;
private Context context;
public ContactsAdapter(List<Contact> mData, Context context) {
this.mData = mData;
this.context = context;
mInflater = LayoutInflater.from(context);
}
#Override
public int getCount() {
return mData.size();
}
#Override
public String getItem(int position) {
switch (context.getSharedPreferences("settings",
HomeScreenActivity.MODE_PRIVATE).getInt("displayChoice", -1)) {
case 1:
return mData.get(position).getLastName() + " "
+ mData.get(position).getFirstName();
case 2:
return mData.get(position).getFirstName() + " "
+ mData.get(position).getMobileNumber();
case 3:
return mData.get(position).getLastName() + " "
+ mData.get(position).getMobileNumber();
default:
return mData.get(position).getFirstName() + " "
+ mData.get(position).getLastName();
}
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
CheckedTextView result;
if (convertView == null) {
result = (CheckedTextView) mInflater.inflate(
R.layout.home_screen_contacts_view, parent, false);
} else {
result = (CheckedTextView) convertView;
}
final String contactRow = getItem(position);
result.setText(contactRow);
result.setBackgroundResource(R.drawable.list_selector);
return result;
}
}