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());
}
Ответы
Ответ 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