Java 为不同的列表视图项选择不同的颜色

Java 为不同的列表视图项选择不同的颜色,java,android,listview,user-interface,Java,Android,Listview,User Interface,我有以下要求: 不同列表视图项的不同颜色 在代码中动态指定颜色 仅当按下/选择列表视图项时,才应显示颜色 列表视图项的颜色不应永久更改 不管出于什么原因,它似乎不像我想的那样直截了当。唯一朝着正确方向发展的解决方案是: 需要注意的是,这不会更改on select颜色,而是永久性地更改背景颜色,并且如果向下滚动一点,它已经更改列表视图项目的背景颜色 我怎样才能做到这一点?我建议采用以下方法: 您需要创建一个支持多个不同项目的列表视图适配器 每个不同的Item类表示不同的颜色,可以有自己的实现

我有以下要求:

  • 不同列表视图项的不同颜色
  • 在代码中动态指定颜色
  • 仅当按下/选择列表视图项时,才应显示颜色
  • 列表视图项的颜色不应永久更改
不管出于什么原因,它似乎不像我想的那样直截了当。唯一朝着正确方向发展的解决方案是:

需要注意的是,这不会更改on select颜色,而是永久性地更改背景颜色,并且如果向下滚动一点,它已经更改列表视图项目的背景颜色


我怎样才能做到这一点?

我建议采用以下方法:

  • 您需要创建一个支持多个不同项目的
    列表视图
    适配器
  • 每个不同的Item类表示不同的颜色,可以有自己的实现来处理按下或选定状态
  • 因为每个
    ListItem
    都有自己的.xml布局文件,所以您可以在那里指定所需的选择器
您需要的:

  • 列表视图中的每个项继承自的基类
    列表项
  • 此类提供抽象方法来获取表示项及其类型的
    视图
  • 如果需要,
    ListItem
    类可以有一个
    Integer
    字段mColor,该字段保存项目表示的颜色
  • 如果需要,
    ListItem
    类可以有一个方法来设置具有特定颜色的选择器
例如:

public abstract class ListItem {

    public static final int TYPE_WHATEVER_1                     = 0;
    public static final int TYPE_WHATEVER_2                     = 1;
    // and so on...

    /** the total number of list-item-types */
    public static final int TYPE_COUNT              = typecounthere;

    // if required for your implementation:
    protected int mColor;

    public abstract int getViewType();
    public abstract View getView(LayoutInflater inflater, View convertView);

    /** creates and sets the selector with your specified color */
    public void setupSelectorColor() {

        StateListDrawable states = new StateListDrawable();

        ColorDrawable cdPressed = new ColorDrawable(mColor);
        ColorDrawable cdSelected = new ColorDrawable(mColor);
        ColorDrawable cdDefault = new ColorDrawable(Color.TRANSPARENT);

        states.addState(new int[] {
                android.R.attr.state_pressed
        },
                cdPressed);
        states.addState(new int[] { 
                android.R.attr.state_selected
        },
                cdSelected);
        states.addState(new int[] {},
                cdDefault);

        setBackgroundDrawable(states);
    }
}
public class ItemTypeOne extends ListItem {

    public ItemTypeOne(int color) {
        mColor = color;
    }

    @Override
    public int getViewType() {
            // return the type
        return TYPE_WHATEVER_1;
    }

    @Override
    public View getView(LayoutInflater inflater, View convertView) {

        if(convertView == null) {
            // inflate the layout 
            convertView = inflater.inflate(R.layout.item_type_one, null);
        }    

        // setup the selector
        setupSelectorColor();

        // do other stuff

        return convertView;
    }
}
public class ListItemAdapter extends ArrayAdapter<ListItem> {

    public ListItemAdapter(Context context, List<ListItem> objects) {
        super(context, 0, objects);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        return getItem(position).getView(LayoutInflater.from(getContext()), convertView);
    }

