I have used a scrollview because my view is long and I need to enable the user to scroll down to view the items such as TextViews and ImageViews. However at the bottom I need to have a GridView to display an infinite list of images.
I need to be able to scroll to view the textviews
And
I also need to be able to reach the GridView and scroll away
However, I realised that you can't have a GridView inside a Scrollview since they both involve scrolling and some weird bugs keeps me from scrolling the GridView. What is the alternative to my situation?
Code sample:
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:id="#+id/text1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="5dp"
android:layout_marginTop="30dp"
android:text="Hello there"
android:textColor="#CC000000"
android:textSize="25sp" />
<TextView
android:id="#+id/text2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="5dp"
android:layout_marginTop="30dp"
android:text="Partner Name: "
android:textColor="#CC000000"
android:textSize="25sp" />
<!-- Lot more TextViews -->
<!-- And then comes the GridView -->
<GridView
android:id="#+id/picturefeed"
android:numColumns="3"
android:layout_marginTop="20dp"
android:layout_below="#+id/partner_details"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</GridView>
</ScrollView>
You need a heterogenous RecyclerView with a GridLayoutManager.
You should check out the Creating Lists and Cards guide.
Here is a sample:
#Override
protected void onCreate (Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.your_main_layout);
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.your_recycler_view);
final MyAdapter adapter = new MyAdapter();
GridLayoutManager layoutManager = new GridLayoutManager(this, 3); // a row can be 3 spans wide
layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
#Override
public int getSpanSize(int position) {
switch(adapter.getItemViewType(position)){
case MyAdapter.TYPE_TEXT:
return 3; // it's going to take up a row
case MyAdapter.TYPE_IMAGE:
return 1; // it's going to take up 1/3 of a row
default:
return -1;
}
}
});
recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(adapter);
}
public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
public static final int TYPE_TEXT = 1;
public static final int TYPE_IMAGE = 2;
#Override
public int getItemViewType (int position) {
if (position < 2) { // the first two items of the RecyclerView will be the TextView ones
// you can (should?) use a more sophisticated method if you want to
return TYPE_TEXT;
}
// the rest of the items are images
return TYPE_IMAGE;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
RecyclerView.ViewHolder viewHolder;
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
switch (viewType) {
case TYPE_TEXT:
View v1 = inflater.inflate(R.layout.layout_vh_text, parent, false);
viewHolder = new TextViewHolder(v1);
break;
case TYPE_IMAGE:
View v2 = inflater.inflate(R.layout.layout_vh_image, parent, false);
viewHolder = new ImageViewHolder(v2);
break;
default:
throw new IllegalArgumentException("Unsupported view type: " + viewType);
}
return viewHolder;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
switch (viewHolder.getItemViewType()) {
case TYPE_TEXT:
TextViewHolder vh1 = (TextViewHolder) viewHolder;
// do something with vh1
break;
case TYPE_IMAGE:
ImageViewHolder vh2 = (ImageViewHolder) viewHolder;
// do something with vh2
break;
default:
throw new IllegalArgumentException("Unsupported view type: " + viewType);
}
}
public class TextViewHolder extends RecyclerView.ViewHolder {
// ...
}
public class ImageViewHolder extends RecyclerView.ViewHolder {
// ...
}
// rest of the adapter's code, not explained here as it's not part of the question
}
Related
I have a RecyclerView that holds user hobbies in profile fragment. I placed items in RecyclerView with StaggeredGridLayout. Like this:
But I want to show my items a little bit of custom view. The custom view I want:
And this is my item XML file:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:gravity="center_horizontal"
android:orientation="vertical"
android:layout_width="match_parent" android:layout_height="wrap_content">
<TextView
android:id="#+id/hobby_profile_title"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:background="#drawable/hobby_background_3"
android:text="Spor"
android:paddingLeft="20dp"
android:paddingRight="20dp"
android:textSize="11sp"
android:layout_marginBottom="10dp"
android:gravity="center"
android:textColor="#fff"
android:fontFamily="#font/inter_semibold"/>
</LinearLayout>
HobbyAdapter:
public class ProfileHobbyAdapter extends RecyclerView.Adapter<ProfileHobbyViewPager> {
private ArrayList<ProfileHobby> hobby_title;
public ProfileHobbyAdapter(ArrayList<ProfileHobby> hobby_title) {
this.hobby_title = hobby_title;
}
#NonNull
#Override
public ProfileHobbyViewPager onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
View view = layoutInflater.inflate(R.layout.profil_hobby_card, parent, false);
ProfileHobbyViewPager profileHobbyViewPager = new ProfileHobbyViewPager(view);
return profileHobbyViewPager;
}
#Override
public void onBindViewHolder(#NonNull ProfileHobbyViewPager holder, int position) {
holder.hobby_profile_title.setText(hobby_title.get(position).getHobby_title());
}
#Override
public int getItemCount() {
return hobby_title.size();
}
}
Can I get this view using StaggeredGrid? Or should I look for another alternative? Thank you for helpings.
you'd better use GridLayoutManager instead of StaggeredGridLayout
I think following code will solve your problem:
in kotlin:
val layoutManager= GridLayoutManager(activity, 3)
layoutManager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
override fun getSpanSize(position: Int): Int {
return when (position % 2) {
0 -> 2 //in even rows you have two columns
else -> 3 //in odd rows you have three columns
}
}
}
recyclerView.layoutManager = layoutManager
in java:
GridLayoutManager layoutManager = new GridLayoutManager(this, 3);
layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
#Override
public int getSpanSize(int position) {
switch (position % 2) {
case 0: return 2; //in even rows you have two columns
case 1: return 3; //in odd rows you have two columns
}
}
});
recyclerview.setlayoutmanager(layoutManager)
in this code, first grid layout has been created with 3 columns, then even rows (even position which specified by position % 2) will return 2 spans and odd rows will show 3 spans.
I want to build a complex layout using recyclerview android. In the layout, I want to have a camera button to the top left fixed and a recyclerview wrapped around it with gallery images. I have checked flexbox layout manager for recyclerview but it doesn't seem to match my use-case.
I want the header to be non-repeating and not to scroll with other items vertically. Here's the layout for the header:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/shareLayout"
android:layout_width="185dp"
android:layout_height="135dp"
android:layout_below="#id/trendingToolbar"
android:background="#color/black">
<ImageView
android:id="#+id/cameraShareIV"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_centerHorizontal="true"
android:layout_marginTop="10dp"
app:srcCompat="#drawable/camera_white" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#id/cameraShareIV"
android:layout_centerHorizontal="true">
<TextView
android:id="#+id/infoTxt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginLeft="20dp"
android:gravity="center_horizontal"
android:text="#string/share_pic_video"
android:textColor="#android:color/white"
android:textSize="13sp"
android:textStyle="bold" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#id/infoTxt"
android:layout_marginLeft="16dp"
android:text="#string/share_timeout_txt"
android:textColor="#color/colorPrimaryDark"
android:textSize="11sp"
android:textStyle="bold" />
</RelativeLayout>
and in my activity, here's the XML:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="base.android.com.thumbsapp.UI.Fragments.TrendingFragment">
<include layout="#layout/trending_toolbar"
android:id="#+id/trendingToolbar"/>
<android.support.v7.widget.RecyclerView
android:id="#+id/trendingRV"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#id/trendingToolbar"/>
Previously, I had the header inside the activity XML but had no way to wrap a recyclerview around it. So, I have decide to use an adapter like below:
public class TrendingAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final String TAG = TrendingAdapter.class.getSimpleName();
private Context context;
private List<Trending> itemList;
private static final int HEADER = 0;
private static final int ITEMS = 1;
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v;
switch (viewType){
case HEADER:
v = LayoutInflater.from(parent.getContext()).inflate(R.layout.trending_header, parent, false);
return new TrendingHeaderViewHolder(v);
case ITEMS:
v = LayoutInflater.from(parent.getContext()).inflate(R.layout.trending_items_layout, parent, false);
return new TrendingItemsViewHolder(v);
}
return null;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
Trending tr = itemList.get(position);
if (holder instanceof TrendingHeaderViewHolder){
((TrendingHeaderViewHolder) holder).cameraShareIV.setOnClickListener( view -> {
// TODO: 4/2/2018 select image from gallery
});
} else if (holder instanceof TrendingItemsViewHolder){
// TODO: 4/2/2018 populate gallery items here with picasso
}
}
#Override
public int getItemCount() {
return itemList.size();
}
#Override
public int getItemViewType(int position) {
return super.getItemViewType(position);
}
}
I'm confused how to make the header stick and also what to do for getItemViewType method.
Is this the right way to approach this?
Can anyone help out? Thanks.
For this lay out i suggest better option is use this header view
https://github.com/edubarr/header-decor
To make things simple i suggest you to look into this library
In your XML Place RecylerView into StickyHeaderView,choose horizontal or vertical orientation for your RecylerView
<tellh.com.stickyheaderview_rv.StickyHeaderView
android:id="#+id/stickyHeaderView"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/white"
android:scrollbars="vertical" />
</tellh.com.stickyheaderview_rv.StickyHeaderView>
Create data bean class for each item type in RecyclerView. They should extend DataBean. Override the method
public boolean shouldSticky() to decide whether the item view should be suspended on the top.
public class User extends DataBean {
private String login;
private int id;
private String avatar_url;
private boolean shouldSticky;
#Override
public int getItemLayoutId(StickyHeaderViewAdapter adapter) {
return R.layout.item_user;
}
public void setShouldSticky(boolean shouldSticky) {
this.shouldSticky = shouldSticky;
}
// Decide whether the item view should be suspended on the top.
#Override
public boolean shouldSticky() {
return shouldSticky;
}
}
public class ItemHeader extends DataBean {
private String prefix;
#Override
public int getItemLayoutId(StickyHeaderViewAdapter adapter) {
return R.layout.header;
}
#Override
public boolean shouldSticky() {
return true;
}
}
Create ViewBinder to bind different type views with specific data beans. As you see, provideViewHolder(View itemView) corresponds for onCreateViewHolder in RecyclerView, and bindView corresponds for onBindViewHolder in RecyclerView.
public class ItemHeaderViewBinder extends ViewBinder<ItemHeader, ItemHeaderViewBinder.ViewHolder> {
#Override
public ViewHolder provideViewHolder(View itemView) {
return new ViewHolder(itemView);
}
#Override
public void bindView(StickyHeaderViewAdapter adapter, ViewHolder holder, int position, ItemHeader entity) {
holder.tvPrefix.setText(entity.getPrefix());
}
#Override
public int getItemLayoutId(StickyHeaderViewAdapter adapter) {
return R.layout.header;
}
static class ViewHolder extends ViewBinder.ViewHolder {
TextView tvPrefix;
public ViewHolder(View rootView) {
super(rootView);
this.tvPrefix = (TextView) rootView.findViewById(R.id.tv_prefix);
}
}
}
Instantiate StickyHeaderViewAdapter for RecyclerView and register ViewBinders for each item types.
rv = (RecyclerView) findViewById(R.id.recyclerView);
rv.setLayoutManager(new LinearLayoutManager(this));
List<DataBean> userList = new ArrayList<>();
adapter = new StickyHeaderViewAdapter(userList)
.RegisterItemType(new UserItemViewBinder())
.RegisterItemType(new ItemHeaderViewBinder());
rv.setAdapter(adapter);
I want to insert/show horizontal recyclerview into specific position (at this example position:1)
Vertical recyclerview - displays TextView + shape (rectange)
Horizontal recyclerview - displays ImageViews (next to each other)
.XML's
horizontal_layout.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="#+id/horizontal_recyclerview"
android:layout_width="368dp"
android:layout_height="wrap_content"
android:layout_marginBottom="60dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginTop="2dp"
android:padding="0dp"/>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.mkalejs.training.MainActivity">
vertical_layout.xml
<android.support.v7.widget.RecyclerView
android:id="#+id/vertical_recyclerview"
android:layout_width="368dp"
android:layout_height="wrap_content"
android:layout_marginBottom="60dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginTop="2dp"
android:padding="0dp"/>
</android.support.constraint.ConstraintLayout>
vertical_layout_item.xml
<EditText
android:id="#+id/lbl_url_text"
android:layout_width="100dp"
android:layout_height="50dp"
android:background="#android:color/transparent"
android:inputType="textPersonName"
android:padding="5dp"
android:layout_gravity="center"
android:text="Name" />
<View
android:id="#+id/rectangle"
android:layout_width="195dp"
android:layout_height="100dp"
android:background="#drawable/rectangle" />
horizontal_layout_item.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="10dp"
android:visibility="visible"
android:weightSum="1">
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/img_horizontal_slider"
android:layout_width="33dp"
android:layout_height="33dp"
android:adjustViewBounds="true"
android:visibility="visible" />
</LinearLayout>
There might be a small misunderstanding in recyclerview concept. I'm not sure where I can call horizontal_recyclerview" to not return it as a null (as I am now) and populate it with data. Is the XML structure wrong? Feel free to update code parts.
THIS SHOULD BE OKAY
MainActivity.class
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.vertical_layout);
ArrayList<PictureData> bundleOfData = prepareData();
RecyclerView rv = (RecyclerView) findViewById(R.id.vertical_recyclerview);
VerticalAdapter adapter = new VerticalAdapter(bundleOfData, this);
rv.setAdapter(adapter);
//rv.setNestedScrollingEnabled(true);
LinearLayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
rv.setLayoutManager(layoutManager);
}
VerticalAdapter.class
public class VerticalAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{
private ArrayList<PictureData> pictures;
Context context;
public VerticalAdapter(ArrayList<PictureData> pictures, Context context)
{
this.pictures = pictures;
this.context = context;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView;
switch (viewType) {
case 1:
itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.horizontal_layout_item, parent, false);
return new HorizontalViewHolder(itemView);
default:
itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.vertical_layout_item, parent, false);
return new VerticalViewHolder(itemView);
}
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
switch (holder.getItemViewType()){
case 1:
HorizontalViewHolder hVh = (HorizontalViewHolder) holder;
HorizontalAdapter horizontal_adapter = new HorizontalAdapter(pictures, context);
hVh.horizontal_rec.setAdapter(horizontal_adapter);
break;
default:
VerticalViewHolder vVh = (VerticalViewHolder) holder;
vVh.textView.setText(pictures.get(position).getPictureUrl());
break;
}
}
#Override
public int getItemCount() {return pictures.size();}
#Override
public int getItemViewType(int position) {
if(position == 1){
return 1;
}else{
return 0;
}
}
}
HorizontalViewHolder.class
I GET A ERROR HERE. OBVIOUSLY, I DON'T HAVE (img_horizontal_slider) IN HORIZONTAL_LAYOUT, but putting ImageView + RecyclerView in one layout file and call here would feel wrong (?)
public class HorizontalViewHolder extends RecyclerView.ViewHolder{
public ImageView imagePositionInLayout;
public RecyclerView horizontal_rec;
public HorizontalViewHolder(View itemView) {
super(itemView);
LinearLayoutManager layoutManager = new LinearLayoutManager(itemView.getContext(), LinearLayoutManager.HORIZONTAL, false);
horizontal_rec = itemView.findViewById(R.id.vertical_recyclerview);
imagePositionInLayout = itemView.findViewById(R.id.img_horizontal_slider);
horizontal_rec.setLayoutManager(layoutManager);
}
public ImageView getView() {
return imagePositionInLayout;
}
}
HorizontalAdapter.class
ublic class HorizontalAdapter extends RecyclerView.Adapter<HorizontalViewHolder> {
private ArrayList<PictureData> pictures;
Context context;
public HorizontalAdapter(ArrayList<PictureData> pictures, Context context) {
this.pictures = pictures;
this.context = context;
}
#Override
public HorizontalViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.horizontal_layout_item, parent, false);
return new HorizontalViewHolder(view);
}
#Override
public void onBindViewHolder(HorizontalViewHolder holder, int position)
{
Picasso.Builder builder = new Picasso.Builder(context);
Picasso picasso = builder.build();
picasso
.load("http://nuclearpixel.com/content/icons/2010-02-09_stellar_icons_from_space_from_2005/earth_128.png")
.placeholder(R.mipmap.ic_launcher_round)
.into(holder.imagePositionInLayout);
}
#Override
public int getItemCount() {
return pictures.size();
}
}
I'm new to Android so I hope people will give some good explanation on what is wrong and how to fix it. Every suggestion will be gladly accepted. I will highly appreciate if someone will actually look into this and explain, because I feel pretty lost right now.
I am trying to create a recyclerview in a nav drawer with the header showing the profile information. I would like to have a header height more than the other row elements. below is my header layout
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="200dp"
android:background="#color/green"
android:orientation="vertical"
android:weightSum="1">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="56dp"
android:orientation="vertical"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true">
<TextView
android:id="#+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:textColor="#ffffff"
android:text="XXXXX"
android:textSize="32sp"
android:textStyle="bold"
/>
</LinearLayout>
</RelativeLayout>
When I set this to the header of the recycler view , the 200dp height is not reflecting in the UI
RecyclerView.Adapter<NavDrawerListViewHolder> adapter = new NavDrawerListAdapter(this,TITLES,this);
navList.setAdapter(adapter);
Below is the adapter for the recyclerview :
public class NavDrawerListAdapter extends RecyclerView.Adapter<NavDrawerListViewHolder> {
private static final int TYPE_HEADER = 0;
private static final int TYPE_ITEM = 1;
Context mContext;
String[] mCharacterList;
IListItemClickListener mListener;
int holderViewType=0;
public NavDrawerListAdapter(Context context, String[] characters, IListItemClickListener clickListener) {
mContext = context;
mCharacterList = characters;
mListener = clickListener;
}
#Override
public NavDrawerListViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
NavDrawerListViewHolder viewHolder;
holderViewType = viewType;
if(viewType == TYPE_HEADER) {
View v = LayoutInflater.from(mContext).inflate(R.layout.header,null);
viewHolder = new NavDrawerListViewHolder(v,TYPE_HEADER,mListener);
} else {
View v = LayoutInflater.from(mContext).inflate(R.layout.nav_item_row,null);
viewHolder = new NavDrawerListViewHolder(v,TYPE_ITEM,mListener);
}
return viewHolder;
}
#Override
public void onBindViewHolder(NavDrawerListViewHolder holder, int position) {
if(holderViewType == TYPE_HEADER) {
Typeface typeface = Typeface.createFromAsset(mContext.getAssets(), "Roboto-Thin.ttf");
holder.name.setTypeface(typeface);
} else {
holder.characterName.setText(mCharacterList[position - 1]);
}
}
#Override
public int getItemViewType(int position) {
if (position == 0) {
return TYPE_HEADER;
}
return TYPE_ITEM;
}
#Override
public int getItemCount() {
return mCharacterList.length + 1;
}
Replace:
LayoutInflater.from(mContext).inflate(R.layout.header,null);
with:
LayoutInflater.from(mContext).inflate(R.layout.header, parent, false);
and the same for all your other inflate() calls. If you know the parent container for the layout being inflated, always supply it to the inflate() call. In particular, RelativeLayout needs this, if it is the root view of the layout being inflated.
Also, consider using getLayoutInflater() on the Activity instead of LayoutInflater.from(). It may be that if you pass the Activity into from() that you will get equivalent results. However, in general, you always want to use a LayoutInflater that knows about the Activity and its theme, so you get the right results.
I want to have a gridview similar to this
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?
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.
Instead of considering a single image views i am taking group of three images as a single grid item,
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
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!
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/
There is how does it work in my project I have different height of cells and also header
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();
}
You should set in RecyclerView :
recyclerView.setLayoutManager(new GridLayoutManager(this, 4));
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
}
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.
Try this ,
https://github.com/etsy/AndroidStaggeredGrid
Staggered-Grid View ,
Extremely simple , easy to use.
Use Expandable list view and provide different view for each row.
http://developer.android.com/reference/android/widget/ExpandableListView.html