web-dev-qa-db-fra.com

StaggeredGridLayoutManager et éléments en mouvement

J'ai créé un projet très simple, affichant 28 images avec StaggeredGridLayoutManager par recyclerview. mais au fur et à mesure que je fais défiler la vue recyclée, il déplace des éléments, par exemple, de gauche à droite ou échange la colonne gauche/droite.

codes:

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);

    }

} 

Et l'adaptateur:

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);

    }

}

et un exemple d'article en mouvement:

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

si vous jouez (faites défiler de haut en bas) vous pouvez découvrir une animation plus intéressante :-)

Comment empêcher cela et avoir une mise en page stable comme une listview ordinaire?

Modifier

@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());
}
20
mmlooloo

Cela se produit car SGLM ne conserve aucune information sur les vues. Ainsi, chaque fois qu’une vue est rebondie, elle obtient d’abord la taille de l’emplacement, puis la taille finale du chargement de l’image.

Le chargement de l'image réelle avec une taille différente (que celle de l'espace réservé) déclenche une nouvelle demande de mise en page. Au cours de cette demande, SGLM détecte qu'il y aura des vides dans l'interface utilisateur (ou qu'un élément avec une position plus élevée apparaît sous un élément avec positionne donc les articles avec une animation.

Vous pouvez l'éviter en définissant votre image de lieu réservé aux dimensions de l'image réelle. Si vous ne l'avez pas à l'avance, vous pouvez les enregistrer une fois que l'image est chargée pour la première fois et les utiliser lors du prochain appel onBind. 

15
yigit

Changer cette ligne

mLayoutManager.setGapStrategy(
        StaggeredGridLayoutManager.GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS); 

à cette ligne

mLayoutManager.setGapStrategy(
        StaggeredGridLayoutManager.GAP_HANDLING_NONE);           
6
Matthias Robbers

Tu peux essayer ça

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

une fois que vous avez défini ceci, vous constaterez qu’il ya un blanc en haut lorsque vous faites défiler vers le haut. continuer à définir cette

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

C'est un travail pour moi, j'arrive là quelque part. J'espère que cela peut vous aider!

6
TC.Martin

Ajoutez la ligne suivante à la fin de la méthode: holder.mImageView.requestLayout ();

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

Cela a résolu le problème pour moi.

2
M. Baumgartner

Tout d'abord définir la stratégie de l'écart comme suit 

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

puis ajoutez votre article à mItems puis utilisez:

mAdapter.notifyItemInserted (mItems.size () - 1); cette méthode est préférable à l'utilisation de:

mAdapter.notifyDataSetChanged ();

0
subhash gaikwad

C'est peut-être un moyen plus efficace:

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

Pour plus d'informations: https://github.com/ibosong/CommonItemDecoration

0
Bos

Définissez la hauteur de votre vue recyclable ainsi que la hauteur et la largeur de l'élément, ainsi que le contenu enveloppant pour le gestionnaire de disposition décalé

0
Roufal