【问题标题】:How to refresh a GridView?如何刷新 GridView?
【发布时间】:2011-05-25 04:47:41
【问题描述】:

我有一个与 Google 教程非常相似的 GridView,除了我想在运行时(通过子活动)添加 ImageView。结果还可以,但是View的布局乱了:GridView没有填满它的parent的内容,我要怎么做才能设计好呢?

这里是添加孩子的代码:

public void initializeWorkbench(GridView gv, Vector<String> items) {
        Prototype.workbench.setDimension(screenWidth, divider.height()+workbenchArea.height());
        Prototype.workbench.activateWorkbench();
        // this measures the workbench correctly
        Log.d(Prototype.TAG, "workbench width: "+Prototype.workbench.getMeasuredWidth());
        // 320
        Log.d(Prototype.TAG, "workbench height: "+Prototype.workbench.getMeasuredHeight());
        // 30
        ImageAdapter imgAdapter = new ImageAdapter(this.getContext(), items);
        gv.setAdapter(imgAdapter);
        gv.measure(screenWidth, screenHeight);
        gv.requestLayout();
        gv.forceLayout();
        Log.d(Prototype.TAG, "gv width: "+gv.getMeasuredWidth());
        // 22
        Log.d(Prototype.TAG, "gv height: "+gv.getMeasuredHeight());
        // 119
        Prototype.workbench.setDimension(screenWidth, divider.height()+workbenchArea.height());
    }
}

activateWorkbench、setDimension 和在工作台中测量(GridView 上方的LinearLayout):

public void activateWorkbench() {
    if(this.equals(Prototype.workbench)) {
        this.setOrientation(VERTICAL);
        show = true;
        measure();
    }
}

public void setDimension(int w, int h) {
    width = w;
    height = h;
    this.setLayoutParams(new LinearLayout.LayoutParams(width, height));
    this.invalidate();
}

private void measure() {
    if (this.getOrientation() == LinearLayout.VERTICAL) {
        int h = 0;
        int w = 0;
        this.measureChildren(0, 0);
        for (int i = 0; i < this.getChildCount(); i++) {
            View v = this.getChildAt(i);
            h += v.getMeasuredHeight();
            w = (w < v.getMeasuredWidth()) ? v.getMeasuredWidth() : w;
        }
        if (this.equals(Prototype.tagarea))
            height = (h < height) ? height : h;
        if (this.equals(Prototype.tagarea))
            width = (w < width) ? width : w;
    }
    this.setMeasuredDimension(width, height);
}

ImageAdapter 构造函数:

public ImageAdapter(Context c, Vector<String> items) {
    mContext = c;

    boolean mExternalStorageAvailable = false;
    boolean mExternalStorageWriteable = false;
    String state = Environment.getExternalStorageState();

    if (Environment.MEDIA_MOUNTED.equals(state)) {
        // We can read and write the media
        mExternalStorageAvailable = mExternalStorageWriteable = true;
    } else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
        // We can only read the media
        mExternalStorageAvailable = true;
        mExternalStorageWriteable = false;
    } else {
        // Something else is wrong. It may be one of many other states, but
        // all we need
        // to know is we can neither read nor write
        mExternalStorageAvailable = mExternalStorageWriteable = false;
    }

    if (mExternalStorageAvailable && mExternalStorageWriteable) {
        for (String item : items) {
            File f = new File(item);
            if (f.exists()) {
                try {
                    FileInputStream fis = new FileInputStream(f);
                    Bitmap b = BitmapFactory.decodeStream(fis);
                    bitmaps.add(b);
                    files.add(f);
                } catch (FileNotFoundException e) {
                    Log.e(Prototype.TAG, "", e);
                }
            }
        }
    }
}

还有xml布局:

