Search code examples
androidlistviewcustom-adapter

Highlight effect while pressing item in custom ListView adapter


There's a system visual effect everytime you click a view in Android. In Lollipop it's the ripple effect. When I created a ListView and associated it to an ordinary ArrayAdapter, this effect was present. Now that I've added a custom ListView, this effect is lost.

Now, I've tried to isolate what the problem is, and since using the same list item layout with a default adapter worked nicely, I would say that the problem is on my custom adapter.

I've seen many solutions related to this case that just implemented the ripple effect calling some drawables; this is not what I'm trying to do. The ripple effect shows only because I'm running the app on Android 5, now what I want to do is to have the default system highlight effect for my items when they're being clicked.

Here are the (hopefully) related pieces of my custom adapter:

public class CustomCardSetsAdapter extends BaseAdapter {
    List<Card> totalList;
    ArrayList<Boolean> hiddenItems;
    ListView parentLV;
    Integer curPosition = -1;

    public static int selectedRowIndex;

    public CustomCardSetsAdapter(CardSets cardList, ListView parentListView)
    {
        this.parentLV = parentListView;
        assignSetValues(cardList);

        totalList =      cardList.getBlackrockMountain();
        totalList.addAll(cardList.getClassic());
        totalList.addAll(cardList.getCurseofNaxxramas());
        totalList.addAll(cardList.getGoblinsvsGnomes());

        Collections.sort(totalList,
                new Comparator<Card>() {
                    public int compare(Card f1, Card f2) {
                        return f1.toString().compareTo(f2.toString());
                    }
                });

        hiddenItems = new ArrayList<>();

        for (int i = 0; i < totalList.size(); i++) {
            if(!totalList.get(i).getCollectible())
                hiddenItems.add(true);
            else
                hiddenItems.add(false);
        }
    }

    @Override
    public int getCount() {
        return (totalList.size() - getHiddenCount());
    }

    @Override
    public View getView(final int position, View convertView, final ViewGroup parent) {
        final int index = getRealPosition(position);

        if(convertView == null) {
            LayoutInflater inflater = LayoutInflater.from(parent.getContext());
            convertView = inflater.inflate(R.layout.card_list_item, parentLV, false);
        }

        convertView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Integer prevPosition = curPosition;
                curPosition = position;

                if(prevPosition >= parentLV.getFirstVisiblePosition() &&
                        prevPosition <= parentLV.getLastVisiblePosition())
                {
                    View view = parentLV.getChildAt(prevPosition- parentLV.getFirstVisiblePosition());
                    parentLV.getAdapter().getView(prevPosition,view, parentLV);
                }

                v.setBackgroundColor(Color.WHITE);
            }
        });


        Card curCard = totalList.get(index);

        TextView cardName = (TextView) convertView.findViewById(R.id.cardName);
        cardName.setText(curCard.getName());
        setRarityColor(curCard,cardName);

        TextView manaCost = (TextView) convertView.findViewById(R.id.manaCost);
        manaCost.setText((curCard.getCost()).toString());

        ImageView setIcon = (ImageView) convertView.findViewById(R.id.setIcon);
        setSetIcon(curCard,setIcon);

        if(position == curPosition)
            convertView.setBackgroundColor(Color.WHITE);
        else
            convertView.setBackgroundColor(Color.TRANSPARENT);

        return convertView;
    }

    @Override
    public int getItemViewType(int position) {
        return R.layout.card_list_item;
    }

    @Override
    public int getViewTypeCount() {
        return 1;
    }

    @Override
    public boolean isEmpty() {
        return false;
    }

    private int getHiddenCount()
    {
        int count = 0;
        for(int i = 0;i <totalList.size();i++)
            if(hiddenItems.get(i))
                count++;
        return count;
    }

    private int getRealPosition(int position) {
        int hElements = getHiddenCountUpTo(position);
        int diff = 0;
        for(int i=0;i<hElements;i++) {
            diff++;
            if(hiddenItems.get(position+diff))
                i--;
        }
        return (position + diff);
    }

    private int getHiddenCountUpTo(int location) {
        int count = 0;
        for(int i=0;i<=location;i++) {
            if(hiddenItems.get(i))
                count++;
        }
        return count;
    }
}

