Подтвердить что ты не робот

StaggeredGridLayoutManager и движущиеся объекты

Я создал очень простой проект, отображающий 28 изображений с помощью StaggeredGridLayoutManager с помощью recyclerview. но когда я просматриваю recyclerview, он перемещает элементы, например, слева направо или заменяет столбец слева и справа.

кода:

import java.util.ArrayList;
import java.util.List;

import android.app.Activity;
import android.os.Bundle;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;


public class MainActivity extends Activity {


    String mImageDir;
    private RecyclerView mRecyclerView;
    private StaggeredGridLayoutManager mLayoutManager;



    MyRecyclerAdapter myRecyclerAdapter;
    List<ImageModel> mImageList;

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);   
        mRecyclerView = (RecyclerView)findViewById(R.id.recyclerview_rootview);
        mLayoutManager = new StaggeredGridLayoutManager(2,StaggeredGridLayoutManager.VERTICAL);     
        mLayoutManager.setGapStrategy(StaggeredGridLayoutManager.GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS);        
        mRecyclerView.setLayoutManager(mLayoutManager);
        mRecyclerView.setHasFixedSize(false);
        mImageList = new ArrayList<ImageModel>();
        for (int i = 1; i < 29 ; i++) {
            ImageModel img = new ImageModel();
            img.setTitle("Image No " + i);
            int drawableResourceId = this.getResources().getIdentifier("image"+String.valueOf(i), "drawable", this.getPackageName());
            img.setResId(drawableResourceId);
            mImageList.add(img);

        }
        myRecyclerAdapter = new MyRecyclerAdapter(MainActivity.this,mImageList);        
        mRecyclerView.setAdapter(myRecyclerAdapter);

    }

} 

И адаптер:

public class MyRecyclerAdapter extends RecyclerView.Adapter<MyRecyclerAdapter.ViewHolder> {


    private List<ImageModel> mItems;
    Context mContext;

    public MyRecyclerAdapter(Context context,List<ImageModel> objects) {
        mContext = context;
        mItems = objects;

    }

    static class ViewHolder extends RecyclerView.ViewHolder{
        public  ImageView mImageView;
        public  TextView mTextView;
        public View rootView;
        public ViewHolder(View itemView) {
            super(itemView);
            rootView = itemView;
            mImageView =(ImageView)itemView.findViewById(R.id.image);
            mTextView =(TextView)itemView.findViewById(R.id.title);
        }
    }

    @Override
    public int getItemCount() {

        return mItems.size();
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {

        ImageModel item = mItems.get(position); 
        Picasso.with(mContext).load(item.getResId()).into(holder.mImageView);
        holder.mTextView.setText(item.getTitle());
    }


    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int arg1) {
        LayoutInflater inflater =    
                (LayoutInflater) mContext.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
        View convertView = inflater.inflate(R.layout.item, parent, false);
        return new ViewHolder(convertView);

    }

}

и образец движущегося элемента:

http://i.imgur.com/FUapm2K.gif?1

если вы играете (прокручивайте вверх и вниз), вы можете обнаружить более интересную анимацию: -)

Как предотвратить это и иметь стабильный макет, как обычный список?

Изменить

@Override
public void onBindViewHolder(ViewHolder holder, int position) {

    ImageModel item = mItems.get(position);
    RelativeLayout.LayoutParams rlp = (RelativeLayout.LayoutParams)holder.mImageView.getLayoutParams();
    float ratio = item.getHeight()/item.getWidth();
    rlp.height = (int)(rlp.width * ratio);
    holder.mImageView.setLayoutParams(rlp);
    Picasso.with(mContext).load(item.getResId()).into(holder.mImageView);
    holder.mTextView.setText(item.getTitle());
}
4b9b3361

Ответ 1

Это происходит потому, что SGLM не сохраняет никакой информации о просмотрах. Поэтому каждый раз, когда "Вид" отскакивает, он сначала получает размер держателя места, а затем конечный размер при загрузке изображения.

Загрузка фактического изображения с разным размером (чем владелец места) запускает новый запрос макета, и в течение этого запроса макета SGLM обнаруживает, что в пользовательском интерфейсе будут пробелы (или позиция элемента с более высокой позицией ниже элемента w/lower position), таким образом, переупорядочивает элементы с анимацией.

Вы можете избежать этого, установив изображение вашего владельца места на размеры фактического изображения. Если у вас его нет, вы можете сохранить их после того, как изображение будет загружено в первый раз и использовать его в следующем вызове onBind.

Ответ 2

Что сработало для меня, так это отключить всю анимацию в режиме просмотра при использовании StaggeredGridLayoutManager.

mRecyclerView.setItemAnimator(null);

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

Ответ 3

Измените эту строку

mLayoutManager.setGapStrategy(
        StaggeredGridLayoutManager.GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS); 

в эту строку

mLayoutManager.setGapStrategy(
        StaggeredGridLayoutManager.GAP_HANDLING_NONE);           

Ответ 4

Вы можете попробовать это

    StaggeredGridLayoutManager manager = new StaggeredGridLayoutManager(2, OrientationHelper.VERTICAL);
    manager.setGapStrategy(StaggeredGridLayoutManager.GAP_HANDLING_NONE);
    mRecyclerView.setLayoutManager(manager);

после того, как вы установите это, вы увидите, что в верхней части экрана есть пробел, когда вы переходите к вершине. продолжайте устанавливать этот

    mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
            super.onScrollStateChanged(recyclerView, newState);
            ((StaggeredGridLayoutManager)recyclerView.getLayoutManager()).invalidateSpanAssignments();
        }
    });

Это работает для меня, я так и получаю этот путь. Надеюсь, это поможет вам!

Ответ 5

Добавьте следующую строку в конце метода: holder.mImageView.requestLayout();

@Override
public void onBindViewHolder(ViewHolder holder, int position) {
    ...
    holder.mImageView.requestLayout();
}

Это исправило проблему для меня.

Ответ 6

Возможно, это более эффективный способ:

mBrandRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
            if(newState == RecyclerView.SCROLL_STATE_IDLE){
                mBrandRecyclerView.invalidateItemDecorations();
            }
        }
    });

Для получения дополнительной информации: https://github.com/ibosong/CommonItemDecoration

Ответ 7

Сначала установите стратегию разрыва, как в следующем коде:

mLayoutManager = new StaggeredGridLayoutManager(SPAN_COUNT, StaggeredGridLayoutManager.VERTICAL);
                            mLayoutManager.setGapStrategy(StaggeredGridLayoutManager.GAP_HANDLING_NONE);

а затем добавьте свой элемент в mItems и затем используйте:

mAdapter.notifyItemInserted(mItems.size() - 1);

этот метод лучше чем использование:

mAdapter.notifyDataSetChanged();

Ответ 8

Установите фиксированную высоту окна рециркуляции и обтекание содержимого и высоты элемента для staggered-layout-manager