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

我有以下要求:

  • 不同的列表视图项目的不同颜色
  • 颜色在代码中动态指定
  • 只有在按下/选择列表视图项时才应显示颜色
  • 列表视图项的颜色不应永久更改

无论出于何种原因,似乎没有像我想象的那样直截了当。 唯一能够朝着正确方向发展的解决方案是: https : //stackoverflow.com/a/16978159/658718

需要注意的是,这不会更改选择颜色,但会永久更改背景颜色,如果向下滚动,它已经更改了列表视图项的背景颜色。

我该如何处理?

这里的难点在于压制/选中的颜色是动态的。 您不能使用静态xml color-state-list。 但您可以通过代码创建ColorStateList 。 这是怎么做的。

您只需要实现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_checked而不是更直观的android.R.attr.state_selected因为state_selected不是用触摸屏非常精确地定义的(即state_selected可以在模拟器上给出预期的行为,但是在真实设备它可能会失败)

另一方面, state_checked + CheckedTextView将在模拟器和真实设备上正常工作。

只需调用List.setChoiceMode(...); 在clickListener中初始化listView和ListView.setItemChecked时。

 final ListView listView = ... listView.setAdapter(new MyListAdapter()); listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE); listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView parent, View view, int position, long id) { listView.setItemChecked(position,true); } }); 

编辑 :更改项目背景:只需创建一个StateListDrawable而不是简单的ColorStateList:

 private Drawable makeBackgroungForItem(int position){ int pressedColor = pressedBackgroundColorForItem(position); int checkedColor = checkedBackgroundColorForItem(position); int defaultColor = defaultBackgroundColorForItem(position); StateListDrawable stateListDrawable = new StateListDrawable(); stateListDrawable.addState(new int[]{android.R.attr.state_list_pressed}, new ColorDrawable(pressedColor)); stateListDrawable.addState(new int[]{android.R.attr.state_list_checked}, new ColorDrawable(checkedColor)); stateListDrawable.addState(new int[]{0, new ColorDrawable(defaultColor)); return stateListDrawable; } 

getView(...)

 textView.setBackground(makeBackgroungForItem(position)); 

我会说具有状态感知的drawables 。 为您想要单个ListView背景的每种颜色创建一个状态感知的可绘制XML文件。 以下是一个名为background_black.xml和background_green.xml的状态感知Drawable的示例。 它们使您的默认背景颜色为白色,而按下/选择时会暂时将其更改为黑色或绿色。 这两个文件都放在Drawable文件夹中。

background_black.xml

      

background_green.xml

      

在ListView项目xml文件中,为根布局或任何提供可见背景颜色的元素指定ID。 对于此示例,Ill假设它是您的根布局。 然后在您的Adapter的getView()中,抓取您已分配id的元素,并使用您想要的背景颜色设置您创建的一个drawable。 像这样:

 @Override public View getView(int position, View convertView, ViewGroup parent){ //inflate your convertView, etc... ... ViewGroup baseLayout = (ViewGroup)convertView.findViewById(R.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; } 

注意:setBackground()是一个新函数,如果编码旧版Android,请使用setBackgroundDrawable()

我建议采用以下方法:

  • 您需要创建一个支持多个不同项目ListView Adapter
  • 每个不同的Item类代表一种不同的颜色,并且可以拥有它自己如何处理按下或选择状态的实现
  • 由于每个ListItem都有自己的.xml布局文件,因此您可以在那里指定所需的选择器

你需要什么:

  • ListView中每个项inheritance自的基类 ListItem
  • 此类提供抽象方法来获取表示项目及其类型的View
  • 如果需要, 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); } } 
  • 对于每种颜色,创建ListItem的子类
  • getView(...)方法中,膨胀您想要的布局
  • 不要忘记在getViewType()方法中返回正确的类型
  • 在这里用你的颜色做任何你想做的事
  • 用您的颜色设置选择器

例:

 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 { public ListItemAdapter(Context context, List 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; } } 

把它们放在一起:

 ArrayList list = new ArrayList(); // 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); 

关于CustomViews选择器及其行为 ,我建议阅读这个问题(和答案): 如何使用自定义选择器状态实现CustomView?

我想说不要过于复杂。 它可以很简单,因为创建一个包含可能颜色的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容器,您应该更改它的’android:foreground’属性:

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