    @Override
    public int getItemViewType(int position) {
        return getItem(position).getViewType();
    }

    @Override
    public int getViewTypeCount() {
        return ListItem.TYPE_COUNT;
    }
}
  • 对于每种颜色,创建一个子类
    ListItem
  • getView(…)
    方法中,膨胀所需的布局
  • 不要忘记在
    getViewType()
    方法中返回正确的类型
  • 你想在这里用你的颜色做什么都行
  • 使用您的颜色设置选择器
例如:

public abstract class ListItem {

    public static final int TYPE_WHATEVER_1                     = 0;
    public static final int TYPE_WHATEVER_2                     = 1;
    // and so on...

    /** the total number of list-item-types */
    public static final int TYPE_COUNT              = typecounthere;

    // if required for your implementation:
    protected int mColor;

    public abstract int getViewType();
    public abstract View getView(LayoutInflater inflater, View convertView);

    /** creates and sets the selector with your specified color */
    public void setupSelectorColor() {

        StateListDrawable states = new StateListDrawable();

        ColorDrawable cdPressed = new ColorDrawable(mColor);
        ColorDrawable cdSelected = new ColorDrawable(mColor);
        ColorDrawable cdDefault = new ColorDrawable(Color.TRANSPARENT);

        states.addState(new int[] {
                android.R.attr.state_pressed
        },
                cdPressed);
        states.addState(new int[] { 
                android.R.attr.state_selected
        },
                cdSelected);
        states.addState(new int[] {},
                cdDefault);

        setBackgroundDrawable(states);
    }
}
public class ItemTypeOne extends ListItem {

    public ItemTypeOne(int color) {
        mColor = color;
    }

    @Override
    public int getViewType() {
            // return the type
        return TYPE_WHATEVER_1;
    }

    @Override
    public View getView(LayoutInflater inflater, View convertView) {

        if(convertView == null) {
            // inflate the layout 
            convertView = inflater.inflate(R.layout.item_type_one, null);
        }    

        // setup the selector
        setupSelectorColor();

        // do other stuff

        return convertView;
    }
}
public class ListItemAdapter extends ArrayAdapter<ListItem> {

    public ListItemAdapter(Context context, List<ListItem> objects) {
        super(context, 0, objects);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        return getItem(position).getView(LayoutInflater.from(getContext()), convertView);
    }

    @Override
    public int getItemViewType(int position) {
        return getItem(position).getViewType();
    }

    @Override
    public int getViewTypeCount() {
        return ListItem.TYPE_COUNT;
    }
}
  • 支持不同项类型的适配器
例如:

public abstract class ListItem {

    public static final int TYPE_WHATEVER_1                     = 0;
    public static final int TYPE_WHATEVER_2                     = 1;
    // and so on...

    /** the total number of list-item-types */
    public static final int TYPE_COUNT              = typecounthere;

    // if required for your implementation:
    protected int mColor;

    public abstract int getViewType();
    public abstract View getView(LayoutInflater inflater, View convertView);

    /** creates and sets the selector with your specified color */
    public void setupSelectorColor() {

        StateListDrawable states = new StateListDrawable();

        ColorDrawable cdPressed = new ColorDrawable(mColor);
        ColorDrawable cdSelected = new ColorDrawable(mColor);
        ColorDrawable cdDefault = new ColorDrawable(Color.TRANSPARENT);

        states.addState(new int[] {
                android.R.attr.state_pressed
        },
                cdPressed);
        states.addState(new int[] { 
                android.R.attr.state_selected
        },
                cdSelected);
        states.addState(new int[] {},
                cdDefault);

        setBackgroundDrawable(states);
    }
}
public class ItemTypeOne extends ListItem {

    public ItemTypeOne(int color) {
        mColor = color;
    }

    @Override
    public int getViewType() {
            // return the type
        return TYPE_WHATEVER_1;
    }

