在真实设备上,ListView中的state_selected状态丢失了。

3

我有一个在三星手机上出现的简单ListView问题。

我通过编程方式创建了一个新的ListView。其中包含简单的TextView项目。我为我的列表视图添加了一个监听器:

listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            view.setSelected(true);
        }
    });
TextView(即listView的项目)使用ColorStateList作为textColor(按下 -> 绿色;选中 -> 蓝色;默认 -> 红色)。
在模拟器上,一切都很好:项目默认为红色,当我按下一个时它变为绿色,当我释放它时它变为蓝色。如果我选择另一个项目:先前选择的将返回红色,并且新选择的将变为蓝色。
在我的三星设备上:项目默认为红色,当我按下一个时它变为绿色,当我释放它时它又变成了红色(即未选中)。 这似乎是三星ListView实现中的一个错误(它是一个自定义实现,因此没有源代码很难跟踪)。 编辑:不是一个错误,而是因为触摸模式略有不同(请参见接受答案中的链接) 您有任何关于如何解决这个错误/行为的想法吗? 附加限制:我不能使用xml selector,因为我只在运行时接收要使用的颜色。
我的设备是三星GT-B5330,API 15。(但我希望它发生在大多数三星设备上)
这是完整(可编译)的代码。
import android.R;
import android.app.Activity;
import android.content.res.ColorStateList;
import android.database.DataSetObserver;
import android.graphics.Color;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.TextView;

public class TestActivity extends Activity {

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    RelativeLayout rootLayout = new RelativeLayout(this);
    setContentView(rootLayout);

    //create listView
    ListView listView = new ListView(this);
    listView.setAdapter(new MyListAdapter());
    listView.setDivider(null);
    listView.setDividerHeight(0);
    listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
    listView.setItemsCanFocus(false);
    listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            view.setSelected(true);
        }
    });
    listView.setBackgroundColor(Color.WHITE);

    //positionning listView
    RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(100,200);
    lp.setMargins(50,50,10,10);
    rootLayout.addView(listView, lp);
}



private class MyListAdapter implements ListAdapter{

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ColorStateList colorStateList = new ColorStateList(
                new int[][]{
                        new int[]{R.attr.state_pressed},
                        new int[]{R.attr.state_selected},
                        new int[]{-R.attr.state_selected},
                },
                new int[]{
                        Color.GREEN,
                        Color.BLUE,
                        Color.RED});
        TextView textView = new TextView(parent.getContext());
        textView.setText("Item " + position);
        textView.setTextColor(colorStateList);
        return textView;
    }

    @Override
    public boolean areAllItemsEnabled() {
        return true;
    }

    @Override
    public boolean isEnabled(int position) {
        return true;
    }

    @Override
    public void registerDataSetObserver(DataSetObserver observer) {
    }

    @Override
    public void unregisterDataSetObserver(DataSetObserver observer) {
    }

    @Override
    public int getCount() {
        return 10;
    }

    @Override
    public Object getItem(int position) {
        return "data "+position;
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public boolean hasStableIds() {
        return true;
    }


    @Override
    public int getItemViewType(int position) {
        return position;
    }

    @Override
    public int getViewTypeCount() {
        return getCount();
    }

    @Override
    public boolean isEmpty() {
        return getCount()>0;
    }
}
}

GT-5330有硬件键盘吗?我找到了一个有硬件键盘的GT-B5330,但是关于你提到的GT-5330没有任何信息。 - Darth Beleg
是的,它有一个硬件键盘,我编辑了我的帖子以设置正确的参考(抱歉)。 - ben75
2个回答

1

我手头上没有三星设备(Galaxy Nexus不算,它有普通的Android系统,而且在你的示例中运行得很好),所以我无法测试我的假设,但似乎ListView在释放后会取消项目的选定状态。您可以使用HierarchyViewer(如果您的手机未经root,则使用Romain Guy的ViewServer)进行检查。

由于TouchMode的存在(请参见http://android-developers.blogspot.ru/2008/12/touch-mode.html),依赖触摸屏幕选择是危险的。简单来说:当用户与触摸屏交互时,您没有选择(或焦点)的概念。模拟器通常具有D-pad,因此可能具有略微不同的行为。

我的建议是使用state_checked而不是state_selected。Android有CheckedTextView可以帮助你。只需调用ListView的setItemChecked即可。这个解决方案还具有很好的属性,可以在配置更改之间保持选中的项目位置,并在按下其他项目时自动取消先前选中的项目(如果使用CHOICE_MODE_SINGLE)。
如果这不可接受,你需要坚持使用state_selected,那么你可以将TextView包装到LinearLayout中,它应该可以防止选择消失。但不要忘记,当ListView滚出屏幕时,它会重复使用相同的视图来显示其他列表项,因此你需要在适配器中跟踪选择状态以正确设置它。

这篇文章中的所有内容都值得点赞。使用state_checked非常完美。所有引用都非常有用。非常感谢。 - ben75

0

我可以确认,我在三星设备(Nexus、S3、Note2)上遇到了类似的 bug。Listview 项具有默认的背景颜色,因此在我的情况下是黑色。但是它会随机变成红色。如果我将 listviewitem 的背景颜色显式设置为黑色,则不会出现该 bug。老实说,我不知道如何解决你的问题,但定义所有状态的颜色可能会对你有所帮助。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接