【问题标题】:Saving and retrieving inflated View's size in RecyclerView在 RecyclerView 中保存和检索膨胀视图的大小
【发布时间】:2016-02-24 23:24:14
【问题描述】:

我有一个 RecyclerView,它有一个 staggeredGridLayoutManager 作为布局管理器。我的布局有 2 个跨度(列),里面的项目可能有不同的高度。 膨胀的项目在 LinearLayout 容器内有一个 ImageView 和一些其他视图。

我想在视图的图像完全加载后保存 Inflated(或者我应该说绑定?)视图的大小(高度和宽度)。因为这个操作让我知道了LinearLayout在final-图片放入layout后-占据了多少宽高。

滚动后,此容器可能会被回收并再次绑定。我想要实现的是在绑定后立即保存绑定布局的大小,根据之前计算的高度和宽度值,因为这使得recyclerView的项目位置更加稳定。他们不太可能四处走动。

我的 ViewHolder 中有 mWidth 和 mHeight 成员,它们基本上存储这些值。但是,我失去了适配器中的项目位置和相应的 ViewHolder 之间的同步。例如,我将第 8 个项目的高度计算为第一次可见时的 380 像素,这是正确的。再次回收并绑定第8个位置后,我的视图高度检索为300 px,这是不正确的。

代码: BasicActivity 派生自 Activity..

public ItemsRVAdapter(BasicActivity activity, JSONArray items){
    this.items = items;
    this.activity = activity;
    this.itemControl = new Items(activity);
}

创建时:

@Override
public ItemListViewHolders onCreateViewHolder(ViewGroup viewGroup, int i) {


    View layoutView =activity.getLayoutInflater().inflate(R.layout.list_element_items, viewGroup, false);
    ItemListViewHolders rcv = new ItemListViewHolders(layoutView);
    return rcv;
}

OnViewAttachedToWindow(我在不同的地方尝试了相同的代码,比如 onViewRecycled 但我不知道这个方法是计算大小的最合适的地方)

@Override
public void onViewAttachedToWindow(ItemListViewHolders holder)
{
    holder.layoutCapsule.measure(LinearLayout.MeasureSpec.makeMeasureSpec(0, LinearLayout.MeasureSpec.UNSPECIFIED), LinearLayout.MeasureSpec.makeMeasureSpec(0, LinearLayout.MeasureSpec.UNSPECIFIED));
    if(holder.image.getDrawable() != null){

        holder.height = holder.layoutCapsule.getHeight();
        holder.width = holder.layoutCapsule.getWidth();
    }else{
        holder.height = 0;
        holder.width = 0;
    }

}

onBindViewHolder:仅相关部分。这里我将位置值和我的数组的成员索引配对

@Override
public void onBindViewHolder(ItemListViewHolders holder, int position) {
    try {

        //JSONObject item = items.getJSONObject(holder.getAdapterPosition());
        JSONObject item = items.getJSONObject(position);
        holder.image.setImageDrawable(null);
        ViewGroup viewGroup = holder.layoutCapsule; //Main Container
        ...
    }
}

【问题讨论】:

  • 如果您不想移动项目,为什么不使用GridLayoutManager 或禁用“四处移动”?
  • 我有 2 个跨度(列),但与网格不同,列中的项目可能有不同的高度。
  • 那你为什么不直接用GAP_HANDLING_NONE禁用物品移动呢?
  • GAP_HANDLING_NONE 不会禁用项目转移,至少不是我想要的方式,或者它有一个错误。它确实会移动项目,即使策略是 GAP_HANDLING_NONE,可能只有当项目具有不同的高度时。你可以在这里看到我的另一个问题,它有一个 youtube 链接显示我所说的内容。 stackoverflow.com/questions/35565743/… 可以看到两行都随着 GAP_HANDLING_NONE 移动,视频顶部的间隙问题
  • 我很好奇你的目的是什么?如果您希望您的 UI 更稳定,您可以将 RecyclerView 设置为将 #setHasFixedSize 设置为 false。 ViewHolders 随时被回收,你为什么要记住它们。如果您的最终目的是禁用项目移位,我想您应该从数据排序、图像大小处理等开始。

标签: android android-layout android-recyclerview


【解决方案1】:

我建议寻找一种不同的方法来解决您的项目移动问题,而不是取决于视图大小,但如果您想以这种方式继续,这是我建议的解决方案:

不要依赖或保存持有人的大小值,因为这会被回收,您需要创建一个对象“描述符”,其中包含每个位置的值(宽度和高度)并将它们保存在 HashMap 或类似的东西上那,保存你正在做的值,我理解“onViewAttachedToWindow”。

class Descriptor(){
   int width;
   int height;

void setWidth(int width){
   this.width = width;
}
int getWidth(){
   return width;
}
void setHeight(int height){
   this.height = height;
}
int getHeight(){
   return height;
}

在构造函数上初始化数组:

descriptors = new HashMap<Integer, Descriptor>();

在 onBindViewHolder 中保存视图标签上的位置以在 OnViewAttachedToWindow 上使用它

public void onBindViewHolder(ItemListViewHolders holder, int position) {
   ....
   holder.image.setTag(position);
   ...
}

在 onViewAttachedToWindow 上填充值

public void onViewAttachedToWindow(ItemListViewHolders holder){
   ...
   int position = (Integer)holder.image.getTag();
   Descriptor d = descriptors.get(position);
   if(d == null){
      d = new Descriptor();
      descriptors.put(position, d);
   }
   d.setWidth(holder.layoutCapsule.getWidth());
   d.setHeight(holder.layoutCapsule.getHeight());
   ...
}

然后在您需要按位置获取它的方法上使用描述符上的大小数据,您将在用户向下滚动时创建描述符,这也适用于数据在生命周期内保持相同位置的假设适配器。

【讨论】:

  • onViewAttachedToWindow 有时不能给出正确的高度。它只是给出了以前的预回收高度。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-09-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-08
  • 1970-01-01
相关资源
最近更新 更多