    @Override
    public View getView(LayoutInflater inflater, View convertView) {

        if(convertView == null) {
            // inflate the layout 
            convertView = inflater.inflate(R.layout.item_type_one, null);
        }    

        // setup the selector
        setupSelectorColor();

        // do other stuff

        return convertView;
    }
}
public class ListItemAdapter extends ArrayAdapter<ListItem> {

    public ListItemAdapter(Context context, List<ListItem> objects) {
        super(context, 0, objects);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        return getItem(position).getView(LayoutInflater.from(getContext()), convertView);
    }

    @Override
    public int getItemViewType(int position) {
        return getItem(position).getViewType();
    }

    @Override
    public int getViewTypeCount() {
        return ListItem.TYPE_COUNT;
    }
}
公共类ListItemAdapter扩展了ArrayAdapter{
公共ListItemAdapter(上下文、列表对象){
超级(上下文,0,对象);
}
@凌驾
公共视图getView(int位置、视图转换视图、视图组父视图){
返回getItem(position).getView(LayoutInflater.from(getContext()),convertView);
}
@凌驾
public int getItemViewType(int位置){
返回getItem(position).getViewType();
}
@凌驾
public int getViewTypeCount(){
返回ListItem.TYPE\u计数;
}
}
总而言之:

ArrayList<ListItem> list = new ArrayList<ListItem>();
// fill the list
list.add(new ItemTypeOne(somecolor));
list.add(new ItemTypeTwo(somecolor));
list.add(new ItemTypeOne(somecolor));
list.add(new ItemTypeWhatever(somecolor));

ListView lv = (ListView) v.findViewById(R.id.listView1);

ListItemAdapter a = new ListItemAdapter(Context, list);         
lv.setAdapter(a);
ArrayList list=new ArrayList();
//填写清单
添加(新的ItemTypeOne(somecolor));
添加(新的ItemTypeTwo(somecolor));
添加(新的ItemTypeOne(somecolor));
添加(新的ItemTypeWhatever(somecolor));
ListView lv=(ListView)v.findViewById(R.id.listView1);
ListItemAdapter a=新的ListItemAdapter(上下文,列表);
低压设置适配器(a);

关于
自定义视图
选择器及其行为,我建议阅读此问题(并回答):

我要说的是,不要将其过分复杂化。它可以简单地创建一个包含可能颜色的
int
数组,并使用
Random
类将它们设置为每个项目

// This goes inside hosting fragment or activity
listview.setOnItemClickListner( new OnItemClickListener() {
      @Override
      public void onItemClick(AdapterView parent, View view, int position, long id) {
           if(view.isSelected()){
               view.setSelected(false);
               // also maybe change bg color back to normal?
           }

           else {
                // This one for always a different color
                view.setBackgroundColor(adapter.getColor());

                // This is for foreground color change instead of background
                FrameLayout frameLayout = (FrameLayout) view.findViewById(R.id.my_frame_layout);

                final Drawable drawable = new ColorDrawable( /*  your getColor() function  */ );
                frameLayout.setForeground(drawable);

                // This one for alwyas the same color for the row at position given by {@param position}
                view.setBackgroundColor(adapter.getColor(position));
                view.setSelected(true);
           }
      }
});



// All this goes inside your custom listview Adapter
int[] colors = {
      R.colors.red,
      R.colors.blue,
      ...
}

Random random = new Random();

// If each time the selection will bring a different color, use this implementation
public int getColor() {
    return colors[random.nextInt(colors.length)]; 
}

