Альтернативный цвет фона для класса ListView, даже без данных
Я хочу установить переменный цвет для моего настраиваемого класса 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);
}
Но он всегда показывает один цвет, красный или белый со всем, что я пытаюсь. Я не получаю чередующихся цветов бело-красно-бело-красного.
Ответы
Ответ 1
Причина, по которой это происходит, заключается в том, что цикл for никогда не изменяется. Вы всегда проверяете getChildCount() % 2
. getChildCount()
вернет то же самое для каждой итерации. Вам нужно сделать чек в зависимости от позиции:
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++;
}
Ответ 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++;
}
Ответ 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() вызывается в каждой строке для рендеринга.
Ваш текущий подход просто вызовет функцию один раз, и вы не добьетесь желаемого результата.
Ответ 4
Вы можете создать тот же эффект для Listview
, просто создав пользовательский Adapter
:
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
...
}
}