如何在 Android 中设置 GridView 的点击项背景 drawable?

4

我有一个带有一堆图标的GridView,我需要选择其中一个。这里的选择意味着:

  • 我需要存储可绘制的id到数据库中(以便稍后访问)
  • 我需要在网格上绘制某种视觉提示,以让用户知道当前选择的图标是哪一个

我找到了这个:
http://groups.google.com/group/android-developers/browse_thread/thread/f08a58167dbaa8c8

所以我想setSelection已经不是合适的方法,我无法使用它来选择图标本身或绘制视觉提示。在onItemClickListener中,我知道网格项的位置,并且可以将其保存为私有类变量。 我最大的问题是如何绘制这个视觉提示。

我该如何实现?如何在单击项目时在其上绘制视觉提示,并且如果用户单击不同的项目,则在新项目中“取消绘制”该视觉提示并重绘它?


我想看到这个问题的答案。我相信,如果你想要某种选择提示,你需要一个可聚焦的对象。然而,对于一个可聚焦的对象,将OnItemClickListener附加到GridView上是不起作用的。相反,在适配器的getView()中,你必须单独地为每个项目附加一个OnClickListener。 - Ian
我假设给每个项目附加OnClickListener并不是真正可行的,对吗?这可能是一个解决方案,所以如果你愿意,你可以在下面给出一个合适的答案。我不介意。 - rfgamaral
2个回答

4

经过几个小时的努力,我终于找到了我一直在寻找的解决方案。虽然答案与原始答案几乎没有关系,但对 Ian 的最初编辑有所帮助,帮助我找到了这个解决方案 :)

我不会解释我做了什么,我认为这是相当自说明的。只有几点说明:

  • 首先,我尝试了 view.Invalidate()view.postInvalidate() ,而不是 iconAdapter.notifyDataSetChanged() ,但两者都没有起作用。文档指出,invalidate 方法只是在“可能”的情况下要求重绘视图。

  • 我在寻找比合并两个可绘制对象更简单的解决方案。例如,在 ImageView 背景上绘制图标和将其视觉提示作为图像。由于某种奇怪的原因,当滚动 GridView 时,视觉提示开始随机显示在其他图标上。我不明白为什么,但在背景图像上放置一个视觉提示的想法对我来说是很合理的,而 ImageView 可以实现这一点,不需要额外的合并方法。然而,我不能在没有它的情况下使它工作...

MyActivity.java

public class MyActivity extends Activity {
    private GridView mGridViewIcon;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        mGridViewIcon = (GridView)findViewById(R.id.gridview_icon);
        mGridViewIcon.setAdapter(new IconAdapter(this));

        mGridViewIcon.setOnItemClickListener(new GridView.OnItemClickListener() {

            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                IconAdapter iconAdapter = (IconAdapter)parent.getAdapter();

                iconAdapter.setSelectedItemPosition(position);
                iconAdapter.notifyDataSetChanged();
            }

        });
    }

}

IconAdapter.java

public class IconAdapter extends BaseAdapter {

    private int mSelectedPosition;
    private Integer[] mThumbIds;
    private int mIconSize;
    private Context mContext;

    public IconAdapter(Context context) {
        mThumbIds = AppHelper.ICON_SET.keySet().iterator().next();
        mIconSize = context.getResources().getDimensionPixelSize(R.dimen.default_icon_size);
        mContext = context;
    }

    @Override
    public int getCount() {
        return mThumbIds.length;
    }

    @Override
    public Object getItem(int position) {
        return mContext.getResources().getDrawable(mThumbIds[position]);
    }

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

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ImageView imageView;

        if(convertView == null) {
            imageView = new ImageView(mContext);
            imageView.setLayoutParams(new GridView.LayoutParams(mIconSize, mIconSize));
        } else {
            imageView = (ImageView)convertView;
        }

        if(mSelectedPosition == position) {
            imageView.setImageDrawable(mergeDrawableLayers(mThumbIds[position],
                    R.drawable.ic_note_selected_mark));
        } else {
            imageView.setImageResource(mThumbIds[position]);
        }

        return imageView;
    }

    public void setSelectedItemPosition(int position) {
        mSelectedPosition = position;
    }

    private Drawable mergeDrawableLayers(int background, int overlay) {
        Drawable[] drawableLayers = new Drawable[2];

        drawableLayers[0] = mContext.getResources().getDrawable(background);
        drawableLayers[1] = mContext.getResources().getDrawable(overlay);

        return new LayerDrawable(drawableLayers);
    }

}

1
我认为,如果你想要某种选择提示,你需要一个可聚焦的对象。然而,如果使用可聚焦的对象(如按钮)将OnItemClickListener附加到GridView上是不起作用的(如果我没记错的话)。相反,你必须在适配器的getView()方法中为每个项目单独附加OnClickListener。
适配器:
// create a new ImageView for each item referenced by the Adapter
    public View getView(int position, View convertView, ViewGroup parent) {
        Button button;
        if (convertView == null) {  // if it's not recycled, initialize some attributes
            button = new Button(mContext);
            // set layout params (make sure its GridView.layoutParams)
            // and other stuff

        } 
        else {
            button = (Button) convertView;
        }

        button.setBackgroundResource(mThumbIds[position]); // mThumbIds hold Resource Ids
        button.setOnClickListener(new OnClickListener() {
           onClick(View v) {
             // store directly to database here, or send it with the activity with sharedPreferences (below)

             // We need an Editor object to make preference changes.
             // All objects are from android.context.Context
             SharedPreferences settings = getSharedPreferences("MY_PREFERENCE", 0);
             SharedPreferences.Editor editor = settings.edit();
             editor.putInt("button_id", mThumbIds[position]);

             // Commit the edits!
             editor.commit();
           } 
        });
        return button;
    }
}

在Activity端,保存按钮的 onClickListener:
onClick(View v) {
// Restore preferences
       SharedPreferences settings = getSharedPreferences("MY_PREFERENCE", 0);
       int id = settings.getInt("button_id", -1);

       // now safe all stuff to database
}

可能会有一些细节缺失,因为按钮是可聚焦的,但我认为应该可以解决这个问题。此外,您将通过使用.xml定义的选择器资源实现选择。然而,这应该在一个单独的问题中解决。
编辑1: 实际上,现在我想起来了,我不确定可绘制的.xml文件(选择器)是否可以有ID。我得回家后再试试。
编辑2: 我添加了sharedPreference部分。
编辑3: 添加了从活动端查询sharedPreference。

我明白你的意思了,只是有一件事我不确定。GridView只是我的Activity中的一个元素,我还有其他东西,比如EditText小部件。然后有一个按钮,它负责将所有数据存储到数据库中,包括GridView项目的ID。我不确定该如何处理这个。 - rfgamaral
“存储信息”部分根本不相关,我的意思是我需要将GridView中点击的项的位置存储在Activity中的某个变量中。如果我有了那个,保存就很简单了(我假设,我正在学习Android,还没有达到那个部分)。但是您之前的答案(第二次编辑之前)给了我一些想法,这些想法我已经在过去几个小时里一直在努力实现。我认为我已经找到了解决我的问题的方法,我会在一个小时左右的时间内发布自己的答案。 - rfgamaral
好的,只需在您的活动中查询sharedPreference。这非常容易。 - Ian
遗憾的是,最简单的方法是使用OnItemClickListener,然后放弃选择要求。 - Ian
我想我终于做到了...几分钟后我会发布我的答案! - rfgamaral
显示剩余2条评论

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