如何在android gridview中为行设置不同的列

Posted

技术标签:

【中文标题】如何在android gridview中为行设置不同的列【英文标题】:How to set different columns for rows in android gridview 【发布时间】:2015-06-10 01:12:19 【问题描述】:

我想要一个类似这样的gridview

每个奇数行将有两个大尺寸的图像,偶数行将有四个较小的图像。我怎样才能做到这一点?

【问题讨论】:

AsymetricGridView 可能会做你想做的事。 @mungaih pk 你在使用RecyclerViewGridView吗? @mungaih pk 你试过我的解决方案了吗?告诉我一些事情,谢谢! @Xcihnegn 正在尝试您的解决方案。我会尽快回复您。谢谢大佬。 或者,也许你可以使用最小图像作为一个单元格的 GridLayout.. 并为 position%3 = 0 的每个图像设置 RowSpan = 2ColSpan = 2 【参考方案1】:

我有类似的东西,我用新的 RecyclerView 解决了。

我创建了一个带有RecyclerView 的片段。 xml 上的 RecyclerView:

<android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/filter_subtypes" android:layout_ android:layout_ />

在您的 Fragment/Activity 上(在我的 Fragment 案例中为 OnViewCreated)。 我找到了 RecyclerView 并设置了一个 Adapter - 一个普通的 Adapter 类继承自 RecyclerView.Adapter- 然后我创建一个 GridLayoutManager

final GridLayoutManager mng_layout = new GridLayoutManager(this.getActivity(), TOTAL_CELLS_PER_ROW/*In your case 4*/);

然后我重写此方法以设置动态列数(单元格)

mng_layout.setSpanSizeLookup( new GridLayoutManager.SpanSizeLookup() 
            @Override
            public int getSpanSize(int position) 
                switch( adapterSubtype.getItemViewType(position) ) 
                    case FilterSubtypesAdapter.TYPE_LOW:
                        return TOTAL_CELLS_PER_ROW;
                    case FilterSubtypesAdapter.TYPE_HIGH:
                        return 2;
                    default:
                        return -1;
                
            
        );
myRecyclerView.setLayoutManager(mng_layout);

这样,您将获得行上单元格的动态数量。

额外: 然后,如果您在适配器上使用相同的视图/类型视图,您将获得相同的 w & h 视图。您需要为 TYPE_HIGH 创建 2 个 xml 视图,为 TYPE_LOW 创建其他视图。

因此,在您的适配器中,您需要有 2 种数据(1 种用于高图像,1 种用于低图像)。 您必须重写此方法

@Override
public SubtypeViewHolder onCreateViewHolder(ViewGroup parent, int viewType) 
    View view = null;
    if (viewType==TYPE_HIGH) 
        view = inflater.inflate(R.layout.item_image_high, parent, false);
     else 
        view = inflater.inflate(R.layout.item_image_low, parent, false);
    
    return new SubtypeViewHolder(view, viewType);


 @Override
 public int getItemViewType(int position) 
     return (list.get(position).getType()==Subtype_type.HIGH) ? TYPE_HIGH : TYPE_LOW;
 

我希望我很清楚,有什么问题告诉我。

【讨论】:

我一直在尝试您的示例,但遇到太多错误,请您分享适配器和片段的代码。我会很感激的。 是的,向您展示我的代码没问题,但它很长,所以如果您告诉我您遇到了什么样的错误,我可以帮助您完成这部分 我不知道 pastebin 是否是 *** 帖子上的有效链接,所以为了帮助你,我在评论 pastebin.com/Fy49p4sT 上发帖,我用 X 重命名我的项目包,有很多依赖项还有你不需要的东西,如果你告诉我问题出在哪里,我更喜欢。但无论如何你有它,我希望它可以帮助你:D @Sulfkain.. 这似乎是合理的解决方案,但您发布的 URL 无法访问 工作!请注意,getSpanSize 的 int 结果不是这种情况下的 spanCount,这个 int 是您的默认 spanCount 的除数。因此,如果您的经理有 spanCount = 4,要获得一行一个项目,您必须返回 4,要获得一行 2 个项目返回 2,要获得一行 4 个项目返回 1。【参考方案2】:

