如何在ListView中正确更改特定行的背景颜色? (机器人)

时间:2011-01-08 16:13:59

标签: android listview background-color

我花了几天时间试图解决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的错误吗?

7 个答案:

答案 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;
    }
相关问题