Проблема прокрутки GridView на Android - PullRequest
8 голосов
/ 20 марта 2011

это должно быть что-то очень простое, я пропускаю, но у меня есть следующая проблема (сообщение довольно длинное, но я хочу предоставить как можно больше информации :)).

У меня естьgridview в моем приложении для Android, где каждая ячейка содержит пользовательский вид:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  >
    <GridView
    android:id = "@+id/photosGridView"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" 
    android:clickable="true" 
    android:drawSelectorOnTop="true" 
    android:focusable="true" 
    android:focusableInTouchMode="true" 
    android:numColumns="6" 
    android:columnWidth="90dp"
    android:verticalSpacing="5dp"
    android:horizontalSpacing="5dp"
    android:stretchMode="columnWidth"     
    >
</GridView>

</RelativeLayout>

, а каждая ячейка

<?xml version="1.0" encoding="utf-8"?>
<com.myapp.widgets.ImageThumbView
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:background = "@android:color/transparent"
  android:paddingLeft = "1dip"
  android:paddingRight = "1dip"
  android:paddingTop = "2dip"
  android:paddingBottom = "2dip"
  >
<ImageView
    android:id="@+id/thumbImage"
    android:layout_width="fill_parent"
    android:layout_height = "fill_parent"
    android:src="@drawable/icon_small"
    /> 

  <RelativeLayout
    android:layout_width="fill_parent"
    android:layout_height = "fill_parent"
    android:background = "@android:color/transparent"
   >

  <ImageView
   android:id="@+id/iconRight"
   android:layout_width="40px"
   android:layout_height = "40px"  
   android:src="@drawable/album_check"
   android:visibility="gone"
   android:layout_alignParentTop = "true"
   android:layout_alignParentRight = "true"     
   />

  <ImageView
   android:id="@+id/iconLeft"
   android:src="@drawable/album_check"
   android:visibility="gone"
   android:layout_width = "40px"
   android:layout_height="40px"
   android:layout_alignParentTop = "true"
   android:layout_alignParentLeft = "true"     
   /> 
</RelativeLayout>

</com.myapp.widgets.ImageThumbView>

Мой адаптер выглядит следующим образом:

public class ImageAdapter extends BaseAdapter {
    private List<String> mPictures = null;

    public ImageAdapter(List<String> pictures) {
         mPictures = pictures;
    }

    public int getCount() {
          return mPictures != null ? mPictures.size() : 0;
    }
    public Object getItem(int position) {
          return mPictures != null ?  mPictures.get(position) : null;
    }
    public long getItemId(int position) {
          return mPictures != null ? position : -1;
    }
    @Override
    public View getView(int position,View convertView,ViewGroup parent) 
    {
        ImageThumbView i = null;
        try
            {               
            Thread.sleep(100);

            if (convertView == null) 
            {
                String path = mPictures.get(position);
                Log.d(((Integer)position).toString(), path);
                i = addSingleView(_li, path);
                TextView idx = (TextView) i.findViewById(R.id.caption);
                if (idx != null)
                    idx.setText(((Integer)position).toString());
            }
            else 
            {
                Log.d(((Integer)position).toString(), "ALREADY NOT NULL");
                i = (ImageThumbView) convertView;
                                    // These 2 lines were added only in desperate attempt to get it working, but it makes no difference
                String path = mPictures.get(position);
                i.updateView(path);
            }
        }
        catch(InterruptedException ie)
        {
            ie.printStackTrace();
        }
    return i;
        }
}

Итакизначально он работает правильно, т.е. показывает первые 18 изображений и несколько пикселей из следующей строки.Но когда я начинаю прокручивать сетку, изображения начинают появляться случайным образом, то есть после последнего изображения я вижу немного с самого начала и так далее.Из любопытства я попробовал несколько примеров, подобных этому: http://androidsamples.blogspot.com/2009/06/how-to-display-thumbnails-of-images.html ... и увидел тот же результат.

Итак, я что-то не так делаю?с какой стати GridView отображает больше элементов, чем предполагалось?и почему предметы появляются в неправильных позициях?

BR, Alex

Ответы [ 5 ]

21 голосов
/ 12 мая 2011

На самом деле проблема здесь в том, что вы устанавливаете содержимое «convertView» в if или else. Или вы всегда должны делать это после создания экземпляра представления, если оно пустое, и устанавливать содержимое только перед возвратом представления.

Следовательно, вы уверены, что содержимое представления всегда правильное, оно обновляется с использованием позиции, а не ложного переработанного представления.

Итак, вы должны, вообще говоря, сделать следующее:
(на основе руководства из Android Guide здесь )

public View getView(int position, View convertView, ViewGroup parent) {
    ImageView imageView;
    if (convertView == null) { 
        imageView = new ImageView(mContext);
        //just creating the view if not already present
    } else {
        imageView = (ImageView) convertView;
        //re-using if already here
    }

    //here is the tricky part : set the content of the view out of the if, else
    //just before returning the view
    imageView.setImageResource(mThumbIds[position]);
    return imageView;
}
10 голосов
/ 20 марта 2011

