webentwicklung-frage-antwort-db.com.de

StaggeredGridLayoutManager und Verschieben von Elementen

Ich habe ein sehr einfaches Projekt erstellt, in dem 28 Bilder mit StaggeredGridLayoutManager durch Recyclingansicht angezeigt werden. Beim Scrollen durch das Recycling-Fenster werden jedoch Elemente beispielsweise von links nach rechts verschoben oder die Spalte von links und rechts ausgetauscht.

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

    }

} 

Und der Adapter:

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

    }

}

und ein Beispiel für einen beweglichen Gegenstand:

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

wenn Sie spielen (nach oben und unten scrollen), können Sie weitere interessante Animationen entdecken :-)

Wie kann man das verhindern und ein stabiles Layout wie eine gewöhnliche Listenansicht haben?

Bearbeiten

@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

Dies geschieht, weil SGLM keine w/h-Informationen zu den Ansichten speichert. Jedes Mal, wenn eine Ansicht zurückgespult wird, erhält sie zuerst die Platzhaltergröße und dann die endgültige Größe, wenn das Bild geladen wird.

Beim Laden des tatsächlichen Bildes mit einer anderen Größe (als Platzhalter) wird eine neue Layoutanforderung ausgelöst. Während dieser Layoutanforderung erkennt SGLM, dass Lücken in der Benutzeroberfläche vorhanden sind (oder ein Element mit einer höheren Position wird unter einem Element mit einem niedrigeren Wert angezeigt) Position) ordnet also Artikel mit Animation neu an.

Sie können dies vermeiden, indem Sie Ihr Platzhalterbild auf die Abmessungen des tatsächlichen Bildes einstellen. Wenn Sie es nicht vorzeitig haben, können Sie sie speichern, nachdem das Image zum ersten Mal geladen wurde, und es beim nächsten Aufruf von onBind verwenden. 

15
yigit

Bei mir funktionierte es, alle Animationen in der Recycling-Ansicht zu deaktivieren, wenn StaggeredGridLayoutManager verwendet wurde.

mRecyclerView.setItemAnimator(null);

Sie können Ihren eigenen Animator erstellen, wenn Sie nur das Verschieben von Animationen einschränken und das Hinzufügen und Entfernen von Elementanimationen beibehalten möchten.

10
Sanchit Gupta

Ändern Sie diese Zeile

mLayoutManager.setGapStrategy(
        StaggeredGridLayoutManager.GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS); 

zu dieser Linie

mLayoutManager.setGapStrategy(
        StaggeredGridLayoutManager.GAP_HANDLING_NONE);           
6

Sie können es versuchen

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

nachdem Sie diese Einstellung vorgenommen haben, wird oben ein Leerzeichen angezeigt, wenn Sie nach oben blättern. setze dies fort

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

Es ist Arbeit für mich, ich komme irgendwo hin. Ich hoffe es kann dir helfen!

6
TC.Martin

Fügen Sie am Ende der Methode die folgende Zeile hinzu: holder.mImageView.requestLayout ();

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

Dies hat das Problem für mich behoben.

2
M. Baumgartner

Stellen Sie zunächst die Lückenstrategie wie folgt ein 

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

und fügen Sie dann Ihren Artikel zu mItems hinzu und verwenden Sie dann:

mAdapter.notifyItemInserted (mItems.size () - 1); Diese Methode ist besser als die Verwendung von:

mAdapter.notifyDataSetChanged ();

0
subhash gaikwad

Vielleicht ist dies ein effizienter Weg:

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

Weitere Informationen: https://github.com/ibosong/CommonItemDecoration

0
Bos

Legen Sie die Höhe Ihres Recyclingberichts fest und den Packungsinhalt für Höhe und Breite der Elemente für den gestaffelten Layout-Manager

0
Roufal