36

I want to have a gridview similar to this

enter image description here

Every odd numbered row will have two images of big size and even numbered rows will have four smaller images.How can I achieve this?

mungaih pk
  • 1,809
  • 8
  • 31
  • 57

10 Answers10

36

I have something similar and i solved with the new RecyclerView.

I created a Fragment with an a RecyclerView. RecyclerView on xml:

<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_width="match_parent" android:layout_height="match_parent" />

On your Fragment/Activity (OnViewCreated in my fragment case). I find the RecyclerView and set an Adapter- a normal Adapter class inherit from RecyclerView.Adapter< YOUR VIEW HOLDER class >- And then i create a GridLayoutManager

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


Then i override this method to set a dynamic numbers of columns (cells)

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);

With this you will get dynamic numbers of cell on your rows.

EXTRA: Then if you are using the same view/type view on your adapter, you will get the same w & h view. You will need to create 2 xml views for TYPE_HIGH and other view for TYPE_LOW.

So, in your adapter, you need to have 2 kind of data (1 for high images and 1 for low images). You must override this methods

@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;
 }

I hope i was clear, any problem tell me.

Sulfkain
  • 5,082
  • 1
  • 20
  • 38
  • I have been trying your example, but am encountering too many errors, could you please share you code for the adapter and the fragment. I will really appreciate. – mungaih pk Apr 22 '15 at 16:35
  • Yeah no problem to show you my code, but it's long so if you tell me what kind of errors you get i can help you with that part – Sulfkain Apr 23 '15 at 08:00
  • I don't know if pastebin it's a valid link on a stackoverflow post, so to help you i post here on the comment http://pastebin.com/Fy49p4sT, i rename my project packages with X, there are many dependencies and thing you don't need, i prefer if you tell me what the problem. but anyway there you have it, i hope it helps you :D – Sulfkain Apr 23 '15 at 08:11
  • @Sulfkain.. This seems like reasonable solution but the URL you posted is no more accessible – Syed Arsalan Kazmi Oct 06 '15 at 07:35
  • @ArsalanShah sorry but i that was a temporally help, the solution it's on my answer, not in my code. – Sulfkain Nov 14 '15 at 12:23
  • 4
    Working! Be aware that the int result of getSpanSize isn't the spanCount for this case, this int is the divider of your default spanCount. So, if you have in your manager spanCount = 4, to get a row of one item you have to return 4, to get a row of 2 items return 2, and to get a row of 4 items return 1. – Pelanes Sep 18 '17 at 09:47
  • @Pelanes You are the saint – Pankaj Dec 13 '18 at 05:23
24

Instead of considering a single image views i am taking group of three images as a single grid item,

enter image description here

try this inside your grid adapter

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

            />
        <ImageView
            android:id="@+id/image_2"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:src="@drawable/user"
            android:scaleType="fitXY"
            android:layout_weight="1"
            />

        </LinearLayout>

    </LinearLayout>

and your grid view would be like

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

</GridView>

The only thing you have to take care of is, the sequence of your image. might be this will help you

Abhishek
  • 1,337
  • 10
  • 29
12

If you are using RecyclerView for GridView, then there is solution that should work for you:

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);

Hope this work for you!

Xcihnegn
  • 11,579
  • 10
  • 33
  • 33
  • @Xchinegn, I am trying to implement your solution with max 3 and min 2 span. But not following. Can u guide me. – BST Kaal Dec 18 '16 at 09:35
1

I guess the best way to do is using recycler view.. Also it is preferred over list/grid for performance

May be below links can help a lot - All are related to Two way View by Lucas

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

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

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

Chimu
  • 758
  • 1
  • 6
  • 16
  • this fork is more stable => https://github.com/Superbalist/twoway-view – java acm Jan 08 '17 at 10:35
  • @javaacm how does it could be more stable if it is completely the same – Sirop4ik Feb 13 '17 at 09:45
  • `lucasr/twoway-view` is a stopped project for development (about 2 years is stopped) so some issues are important and if you see `Network` state at > https://github.com/lucasr/twoway-view/network and their commits detail `Superbalist`'s fork is more clean for working , anyway `lucasr` repo is Ok but if you dont want to have some features that reported in the issues section , in the `Superbalist`'s commit detail i see some important issues are fixed – java acm Feb 14 '17 at 06:18
1

There is how does it work in my project I have different height of cells and also header

enter image description here

adapter:

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);

    }
}
}

In your activity :

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();
}
Sirop4ik
  • 4,543
  • 2
  • 54
  • 121
1

You should set in RecyclerView :

recyclerView.setLayoutManager(new GridLayoutManager(this, 4));
Dima Kozhevin
  • 3,602
  • 9
  • 39
  • 52
0

Create two different XML files and inflate based on position in your Adapter like below.

if(position%2==0){
//Inflate Even number layout with 4 images
}else{
//Inflate ODD number layout with 2 images
}
Santhi Bharath
  • 2,818
  • 3
  • 28
  • 42
0

Did you try a RecyclerView in a combination with a StaggeredGridLayoutManager?

This combination results in something like this: video.

I think, this is what you are looking for.

ivtoto
  • 241
  • 1
  • 9
0

Try this ,

https://github.com/etsy/AndroidStaggeredGrid

Staggered-Grid View ,

Extremely simple , easy to use.

TheAnimatrix
  • 566
  • 1
  • 6
  • 19
-1

Use Expandable list view and provide different view for each row.

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

user3911501
  • 39
  • 1
  • 6