[英]Different select colors for different list view items
我有以下要求:
無論出於何種原因,它似乎都沒有像我想象的那樣直截了當。 唯一能夠朝着正確方向發展的解決方案是: https : //stackoverflow.com/a/16978159/658718
需要注意的是,這不會更改選擇顏色,但會永久更改背景顏色,如果向下滾動,它已經更改了列表視圖項的背景顏色。
我怎么處理這個?
我會說具有狀態意識的drawables 。 為您想要單個ListView背景的每種顏色創建一個狀態感知的可繪制XML文件。 以下是一個名為background_black.xml和background_green.xml的狀態感知Drawable的示例。 它們使您的默認背景顏色為白色,而按下/選擇時會暫時將其更改為黑色或綠色。 這兩個文件都放在Drawable文件夾中。
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
<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>
在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.<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;
}
注意:setBackground()是一個新函數,如果編碼舊版Android,請使用setBackgroundDrawable()
這里的困難是按下/檢查的顏色是動態的。 您不能使用靜態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));
我建議采用以下方法:
ListView
Adapter
ListItem
都有自己的.xml布局文件,因此您可以在那里指定所需的選擇器 你需要什么:
ListView
中每個項繼承自的基類 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<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;
}
}
把它們放在一起:
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);
關於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);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.