我花了几天时间试图解决Android上的ListViews问题。我想使用ListView实现一个选择列表框。因此,我希望只有一行具有预定义的浅色背景颜色,其余行具有另一种预选颜色。我遇到的问题是,当我点击特定行时,另一行是突出显示的而不是我按下的那一行。我添加了几条消息来记录正在发生的事情,但似乎一切正常。这是我的代码:
public class TryListViewActivity extends Activity {
protected static final int NO_SELECTED_COLOR = 0xFF191919;
protected static final int SELECTED_COLOR = 0xFF3366CC;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ListView listView = new ListView(this);
ArrayList<String> list = new ArrayList<String>();
list.add("Option 1");
list.add("Option 2");
list.add("Option 3");
list.add("Option 4");
list.add("Option 5");
list.add("Option 6");
list.add("Option 7");
list.add("Option 8");
list.add("Option 9");
list.add("Option 10");
list.add("Option 11");
list.add("Option 12");
list.add("Option 13");
list.add("Option 14");
list.add("Option 15");
ArrayAdapter<String> listAdapter = new ArrayAdapter<String>(
this,
R.layout.list_box_entry,
list
);
listView.setAdapter(listAdapter);
listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
// Set the listener
listView.setOnItemClickListener(
new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
Log.i(
"Log",
"[SingleSelectionListBox] Item clicked: position="
+ position + ";id=" + id
);
// First, set all rows to be unselected
int counter = parent.getCount();
Log.i(
"Log",
"[SingleSelectionListBox] "
+ counter + " items found inside the parent"
);
int children = parent.getChildCount();
Log.i(
"Log",
"[SingleSelectionListBox] "
+ children + " views found inside the parent"
);
for(int i=0;i<children;i++) {
Log.i(
"Log",
"[SingleSelectionListBox] Child "
+ i + " has message "
+ ((TextView)parent.getChildAt(i)).getText()
);
}
// Too inefficient but for now is OK
for(int i=0;i<children;i++)
parent.getChildAt(i)
.setBackgroundColor(NO_SELECTED_COLOR);
Log.i("Log",
"[SingleSelectionListBox] First visible position: "
+ parent.getFirstVisiblePosition()
);
// Set the background color
TextView textView = (TextView)(parent.getChildAt(
position-parent.getFirstVisiblePosition()));
textView.setBackgroundColor(SELECTED_COLOR);
Log.i(
"Log",
"[SingleSelectionListBox] Text inside the "
+ " View changing the color " + textView.getText()
);
}
}
);
setContentView(listView);
}
}
在资源(res / layout)中,我插入了一个名为list_text_entry.xml的文件,其中包含以下内容
<TextView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent"
android:layout_height="fill_parent" android:gravity="center"
android:textColor="#FFFFFF" android:padding="10dp" android:textSize="16sp">
</TextView>
例如,如果我在listView先前已向下滚动直到我看到的第一行是“选项4”时单击“选项11”条目,则“选项7”行显示为选中的唯一一行背景中的蓝色。有人能解释一下这里发生了什么吗?我在下面发布了我扔掉日志的消息。
[SingleSelectionListBox] Item clicked: position=10;id=10
[SingleSelectionListBox] 15 items found inside the parent
[SingleSelectionListBox] 11 views found inside the parent
[SingleSelectionListBox] Child 0 has message Option 4
[SingleSelectionListBox] Child 1 has message Option 5
[SingleSelectionListBox] Child 2 has message Option 6
[SingleSelectionListBox] Child 3 has message Option 7
[SingleSelectionListBox] Child 4 has message Option 8
[SingleSelectionListBox] Child 5 has message Option 9
[SingleSelectionListBox] Child 6 has message Option 10
[SingleSelectionListBox] Child 7 has message Option 11
[SingleSelectionListBox] Child 8 has message Option 12
[SingleSelectionListBox] Child 9 has message Option 13
[SingleSelectionListBox] Child 10 has message Option 14
[SingleSelectionListBox] First visible position: 3
[SingleSelectionListBox] Text inside the View changing the color Option 11
我可以猜测ViewGroup中的所有子项从上到下排序,甚至在代码中执行此操作时:
TextView textView = (TextView)(parent.getChildAt(
position-parent.getFirstVisiblePosition()
));
textView.setBackgroundColor(SELECTED_COLOR);
显示消息Option 11
,但实际上是option 7
已选中。这是Android的错误吗?
答案 0 :(得分:7)
我已经使用过这段代码了,你应该试试这个:
listView.getChildAt(0).setBackgroundColor(Color.BLUE);
答案 1 :(得分:5)
是的,你应该像Dave说的那样使用:
view.setBackgroundColor(SELECTED_COLOR);
也许
view.refreshDrawableState();
但是因为Android回收列表,它会在屏幕上未显示的每个第一项上重复您选择的颜色。因此,如果您的屏幕尺寸可以显示十个项目而不是第11个,则第21个等也会在您滚动时显示为已选中。
要避免这种情况,您必须创建自定义适配器。然后在getView中你需要这样说:
if (myActivity.selectedRow != position){
v.setBackgroundColor(Color.TRANSPARENT);
} else {
v.setBackgroundColor(SELECTED_COLOUR);
}
其中selectedRow是myActivity中的public static int selectedRow
,即创建列表的活动。在那里存储单击列表时选择的行号。
答案 2 :(得分:5)
感谢Dave和ChristianB的回答。我仍然不知道为什么Android会这样做,所以这个问题仍然没有得到解决。但是,我找到了一种方法来获得创建自定义适配器所需的内容。如果有人需要,我会给你代码。
public class CustomAdapter extends ArrayAdapter<String> {
protected static final int NO_SELECTED_COLOR = 0xFF191919;
protected static final int SELECTED_COLOR = 0xFF3366CC;
private ArrayList<String> items;
private LayoutInflater mInflater;
private int viewResourceId;
private int selectedPosition;
public CustomAdapter(Activity activity,int resourceId,
ArrayList<String> list) {
super(activity,resourceId,list);
// Sets the layout inflater
mInflater = (LayoutInflater)activity
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
// Set a copy of the layout to inflate
viewResourceId = resourceId;
// Set a copy of the list
items = list;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
TextView tv = (TextView)convertView;
if (tv == null) {
tv = (TextView)mInflater.inflate(viewResourceId, null);
}
tv.setText(items.get(position));
// Change the background color
if (position==selectedPosition) tv.setBackgroundColor(SELECTED_COLOR);
else tv.setBackgroundColor(NO_SELECTED_COLOR);
return tv;
}
public void setSelected(int position) {
selectedPosition = position;
}
}
因此,在ListView初始化中我只需要放置这个监听器:
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
((CustomAdapter)listAdapter).setSelected(position);
listView.invalidate();
}
});
这不是一个有效的解决方案,因为我从ArrayAdapter扩展,假设有一个提供的所有数据的副本。因此,我使用的内存比需要的多得多,如果列表变得非常大,我可能会遇到内存问题。所以,如果有人知道更好的解决方案,请发帖!
答案 3 :(得分:0)
我相信这是由于ListViews编号和重用行的方式。因此,不要使用parent.getChildAt(i)
来获取您想要操作的行,而是使用传递给View
本身的onItemClick
对象。
view.setBackgroundColor(SELECTED_COLOR);
答案 4 :(得分:0)
listview.setOnItemClickListener(new AdapterView.OnItemClickListener(){
@Override
public void onItemClick(AdapterView<?> parent, final View view, int position, long id)
{
View v;
int count = parent.getChildCount();
v =parent.getChildAt(position);
parent.requestChildFocus(v, view); v.setBackground(res.getDrawable(R.drawable.transparent_button));
for (int i=0; i<count; i++)
{
if (i!= position)
{
v = parent.getChildAt(i);t v.setBackground(res.getDrawable(R.drawable.not_clicked));
}
}
}
});
基本上,创建两个drawable - 一个是透明的,另一个是所需的颜色。请求焦点在单击的位置(定义的int位置)并更改所述行的颜色。然后遍历父列表视图,并相应地更改所有其他行。这说明了用户多次点击列表视图的时间。
答案 5 :(得分:0)
@Override
public View getView(int position, View convertView, ViewGroup parent)
{
LayoutInflater inflater=(LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View itemView = inflater.inflate(R.layout.verselayout, parent, false);
txttitle = (TextView) itemView.findViewById(R.id.Versetxt);
if (position%2 == 0) {
txttitle.setTextColor(Color.parseColor("#FFFFFF"));
}
else
{
txttitle.setTextColor(Color.parseColor("#FFFF00"));
}
return itemView;
}
答案 6 :(得分:0)
试试这个,
OnItemClickListener onitemclick = new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapter, View arg1, int position, long id) {
selectedItem= position;
adapter.notifyDataSetChanged();
}
};
覆盖适配器的getView()方法:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final View view = View.inflate(context, R.layout.item_list, null);
if (position == selectedItem) {
// set your color
}
return view;
}