Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Alternate background color for ListView class even without data

I want to set an alternating color for my custom ListView class.

The code is given below:

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ListView;

   public class CustomListView extends ListView {
    private Paint   mPaint              = new Paint();
    private Paint   mPaintBackground    = new Paint();

    public CustomListView(Context context, AttributeSet attrs) {
        super(context, attrs);

        mPaint.setColor(Color.parseColor("#1A000000"));

    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        super.dispatchDraw(canvas);
        final int currentHeight = getMeasuredHeight();

        final View lastChild = getChildAt(getChildCount() - 1);
        if (lastChild == null)
            return;
        for (int i = 0; i < getChildCount(); i++) {
            if (getChildCount() % 2 == 0) {
                mPaintBackground.setColor(Color.WHITE);
            } else {
                mPaintBackground.setColor(Color.RED);
            }
        }

        final int lastChildBottom = lastChild.getBottom();

        final int lastChildHeight = lastChild.getMeasuredHeight();

        final int nrOfLines = (currentHeight - lastChildBottom) / lastChildHeight;

        Rect r = new Rect(0, lastChildBottom, getMeasuredWidth(), getMeasuredHeight());
        canvas.drawRect(r, mPaintBackground);
        canvas.drawLine(0, lastChildBottom, getMeasuredWidth(), lastChildBottom, mPaint);
        for (int i = 0; i < nrOfLines; i++) {
            canvas.drawLine(0, lastChildBottom + (i + 1) * lastChildHeight, getMeasuredWidth(), lastChildBottom + (i + 1) * lastChildHeight, mPaint);
        }
        return;
    }
    }

To get an alternating background color for ListView, I have used this code:

for (int i = 0; i < getChildCount(); i++) {
   if (getChildCount() % 2 == 0) {
      mPaintBackground.setColor(Color.WHITE);
   } else {
      mPaintBackground.setColor(Color.RED);
   }
}

Inside of the adapter:

    if (position % 2 == 0) {
        view.setBackgroundColor(Color.RED);
    } else {
        view.setBackgroundColor(Color.WHITE);
    }

But it always shows one color, red or white with everything I try. I am not getting alternating colors white-red-white-red.

like image 573
Piyush Avatar asked Aug 10 '15 11:08

Piyush


2 Answers

The reason this is failing is because your for loop never changes. You are always checking getChildCount() % 2. getChildCount() will return the same for each iteration. You need to do your check based on position:

for(int i = 0; i < getChildCount(); i++){
   if(i % 2 == 0){
      mPaintBackground.setcolor(Color.WHITE);
   } else{
      mPaintBackground.setColor(Color.RED);
   }
}

If it helps, rename your counter variable from i to position so that this will be more readable for you in the future, or make a note of it to help yourself out.

I would also like to add that, given the code you have now, your for loop isn't changing anything. It is just iterating through the number of children and setting mPaintBackground. In the end, it will be left with whatever value it receives from the last iteration.

I think the best way to handle drawing the background color would be in the adapter for the Listview, in which case you can override getView() and do a check based on the position parameter:

int backgroundResource;
if(position % 2 == 0){
   backgroundResource = getResources.getColor(android.R.color.WHITE);
} else{
   backgorundResource = getResources.getColor(android.R.color.RED);
}
view.setBackground(backgroundResource);

Of course, the above is just pseudocode, it may need to be adjusted to your project.


The above solution will work only for existing data. If you need an alternating color regardless of whether or not there is data, which if I understand now is what you were trying to achieve in dispatchDraw. I will be very honest that I am not 100% sure how to do this, and I cannot test it, but I imagine the steps going like this:

  • Get the height of the ListView
  • Get the width of the ListView
  • Get the height of one child (listPreferredItemHeight, if you use that. If you use wrap content, this might be trickier because you cannot predict the size of the items, so alternating colors for an empty ListView would be difficult).
  • While there is space left in the ListView, draw a rectangle.

Note here that you cannot iterate based on number of children, because you might not have any at this point.

Pseudocode:

listViewWidth = getMeasuredWidth();
listViewHeight = getMeasuredHeight();
numChildren = getChildCount();
itemHeight = getItemHeight(); // See comments above, adjust this for your problem.
currentTop = 0; // Used to keep track of the top of the rectangle we are drawing.
currentBottom = itemHeight; // Used to keep track of the bottom rectangle we are currently drawing.

int currentRectangle = 0;
while(currentBottom <= listViewHeight){
   if(currentRectangle  % 2 == 0){
      mPaintBackground.setColor(Color.WHITE);
   } else{
      mPaintBackground.setColor(Color.RED);
   }

   Rect r = new Rect(0, currentBottom, getMeasuredWidth(), getMeasuredHeight());
   canvas.drawRect(r, mPaintBackground);

   // Move to next
   currentTop += itemHeight;
   currentBottom += itemHeight;
   currentRectangle++;
}
like image 90
AdamMc331 Avatar answered Oct 21 '22 07:10

AdamMc331


Finally I got my answer with the huge help of @McAdam331. After using his code i got some weird thing but after that i have repaired code using this one

        int listViewHeight = getMeasuredHeight();
        int itemHeight = lastChild.getMeasuredHeight();
        int currentTop = 0;
        int currentBottom = lastChild.getBottom();

        int currentRectangle = 0;
        while (currentBottom <= listViewHeight) {
            if (currentRectangle % 2 == 0) {
                mPaintBackground.setColor(Color.WHITE);
            } else {
                mPaintBackground.setColor(Color.parseColor("#f7f7f7"));
            }

            Rect r = new Rect(0, currentBottom, getMeasuredWidth(), getMeasuredHeight());
            canvas.drawRect(r, mPaintBackground);

            // Move to next
            currentTop += itemHeight;
            currentBottom += itemHeight;
            currentRectangle++;
        }
like image 43
Piyush Avatar answered Oct 21 '22 08:10

Piyush