【问题标题】:Why is changing where layout parameters are set solving my "OnClickListener not working for first item in GridView" issue?为什么要更改布局参数的设置位置来解决我的“OnClickListener 不适用于 GridView 中的第一项”问题?
【发布时间】:2013-12-07 03:58:40
【问题描述】:

我正在使用 GridView 显示一些图像,但我遇到了问题,因为 onClickListener 不适用于第一张图像。我在 SO 发现了一些其他问题,有同样的问题,但我不喜欢他们的“正确答案”,因为他们中的大多数人都采用相同的方法:

基本上,每次调用 getview 时都会实例化视图。这对性能来说很糟糕,而且它们可能会在许多设备中面临内存不足的问题。

在我的例子中,我在 GridView 中显示位于 assets 文件夹中子文件夹内的图像。

我的原始代码存在“第一项”问题(实际上,我的原始代码实现了 viewholder 模式,但这个更简单一些,并且面临同样的问题):

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

    if (convertView == null) {
        imageView = new ImageView(_activity);

    } else {
        imageView = (ImageView) convertView;
    }

    // get screen dimensions
    AssetManager assetManager = _activity.getAssets();
    InputStream assetIn = null;
    try {
        assetIn = assetManager.open(_assets_subdir + File.separator + _filePaths.get(position));
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    Bitmap image = BitmapFactory.decodeStream(assetIn);
    imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
    imageView.setLayoutParams(new GridView.LayoutParams(imageWidth, imageWidth));
    imageView.setImageBitmap(image);

    // image view click listener
    imageView.setOnClickListener(new OnImageClickListener(position));

    return imageView;

}

我解决问题的最终代码:

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

    if (convertView == null) {
        imageView = new ImageView(_activity);
        imageView.setLayoutParams(new GridView.LayoutParams(imageWidth, imageWidth));

    } else {
        imageView = (ImageView) convertView;
    }

    // get screen dimensions
    AssetManager assetManager = _activity.getAssets();
    InputStream assetIn = null;
    try {
        assetIn = assetManager.open(_assets_subdir + File.separator + _filePaths.get(position));
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    Bitmap image = BitmapFactory.decodeStream(assetIn);
    imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
    imageView.setImageBitmap(image);

    // image view click listener
    imageView.setOnClickListener(new OnImageClickListener(position));

    return imageView;

}

问题已通过移动代码imageView.setLayoutParams(new GridView.LayoutParams(imageWidth, imageWidth)); 得到解决。

但是为什么呢?我不确定。

我在某处(在 SO 中)读到它可能是因为尝试访问尚未膨胀的视图而发生的,并且用户建议使用 getViewTreeObserver(),但我尝试了这种方法并无法解决问题.

因此,我决定对代码进行反复试验,以查看可能出现瓶颈的位置并找到给定的解决方案。

任何人都知道为什么这可以解决问题?

【问题讨论】:

  • 这可能会有所帮助[链接] [1]:stackoverflow.com/questions/11778228/…
  • 谢谢@anish,但这是我在问题中提到的(恕我直言)错误修复的一个例子。从字面上看,他的解决方法是“最终通过在每次传递中使持有者实例化来解决它,而不是通过标签获取它(这对性能更好,但是哦)。” getView() 可以被多次调用,他绕过了convertView 的用处,通过膨胀布局并每次调用getView() 两次调用findViewById。在 GridView 中使用图像可能会导致 OutOfMemory 崩溃。
  • 添加 LayoutParams 解决您的问题的可能原因是它触发了另一个布局传递。这似乎表明您的视图正在其他地方重用,并且它的 OnClickListener 正在被替换。我记得我自己也遇到过这种奇怪的行为,但不太记得我是如何解决它的。我会看看我是否能弄清楚它与哪个项目有关。
  • 好的,谢谢!我会很感激这些额外的信息。
  • 以防万一,这正常吗:GridView.LayoutParams(imageWidth, imageWidth)?应该是:GridView.LayoutParams(imageWidth, **imageHeight**) 还是只是复制/粘贴错误?

标签: android gridview onclicklistener


【解决方案1】:

GridView继承自AbsListView -> GridView.LayoutParams其实就是AbsListView.LayoutParams,里面包含了一些关于view的类型和是否被回收的状态数据。

通过在每次调用 getView 时初始化一组新的布局参数(而不仅仅是在重新创建视图时),您将丢失这些状态数据。

我(目前)不确定为什么它只会导致网格中的第一项出现问题。

【讨论】:

  • 我不确定你的答案是否正确,但恕我直言,它值得赏金。
【解决方案2】:

您的 GridView 中只有一个 ImageView 吗?为什么不使用setOnItemClickListener 而不是OnItemClickListener

像这样,在你的Activity

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // ...
    gridView.setOnItemClickListener(new OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View v,
                    int position, long id) {
                    // here you have what you want ...
            }
    });
}

【讨论】:

  • 对不起,我没听懂你的意思:你的意思是使用 setOnItemClickListener 而不是 setOnClickListener?
  • 通过将 imageView 设置为可点击而不是 setOnItemClickListener,imageView 周围可能存在不响应触摸事件的区域
  • 好吧,正如@FunkTheMonk 所说,我实际上希望整个地区都做出回应,尽管它可能不会有太大的不同。
  • 如果您希望整个区域(包括由中心重心创建的空间)响应,而不仅仅是 imageView,您应该使用 onItemClickListener
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-11
  • 1970-01-01
  • 2013-09-25
  • 2022-01-10
  • 1970-01-01
  • 2017-09-29
相关资源
最近更新 更多