Thanks in advance.


Solution

  • in your ListView XML, add:

     android:drawSelectorOnTop="true"
    

    I also think you are using your adapter wrong...

    Use the ViewHolder Pattern on your Adapter:

    public class CustomCardSetsAdapter extends BaseAdapter {
        List<Card> totalList;
        ArrayList<Boolean> hiddenItems;
        ListView parentLV;
        Integer curPosition = -1;
        public static int selectedRowIndex;
    
        private class ViewHolderRow{
            TextView cardName;
            TextView manaCost;
            ImageView setIcon;
        }
    
    
    
       public CustomCardSetsAdapter(CardSets cardList, ListView parentListView)
       {
           this.parentLV = parentListView;
           assignSetValues(cardList);
    
           totalList =      cardList.getBlackrockMountain();
           totalList.addAll(cardList.getClassic());
           totalList.addAll(cardList.getCurseofNaxxramas());
           totalList.addAll(cardList.getGoblinsvsGnomes());
    
           Collections.sort(totalList,
                new Comparator<Card>() {
                    public int compare(Card f1, Card f2) {
                        return f1.toString().compareTo(f2.toString());
                    }
                });
    
           hiddenItems = new ArrayList<>();
    
           for (int i = 0; i < totalList.size(); i++) {
               if(!totalList.get(i).getCollectible())
                   hiddenItems.add(true);
               else
                   hiddenItems.add(false);
           }
        }
    
        @Override
        public int getCount() {
            return (totalList.size() - getHiddenCount());
        }
    
        @Override
        public View getView(final int position, View convertView, final ViewGroup parent) {
            final int index = getRealPosition(position);
             ViewHolderRow theRow;
            if(convertView == null) {
               theRow = new ViewHolderRow();
               LayoutInflater inflater = LayoutInflater.from(parent.getContext());
                convertView = inflater.inflate(R.layout.card_list_item, parentLV, false);
    
                // Cache your views
                theRow.cardName = (TextView) convertView.findViewById(R.id.cardName);
                theRow.manaCost = (TextView) convertView.findViewById(R.id.manaCost);
                theRow.setIcon = (ImageView) convertView.findViewById(R.id.setIcon);
    
                // Set the Tag to the ViewHolderRow
                convertView.setTag(theRow);
            }else{
               // get the Row to re-use
               theRow = (ViewHolderRow) convertView.getTag();
            }
    
        //... Removed convertView.setOnClickListener  
    
        Card curCard = totalList.get(index);
    
        // Set Items
        theRow.cardName.setText(curCard.getName());
        setRarityColor(curCard,theRow.cardName);
        theRow.manaCost.setText((curCard.getCost()).toString());
        setSetIcon(curCard,theRow.setIcon);
    
           if(position == curPosition){
                convertView.setBackgroundColor(Color.WHITE);
           }else{
                convertView.setBackgroundColor(Color.TRANSPARENT);
           }
    
            return convertView;
        }
    
        @Override
        public int getItemViewType(int position) {
            return R.layout.card_list_item;
        }
    
        @Override
        public int getViewTypeCount() {
            return 1;
        }
    
        @Override
        public boolean isEmpty() {
            return false;
        }
    
        private int getHiddenCount()
        {
            int count = 0;
            for(int i = 0;i <totalList.size();i++)
                if(hiddenItems.get(i))
                    count++;
             return count;
        }
    
        private int getRealPosition(int position) {
            int hElements = getHiddenCountUpTo(position);
            int diff = 0;
            for(int i=0;i<hElements;i++) {
                diff++;
                if(hiddenItems.get(position+diff))
                    i--;
            }
            return (position + diff);
        }
    
        private int getHiddenCountUpTo(int location) {
           int count = 0;
           for(int i=0;i<=location;i++) {
                 if(hiddenItems.get(i))
                    count++;
                 }
               return count;
         }
    }
    

    Set an onListItemClickListener instead of using this on the entire convertView...

    yourListView.setOnItemClickListener(ListListener);
    
    
    private final OnItemClickListener ListListener = new OnItemClickListener{
        @Override
        public void onItemClick(AdapterView<?> arg0, View view, int position, long arg3)     {
              // ... Do something on click       
        }
    }