<LinearLayout   xmlns:android="http://schemas.android.com/apk/res/android" 
            android:layout_width="fill_parent" 
            android:layout_height="fill_parent"
                android:orientation="vertical"
                android:gravity="bottom"

                android:paddingLeft="0px"
                android:paddingTop="0px"
                android:paddingRight="0px">

    <com.unimelb.pt3.ui.TransparentPanel
            android:id="@+id/workbench" 
            android:layout_width="fill_parent"
            android:layout_height="10px"
            android:paddingTop="0px"
            android:paddingLeft="0px"
            android:paddingBottom="0px"
            android:paddingRight="0px">

        <GridView xmlns:android="http://schemas.android.com/apk/res/android" 
            android:id="@+id/gridview"
            android:layout_width="fill_parent" 
            android:layout_height="fill_parent"
            android:columnWidth="90dp"
            android:numColumns="auto_fit"
            android:verticalSpacing="10dp"
            android:horizontalSpacing="10dp"
            android:stretchMode="columnWidth"
            android:gravity="center" />

    </com.unimelb.pt3.ui.TransparentPanel>

</LinearLayout>

【问题讨论】:

    标签: android xml gridview layout


    【解决方案1】:

    GridView 有一个 invalidateViews() 方法。

    当您调用此方法时:“所有要重建和重绘的视图”。 http://developer.android.com/reference/android/widget/GridView.html

    我认为这就是你需要的:)

    【讨论】:

    • 只有创建视图层次结构的原始线程才能触及它的视图。当您刷新网格视图时,您经常这样做是因为您正在从网络上检索信息,在这种情况下,情况并非如此。
    • 这并没有强制我重绘视图。
    【解决方案2】:

    必须的,先告诉适配器通知数据发生了变化,再把适配器设置成网格

    adapter.notifyDataChanged();
    grid.setAdapter(adapter);
    

    【讨论】:

    【解决方案3】:

    这可能会有所帮助。 在对项目执行删除后,我刷新书籍图像缩略图的网格视图。 使用 adapter.notifyDataChanged();如上所述对我不起作用,因为它在我的适配器中被调用。

    //this is a call that retrieves cached data.
    //your constructor can be designed and used without it.
    final Object data = getLastNonConfigurationInstance();
    

    我基本上只是重新加载适配器并将其绑定到同一个视图。

    //reload the adapter
    adapter = new BooksAdapter(MyBooks.this, MyBooks.this, data, show_collection );
    grid.invalidateViews();
    grid.setAdapter(adapter);
    

    【讨论】:

    • 谢谢!你的方法对我有用。我的适配器使用随机项目,并在我需要创建一个新的适配器对象时重新创建它们。你为我节省了很多搜索时间。非常感谢。
    【解决方案4】:

    @flyerz @snagnever

    你们一起得到它。应该是:

    adapter.notifyDataChanged();
    grid.invalidateViews();
    

    这将标记适配器其数据已更改,然后在调用 invalidateViews() 方法后将其传播到网格。

    很高兴我发现了这个问题,因为我不知道如何在渲染后将项目添加到网格中。

    【讨论】:

      【解决方案5】:

      这些答案都没有真正对我有用,我不得不将它们全部混合在一起。要真正让 GridView 更新,您需要这样做:

       adapter.notifyDataChanged();
       grid.invalidateViews();
       grid.setAdapter(adapter);
      

      希望这可以帮助那些无法使用其他解决方案的人。

      【讨论】:

      • 您不必使用新值创建新适配器吗?
      • 我确认了这一点,我很尴尬地使用旧适配器,因为只有数据发生变化,而不是整个适配器。
      【解决方案6】:

      您不应调用invalidateViewssetAdapter 来刷新您的grid view。让grid view 保持更新不是一个好主意,如果以这种方式更新将花费大量时间和内存。

      如果您有机会查看getView 方法,您会发现convertView 只创建了一次。当您调用notifyDataChanged 时,它将更新此视图。而如果您调用invalidateViews,则会重新创建以前创建的视图。这不是一个好的解决方案。

      当您调用 notifyDataChanged 时,会调用您的 getView 方法。所以你的 getView 方法应该类似于下面的代码。

      public List list;
      
      public class SimpleItemViewHolder extends Object
      {
          public TextView textView;
          public ImageView imageView;
      }
      
      public View getView(int position, View convertView, ViewGroup parent){
      
          View itemView = convertView;
          SimpleItemViewHolder viewHolder;
      
          if(convertView==null)
          {
              viewHolder = (SimpleItemViewHolder)itemView.getTag();
      
          }else{
              LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
              itemView = inflater.inflate(R.layout.layout_name, null);
              TextView labelField = (TextView) itemView.findViewById(R.id.label_field);
              labelField.setText(list.get(position).Name);
              //Typeface boldFont = Typeface.createFromAsset(context.getAssets(), "fonts/Font-Bold.ttf");
              //labelField.setTypeface(boldFont);
      
              ImageView imageView = (ImageView) itemView.findViewById(R.id.image_view);
              //Bitmap bitmap = init your bitmap here;
              //imageView.setImageBitmap(bitmap);  
      
              viewHolder = new SimpleItemViewHolder();
              viewHolder.imageView = imageView;
              viewHolder.textView = labelField;
              itemView.setTag(viewHolder);
      
          }
      
          //don't create new views, instead use previous ones and update them.
          viewHolder.textView.setText(list.get(position).Name);
          //viewHolder.imageView.setImageBitmap(your_bitmap);  
          return itemView;
      }
      

      【讨论】:

      • 是的。这是理论。如果 Grid 在 convertViews 改变它们的大小时没有更新它的布局,你会怎么做?
      • @EmrysMyrooin 我认为如果更改单元格的大小不会有任何区别。您只需要设置 itemView 的 layoutparams。此外,覆盖和调用 gridview 的 onMeasure 方法可能会有所帮助。
      • 不,它不起作用。如果 itemView 的高度随时间变化,GridView 将不会检测到这些变化,即使是 adapter.notifySetChanges()gridView.invalidateViews()。也许它适用于 onMeasure 覆盖,但我只是不会为了实现这样的基本行为而实现自定义 GridView...
      • @EmrysMyrooin 这一切都是为了性能,你也可以使用 invalidateViews,但是如果你的 gridview 中有数百个单元格,你会看到你的应用在调用 invalidateViews 时挂了几秒钟。所以我推荐你使用 onMeasure 方法。
      • 调用invalidateViews() 并不能解决问题...唯一有效的方法是手动设置每个销售的高度...
      【解决方案7】:
      adapter.notifyDataChanged();
      

      可能仅仅因为适配器的数据过时而无法工作(例如,如果 Activity 或 Fragment 没有被销毁并且一直位于后台堆栈中)。

      所以,如果先刷新数据,然后它就会工作。

      【讨论】:

        【解决方案8】:

        您将GridView 放置在com.unimelb.pt3.ui.TransparentPanel 中,即10px 高。

        • 你不应该使用px,你应该使用dp
        • com.unimelb.pt3.ui.TransparentPanelandroid:layout_height="10px" 更改为android:layout_height="fill_parent"

        【讨论】:

        • 我改变了它,但它没有帮助。问题不在于 GridView 的高度,它以全尺寸放置在透明面板中,并且有一个用于超大内容的滚动条,而是宽度。这只是 22,虽然它的 LayoutParams 是 fill_parent 并且 TransparentPanel 的全尺寸宽度为 320。我想我需要更新/刷新布局过程,但不知道如何正确地做到这一点。
        【解决方案9】:

        在您的适配器中:

        class MAdapter extends BaseAdapter{
           List<Objects> mObjects;
        ...
        
         public void clearAdapter(){
                mObjects.clear();
            }
        
         public void addNewValues(List<Objects> mObjects){
                this.mObjects = mObjects;
            }
        
        ...
        
        }
        
        
        adapter.clearAdapter(); // clear old values
        adapter.addNewValues(MObjects);
        adapter.notifyDataChanged();
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2019-02-05
          • 1970-01-01
          • 2012-12-15
          • 1970-01-01
          • 1970-01-01
          • 2020-01-03
          • 1970-01-01
          相关资源
          最近更新 更多