我不考虑单个图像视图,而是将三个图像组作为单个网格项,

在你的网格适配器中试试这个

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/linear"
    android:layout_
    android:layout_
    android:background="@color/green"
    android:orientation="vertical">
<ImageView
    android:id="@+id/image"
    android:layout_
    android:layout_
    android:scaleType="fitXY"
    android:src="@drawable/user"
     />
    <LinearLayout
        android:layout_
        android:layout_
        android:orientation="horizontal">
        <ImageView
            android:id="@+id/image_1"
            android:layout_
            android:layout_
            android:layout_weight="1"
            android:scaleType="fitXY"
            android:src="@drawable/user"

            />
        <ImageView
            android:id="@+id/image_2"
            android:layout_
            android:layout_
            android:src="@drawable/user"
            android:scaleType="fitXY"
            android:layout_weight="1"
            />

        </LinearLayout>

    </LinearLayout>

你的网格视图会像

<GridView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/RelativeLayout1"
    android:layout_
    android:layout_
    android:numColumns="2"
    >

</GridView>

您唯一需要注意的是图像的顺序。这可能对你有帮助

【讨论】:

这种方法的问题在于clickListeners,你不知道点击了哪个图片 我认为您可以使用 arg1 在方法 public void onItemClick(AdapterView> arg0, View arg1, int arg2, long arg3) 中访问带有 id 的子图像视图。 如果一行是 3,另一行是 4 会怎样? 这不是我想要的。【参考方案3】:

如果您将RecyclerView 用于GridView,那么有适合您的解决方案:

GridLayoutManager layoutManager = new GridLayoutManager(this, 4);
layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() 
    @Override
    public int getSpanSize(int position) 
         int mod = position % 6;    

         if(position == 0 || position == 1)
              return 2;
         else if(position < 6)
              return 1;
         else if(mod == 0 || mod == 1)
              return 2;
         else
              return 1;
    
);

recyclerView.setLayoutManager(layoutManager);

希望这对你有用!

【讨论】:

@Xchinegn,我正在尝试以最大 3 和最小 2 跨度来实施您的解决方案。但不跟随。你能指导我吗?【参考方案4】:

我想最好的方法是使用回收站视图.. 在性能方面,它也优于列表/网格

下面的链接可能会有很大帮助 - 所有都与卢卡斯的双向视图有关

https://github.com/lucasr/twoway-view

https://plus.google.com/+LucasRocha/posts/WBaryNqAHiy

http://lucasr.org/2014/07/31/the-new-twowayview/

【讨论】:

这个分叉更稳定 => github.com/Superbalist/twoway-view @javaacm 完全一样怎么能更稳定 lucasr/twoway-view 是一个停止的开发项目(大约 2 年停止)所以有些问题很重要,如果你看到 Network 状态 > github.com/lucasr/twoway-view/network 和他们的提交细节 Superbalist' s fork 工作起来更干净,无论如何lucasr repo 还可以,但如果您不想拥有问题部分中报告的某些功能,在Superbalist 的提交详细信息中,我看到一些重要问题已修复【参考方案5】:

在我的项目中它是如何工作的我有不同高度的单元格和标题

适配器:

public class AdapterRecViewMain
    extends RecyclerView.Adapter<RecyclerView.ViewHolder> 

private List<BaseMarkerElement> mainCardList;
private final int HEADER_VIEW = 0;
private final int FOOTER_VIEW = 1;

public AdapterRecViewMain() 


public void setData(List<BaseMarkerElement> mainCardList) 
    this.mainCardList = mainCardList;


@Override public int getItemViewType(int position) 
    if (position == 0) 
        return HEADER_VIEW;
    
    return FOOTER_VIEW;


@Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int type) 
    if (type == FOOTER_VIEW) 
        View v = LayoutInflater.from(viewGroup.getContext())
                .inflate(R.layout.card_main_activity, viewGroup, false);
        return new MainCardViewHolder(v);
     else 
        View v = LayoutInflater.from(viewGroup.getContext())
                .inflate(R.layout.header_view_main_activity, viewGroup, false);
        return new HeaderViewHolder(v);
    


