在垂直 recyclerView 中带有 wrap_content 的水平 recyclerView

Posted

技术标签:

【中文标题】在垂直 recyclerView 中带有 wrap_content 的水平 recyclerView【英文标题】:horizontal recyclerView with wrap_content in vertical recyclerView 【发布时间】:2015-12-17 19:48:40 【问题描述】:

在我的应用程序中,我必须在垂直 RecyclerView 中创建水平 RecyclerView。它们是一些将显示随意细节的行,在某些行中将显示一个水平的 RecyclerView。

我已将水平 RecyclerView 的高度设置为不可见的 wrap_content。但是当我向它添加硬编码高度时,RecyclerView 是可见的。关于这个问题,我进行了很多搜索,但没有找到任何有效或令人信服的解决方案。

这是我的适配器类

public class HomeRVAdapter extends RecyclerView.Adapter<HomeRVAdapter.HomeViewHolder> 
private ArrayList<LinkedHashMap<String, Object>> data;
private Context ctx;
private int selectedIndex;

public HomeRVAdapter(Context ctx, ArrayList<LinkedHashMap<String, Object>> val) 
    data = val;
    this.ctx = ctx;
    selectedIndex = -1;


@Override
public HomeViewHolder onCreateViewHolder(ViewGroup parent, int viewType) 
    LayoutInflater inflater = ((Activity) ctx).getLayoutInflater();

    View view = inflater.inflate(R.layout.custom_home_recycler, null);

    return new HomeViewHolder(view);


@Override
public int getItemCount() 
    return data.size();


@Override
public void onBindViewHolder(final HomeViewHolder holder, final int position) 
    if (getItemCount() == position+1) 
        holder.categoryLL.setVisibility(View.GONE);
        holder.productLL.setVisibility(View.VISIBLE);

        LinearLayoutManager manager = new LinearLayoutManager(ctx);
        manager.setOrientation(LinearLayoutManager.HORIZONTAL);

        ArrayList<SubCategoryDetails> list = new ArrayList<>();
        list.add(new SubCategoryDetails());
        list.add(new SubCategoryDetails());
        list.add(new SubCategoryDetails());
        list.add(new SubCategoryDetails());
        list.add(new SubCategoryDetails());
        list.add(new SubCategoryDetails());
        list.add(new SubCategoryDetails());
        list.add(new SubCategoryDetails());
        list.add(new SubCategoryDetails());
        list.add(new SubCategoryDetails());
        list.add(new SubCategoryDetails());
        list.add(new SubCategoryDetails());

        holder.subCatRV.setAdapter(new PromoProductAdapter(list, holder.subCatRV));
        holder.subCatRV.setLayoutManager(manager);

     else 
        holder.categoryLL.setVisibility(View.VISIBLE);
        holder.productLL.setVisibility(View.GONE);

        if (selectedIndex == position) 
            holder.subCatGrid.setVisibility(View.VISIBLE);
            showGrid(holder);
         else 
            holder.subCatGrid.setVisibility(View.GONE);
        

        holder.catTR.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View v) 
                if (selectedIndex == position) 
                    holder.subCatGrid.setVisibility(View.GONE);
                    selectedIndex = -1;
                 else 
                    selectedIndex = position;
                    showGrid(holder);
                
            
        );
    


private void showGrid(HomeViewHolder holder) 
    ArrayList<SubCategoryDetails> list = new ArrayList<>();
    list.add(new SubCategoryDetails());
    list.add(new SubCategoryDetails());
    list.add(new SubCategoryDetails());
    list.add(new SubCategoryDetails());
    list.add(new SubCategoryDetails());
    list.add(new SubCategoryDetails());
    list.add(new SubCategoryDetails());

    SubCategoryGridAdapter adapter = new SubCategoryGridAdapter(list);

    holder.subCatGrid.setAdapter(adapter);
    holder.subCatGrid.setVisibility(View.VISIBLE);


class HomeViewHolder extends RecyclerView.ViewHolder 
    RecyclerView subCatRV;
    TextView catTitleTV, productNameTV;
    ImageView productIV;
    NonScrollableGridView subCatGrid;
    LinearLayout categoryLL, productLL;
    TableRow catTR;

    public HomeViewHolder(View view) 
        super(view);

        subCatRV = (RecyclerView) view.findViewById(R.id.subCatRV);
        productNameTV = (TextView) view.findViewById(R.id.productNameTV);

        catTitleTV = (TextView) view.findViewById(R.id.catTitleTV);
        productIV = (ImageView) view.findViewById(R.id.productIV);
        subCatGrid = (NonScrollableGridView) view.findViewById(R.id.subCatGrid);
        categoryLL = (LinearLayout) view.findViewById(R.id.categoryLL);
        productLL = (LinearLayout) view.findViewById(R.id.productLL);
        catTR = (TableRow) view.findViewById(R.id.catTR);
    