// If each row should have different color, but always the same color for a row then use this one instead
SparseIntArray spa = new SparseIntArray();
public int getColor(int position) {
     if(spa.get(position) == 0) {
         // the color hasnt been created for that row yet
         spa.put(position, colors[random.nextInt(colors.length)];
     }

     return spa.get(position);     
}
**编辑:**现在,如果您想要的是前景选择,那么您的行应该有一个
FrameLayout
容器,并且您应该更改它的“安卓:前景”属性:

final Drawable drawable = new ColorDrawable( /*  your getColor() function  */ );
frameLayout.setForeground(drawable);
我得说跟我一起去。为单个ListView的背景颜色创建一个状态感知的可绘制XML文件。下面是一个名为background_black.xml和background_green.xml的状态感知可绘制文件的示例。它们使默认背景色变为白色,并在按下/选择时将其临时更改为黑色或绿色。这两个文件都放在您的Drawable文件夹中

background\u black.xml


background\u green.xml


在ListView项xml文件中,为根布局或提供可见背景色的任何元素指定一个ID。对于这个例子,我假设它是您的根布局。然后在适配器的getView()中,抓取已为其分配id的元素,并将您创建的其中一个可绘制项设置为所需的背景颜色。像这样:

@Override
public View getView(int position, View convertView, ViewGroup parent){
     //inflate your convertView, etc...
     ...
     ViewGroup baseLayout = (ViewGroup)convertView.findViewById(R.id.<your base layout id>);

     //these conditions need to reflect how you decide which list item gets which color
     if(position % 2 == 0){
         baseLayout.setBackground(R.drawable.background_black);
     } else {
         baseLayout.setBackground(R.drawable.background_green);
     //do whatever else you need
     ...
     return convertView;
}
@覆盖
公共视图getView(int位置、视图转换视图、视图组父视图){
//膨胀你的视野,等等。。。
...
ViewGroup baseLayout=(ViewGroup)convertView.findViewById(R.id.);
//这些条件需要反映您如何决定哪个列表项获得哪个颜色
如果(位置%2==0){
底座布局。立根台(右拉深。背景为黑色);
}否则{
基础布局。立根背景(右侧可拉深。背景为绿色);
//你还需要什么就做什么
...
返回视图;
}

注意:setBackground()是一个新函数,如果为旧版本的Android编码,请使用setBackgroundDrawable()。这里的困难在于按下/选中的颜色是动态的。您不能使用静态xml颜色状态列表。但您可以通过代码创建。下面是如何做到这一点

您只需实现ListAdapter:

private class MyListAdapter implements ListAdapter{

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if(convertView!=null){
             CheckedTextView textView = (CheckedTextView)convertView;
             textView.setText("the text for item "+position);
             textView.setTextColor(makeColorStateListForItem(position));
             return textView;
        }else{
             CheckedTextView textView = new CheckedTextView(parent.getContext());
             textView.setText("the text for item "+position);
             textView.setTextColor(makeColorStateListForItem(position));
             return textView;
        }
    }

    private ColorStateList makeColorStateListForItem(int position){
        int pressedColor = pressedColorForItem(position);
        int checkedColor = checkedColorForItem(position);
        int defaultColor = defaultColorForItem(position);
        ColorStateList colorStateList = new ColorStateList(
                new int[][]{
                        new int[]{android.R.attr.state_pressed},
                        new int[]{android.R.attr.state_checked},
                        new int[]{0},
                },
                new int[]{
                        pressedColor, //use when state is pressed
                        checkedColor, //use when state is checked, but not pressed
                        defaultColor}); //used when state is not pressed, nor checked 
    }

    private int pressedColorForItem(int position){
        //write your business logic to determine color here
        return ...;
    }

    private int checkedColorForItem(int position){
        //write your business logic to determine color here
        return ...;
    }

    private int defaultColorForItem(int position){
        return Color.WHITE;
    }

    //all other adapter methods
    //...
请注意,使用选中的
android.R.attr.state\u
而不是更直观的
android.R.attr.state\u选择的
,因为
state\u selected
不是用触摸屏非常精确地定义的(即,state\u selected可以在模拟器上给出预期的行为,但在真实设备上可能会失败)

另一方面,
state\u checked
+将在模拟器和真实设备上正常工作

什么时候打电话