android - StaggeredGridLayoutManager y elementos en movimiento
android-recyclerview recycler-adapter (8)
Agregue la siguiente línea al final del método: holder.mImageView.requestLayout ();
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
...
holder.mImageView.requestLayout();
}
Esto solucionó el problema para mí.
He creado un proyecto muy simple, mostrando 28 imágenes con StaggeredGridLayoutManager
por recyclerview. pero a medida que recorro la vista de reciclaje, mueve elementos, por ejemplo, de izquierda a derecha o intercambiando la columna de izquierda y derecha.
códigos:
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);
}
}
Y el adaptador:
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);
}
}
y un elemento móvil de muestra:
http://i.imgur.com/FUapm2K.gif?1
Si juegas (desplázate hacia arriba y hacia abajo) puedes descubrir animaciones más interesantes :-)
¿Cómo evitar eso y tener un diseño estable como una vista de lista ordinaria?
Editar
@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());
}
Cambia esta linea
mLayoutManager.setGapStrategy(
StaggeredGridLayoutManager.GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS);
a esta linea
mLayoutManager.setGapStrategy(
StaggeredGridLayoutManager.GAP_HANDLING_NONE);
En primer lugar establecer la estrategia de brecha como siguiendo
mLayoutManager = new StaggeredGridLayoutManager (SPAN_COUNT, StaggeredGridLayoutManager.VERTICAL); mLayoutManager.setGapStrategy (StaggeredGridLayoutManager.GAP_HANDLING_NONE);
y luego agregue su artículo a artículos y luego use:
mAdapter.notifyItemInserted (mItems.size () - 1); este método es mejor que usar:
mAdapter.notifyDataSetChanged ();
Establezca la altura fija de su recyclerview y el contenido envolvente de la altura y el ancho del elemento para el administrador de diseño escalonado
Esto está sucediendo porque SGLM no guarda ninguna información w / h sobre las vistas. Por lo tanto, cada vez que una Vista rebota, primero se obtiene el tamaño del marcador de posición y luego el tamaño final cuando se carga la imagen.
La carga de la imagen real con un tamaño diferente (que el marcador de posición) desencadena una nueva solicitud de diseño, y durante esa solicitud de diseño, SGLM detecta que habrá espacios en la interfaz de usuario (o algún elemento con una posición más alta aparece debajo de un artículo con una posición más baja) posición) por lo tanto, reordena los artículos con una animación.
Puede evitarlo configurando la imagen del marcador de posición según las dimensiones de la imagen real. Si no lo tiene con anticipación, puede guardarlos después de que la imagen se cargue por primera vez y usarla en la próxima llamada en enlace.
Lo que funcionó para mí fue deshabilitar todas las animaciones en la vista de reciclaje al usar StaggeredGridLayoutManager.
mRecyclerView.setItemAnimator(null);
Puede crear su propio animador si solo desea restringir las animaciones en movimiento y mantener las animaciones de agregar y eliminar elementos.
Puedes probar esto
StaggeredGridLayoutManager manager = new StaggeredGridLayoutManager(2, OrientationHelper.VERTICAL);
manager.setGapStrategy(StaggeredGridLayoutManager.GAP_HANDLING_NONE);
mRecyclerView.setLayoutManager(manager);
después de configurar esto, verá que hay un espacio en blanco en la parte superior cuando se desplaza hacia la parte superior. sigue configurando esto
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
((StaggeredGridLayoutManager)recyclerView.getLayoutManager()).invalidateSpanAssignments();
}
});
Es un trabajo para mí, llego a este lado en alguna parte. Espero que te pueda ayudar!
Tal vez esta es una manera más eficiente:
mBrandRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
if(newState == RecyclerView.SCROLL_STATE_IDLE){
mBrandRecyclerView.invalidateItemDecorations();
}
}
});
Para obtener más información: https://github.com/ibosong/CommonItemDecoration