class SubCategoryGridAdapter extends BaseAdapter 
    ArrayList<SubCategoryDetails> subCatData;

    public SubCategoryGridAdapter(ArrayList<SubCategoryDetails> subCatData)
        this.subCatData = subCatData;
    

    @Override
    public int getCount() 
        return subCatData.size();
    

    @Override
    public Object getItem(int position) 
        return null;
    

    @Override
    public View getView(int position, View convertView, ViewGroup parent) 
        if (convertView == null) 
            convertView = ((Activity) ctx).getLayoutInflater().inflate(R.layout.custom_sub_cat_grid, null, true);
        

        return convertView;
    

    @Override
    public long getItemId(int position) 
        return 0;
    


class PromoProductAdapter extends RecyclerView.Adapter<PromoProductAdapter.PromoHolder> 
    ArrayList<SubCategoryDetails> data;
    RecyclerView horizontalRV;

    public PromoProductAdapter(ArrayList<SubCategoryDetails> data, RecyclerView horizontalRV)
        this.data = data;
        this.horizontalRV = horizontalRV;
    

    @Override
    public PromoHolder onCreateViewHolder(ViewGroup parent, int viewType) 
        LayoutInflater inflater = ((Activity) ctx).getLayoutInflater();

        View view = inflater.inflate(R.layout.custom_promoted_product, null);

        if (horizontalRV != null) 
            int height = view.getMeasuredHeight();
            horizontalRV.getLayoutParams().height = height;
        

        return new PromoHolder(view);
    

    @Override
    public int getItemCount() 
        return data.size();
    

    @Override
    public void onBindViewHolder(PromoHolder holder, int position) 

    

    class PromoHolder extends RecyclerView.ViewHolder 
        public PromoHolder(View view) 
            super(view);
        
    

请帮我解决这个问题。

【问题讨论】:

能贴出适配器代码吗? 通常 RecyclerView 不会wrap_content height。 我已经更新了我的问题 @mr.icetea 你有什么建议来管理我的 RecyclerView 的高度 @KislayKumar 它看起来像 hack,但是您是否尝试将您的 RecyclerView 包装在某个布局中并设置高度(如果此布局)并将 RecyclerView 保留为 match_parent 属性? 【参考方案1】:

一个更简单的解决方案是保持高度硬编码(因为它是一个水平视图,高度可以保持固定),然后如果输入为空,则隐藏水平回收器视图。

if(list.size() == 0)
   horizontalRecyclerView.setVisibility(View.GONE);

【讨论】:

【参考方案2】:

我自己解决了这个问题。我使用了从link 找到的自定义 LinearLayoutManager。

public class MyLinearLayoutManager extends LinearLayoutManager 

public MyLinearLayoutManager(Context context) 
    super(context);


private int[] mMeasuredDimension = new int[2];

@Override
public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state,
                      int widthSpec, int heightSpec) 
    final int widthMode = View.MeasureSpec.getMode(widthSpec);
    final int heightMode = View.MeasureSpec.getMode(heightSpec);
    final int widthSize = View.MeasureSpec.getSize(widthSpec);
    final int heightSize = View.MeasureSpec.getSize(heightSpec);

    measureScrapChild(recycler, 0,
            View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
            View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
            mMeasuredDimension);

    int width = mMeasuredDimension[0];
    int height = mMeasuredDimension[1];

    switch (widthMode) 
        case View.MeasureSpec.EXACTLY:
        case View.MeasureSpec.AT_MOST:
            width = widthSize;
            break;
        case View.MeasureSpec.UNSPECIFIED:
    

    switch (heightMode) 
        case View.MeasureSpec.EXACTLY:
        case View.MeasureSpec.AT_MOST:
            height = heightSize;
            break;
        case View.MeasureSpec.UNSPECIFIED:
    

    setMeasuredDimension(width, height);


private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec,
                               int heightSpec, int[] measuredDimension) 
    View view = recycler.getViewForPosition(position);
    if (view != null) 
        RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams();
        int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec,
                getPaddingLeft() + getPaddingRight(), p.width);
        int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec,
                getPaddingTop() + getPaddingBottom(), p.height);
        view.measure(childWidthSpec, childHeightSpec);
        measuredDimension[0] = view.getMeasuredWidth();
        measuredDimension[1] = view.getMeasuredHeight();
        recycler.recycleView(view);
    

只需将此 LinearLayoutManager 添加到您的 RecyclerView 即可。

谢谢大家 干杯!!!

【讨论】:

这可能曾经有效,但不再有效。试过了,它在尝试测量不存在的东西时崩溃了。但无论如何只测量第一项似乎并不合适。

以上是关于在垂直 recyclerView 中带有 wrap_content 的水平 recyclerView的主要内容,如果未能解决你的问题,请参考以下文章

安卓多个RecyclerView滑动与显示问题

带有水平溢出的Android垂直recyclerview

首先滚动到 RecyclerView 之外

覆盖中带有 wrap_content 的 TextView 未扩展到完整内容宽度

ViewPager中带有StaggeredGridLayoutManager的RecyclerView,返回fragment时自动排列item

Firefox Android 中带有“white-space:pre-wrap”的“input”高度大于 Android 中的 Chrome