I am trying to have 2 layout in one RecyclerView
I have a recycler view list which is called Bookmark and it is parsed from an xml and this is all working , but I wanna in this recyclerview to put another layout which contains a button and that can be clickable.
Like in the photo the icons are from recyclerview and the plus button need to be compatible with the list, if the list is larger or smaller the button will be compatible with the space of list.
This is my new code for the Adapter which depends on the answer #LluisFelisart
And this is the error
ViewHolder views must not be attached when created. Ensure that you are not passing 'true' to the attachToRoot parameter of LayoutInflater.inflate(..., boolean attachToRoot)
public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private Context context;
ArrayList<Bookmark> arrayList = new ArrayList<>();
public MyAdapter(Context context, ArrayList<Bookmark> arrayList) {
this.context = context;
this.arrayList = arrayList;
}
public class ViewHolder0 extends RecyclerView.ViewHolder {
TextView tvName,tvId,tvSearchUrl,tvNativeUrl;
ImageView tvIcon;
public ViewHolder0(#NonNull View itemView) {
super(itemView);
tvName=itemView.findViewById(R.id.textView);
tvIcon = itemView.findViewById(R.id.image_view);
/* tvId=itemView.findViewById(R.id.tvId);
tvSearchUrl=itemView.findViewById(R.id.tvSearchUrl);
tvNativeUrl=itemView.findViewById(R.id.tvNativeUrl);*/
}
}
public class ViewHolder2 extends RecyclerView.ViewHolder {
ImageView tvAddBookmark;
public ViewHolder2(#NonNull View itemView) {
super(itemView);
tvAddBookmark = itemView.findViewById(R.id.image_button_add);
}
}
#Override
public int getItemViewType(int position) {
// Just as an example, return 0 or 2 depending on position
// Note that unlike in ListView adapters, types don't have to be contiguous
return position % 2 * 2;
}
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.grid_item, viewGroup, false);
switch (i) {
case 0: return new ViewHolder0(viewGroup);
case 2: return new ViewHolder2(viewGroup);
}
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder holder, int position) {
switch (holder.getItemViewType()) {
case 0:
ViewHolder0 viewHolder0 = (ViewHolder0) holder;
((ViewHolder0) holder).tvName.setText(arrayList.get(position).getName());
((ViewHolder0) holder).tvIcon.setImageResource(arrayList.get(position).getIcon());
break;
case 2:
ViewHolder2 viewHolder2 = (ViewHolder2) holder;
}
((ViewHolder0) holder).tvIcon.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent;
intent = new Intent(context, BookmarkActivity.class);
v.getContext().startActivity(intent);
}
});
((ViewHolder0) holder).tvIcon.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
Intent intent = new Intent(context, ActivityBookmarksFavorites.class);
v.getContext().startActivity(intent);
return false;
}
});
}
#Override
public int getItemCount() {
return arrayList.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView tvName,tvId,tvSearchUrl,tvNativeUrl;
ImageView tvIcon;
public ViewHolder(#NonNull View itemView) {
super(itemView);
tvName=itemView.findViewById(R.id.textView);
tvIcon = itemView.findViewById(R.id.image_view);
/* tvId=itemView.findViewById(R.id.tvId);
tvSearchUrl=itemView.findViewById(R.id.tvSearchUrl);
tvNativeUrl=itemView.findViewById(R.id.tvNativeUrl);*/
}
}
}
This is the grid item layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:orientation="vertical"
android:visibility="visible"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
xmlns:android="http://schemas.android.com/apk/res/android">
<ImageView
android:id="#+id/image_view"
style="#style/BookmarkIconIv" />
<TextView android:id="#+id/textView"
android:layout_marginTop="1.0dip"
style="#style/BookmarkTextTv" />
</LinearLayout>
This is the layout of button which I want to be in the recycler view
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageButton
android:id="#+id/image_button_add"
android:layout_width="45dp"
android:layout_height="45dp"
android:src="#drawable/ic_add_black_24dp"
android:background="#color/transparent" />
</android.support.constraint.ConstraintLayout>
This is the Fragment which the recycler view it is shown
public class FragmentBookmark extends Fragment {
ArrayList<Bookmark> arrayList = new ArrayList<>();
XmlPullParser pullParser;
MyAdapter myAdapter;
View paramView;
RecyclerView myRecyclerView;
private Context mContext;
#Override
public void onAttach(Context context) {
super.onAttach(context);
mContext = context;
}
#Nullable
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
paramView = inflater.inflate(R.layout.bookmark, container, false);
myRecyclerView = paramView.findViewById(R.id.myRecyclerView);
myRecyclerView.setLayoutManager(new GridLayoutManager(mContext, 4));
myRecyclerView.setHasFixedSize(true);
myAdapter = new MyAdapter(mContext, arrayList);
myRecyclerView.setAdapter(myAdapter);
try {
XmlPullParser xpp = getResources().getXml(R.xml.bookmarks);
while (xpp.getEventType() != XmlPullParser.END_DOCUMENT) {
if (xpp.getEventType() == XmlPullParser.START_TAG) {
if (xpp.getName().equals("Bookmark")) {
Bookmark bookmark = new Bookmark();
bookmark.setName(xpp.getAttributeValue(null, "name"));
int drawableResourceId = getResources().getIdentifier(xpp.getAttributeValue(null, "icon"),"drawable", mContext.getPackageName());
bookmark.setIcon(drawableResourceId);
arrayList.add(bookmark);
}
}
xpp.next();
}
} catch (XmlPullParserException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
myAdapter.notifyDataSetChanged();
return paramView;
}
}
This is the layout bookmark which contains recyclerview
<LinearLayout android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:android="http://schemas.android.com/apk/res/android">
<android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/myRecyclerView"
android:layout_height="match_parent"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:fillViewport="false">
</android.support.v7.widget.RecyclerView>
</LinearLayout>
Here is the answer
Follow this steps
First Create a two layout for your Multiple viewType
SAMPLE CODE
layout.layout_one
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
app:cardCornerRadius="15dp"
app:cardElevation="5dp"
app:cardUseCompatPadding="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="Name : " />
<TextView
android:id="#+id/tvName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="Icon : " />
<ImageView
android:id="#+id/tvIcon"
android:layout_width="20dp"
android:layout_height="20dp"
android:padding="10dp"
android:text="" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="Id : " />
<TextView
android:id="#+id/tvId"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="SearchUrl : " />
<TextView
android:id="#+id/tvSearchUrl"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="NativeUrl : " />
<TextView
android:id="#+id/tvNativeUrl"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="" />
</LinearLayout>
</LinearLayout>
</android.support.v7.widget.CardView>
layout.button_two
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/imgButton"
android:layout_width="50dp"
android:layout_height="50dp" />
</LinearLayout>
Now you need to create two RecyclerView.ViewHolder for your both viewType
Now you need to Override getItemViewType()
it Return the viewType of the item at position for the purposes of view recycling.
Now in your onCreateViewHolder() method you need to return your instance of your ViewHolder based on your viewType which you will get using getItemViewType() method
Than in your onBindViewHolder() method based your viewType set your view property
here is the sample code of RecyclerView.Adapter with multiple view types
DataAdapter
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.ArrayList;
public class DataAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private Context context;
ArrayList<Bookmark> arrayList = new ArrayList<>();
public static final int ITEM_TYPE_ONE = 0;
public static final int ITEM_TYPE_TWO = 1;
public DataAdapter(Context context, ArrayList<Bookmark> arrayList) {
this.context = context;
this.arrayList = arrayList;
}
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = null;
// check here the viewType and return RecyclerView.ViewHolder based on view type
if (viewType == ITEM_TYPE_ONE) {
view = LayoutInflater.from(context).inflate(R.layout.layout_one, parent, false);
return new ViewHolder(view);
} else if (viewType == ITEM_TYPE_TWO) {
view = LayoutInflater.from(context).inflate(R.layout.button_two, parent, false);
return new ButtonViewHolder(view);
}else {
return null;
}
}
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder holder, int position) {
final int itemType = getItemViewType(position);
// First check here the View Type
// than set data based on View Type to your recyclerview item
if (itemType == ITEM_TYPE_ONE) {
ViewHolder viewHolder = (ViewHolder) holder;
viewHolder.tvName.setText(arrayList.get(position).getName());
viewHolder.tvIcon.setImageResource(arrayList.get(position).getIcon());
viewHolder.tvSearchUrl.setText(arrayList.get(position).getSearchUrl());
viewHolder.tvNativeUrl.setText(arrayList.get(position).getNativeUrl());
} else if (itemType == ITEM_TYPE_TWO) {
ButtonViewHolder buttonViewHolder = (ButtonViewHolder) holder;
buttonViewHolder.imgButton.setImageResource(arrayList.get(position).getIcon());
}
}
#Override
public int getItemViewType(int position) {
// based on you list you will return the ViewType
if (arrayList.get(position).getViewType() == 0) {
return ITEM_TYPE_ONE;
} else {
return ITEM_TYPE_TWO;
}
}
#Override
public int getItemCount() {
return arrayList.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView tvName, tvId, tvSearchUrl, tvNativeUrl;
ImageView tvIcon;
public ViewHolder(#NonNull View itemView) {
super(itemView);
tvName = itemView.findViewById(R.id.tvName);
tvIcon = itemView.findViewById(R.id.tvIcon);
tvId = itemView.findViewById(R.id.tvId);
tvSearchUrl = itemView.findViewById(R.id.tvSearchUrl);
tvNativeUrl = itemView.findViewById(R.id.tvNativeUrl);
}
}
public class ButtonViewHolder extends RecyclerView.ViewHolder {
ImageView imgButton;
public ButtonViewHolder(#NonNull View itemView) {
super(itemView);
imgButton = itemView.findViewById(R.id.imgButton);
}
}
}
When you adding data in your list you need to provide the viewtype in list
Make some changes in your Bookmark POJO class
Bookmark POJO class
public class Bookmark
{
String name,id,nativeUrl,searchUrl;
int icon;
int viewType;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public int getIcon() {
return icon;
}
public void setIcon(int icon) {
this.icon = icon;
}
public String getNativeUrl() {
return nativeUrl;
}
public void setNativeUrl(String nativeUrl) {
this.nativeUrl = nativeUrl;
}
public String getSearchUrl() {
return searchUrl;
}
public void setSearchUrl(String searchUrl) {
this.searchUrl = searchUrl;
}
public int getViewType() {
return viewType;
}
public void setViewType(int viewType) {
this.viewType = viewType;
}
#Override
public String toString() {
return "Bookmark{" +
"name='" + name + '\'' +
", icon='" + icon + '\'' +
", id='" + id + '\'' +
", nativeUrl='" + nativeUrl + '\'' +
", searchUrl='" + searchUrl + '\'' +
'}';
}
}
Sample activity code
import android.content.Context;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
private Context mContext;
ArrayList<Bookmark> arrayList = new ArrayList<>();
RecyclerView myRecyclerView;
DataAdapter dataAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mContext = this;
myRecyclerView = findViewById(R.id.myRecyclerView);
myRecyclerView.setLayoutManager(new LinearLayoutManager(mContext));
myRecyclerView.setHasFixedSize(true);
dataAdapter = new DataAdapter(mContext, arrayList);
myRecyclerView.setAdapter(dataAdapter);
try {
XmlPullParser xpp = getResources().getXml(R.xml.bookmarks);
while (xpp.getEventType() != XmlPullParser.END_DOCUMENT) {
if (xpp.getEventType() == XmlPullParser.START_TAG) {
if (xpp.getName().equals("Bookmark")) {
Log.e("MY_VALUE", " * " + xpp.getAttributeValue(0) + " * ");
Log.e("MY_VALUE", " * " + xpp.getAttributeValue(1) + " * ");
Log.e("MY_VALUE", " * " + xpp.getAttributeValue(5) + " * ");
Log.e("MY_VALUE", " * " + xpp.getAttributeValue(2) + " * ");
Log.e("MY_VALUE", " * " + xpp.getAttributeValue(3) + " * ");
Log.e("MY_VALUE", " * " + xpp.getAttributeValue(4) + " * ");
Bookmark bookmark = new Bookmark();
bookmark.setName(xpp.getAttributeValue(0));
int drawableResourceId = this.getResources().getIdentifier(xpp.getAttributeValue(1), "drawable", mContext.getPackageName());
bookmark.setIcon(drawableResourceId);
bookmark.setId(xpp.getAttributeValue(2));
bookmark.setSearchUrl(xpp.getAttributeValue(3));
bookmark.setNativeUrl(xpp.getAttributeValue(4));
// here you need to set view type
bookmark.setViewType(0);
arrayList.add(bookmark);
}
}
xpp.next();
}
} catch (XmlPullParserException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
// here i have added second viewType
// you need to set as per your requirement
Bookmark bookmark = new Bookmark();
bookmark.setViewType(1);
bookmark.setIcon(R.drawable.dishu);
arrayList.add(bookmark);
dataAdapter.notifyDataSetChanged();
}
}
NOTE
In the below code i have set second viewType at the last index of Arraylist
you need to set viewType as per your requirement
For more information you can check below articles
Working with RecyclerView and multiple view types
A RecyclerView with multiple item types
Android RecyclerView with Different Child Layouts
Android Pagination Tutorial—Handling Multiple View Types
Heterogenous Layouts inside RecyclerView
Android RecyclerView Example – Multiple ViewTypes
How to create RecyclerView with multiple view type?
Android Multiple row layout using RecyclerView
You can use different layouts on the same RecyclerView , just override adapter getItemViewType() method and return a different int value for the button layout, in your example you should return for example 1 for the normal item and 2 for the button item.
The view type is passed as argument to onCreateViewHolder() method and depending of the viewType value you inflate the normal layout or the button layout.
It seems that you need also make getItemCount() to return one more than the array size
Hope it will help
Here an example:
How to create RecyclerView with multiple view type?
Do this operations in your Activity.
ArrayList<Bookmark> data = new ArrayList<>();
//data.addAll(your array list bookmark); uncomment this line add your all array list of bookmark
Bookmark d = new Bookmark(0);
data.add(d);
mList.setAdapter(new BookMarkAdapter(activity, data));
Try This adapter
public class BookMarkAdapter extends RecyclerView.Adapter {
private Context context;
private ArrayList<Bookmark> data;
public BookMarkAdapter(Context context, ArrayList<Bookmark> data) {
this.context = context;
this.data = data;
}
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
if (viewType == 1)
return new ViewBookmarkHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.cell_with_normal_image_and_textview, parent, false));
else
return new AddBookmarkHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.cell_with_image, parent, false));
}
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder holder, int position) {
Bookmark d = data.get(position);
if (d.getType()==1) {
ViewBookmarkHolder viewBookmarkHolder =(ViewBookmarkHolder) holder;
// do your show image and textview operation here
} else {
AddBookmarkHolder addBookmarkHolder =(AddBookmarkHolder) holder;
// do your on click operation here. Like adding new bookmark and update your arraylist and notify data changed for adapter.
}
}
#Override
public int getItemViewType(int position) {
return data.get(position).getType();
}
#Override
public int getItemCount() {
return data.size();
}
}
Update this methods and variables in your Bookmark Pojo
public class Bookmark {
private Integer type;
public Bookmark(Integer type) {
this.type = type;
}
public void setType(Integer type) {
this.type = type;
}
public Integer getType() {
if(type==null)
return 1;
return type;
}
}
Related
I have this working perfectly with a ListView, but decided to update my code to use RecyclerView.
I see there is no default implementation, and the responses to similar questions are quite old.
Is using a sort of cursor the best way to go, or is there a better option?
These are my code snippets for a working RecyclerView with hard-coded values:
MainActivity
recyclerView = (RecyclerView)findViewById(R.id.recycler_view);
mLayoutmanager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(mLayoutmanager);
mAdapter = new recyclerViewDataAdapter();
recyclerView.setAdapter(mAdapter);
recyclerViewDataAdapter
public class recyclerViewDataAdapter extends RecyclerView.Adapter {
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
//lets populate our recyler view with the item created;
//get the view from the layout inflator
// third parameter is set to false to prevent viewgroup to attach to root
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_item,parent,false);
// as this method need to return the viewHolder type
// need to convert our view to the view holder
RecyclerView.ViewHolder viewHolder = new RecyclerView.ViewHolder(view) {
#Override
public String toString() {
return super.toString();
}
};
return viewHolder;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
}
#Override
public int getItemCount() {
return 3000;
}
}
activity_main
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler_view"
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
recycler_item
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:orientation="vertical">
<TextView
android:id="#+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Hii "
android:textSize="30sp" />
</LinearLayout>
Here is my DatabaseAdapter which worked perfectly with a ListView:
public class DatabaseHelper extends SQLiteAssetHelper {
private static final int DATABASE_VERSION = 1;
private static final String DATABASE_NAME = "database9.db";
private static final String BOOKS = "books";
private static final String AUTHORS = "authors";
public DatabaseHelper (Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
// setForcedUpgrade();
}
// Getting all books
public ArrayList<Author> getAllAuthors() {
ArrayList<Author> authorList = new ArrayList<>();
// Select all query
String selectQuery = "SELECT id, name FROM " + AUTHORS + " ORDER BY name_alphabetic";
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(selectQuery, null);
// looping through all rows and adding to list
if (cursor.moveToFirst()) {
do {
// create new author object
Author author = new Author();
// set ID and name of author object
author.setID(Integer.parseInt(cursor.getString(0)));
author.setName(cursor.getString(1));
// pass author object to authorList array
authorList.add(author);
} while (cursor.moveToNext());
}
// return author list
return authorList;
}
}
Your can try
In your activity
ArrayList<Author> authors = dbHandler. getAllAuthors();
recyclerView.setHasFixedSize(true);
// ListView
recyclerView.setLayoutManager(new LinearLayoutManager(youractivity.this));
// create an Object for Adapter
CardViewDataAdapter1 mAdapter = new CardViewDataAdapter1(authors);
// set the adapter object to the Recyclerview
recyclerView.setAdapter(mAdapter);
Your adapter is look like
class CardViewDataAdapter1 extends RecyclerView.Adapter<CardViewDataAdapter1.ViewHolder> {
private ArrayList<Author> dataSet;
public CardViewDataAdapter1(ArrayList<Author> os_versions) {
dataSet = os_versions;
}
#Override
public CardViewDataAdapter1.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
// create a new view
View itemLayoutView = LayoutInflater.from(viewGroup.getContext()).inflate(
R.layout.recycler_item, null);
itemLayoutView.setLayoutParams(new RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, RecyclerView.LayoutParams.WRAP_CONTENT));
// create ViewHolder
CardViewDataAdapter1.ViewHolder viewHolder = new CardViewDataAdapter1.ViewHolder(itemLayoutView);
return viewHolder;
}
#Override
public void onBindViewHolder(CardViewDataAdapter1.ViewHolder viewHolder, int i) {
Author fp = dataSet.get(i);
viewHolder.tv_name.setText(fp.getName());
viewHolder.menu = fp;
}
#Override
public int getItemCount() {
return dataSet.size();
}
public void updateList(List<Author> temp) {
dataSet = (ArrayList<Author>) temp;
notifyDataSetChanged();
}
// inner class to hold a reference to each item of RecyclerView
public class ViewHolder extends RecyclerView.ViewHolder {
public TextView tv_name;
public Author menu;
public ViewHolder(View itemLayoutView) {
super(itemLayoutView);
tv_name = (TextView) itemLayoutView .findViewById(R.id.tv_name);
}
}
}
Your recycler_item.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
card_view:cardCornerRadius="5dp"
card_view:cardBackgroundColor="#FFFFFF"
card_view:cardUseCompatPadding="true"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="#+id/tv_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Enamul"/>
</LinearLayout>
</android.support.v7.widget.CardView>
I am using RecyclerView in Android with a model class that has title and details. Nothing is showing. Even after log inside Adapter nothing is shown in Android Monitor.
MainActivity.class
public ArrayList<Menu> menu_list;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_menu);
initUi();
}
public void initUi(){
RecyclerView menu_recycler = (RecyclerView) findViewById(R.id.main_menu_recycler_view);
//set the layout manager
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
linearLayoutManager.setOrientation( linearLayoutManager.VERTICAL );
menu_recycler.setLayoutManager( linearLayoutManager );
//set adapter
MainMenuAdapter mainMenuAdapter = new MainMenuAdapter( getMenulist() );
menu_recycler.setAdapter( mainMenuAdapter );
}
public ArrayList<Menu> getMenulist() {
menu_list = new ArrayList<Menu>();
menu_list.add( new Menu("About Us", " Learn more about our values, mission and vision ") );
menu_list.add( new Menu("Services ", " In implementing its mandate, the Agency will provide the following to its external and internal customers:\n"));
menu_list.add( new Menu("Stakeholders", " Who are the key players, Find out more") );
menu_list.add( new Menu("Learn about Counterfeits", "Gain more insight on counterfeit products"));
return menu_list;
}
and here is my adapter
public class MainMenuAdapter extends RecyclerView.Adapter<MainMenuAdapter.MyViewHolder> {
public List<Menu> list_of_menus;
public MainMenuAdapter( List<Menu> list_of_menus){
this.list_of_menus = list_of_menus;
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.row,parent, false);
return new MyViewHolder(v);
}
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
Menu menu = list_of_menus.get(position);
Log.e("MENU IN ADAPTER TITLE", menu.title);
holder.title_text.setText( menu.title );
holder.details_text.setText( menu.details );
}
#Override
public int getItemCount() {
return 0;
}
/*
View Holder class
* */
public class MyViewHolder extends RecyclerView.ViewHolder{
public TextView title_text, details_text;
public MyViewHolder(View itemView) {
super(itemView);
title_text = (TextView) itemView.findViewById(R.id.menu_title);
details_text = (TextView) itemView.findViewById(R.id.menu_details);
}
}
}
And the Model Class
public class Menu {
public String title, details;
public Menu(String title, String details){
this.details = details;
this.title = title;
}
}
And the layout file main_activity
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.maos.aca.MainMenuActivity">
<android.support.v7.widget.RecyclerView
android:layout_width="334dp"
android:layout_height="453dp" app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="8dp" app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginBottom="8dp" android:layout_marginLeft="8dp"
app:layout_constraintLeft_toLeftOf="parent" android:layout_marginRight="8dp"
app:layout_constraintRight_toRightOf="parent" android:id="#+id/main_menu_recycler_view"
android:scrollbars="vertical"/>
</android.support.constraint.ConstraintLayout>
And finally the row
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/menu_title"
android:textStyle="bold"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/app_name"
android:id="#+id/menu_details"/>
</LinearLayout>
I know this question has been asked before, but none of the answers helped me out.I'll appreciate any lead.
You need to change the getItemCount() method to this:
#Override
public int getItemCount() {
return list_of_menus.size();
}
The RecyclerView will not display any elements if you are reporting that its size is zero.
Change this:
#Override
public int getItemCount() {
return 0;
}
To this:
#Override
public int getItemCount() {
return list_of_menus.size();
}
i already success to make one Recyclerview and i want to add new Recyclerview Horizontal on top. i will explain in my code :
<android.support.v7.widget.RecyclerView
android:id="#+id/arrayListUser"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:divider="#color/white">
</android.support.v7.widget.RecyclerView>
<android.support.v7.widget.RecyclerView
android:id="#+id/arrayList"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentTop="true"
android:divider="#color/white">
</android.support.v7.widget.RecyclerView>
id:arrayList is my first Recyclerview have name xml feeds_listview
id:arrayListUser is my new Recyclerview, i want make this Recyclerview Horizontal
xml for new Recylerview is feeds_listviewUser
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<de.hdodenhof.circleimageview.CircleImageView
android:id="#+id/profil"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_marginBottom="5dp"
android:layout_marginTop="30dp"
android:layout_gravity="center"
android:src="#drawable/cthprofil" />
<TextView
android:id="#+id/fullName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_marginTop="5dp"
android:layout_marginBottom="20"
android:text="Megi Fernanda"
android:textSize="17sp"
android:textColor="#color/colordefault"
android:textStyle="bold" />
</LinearLayout>
and this is my class adapter
public class FeedsCustomAdapter extends RecyclerView.Adapter<FeedsCustomAdapter.ViewHolder> {
private Context context;
private List<FeedsAdapter> feeds_list;
private ArrayList<Feeds> mFeedsList = new ArrayList<Feeds>();
private OnItemClickListener mListener;
private OnItemClickListener mListener2;
public FeedsCustomAdapter(Context context, ArrayList<Feeds> mFeedsList) {
this.context = context;
this.mFeedsList = mFeedsList;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.feeds_listview, parent, false);
return new ViewHolder(itemView);
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
Feeds feed = getFeeds().get(position);
int textColor = context.getResources().getColor(R.color.btn_next);
int textColor2 = context.getResources().getColor(R.color.text_color_black);
holder.fullName.setText(feed.user.fullName);
holder.location.setText(feed.user.location);
holder.topic.setText(Html.fromHtml( "Menyelesaikan Tantangan " + " <font color = '" + String.valueOf(textColor2) + "'>" + feed.topic + "</font>" ) );
Picasso.with(context)
.load(feed.user.avatar)
.into(holder.profile);
PrettyTime prettyTime = new PrettyTime();
String times = prettyTime.format(DateUtil.timeMilisTodate(feed.timestamp * 1000));
holder.times.setText(times);
}
#Override
public int getItemCount() {
return mFeedsList.size();
}
public ArrayList<Feeds> getFeeds() {
return mFeedsList;
}
public void setComplete(int position) {
mFeedsList.get(position).isComplete = 1;
}
public boolean last() {
boolean result = false;
int total = mFeedsList.size();
for (int i = 0; i < mFeedsList.size(); i++) {
if (mFeedsList.get(i).isComplete == 1) {
total--;
}
}
if (total == 1) {
result = true;
}
return result;
}
class ViewHolder extends RecyclerView.ViewHolder {
public TextView fullName;
public TextView location;
public TextView topic;
public ImageView profile;
public TextView times;
public ViewHolder(View itemView) {
super(itemView);
fullName = (TextView) itemView.findViewById(R.id.fullName);
location = (TextView) itemView.findViewById(R.id.location);
topic = (TextView) itemView.findViewById(R.id.topic);
profile = (ImageView) itemView.findViewById(R.id.profil);
times = (TextView) itemView.findViewById(R.id.times);
profile.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(mListener2 != null){
mListener2.onItemClick2(v ,getPosition());
}
}
});
topic.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(mListener != null){
mListener.onItemClick(v ,getPosition());
}
}
});
}
}
public void setClickListener(OnItemClickListener clickListener) {
this.mListener = clickListener;
}
public void setClickListenerProfile(OnItemClickListener clickListener2){
this.mListener2 = clickListener2;
}
public interface OnItemClickListener {
public abstract void onItemClick(View view, int position);
public abstract void onItemClick2(View view, int position);
}
so, in my code i success to display first recylerview with my first xml and i want add new recylerview horizontal with new xml feeds_listviewUser
You can use LinearLayout to wrap both recyclerView.
<android.support.v7.widget.RecyclerView
android:id="#+id/arrayListUser"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:divider="#color/white">
</android.support.v7.widget.RecyclerView>
<android.support.v7.widget.RecyclerView
android:id="#+id/arrayList"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:divider="#color/white">
</android.support.v7.widget.RecyclerView>
And assign horizontal layout manager to one recyclerview and vertical layout manager to other
LinearLayoutManager userManager = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);
arrayListUser.setLayoutManager(userManager);
LinearLayoutManager listManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
arrayList.setLayoutManager(listManager);
Put your recyclerviews in Relative layout.
First add horizontal recyclerView to alignParentTop true and fix height according to visibility of feeds_listviewUser next add vertical recyclerView with layout_below horizontal recyclerview id.
I would like to insert a small image to the right of each item in a listview
basically my app should do so as soon as the user clicks on an item in the list view, the image becomes visible, otherwise it must remain invisible.
below is my activity with its XML
Activity
public class EpisodiActivity extends Activity {
public class ViewModel {
private String url;
private String name;
public ViewModel(String url, String name) {
this.url = url;
this.name = name;
}
public String getUrl() {
return this.url;
}
public void setUrl(String url) {
this.url = url;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public String toString() {
return this.name;
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//creazione fullscreen activity
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.episodi_activity);
String[] episodi = getIntent().getStringArrayExtra("Product");
String[] urls = getIntent().getStringArrayExtra("urls");
ListView mylist = (ListView) findViewById(R.id.listView1);
// And in this loop we create the ViewModel instances from
// the name and url and add them all to a List
List<ViewModel> models = new ArrayList<ViewModel>();
for (int i = 0; i < episodi.length; i++) {
String name = episodi[i];
String url = "No value";
if (i < urls.length) {
url = urls[i];
}
ViewModel model = new ViewModel(url, name);
models.add(model);
}
// Here we create the ArrayAdapter and assign it to the ListView
// We pass the List of ViewModel instances into the ArrayAdapter
final ArrayAdapter<ViewModel> adapter = new ArrayAdapter<ViewModel>(this, android.R.layout.simple_list_item_1, models);
mylist.setAdapter(adapter);
mylist.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> arg0, View v, int position, long id) {
// Here we get the ViewModel at the given position
ViewModel model = (ViewModel) arg0.getItemAtPosition(position);
// And the url from the ViewModel
String url = model.getUrl();
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url)));
}
});
}
XML
RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<ListView
android:id="#+id/listView1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_above="#id/pubblicita"
android:cacheColorHint="#ffd700"
android:background="#drawable/sfondobottone" />
I think you want this kind of output in listview
text with image in listview
You can use custom listview . Make a class which extends BaseAdapter class
here is the exmaple that i am using
Your BaseAdapter
import java.util.ArrayList;
import android.content.Context;
import android.graphics.Bitmap;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
public class FrontListBaseAdapter extends BaseAdapter {
private static ArrayList<FrontDetails> itemDetailsrrayList;
private LayoutInflater l_Inflater;
public FrontListBaseAdapter(Context context, ArrayList<FrontDetails> results) {
itemDetailsrrayList = results;
l_Inflater = LayoutInflater.from(context);
}
public int getCount() {
return itemDetailsrrayList.size();
}
public Object getItem(int position) {
return itemDetailsrrayList.get(position);
}
public long getItemId(int position) {
return position;
}
// get the views in frontview xml file where you have
// define multiple views that will appear in listview each row
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = l_Inflater.inflate(R.layout.frontview, null);
holder = new ViewHolder();
holder.Image = (ImageView) convertView.findViewById(R.id.adminpic1);
holder.MsgType = (TextView) convertView.findViewById(R.id.msgtype1);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.Image.setImageResource(R.drawable.mainlogo); // you can set your setter here
holder.MsgType.setText(itemDetailsrrayList.get(position).getMsgType());
return convertView;
}
// holder view for views
static class ViewHolder {
ImageView Image;
TextView MsgType;
}
}
your FrontDetails class where you will make getters and setters and this class will be used in final ArrayList resultse = new ArrayList();
import android.graphics.Bitmap;
public class FrontDetails {
public int getImage() {
return image;
}
public void setImage(int imageN) {
this.image = imageN;
}
public String getMsgType() {
return MsgType;
}
public void setMsgType(String text) {
this.MsgType = text;
}
private int image;
private String MsgType;
}
your frontview.XML where you put your multiple views that will be in each row or your layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="100dp"
android:orientation="vertical"
android:layout_margin="10dp" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="80dp" >
<ImageView
android:id="#+id/adminpic1"
android:layout_width="60dp"
android:layout_height="60dp"
android:src="#drawable/ic_launcher" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="#+id/msgtype1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginTop="4dp"
android:textSize="1sp"
android:text="MsgType" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
and your listview in xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<Button
android:id="#+id/sync"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Sync" />
<ListView
android:id="#+id/listView1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp" >
</ListView>
</LinearLayout>
now in your main activity
final ArrayList<FrontDetails> resultse = new ArrayList<FrontDetails>();
FrontListBaseAdapter asdf = new FrontListBaseAdapter(context, resultse);
lv1.setAdapter(new FrontListBaseAdapter(Front.this, resultse));
lv1.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View arg1,
int position, long arg3) {
Object o = lv1.getItemAtPosition(position);
FrontDetails obj_itemDetails = (FrontDetails)o;
Toast.makeText(context, "You have chosen " + ' ' + obj_itemDetails.getMsgType(), Toast.LENGTH_LONG).show();
}
});
EDIT:
From here i learned Custom Listview its a simple exmaple with image
http://www.javasrilankansupport.com/2012/05/android-listview-example-with-image-and.html
http://www.javacodegeeks.com/2012/10/android-listview-example-with-image-and.html
Use custom listview with BaseAdapter
Your Adapter
public class CustomBaseAdapter extends BaseAdapter {
Context context;
List<RowItem> rowItems;
public CustomBaseAdapter(Context context, List<RowItem> items) {
this.context = context;
this.rowItems = items;
}
/*private view holder class*/
private class ViewHolder {
ImageView imageView;
TextView txtTitle;
TextView txtDesc;
}
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
LayoutInflater mInflater = (LayoutInflater)
context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
if (convertView == null) {
convertView = mInflater.inflate(R.layout.list_item, null);
holder = new ViewHolder();
holder.txtDesc = (TextView) convertView.findViewById(R.id.desc);
holder.txtTitle = (TextView) convertView.findViewById(R.id.title);
holder.imageView = (ImageView) convertView.findViewById(R.id.icon);
convertView.setTag(holder);
}
else {
holder = (ViewHolder) convertView.getTag();
}
RowItem rowItem = (RowItem) getItem(position);
holder.txtDesc.setText(rowItem.getDesc());
holder.txtTitle.setText(rowItem.getTitle());
holder.imageView.setImageResource(rowItem.getImageId());
return convertView;
}
#Override
public int getCount() {
return rowItems.size();
}
#Override
public Object getItem(int position) {
return rowItems.get(position);
}
#Override
public long getItemId(int position) {
return rowItems.indexOf(getItem(position));
}
}
Your list_item.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<ImageView
android:id="#+id/icon"
android:layout_width="80dp"
android:layout_height="80dp"
android:contentDescription="#string/image"
android:paddingLeft="10dp"
android:paddingRight="10dp" />
<TextView
android:id="#+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="#+id/icon"
android:paddingBottom="10dp"
android:textColor="#CC0033"
android:textSize="16dp" />
<TextView
android:id="#+id/desc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/title"
android:layout_toRightOf="#+id/icon"
android:paddingLeft="10dp"
android:textColor="#3399FF"
android:textSize="14dp" />
</RelativeLayout>
Your Single Row item class
public class RowItem {
private int imageId;
private String title;
private String desc;
public RowItem(int imageId, String title, String desc) {
this.imageId = imageId;
this.title = title;
this.desc = desc;
}
public int getImageId() {
return imageId;
}
public void setImageId(int imageId) {
this.imageId = imageId;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
#Override
public String toString() {
return title + "\n" + desc;
}
}
List view implementation
listView = (ListView) findViewById(R.id.list);
CustomBaseAdapter adapter = new CustomBaseAdapter(this, rowItems);
listView.setAdapter(adapter);
I can give some tips ,but unfortunately couldn't help you by example..
First of all create one custom adapter(extends BaseAdapter) followed by one custom layout..
Here the custom layout contains the textview and one image view(by default invisible) at the right.
Just customize your list view with your adapter and put text inside TextView through get view()..
At last in your listItemClickListener make the image visible by its position.
You can set here on xml like this
android:visibility="visible"
or
android:visibility="invisible"
or
android:visibility="gone"
Java program:
ImageView imgView = (ImageView)findViewById(R.id.custom);
set your ImageView like this
imgView .setVisibility(View.VISIBLE);
imgView .setVisibility(View.INVISIBLE);
imgView .setVisibility(View.GONE);
Difference between INVISIBLE and GONE.
INVISIBLE - The widget will be invisible but space for the widget will be show.
GONE - Both space and widget is invisible.
Now you can hook your setOnItemClickListener()
listview.setOnItemClickListener(new OnItemClickListener()
{
#Override
public void onItemClick(AdapterView<?> arg0, View arg1,int position, long arg3)
{
imgView .setVisibility(View.VISIBLE);
}
});
So I have the following view
list_view_item.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/layoutSessionItem"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:id="#+id/lblGroupDate"
style="#style/CustomText.GrayTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</TextView>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:id="#+id/lblCourseCode"
style="#style/CustomText.GrayText"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/lblSessionCode"
style="#style/CustomText.GrayText"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</RelativeLayout>
So basically I get the following data from the database:
COURSE_CODE
SESSION_CODE
SESSION_DATE
I need to group the ListView items by SESSION_DATE, what I do is I keep a variable called "PreviousDate" and I compare it to the current SESSION_DATE, if it's different then I enable the header with the ID: "lblGroupDate" if the dates are the same I Hide "lblGroupDate".
Here's my Adapter:
public class SessionListAdapter extends BaseAdapter {
private Date PreviousDate = new Date();
static class ViewHolder {
TextView lblGroupDate;
TextView lblCourseCode;
TextView lblSessionCode;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = mLayoutInflater.inflate(R.layout.list_view_item, null);
holder = new ViewHolder();
holder.lblGroupDate = (TextView) convertView.findViewById(R.id.lblGroupDate);
holder.lblCourseCode = (TextView) convertView.findViewById(R.id.lblCourseCode);
holder.lblSessionCode = (TextView) convertView.findViewById(R.id.lblSessionCode);
} else {
holder = (ViewHolder)convertView.getTag();
}
SessionData session = (SessionData) getItem(position);
if(session != null) {
Date sessionDate = session.SESSION_DATE;
if (!mPrevDate.equals(sessionDate)) {
PreviousDate = sessionDate;
// HIDE GROUP HEADER
holder.lblGroupDate.setVisibility(View.GONE);
}
else {
// SHOW GROUP HEADER
holder.lblGroupDate.setVisibility(View.VISIBLE);
}
holder.lblCourseCode.setText(session.COURSE_CODE);
holder.lblSessionCode.setText(session.SESSION_CODE);
}
}
}
Here's the PROBLEM:
Lets say I have 20 records, when I scroll down and then scroll up again the rows that had the Group Header (lblGroupDate) enabled get shifted up without a header, it's the header was shifted to the next 3 rows. Why is this happening?
It's happening because getView() can be called at anytime and out-of-order from your data-set. You need to create a data-set that the adapter can be backed by. Just sorting your adapter out. Will update answer with code in a moment.
SessionListAdapter.java
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import android.content.Context;
import android.text.format.DateUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
public class SessionListAdapter extends BaseAdapter
{
private static final int TYPE_GROUP = 0;
private static final int TYPE_SESSION = 1;
private static final int MAX_TYPES = 2;
private final LayoutInflater mLayoutInflater;
private ArrayList<SessionViewData> mData;
public SessionListAdapter(Context context, List<SessionData> sessionData)
{
mLayoutInflater = LayoutInflater.from(context);
updateSessionViewData(sessionData);
}
public void updateSessionViewData(List<SessionData> sessionData)
{
Date previousDate = new Date();
ArrayList<SessionViewData> data = new ArrayList<SessionViewData>();
for(SessionData session: sessionData){
if(!previousDate.equals(session.SESSION_DATE)){
data.add(new SessionViewData(TYPE_GROUP, session));
previousDate = session.SESSION_DATE;
}
data.add(new SessionViewData(TYPE_SESSION, session));
}
mData = data;
notifyDataSetChanged();
}
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
SessionViewData data = mData.get(position);
if(convertView == null){
final int layoutId;
switch(data.type){
case TYPE_GROUP: layoutId = R.layout.list_session_group; break;
case TYPE_SESSION: layoutId = R.layout.list_session_item; break;
default:
throw new IllegalArgumentException("Bad type for: " + data.session);
}
convertView = mLayoutInflater.inflate(layoutId, parent, false);
}
switch(data.type){
case TYPE_GROUP:
TextView lblGroupDate = ((TextView)convertView.findViewById(R.id.lblGroupDate));
lblGroupDate.setText(DateUtils.formatDateTime(convertView.getContext(),
data.session.SESSION_DATE.getTime(), DateUtils.FORMAT_SHOW_DATE));
break;
case TYPE_SESSION:
TextView lblCourseCode = (TextView)convertView.findViewById(R.id.lblCourseCode);
lblCourseCode.setText(data.session.COURSE_CODE);
TextView lblSessionCode = (TextView)convertView.findViewById(R.id.lblSessionCode);
lblSessionCode.setText(data.session.SESSION_CODE);
break;
}
return convertView;
}
#Override
public Object getItem(int position)
{
return mData.get(position);
}
#Override
public long getItemId(int position)
{
return position;
}
#Override
public int getItemViewType(int position)
{
return mData.get(position).type;
}
#Override
public int getViewTypeCount()
{
return MAX_TYPES;
}
#Override
public int getCount()
{
return mData.size();
}
static class SessionViewData
{
int type;
SessionData session;
public SessionViewData(int type, SessionData session)
{
this.type = type;
this.session = session;
}
}
}
list_session_group.xml
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/lblGroupDate"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="#style/CustomText.GrayTitle"
/>
list_session_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/layoutSessionItem"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
>
<TextView
android:id="#+id/lblCourseCode"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="#style/CustomText.GrayText"
/>
<TextView
android:id="#+id/lblSessionCode"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="#style/CustomText.GrayText"
/>
</LinearLayout>