@Override public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int positionItem) 
    final int position = viewHolder.getAdapterPosition();

    if (viewHolder instanceof HeaderViewHolder) 
        StaggeredGridLayoutManager.LayoutParams layoutParams =
                (StaggeredGridLayoutManager.LayoutParams) viewHolder.itemView.getLayoutParams();
        layoutParams.setFullSpan(true);

        BaseMarkerElement item = mainCardList.get(position);
        if (item instanceof HeaderView) 
            HeaderView header = (HeaderView) mainCardList.get(position);
            // need to add implementation
        
     else if (viewHolder instanceof MainCardViewHolder) 
        MainCardViewHolder currentView = (MainCardViewHolder) viewHolder;
        CardMainActivity currentCard = (CardMainActivity) mainCardList.get(position);

        currentView.ivMainCard.setImageResource(currentCard.getIvMainCard());
        currentView.tvBrandName.setText(currentCard.getTvBrandName());
        currentView.tvPrice.setText(currentCard.getTvPrice());
        currentView.tvType.setText(currentCard.getTvType());
    


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


private class MainCardViewHolder extends RecyclerView.ViewHolder 
    ImageView ivMainCard;
    TextView tvBrandName;
    TextView tvType;
    TextView tvPrice;

    MainCardViewHolder(View view) 
        super(view);
        ivMainCard = (ImageView) view.findViewById(R.id.imageViewMainCard);
        tvBrandName = (TextView) view.findViewById(R.id.tvBrandName);
        tvType = (TextView) view.findViewById(R.id.tvType);
        tvPrice = (TextView) view.findViewById(R.id.tvPrice);
    


private class HeaderViewHolder extends RecyclerView.ViewHolder 

    public HeaderViewHolder(View itemView) 
        super(itemView);

    


在你的活动中:

private AdapterRecViewMain adapter;
private RecyclerView rvMain;

@Override protected void onResume() 
    super.onResume();
    Logger.logGeneral("onResume()");

    if (adapter == null) 
        setUpRecView();
    


private void setUpRecView() 
    adapter = new AdapterRecViewMain();
    adapter.setData(controller.loadData());
    rvMain = (RecyclerView) findViewById(R.id.rvMain);
    final StaggeredGridLayoutManager layoutManager =
            new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
    rvMain.setLayoutManager(layoutManager);

    rvMain.addOnScrollListener(scrollListener);
    rvMain.setAdapter(adapter);
    adapter.notifyDataSetChanged();
    rvMain.invalidate();

【讨论】:

【参考方案6】:

你应该设置RecyclerView

recyclerView.setLayoutManager(new GridLayoutManager(this, 4));

【讨论】:

【参考方案7】:

创建两个不同的 XML 文件并根据适配器中的位置进行扩展,如下所示。

if(position%2==0)
//Inflate Even number layout with 4 images
else
//Inflate ODD number layout with 2 images

【讨论】:

请多解释。我不明白你的意思。 @mungaihpk,这很简单,您只需根据您想要的视图类型在适配器中使用不同类型的视图。【参考方案8】:

您是否尝试过将RecyclerView 与StaggeredGridLayoutManager 结合使用?

这种组合结果如下:video。

我想,这就是你要找的。​​p>

【讨论】:

加上例子会简单很多【参考方案9】:

试试这个,

https://github.com/etsy/AndroidStaggeredGrid

交错网格视图,

非常简单,易于使用。

【讨论】:

这是在 2015 年,现在有了 Recyclerview 和 StaggeredGridLayoutManager(),生活变得更轻松了【参考方案10】:

使用可展开的列表视图并为每一行提供不同的视图。

http://developer.android.com/reference/android/widget/ExpandableListView.html

【讨论】:

在这种情况下,可展开的列表视图如何帮助他?

以上是关于如何在android gridview中为行设置不同的列的主要内容,如果未能解决你的问题,请参考以下文章

如何在 MySQL 中为行保留一个计数器

在树视图 gtkmm 中为行设置标题

如何设置 android gridview 怎么设置 , 一些item可以点击,另外.....

如何在 Table Bootstrap Vue 中为行禁用 v-slot

android GridView 如何设置为左右可滚动?

使用后面的代码在 Gridview 中为 DropDownList 设置数据源时出错