【问题标题】:StaggeredGridLayoutManager and moving itemsStaggeredGridLayoutManager 和移动项目
【发布时间】:2015-02-22 13:51:43
【问题描述】:

我创建了一个非常简单的项目,通过 recyclerview 显示 28 张带有StaggeredGridLayoutManager 的图像。但是当我滚动 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());
}

【问题讨论】:

  • 你最后做了什么?我有同样的问题,@yigit 的回答听起来不错,但是代码示例会很有帮助。您将这些数据存储在哪里以及如何恢复它?您使用什么唯一 ID?

标签: android android-recyclerview staggeredgridlayout


【解决方案1】:

首先设置差距策略,如下代码:

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

然后将您的项目添加到mItems,然后使用:

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

这种方法比使用更好:

mAdapter.notifyDataSetChanged();

【讨论】:

    【解决方案2】:

    为 staggered-layout-manager 设置 recyclerview 的固定高度和项目高度和宽度包装内容

    【讨论】:

      【解决方案3】:

      也许这是一种更有效的方法:

      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

      【讨论】:

        【解决方案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();
          }
          

          这为我解决了这个问题。

          【讨论】:

          • 你节省了我的时间。谢谢。请使用 itemLayout.requestLyout(),它会起作用
          【解决方案6】:

          对我有用的是在使用 StaggeredGridLayoutManager 时禁用回收视图上的所有动画。

          mRecyclerView.setItemAnimator(null);

          如果您只想限制移动动画并保留添加和删除项目动画,则可以创建自己的动画师。

          【讨论】:

            【解决方案7】:

            发生这种情况是因为 SGLM 不保留有关视图的任何 w/h 信息。所以每次 View 被反弹时,它会先获取占位符大小,然后是加载图像时的最终大小。

            加载具有不同尺寸(而不是占位符)的实际图像会触发新的布局请求,并且在该布局请求期间,SGLM 检测到 UI 中将存在间隙(或某些具有更高位置的项目出现在项目下方w/ 较低的位置)因此重新排序带有动画的项目。

            您可以通过将占位符图像设置为实际图像的尺寸来避免这种情况。如果您没有提前获得,您可以在第一次加载图像后保存它们,并在下一次 onBind 调用中使用它。

            【讨论】:

            • 我尝试过使用getViewType(),但我仍然有同样的问题,也许我做错了什么,你知道SGLM的任何示例代码吗?
            • 这与 getViewType() 无关。您需要在本地保存图像尺寸,以便下次重新绑定视图时,可以在 ImageView 上设置正确的尺寸以避免调整大小。
            • 您使用毕加索,为什么不使用占位符图像。这样一来,如果您使用 Dane 大小的图片作为下载的图片,您就不应该出现跳动的动画。
            • 不,您从图像视图中获取尺寸,它没有最终的图像尺寸,因此无济于事。对于每张图片,在加载时,需要从 ImageView 中获取尺寸并保存,以便下次重新加载图片时,可以在 ImageView 上进行设置。
            • 现在我只是从我的drawable文件夹中加载图像,所以item.getHeight()item.getWidth()的图像尺寸正确,现在我该怎么办? SGLM 的任何示例代码?
            【解决方案8】:

            改变这一行

            mLayoutManager.setGapStrategy(
                    StaggeredGridLayoutManager.GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS); 
            

            到这一行

            mLayoutManager.setGapStrategy(
                    StaggeredGridLayoutManager.GAP_HANDLING_NONE);           
            

            【讨论】:

            • 当我从互联网下载图像时运气不好,仍然会出现很多错误的动画。你有没有用StaggeredGridLayoutManager
            猜你喜欢
            • 2015-04-15
            • 2017-06-16
            • 2020-06-28
            • 1970-01-01
            • 1970-01-01
            • 2011-10-07
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多