【问题标题】:Alternate background color for ListView class even without data即使没有数据,ListView 类的备用背景颜色
【发布时间】:2015-08-10 11:11:39
【问题描述】:

我想为我的自定义 ListView 类设置交替颜色。

代码如下:

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;
    }
    }

为了获得ListView 的交替背景颜色,我使用了以下代码:

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

适配器内部:

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

但它总是显示一种颜色,红色或白色与我尝试的一切。我没有得到白色-红色-白色-红色交替的颜色。

【问题讨论】:

  • 你使用了错误的方法来达到你的结果。 dispatchDraw 方法只被调用一次。对于每个项目都调用的这种行为,您应该使用 getView 方法。 @faizan 提出了正确的解决方案
  • 哦。真的吗 ?那会怎么样呢?
  • 查看完整评论。
  • @SAIR 你检查过我编辑过的问题吗?我还发布了我的适配器代码。!
  • 适配器代码只有在有数据时才会起作用。如果你想在没有数据的情况下为整个 ListView 交替颜色,则必须在 dispatchDraw 中完成。我现在正在尝试编辑我的答案。

标签: android listview


【解决方案1】:

失败的原因是你的 for 循环永远不会改变。你总是在检查getChildCount() % 2getChildCount() 将为每次迭代返回相同的值。您需要根据职位进行检查:

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

如果有帮助,请将您的计数器变量从 i 重命名为 position,以便将来对您更具可读性,或者记下它以帮助您自己。

我还想补充一点,鉴于您现在拥有的代码,您的 for 循环并没有改变任何东西。它只是遍历孩子的数量并设置mPaintBackground。最后,它将保留从上次迭代中接收到的任何值。

我认为处理绘制背景颜色的最佳方法是在 Listview 的适配器中,在这种情况下,您可以覆盖 getView() 并根据 position 参数进行检查:

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

当然,以上只是伪代码,可能需要根据你的项目进行调整。


上述解决方案仅适用于现有数据。如果无论是否有数据都需要交替颜色,如果我现在理解这就是您在dispatchDraw 中试图实现的目标。老实说,我不能 100% 确定如何执行此操作,也无法对其进行测试,但我想这些步骤是这样的:

  • 获取ListView的高度
  • 获取ListView的宽度
  • 获取一个孩子的高度(listPreferredItemHeight,如果你使用它。如果你使用包装内容,这可能会比较棘手,因为你无法预测项目的大小,所以为空的 ListView 交替颜色会很困难)。
  • 当 ListView 中还有空间时,绘制一个矩形。

请注意,您不能根据子代的数量进行迭代,因为此时您可能没有任何子代。

伪代码:

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++;
}

【讨论】:

  • 感谢您的快速回复。但如果我使用它,那么它只会显示白色。
  • @PiyushGupta 你在哪一行画背景?在您拥有的代码中,您似乎遍历并迭代了getChildCount(),但除了设置绘制背景颜色之外什么都不做,它将保留在最后一次迭代中给出的任何值。也许当您在适配器中调用getView() 时,您可以根据position 进行检查:developer.android.com/reference/android/widget/…, android.view.View, android.view.ViewGroup)
  • 是的,我正在检查它的位置。但至少如果数据可能是空的,那么 listView 将显示为具有交替的白红背景颜色。但它没有显示!
  • @PiyushGupta 你的 ListView 有适配器类吗?可以分享一下适配器代码吗?
  • 好的。感谢您的努力。让我检查一下。我会回复你的!!
【解决方案2】:

在@McAdam331 的大力帮助下,我终于得到了答案。使用他的代码后,我得到了一些奇怪的东西,但之后我用这个修复了代码

        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++;
        }

【讨论】:

  • 很高兴你得到这个工作,我更新了我的答案以反映正确的 Rect() 构造函数。
【解决方案3】:

逻辑上有一个小错误。 这是该部分的更新代码:

for (int i = 0; i < getChildCount(); i++) {
        if (i % 2 == 0) {
            view.setBackgroundColor(getResources.getColor(Color.WHITE));
        } else {
            view.setBackgroundColor(getResources.getColor(Color.RED));
        }
    }

检查应该在计数器控制变量上,getChildCount 将始终返回项目的总数,这就是为什么您总是看到相同的颜色。 上面粘贴的代码将解决您的问题。但是这段代码应该在你的适配器类的 getView() 中,因为在每一行上都会调用 getView() 函数进行渲染。 您当前的方法只会调用该函数一次,您将无法获得所需的结果。

【讨论】:

  • 我已经更新了答案。这段代码 sn-p 应该在适配器类的 getView() 中。您当前的代码 sn-p 与 listview 小部件相关,但您真正想要的是对 listview 行的自定义。
【解决方案4】:

您可以通过简单地创建自定义Adapter 来为Listview 创建相同的效果:

public class MyAlternateColorAdapter extends ArrayAdapter<SomeObject> {

    private Context context; //Get the Context from the constructor

    ...

    @Override 
    public View getView(int position, View convertView, ViewGroup parent) { 
        LayoutInflater inflater = (LayoutInflater) context .getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
        View rowView = inflater.inflate(R.layout.rowlayout, parent, false);

        if (position % 2 == 0) {
            rowView.setBackgroundColor(Color.RED); // Or use rowView.setBackgroundResource(R.drawable.bg_red); where bg_red is a drawable with a selector to provide touch feedback
        } else {
            rowView.setBackgroundColor(Color.WHITE);
        }
        // Set the data of the row
        ...
    }
}

【讨论】:

    猜你喜欢
    • 2012-09-29
    • 1970-01-01
    • 1970-01-01
    • 2011-09-05
    • 1970-01-01
    • 2019-11-02
    • 2023-03-06
    • 2011-10-13
    • 1970-01-01
    相关资源
    最近更新 更多