Ответ - просмотр рециркуляции.

В общем, ваш getView всегда должен иметь вид:

public class ImageAdapter extends BaseAdapter {

    private List<String> mUrls; // put your urls here
    private Map<String, Drawable> mImages; // cache your images here

    public ImageAdapter() {
        ...
        mUrls = new ArrayList<String>();
        mImages = new HashMap<String, Drawable>();
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder; // Use the ViewHolder pattern for efficiency

        if (convertView == null) {
            // first time this view has been created so inflate our layout
            convertView = View.inflate(this, R.layout.my_grid_item, null);
            holder = new ViewHolder();
            holder.image = convertView.findViewById(R.id.image);
            holder.text = convertView.findViewById(R.id.text);
            convertView.setTag(holder); // set the View holder
        } else {
           holder = (ViewHolder) convertView.getTag();
        }

        // update the current view - this must be done EVERY
        // time getView is called due to view recycling
        holder.text.setText(Integer.toString(position));

        // check our cache for the downloaded image
        final String url = mUrls.get(position);
        if (mImages.get(url) != null)
            holder.image.setImageDrawable(mImages.get(url));
        else
            loadImage(url, holder.image);

        // return our view
        return convertView;
    }

    public loadImage(final String url, final ImageView image) {
        // load an image (maybe do this using an AsyncTask
        // if you're loading from network
    }

    ...
}

Где ваш ViewHolder класс будет выглядеть примерно так:

public class ViewHolder {
    ImageView thumbImage;
    TextView text;
}

Тогда у вас не должно быть проблем. Также я не уверен, почему вам нужно было спать в вашем getView? Это замедлит прокрутку вашего GridView.

3 голосов
/ 26 апреля 2012

Используйте стандартный Lazy Loader для получения изображений, но никогда не обновляйте onpostexecute, что приводит к слишком быстрому обновлению изображений и получению случайности, которую вы не желаете.

Я даже использовал код:

if (result != null && !mFlinging && myPosition < 12)
{   
   imageView.setImageBitmap(result);
}

int onpostexecute, который затем корректно обновит изображения для первого экрана, но если вы перевернете экран изображений, то слишком быстро вернетесь к первому экрану, снова получите случайность, поэтому я теперь использую:

mPhotoView.setOnScrollListener(new OnScrollListener() { 



            public void onScroll(AbsListView view, int firstVisibleItem,
                    int visibleItemCount, int totalItemCount) {
                // TODO Auto-generated method stub

            }

            public void onScrollStateChanged(AbsListView view, int scrollState) {
                // TODO Auto-generated method stub
                if(scrollState != SCROLL_STATE_IDLE) {
                  mAdapter.setFlinging(true);
                } else {
                  mAdapter.setFlinging(false);   
                }

                int first = view.getFirstVisiblePosition(); 
                int count = view.getChildCount(); 

                if (scrollState == SCROLL_STATE_IDLE || (first + count > mAdapter.getCount()) ) { 
                    mPhotoView.invalidateViews(); 
                }

            } 
        }); 

чтобы обновить вид.

0 голосов
/ 19 января 2012

ребята, чтобы избежать этой проблемы, всегда возвращайте вновь созданный объект в getView ()

public View getView(int position, View convertView, ViewGroup parent) {
                ImageView       imageView;
                TextView        textView;
                LinearLayout    linearlayout  = new LinearLayout(mContext);
                //if (convertView == null) {
                    imageView       = new ImageView(mContext);
                    textView        = new TextView(mContext);

                    //imageView.setLayoutParams(new GridView.LayoutParams(85, 85));
                    imageView.setAdjustViewBounds(false);
                    imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
                    imageView.setPadding(4, 8, 8, 8);                   
                    imageView.setBackgroundResource(mThumbIds[position]);

                    textView.setText(mThumbText[position]);                
                    textView.setGravity(0x01);
                    textView.setMaxLines(2);

                    //textView.setPadding(20, 0, 0, 0);
                    linearlayout.addView(imageView,0);
                    linearlayout.addView(textView,1);
                    linearlayout.setPadding(4, 4, 4, 4);
                    linearlayout.setOrientation(LinearLayout.VERTICAL);
                    linearlayout.setGravity(0x01);

               // } else {
                    //linearlayout = (LinearLayout) convertView;
                //}

                return linearlayout;
            }
0 голосов
/ 26 сентября 2011

У меня такая же проблема. Я двигаюсь в направлении рендеринга видов в фоновом режиме;

Я изучаю эти коды, если должно помочь:

http://blog.tomgibara.com/post/7665158012/android-adapter-view-rendering

https://github.com/desertjim/LazyLoadingGridView

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...