android - 自定义 ListView 适配器,奇怪的 ImageView 行为

标签 android caching android-listview adapter

我有一个自定义 ListView Adapter ,我正在使用它为列表创建行。我的问题是,它似乎无法区分 ImageView s,彼此。好像是随机采摘ImageViews在我上下滚动时卡入到位。文本信息(在此 fragment 中省略)不会中断。它按预期工作。

下面是我的Adapter的相关方法:

  public View getView( int position, View convertView, ViewGroup parent )
  {
    View v = convertView;

    if( v == null )
    {
      LayoutInflater vi = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
      v = vi.inflate( R.layout.generic_row, null );
    }

    // find the image
    ImageView favImage = (ImageView)v.findViewById( R.id.toggle_favorite );

   // when clicked...
   favImage.setOnClickListener( new OnClickListener() {

     @Override
     public void onClick( View v )
     {
       // make the gray star a yellow one
       int newImage = R.drawable.ic_star_yellow_embossed;
       ((ImageView)v).setImageBitmap(BitmapFactory.decodeResource(getContext().getResources(), newImage));
     }

   });

  return v;
  }

最佳答案

出现这种行为是因为 ListView当您向上和向下滚动列表时回收行 View ,因此您会获得由用户操作的行(图像已更改)在图像应该未被修改的位置。为避免这种情况,您必须以某种方式保持 ImageView 的状态。对于列表中的每一行,并使用此状态在 getView() 中设置正确的图像方法。因为您没有说明您是如何实现适配器的,所以我将向您展示一个简单的示例。

首先,您应该存储 ImageView 的状态。 .我使用了 ArrayList<Boolean>作为自定义适配器的成员,如果此列表中的位置(对应行在列表中的位置)为false则图片为默认图片,否则为true然后用户单击它,我们应该放置新图像:

private ArrayList<Boolean> imageStatus = new ArrayList<Boolean>();

在您的自定义适配器构造函数中初始化此列表。例如,如果你在你的适配器里放了一个列表,那么你应该把你的 imageStatus和那个列表一样大,里面装满了false (默认/启动状态):
//... initialize the imageStatus, objects is the list on which your adapter is based
for (int i = 0; i < objects.size(); i++) {
    imageStatus.add(false);
}

然后在你的getView()方法:
View v = convertView;

            if (v == null) {
                LayoutInflater vi = (LayoutInflater) getContext()
                        .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                v = vi.inflate(R.layout.adapters_adapter_with_images, null);
            }

            // find the image
            ImageView favImage = (ImageView) v
                    .findViewById(R.id.toggle_favorite);
            // Set the image bitmap. If the imageStatus flag for this position is TRUE then we
            // show the new image because it was previously clicked by the user
            if (imageStatus.get(position)) {
                int newImage = R.drawable.ic_star_yellow_embossed;
                favImage.setImageBitmap(BitmapFactory.decodeResource(
                        getContext().getResources(), newImage));
            } else {
                // If the imageStatus is FALSE then we explicitly set the image
                // back to the default because we could be dealing with a
                // recycled ImageView that has the new image set(there is no need to set a default drawable in the xml layout)                                       
                int newImage = R.drawable.basket_empty; //the default image
                favImage.setImageBitmap(BitmapFactory.decodeResource(
                        getContext().getResources(), newImage));
            }
            // when clicked... we get the real position of the row and set to TRUE
            // that position in the imageStatus flags list. We also call notifyDataSetChanged
            //on the adapter object to let it know that something has changed and to update!
            favImage.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {
                    Integer realPosition = (Integer) v.getTag(); //get the position from the view's tag
                    imageStatus.set(realPosition, true); //this position has been clicked be the user
                    adapter.notifyDataSetChanged(); //notify the adapter
                }

            });
            // set the position to the favImage as a tag, we later retrieve it
            // in the onClick method
            favImage.setTag(new Integer(position));
            return v;

        }

如果您不打算动态修改列表(删除/添加行),这应该很有效,否则您还必须注意修改 imageStatus 的列表来反射(reflect)变化。您没有说您的行数据是什么,另一种方法(如果您打算在用户单击该图像(除了更改它)时做某事,那么正确的方法)是将图像的状态合并到行的数据模型中。关于这一点,这里有一些教程:

Android ListView Advanced Interactive
Commonsware-Android Excerpt (互动行)

关于android - 自定义 ListView 适配器,奇怪的 ImageView 行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9754057/

相关文章:

android - 以编程方式设置组件的宽度和高度

caching - 用于大型网站的 AppFabric 缓存

c - 如何从使用库的文件中访问共享库中提到的指令的地址?

android - 自定义适配器和 ListView 崩溃

android - 如何将 ExecutorService 与 Android AsyncTask 一起使用?

android - 如何在 Android 中删除画线

Android LocationClient.getLastLocation() 返回带有新时间戳的旧且不准确的位置

node.js - Express + Request 中途更改 header

android - 多条推送消息 : The content of the adapter has changed but ListView did not receive a notification

android - 自定义 ListView 不显示