我有一个 GridView
,其元素基于包含一个 ImageView
和一个 CheckedTextView
的 FrameLayout
。 FrameLayout 的 xml 文件如下:
<FrameLayout
xmlns:android = "http://schemas.android.com/apk/res/android"
android:id="@+id/gridImage"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:gravity="center_horizontal">
<ImageView
android:id="@+id/image"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:adjustViewBounds="false">
</ImageView>
<CheckedTextView
android:id="@+id/imageTick"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:layout_gravity="center_horizontal|bottom"
android:checkMark="@drawable/icon"
android:checked="false"
android:visibility="invisible"
>
</CheckedTextView>
</FrameLayout>
编辑:这是我为每个元素使用的适配器的 getView()
方法:
public View getView(int position, View convertView, ViewGroup parent) {
Log.d("getView()", position+"");
View v;
ImageView imageView;
if(convertView == null) {
v = LayoutInflater.from(mContext).inflate(R.layout.photo_text_view, null);
v.setLayoutParams(new GridView.LayoutParams(100,100));
}
else
{
v = convertView;
}
imageView = (ImageView) v.findViewById(R.id.image);
imageView.setImageBitmap(mThumbsIds.get().get(position));
v.setPadding(8, 8, 8, 8);
return v;
}
在我的 Activity 类中,我加载了一个上下文菜单,一旦我选择了一个选项,我就使该 GridView
元素的 CheckedTextView
可见,如下所示:
GridView gridView = (GridView) findViewById(R.id.gridview);
View selected =gridView.getChildAt(position);
CheckedTextView selectedCheck = (CheckedTextView)selected.findViewById(R.id.imageTick);
selectedCheck.setChecked(true);
selectedCheck.setVisibility(View.VISIBLE);
因此从这一点开始可能会发生两件事:
1) 假设我选择了位置 0 处的元素,CheckedTextView 变得可见,但是当我向下滚动 GridView 时,另一个元素(例如位置 17)的 CheckedTextView 也可见。当我向下滚动到底部时,这会继续出现在随机元素上。
2) 如果我选择底部的元素,向上滚动到顶部,并运行其中一种方法使所有 CheckedTextView 不可见,则会为底部的元素抛出 NullPointerException
。这发生在此时:View selected =gridView.getChildAt(position);
where selected 变为 null。
这是怎么回事?为什么这些随机的 CheckedTextView 变得可见,为什么我会得到异常?
最佳答案
问题在于您跟踪托运项目的方式:
GridView gridView = (GridView) findViewById(R.id.gridview);
View selected =gridView.getChildAt(position);
CheckedTextView selectedCheck = (CheckedTextView)selected.findViewById(R.id.imageTick);
selectedCheck.setChecked(true);
selectedCheck.setVisibility(View.VISIBLE);
1) getChildAt
如果您滚动到内容中并且您正在按适配器位置编制索引,则不会为您提供正确的 View 。在 GridView
或 ListView
中引用 Activity View 时,您需要执行如下操作:
final int index = position - gridView.getFirstVisiblePosition();
View selected = gridView.getChildAt(index);
原因是您的 GridView
只保留当前显示的适配器项的 subview 。如果元素 0 到 3 较早地滚出顶部,它可能只有元素 4 到 23 的 subview 。
这就是为什么当您执行 View selected =gridView.getChildAt(position);
时会出现异常的原因,该位置的 View 在屏幕外时实际上并不存在,因此 getChildAt
返回 null
。
2) 当 ListView
或 GridView
的内容发生变化或需要重新布局其 subview 时,它通过使用重新绑定(bind)现有 View 来实现convertView
参数到您的适配器。您的适配器从不调整项目 View 的选中状态,因此选中的 View 可以重新用于以后应该取消选中的项目。
要解决这个问题,您应该让您的适配器呈现的数据模型跟踪项目的检查状态,而不是依赖项目 View 来执行此操作。这意味着您的适配器应始终在 getView
中验证/设置项目的选中状态。它可能看起来像这样:
imageView = (ImageView) v.findViewById(R.id.image);
imageView.setImageBitmap(mThumbsIds.get().get(position));
CheckedTextView checkView = (CheckedTextView) v.findViewById(R.id.imageTick);
if (mData.isItemChecked(position)) {
checkView.setChecked(true);
checkView.setVisibility(View.VISIBLE);
} else {
checkView.setVisibility(View.GONE);
}
然后当您选择应该更改项目的选中状态的选项时,而不是上面的代码 fragment 执行如下操作:
data.setItemChecked(position, true);
adapter.notifyDataSetChanged();
notifyDataSetChanged()
将告诉 GridView
它应该重新绑定(bind)项目 View ,这将使您的 getView
方法修复正确检查状态。
关于android - 为什么我的 CheckedTextView 图标跳转到我的 GridView 中的不同元素?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5850456/