[英]Different select colors for different list view items
I have the following requirements: 我有以下要求:
For whatever reasons it seems not to be as straight forward as I thought. 无论出于何种原因,它似乎都没有像我想象的那样直截了当。 The only solution that goes at least a little bit in the right direction is this one: https://stackoverflow.com/a/16978159/658718
唯一能够朝着正确方向发展的解决方案是: https : //stackoverflow.com/a/16978159/658718
The caveat is, that this does not change the on select color, but changes the background color permanently, plus it already changes the background color for list view items if you scroll down a bit. 需要注意的是,这不会更改选择颜色,但会永久更改背景颜色,如果向下滚动,它已经更改了列表视图项的背景颜色。
How can I approach this? 我怎么处理这个?
I'd say go with state-aware drawables . 我会说具有状态意识的drawables 。 Create a state-aware drawable XML file for each of the colors you want the background of your single ListView to be.
为您想要单个ListView背景的每种颜色创建一个状态感知的可绘制XML文件。 Here is an example of state- aware Drawables called background_black.xml and background_green.xml.
以下是一个名为background_black.xml和background_green.xml的状态感知Drawable的示例。 They makes your default background color white and while pressed/selected temporarily changes it to black or green.
它们使您的默认背景颜色为白色,而按下/选择时会暂时将其更改为黑色或绿色。 Both of these files go in your Drawable folder.
这两个文件都放在Drawable文件夹中。
background_black.xml background_black.xml
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_window_focused="false" android:drawable="@android:color/white" />
<item android:state_pressed="true" android:color="@android:color/black" />
<item android:state_selected="true" android:color="@android:color/black" />
</selector>
background_green.xml background_green.xml
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_window_focused="false" android:drawable="@android:color/white" />
<item android:state_pressed="true" android:color="@android:color/green" />
<item android:state_selected="true" android:color="@android:color/green" />
</selector>
In your ListView item xml file, assign an ID to your root layout or whichever element is providing the visible background color. 在ListView项目xml文件中,为根布局或任何提供可见背景颜色的元素指定ID。 For this example, Ill assume its your root layout.
对于此示例,Ill假设它是您的根布局。 Then in your Adapter's getView(), grab the element that you've assigned the id to and set one of the drawables you created with the color you want for its background.
然后在您的Adapter的getView()中,抓取您已分配id的元素,并使用您想要的背景颜色设置您创建的一个drawable。 Like so:
像这样:
@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;
}
NOTE: setBackground() is a new function, use setBackgroundDrawable() if coding for older versions of Android 注意:setBackground()是一个新函数,如果编码旧版Android,请使用setBackgroundDrawable()
The difficulty here is that pressed/checked color is dynamic. 这里的困难是按下/检查的颜色是动态的。 You cannot use static xml color-state-list.
您不能使用静态xml color-state-list。 But you can create ColorStateList by code.
但您可以通过代码创建ColorStateList 。 Here is how to do that.
这是怎么做的。
You just have to implement the ListAdapter : 您只需要实现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
//...
Note the use of android.R.attr.state_checked
instead of the more intuitive android.R.attr.state_selected
because the state_selected
is not very precisely define with a touch screen (ie state_selected can give the expected behavior on the emulator, but on a real device it will probably fail) 注意使用
android.R.attr.state_checked
而不是更直观的android.R.attr.state_selected
因为state_selected
不是用触摸屏非常精确地定义的(即state_selected可以在模拟器上给出预期的行为,但是在真正的设备,它可能会失败)
On the other hand state_checked
+ CheckedTextView is going to work correctly on both simulator and real device. 另一方面,
state_checked
+ CheckedTextView将在模拟器和真实设备上正常工作。
Just call List.setChoiceMode(...);
只需调用
List.setChoiceMode(...);
when initializing listView and ListView.setItemChecked
in the clickListener. 在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);
}
});
EDIT : to change the item background : just create a StateListDrawable instead of a simple ColorStateList : 编辑 :更改项目背景:只需创建一个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;
}
And in the getView(...)
在
getView(...)
textView.setBackground(makeBackgroungForItem(position));
I suggest the following approach: 我建议采用以下方法:
ListView
Adapter
that supports multiple different items ListView
Adapter
ListItem
will have it's own .xml layout file, you can specify the desired selector there ListItem
都有自己的.xml布局文件,因此您可以在那里指定所需的选择器 What you need: 你需要什么:
ListItem
that every item in the ListView
inherits from ListView
中每个项继承自的基类 ListItem
View
that represents the item and it's type View
ListItem
class could have an Integer
field mColor, that holds the color the item represents ListItem
类可以有一个Integer
字段mColor,它保存项表示的颜色 ListItem
class could have a method to setup the selector with the speficied color ListItem
类可以有一个方法来设置具有特定颜色的选择器 Example: 例:
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
ListItem
的子类 getView(...)
method, inflate your desired layout getView(...)
方法内部,膨胀您想要的布局 getViewType()
method getViewType()
方法中返回正确的类型 Example: 例:
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;
}
}
Example: 例:
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;
}
}
Putting it all together: 把它们放在一起:
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);
Concerning CustomViews
and selectors and their behaviour , I suggest reading this question (and answer): How to implement a CustomView with custom selector states? 关于
CustomViews
和选择器及其行为 ,我建议阅读这个问题(和答案): 如何使用自定义选择器状态实现CustomView?
I'd say don't overcomplicate this. 我想说不要过于复杂。 It can be simple as create an array of
int
that will contain possible colors, and set them to each item using Random
class. 它可以很简单,因为创建一个包含可能颜色的
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);
}
**Edit: ** now, if what you want is a foreground selection, then your row should have a FrameLayout
container, and you should change it's 'android:foreground' property: **编辑:**现在,如果您想要的是前景选择,那么您的行应该有一个
FrameLayout
容器,您应该更改它的'android:foreground'属性:
final Drawable drawable = new ColorDrawable( /* your getColor() function */ );
frameLayout.setForeground(drawable);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.