How to add a footer button to my recycler view - java

I want to add a footer to my recycler view. I have attached the custom adapter code below. How can I do this? I want the button to fill the recycler view with new items. I can do the button functioning on my own. I'm only facing the problem adding the footer.
I want something like the image attached below:
package com.example.myapplication.Adapter;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.support.v7.widget.CardView;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.example.myapplication.Interface.ItemClickListener;
import com.example.myapplication.Model.RSSObject;
import com.example.myapplication.R;
class FeedViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener{
public TextView textTitle,txtDate,textContent;
private ItemClickListener itemClickListener;
public FeedViewHolder(View itemView) {
super(itemView);
textTitle = (TextView) itemView.findViewById(R.id.textTitle);
txtDate = itemView.findViewById(R.id.textPubDate);
textContent = itemView.findViewById(R.id.textContent);
itemView.setOnClickListener(this);
itemView.setOnLongClickListener(this);
}
public FeedViewHolder(View itemView, ItemClickListener itemClickListener) {
super(itemView);
this.itemClickListener = itemClickListener;
}
#Override
public void onClick(View v) {
itemClickListener.onClick(v, getAdapterPosition(), false);
}
#Override
public boolean onLongClick(View v) {
itemClickListener.onClick(v, getAdapterPosition(), true);
return true;
}
}
public class FeedAdapter extends RecyclerView.Adapter<FeedViewHolder> {
private RSSObject.RssObject rssObject;
private Context mContext;
private LayoutInflater layoutInflater;
public FeedAdapter(RSSObject.RssObject rssObject, Context mContext) {
this.rssObject = rssObject;
this.mContext = mContext;
layoutInflater = layoutInflater.from(mContext);
}
#Override
public int getItemViewType(int position) {
return super.getItemViewType(position);
}
#Override
public FeedViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
final View itemView = layoutInflater.inflate(R.layout.row,parent,false);
return new FeedViewHolder(itemView);
}
#Override
public void onBindViewHolder(final FeedViewHolder holder, final int position) {
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String url = rssObject.getItems().get(holder.getAdapterPosition()).getLink();
Intent i = new Intent(Intent.ACTION_VIEW);
i.setData(Uri.parse(url));
v.getContext().startActivity(i);
}
});
String title = rssObject.getItems().get(position).getTitle();
title = title.replace("&","");
holder.textTitle.setText(title);
String description = rssObject.getItems().get(position).getDescription();
description = android.text.Html.fromHtml(description).toString();
holder.textContent.setText(description);
holder.txtDate.setText(rssObject.getItems().get(position).getPubDate());
}
#Override
public int getItemCount() {
return rssObject.items.size();
}
}

There are two ways:
If you want a fixed view put under RecyclerView in your xml file a Relative Layout (or orher) with the button inside
Or if you want the button as an element of the list you should add a view with the button ad the last position of your view

If you wish to add a footer, you need to specify it as another type of view.
In your adapter code you should add logic for creation of another holder for the footer.
Please see the following Kotlin example:
const val REGULAR_VIEW_TYPE = 0
const val FOOTER_VIEW_TYPE = 1
class FooterExampleAdapter(
private val data: List<String>
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
when (viewType) { // Use 'when' to create the correct holder for any position
REGULAR_VIEW_TYPE -> RegularViewHolder(parent.inflateView(R.layout.regular_layout))
FOOTER_VIEW_TYPE -> FooterViewHolder(parent.inflateView(R.layout.footer_layout))
}
// Handle binding by checking holder type
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
if (holder is RegularViewHolder) holder.bind(data[position])
else if (holder is FooterViewHolder) holder.bind()
}
override fun getItemCount() = data.size + 1 // We need the extra 1 for the footer to be counted
// Here is where we specify which view type should be presented at position
override fun getItemViewType(position: Int) =
if (position == data.size) FOOTER_VIEW_TYPE else REGULAR_VIEW_TYPE
}
class RegularViewHolder(v: View) : RecyclerView.ViewHolder(v) {
fun bind(string: String) {}
}
class FooterViewHolder(v: View) : RecyclerView.ViewHolder(v) {
fun bind() {}
}

Related

Loading images in gridView sometimes mixes up

I am having a problem with my GridView wherein the images loads in different places when scrolling. I know this has something to do with recycling but as I am new to Android, I have no idea about this.
public View getView(int position, #Nullable View convertView, #NonNull ViewGroup parent) {
final Listing listing = getItem(position);
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.listing_items, parent, false);
}
final ImageView imageView = (ImageView) convertView.findViewById(R.id.imageView);
FirebaseStorage.getInstance().getReference().child(listing.authorUid).child(listing.adId).child(listing.images.get(0)).getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
#Override
public void onSuccess(Uri uri) {
try {
GlideApp.with(getContext())
.load(new URL(uri.toString()))
.into(imageView);
} catch(Exception e) {
e.printStackTrace();
}
}
});
imageView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(getContext(), ItemInfoActivity.class);
intent.putExtra("title", listing.title);
intent.putExtra("location", listing.city);
intent.putExtra("price", listing.price);
intent.putExtra("desc", listing.description);
intent.putExtra("category", listing.category);
intent.putExtra("author", listing.authorUid);
intent.putExtra("adId", listing.adId);
intent.putExtra("authorId", listing.authorUid);
startActivity(intent);
}
});
TextView price = (TextView)convertView.findViewById(R.id.price_txt);
TextView title = (TextView)convertView.findViewById(R.id.title_txt);
title.setText(listing.title);
price.setText(listing.price +"DH");
return convertView;
}
Please advise on what to do.
import android.content.Context;
import android.content.Intent;
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 CustomAdapter extends RecyclerView.Adapter {
ArrayList personNames;
ArrayList personImages;
Context context;
public CustomAdapter(Context context, ArrayList personNames, ArrayList personImages) {
this.context = context;
this.personNames = personNames;
this.personImages = personImages;
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// infalte the item Layout
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.rowlayout, parent, false);
// set the view's size, margins, paddings and layout parameters
MyViewHolder vh = new MyViewHolder(v); // pass the view to View Holder
return vh;
}
#Override
public void onBindViewHolder(MyViewHolder holder, final int position) {
// set the data in items
holder.name.setText(personNames.get(position));
holder.image.setImageResource(personImages.get(position));
// implement setOnClickListener event on item view.
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// open another activity on item click
Intent intent = new Intent(context, SecondActivity.class);
intent.putExtra("image", personImages.get(position)); // put image data in Intent
context.startActivity(intent); // start Intent
}
});
}
#Override
public int getItemCount() {
return personNames.size();
}
public class MyViewHolder extends RecyclerView.ViewHolder {
// init the item view's
TextView name;
ImageView image;
public MyViewHolder(View itemView) {
super(itemView);
// get the reference of item view's
name = (TextView) itemView.findViewById(R.id.name);
image = (ImageView) itemView.findViewById(R.id.image);
}
}
}
Use this adapter structure.
import android.content.Context;
import android.content.Intent;
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 CustomAdapter extends RecyclerView.Adapter {
ArrayList personNames;
ArrayList personImages;
Context context;
public CustomAdapter(Context context, ArrayList personNames, ArrayList personImages) {
this.context = context;
this.personNames = personNames;
this.personImages = personImages;
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// infalte the item Layout
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.rowlayout, parent, false);
// set the view's size, margins, paddings and layout parameters
MyViewHolder vh = new MyViewHolder(v); // pass the view to View Holder
return vh;
}
#Override
public void onBindViewHolder(MyViewHolder holder, final int position) {
// set the data in items
holder.name.setText(personNames.get(position));
holder.image.setImageResource(personImages.get(position));
// add your firebase code here
// implement setOnClickListener event on item view.
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// open another activity on item click
Intent intent = new Intent(context, SecondActivity.class);
intent.putExtra("image", personImages.get(position)); // put image data in Intent
context.startActivity(intent); // start Intent
}
});
}
#Override
public int getItemCount() {
return personNames.size();
}
public class MyViewHolder extends RecyclerView.ViewHolder {
// init the item view's
TextView name;
ImageView image;
public MyViewHolder(View itemView) {
super(itemView);
// get the reference of item view's
name = (TextView) itemView.findViewById(R.id.name);
image = (ImageView) itemView.findViewById(R.id.image);
}
}
}
Here is the updated answer of above answer.
if you are using recyclerview you can not override getView() method.
i would suggest you to use recyclerview.

How to get a View from xml file using LayoutInflater in a java class not extending Activity

I have a java class where I am displaying a dialog using an XML layout file. I want to set the text/contents of the layout dynamically.
To achieve this I am writing a method like this :
private void setContentMessage(String theMessage)
{
View contentView = LayoutInflater.from(context).inflate(R.layout.dialog_content, null, false);
TextView titleMessage = (TextView) contentView.findViewById(R.id.title_message);
titleMessage.setText(theMessage);
}
So here inside the inflate method I am using null because I don't know what to use.
Generally, we use ViewGroup object as the second argument in inflate method but I don't know how to create a ViewGroup inside a java class not extending Activity.
The function that I have written above is making not change inside the dialog layout. So please tell how can I inflate a layout in a java class.
AmitSmartDialog.java
package com.amitupadhyay.touchme.utility;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import android.widget.Toast;
import com.amitupadhyay.touchme.R;
import com.orhanobut.dialogplus.DialogPlus;
import com.orhanobut.dialogplus.Holder;
import com.orhanobut.dialogplus.OnCancelListener;
import com.orhanobut.dialogplus.OnClickListener;
import com.orhanobut.dialogplus.OnDismissListener;
import com.orhanobut.dialogplus.OnItemClickListener;
import com.orhanobut.dialogplus.ViewHolder;
/**
* Created by aupadhyay on 12/9/16.
*/
public class AmitSmartDialog {
Context context;
public AmitSmartDialog(Context context) {
this.context = context;
}
public void showDialog(int holderId, int gravity, boolean showHeader, boolean showFooter, boolean expanded, String message) {
setContentMessage(message);
Holder holder;
holder = new ViewHolder(R.layout.dialog_content);
OnClickListener clickListener = new OnClickListener() {
#Override
public void onClick(DialogPlus dialog, View view) {
switch (view.getId()) {
case R.id.like_it_button:
Toast.makeText(context, "We're glad that you like it", Toast.LENGTH_LONG).show();
break;
case R.id.love_it_button:
Toast.makeText(context, "We're glad that you love it", Toast.LENGTH_LONG).show();
break;
}
dialog.dismiss();
}
};
OnItemClickListener itemClickListener = new OnItemClickListener() {
#Override
public void onItemClick(DialogPlus dialog, Object item, View view, int position) {
}
};
OnDismissListener dismissListener = new OnDismissListener() {
#Override
public void onDismiss(DialogPlus dialog) {
}
};
OnCancelListener cancelListener = new OnCancelListener() {
#Override
public void onCancel(DialogPlus dialog) {
}
};
showCompleteDialog(holder, gravity, new BaseAdapter() {
#Override
public int getCount() {
return 0;
}
#Override
public Object getItem(int i) {
return null;
}
#Override
public long getItemId(int i) {
return 0;
}
#Override
public View getView(int i, View view, ViewGroup viewGroup) {
return null;
}
}, clickListener, itemClickListener, dismissListener, cancelListener,
expanded);
}
private void showCompleteDialog(Holder holder, int gravity, BaseAdapter adapter,
OnClickListener clickListener, OnItemClickListener itemClickListener,
OnDismissListener dismissListener, OnCancelListener cancelListener,
boolean expanded) {
final DialogPlus dialog = DialogPlus.newDialog(context)
.setContentHolder(holder)
.setHeader(R.layout.dialog_header)
.setCancelable(false)
.setGravity(gravity)
.setAdapter(adapter)
.setOnClickListener(clickListener)
.setOnItemClickListener(new OnItemClickListener() {
#Override public void onItemClick(DialogPlus dialog, Object item, View view, int position) {
}
})
.setOnDismissListener(dismissListener)
.setExpanded(expanded)
.setContentHeight(ViewGroup.LayoutParams.WRAP_CONTENT)
.setOnCancelListener(cancelListener)
.setOverlayBackgroundResource(android.R.color.transparent)
.create();
dialog.show();
}
private void setContentMessage(String theMessage)
{
Toast.makeText(context, "HI BRO", Toast.LENGTH_SHORT).show();
View contentView = LayoutInflater.from(context).inflate(R.layout.dialog_content, null, false);
TextView titleMessage = (TextView) contentView.findViewById(R.id.title_message);
titleMessage.setText(theMessage);
}
}
Use this way :
LayoutInflater inflater = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View contentView = inflater.inflate(R.layout.dialog_content, null,false);
Or
LayoutInflater inflater = LayoutInflater.from(getApplicationContext);
View contentView = inflater.inflate(R.layout.dialog_content, null,false);
UpDate :
Do some Change like this way
setContentMessage(message); pass context as parameter.
so change like this
setContentMessage(message, context);
and change this also.
private void setContentMessage(String theMessage,Context context)
{
View contentView = contxet.getLayoutInflater().inflate(R.layout.dialog_content, null);
TextView titleMessage = (TextView) contentView.findViewById(R.id.title_message);
titleMessage.setText(theMessage);
}
Pass context in an argument of that method then use this
"(LayoutInflater)
mActivity.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);"
private void setContentMessage(String theMessage, Activity mActivity)
{
LayoutInflater mInflater = (LayoutInflater)
mActivity.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
View contentView = mInflater.inflate(R.layout.dialog_content, null, false);
TextView titleMessage = (TextView) contentView.findViewById(R.id.title_message);
titleMessage.setText(theMessage);
}
From what I'm understanding from your code, you are creating a dialog with a custom view, and then you want to set a message to some textview inside that dialog.
I see that you also use a holder, so instead of calling setContentMessage(message), which is redundant, you could something like this
Holder holder;
holder = new ViewHolder(R.layout.dialog_content);
holder.titleMessage = message
Inside the Holder implementation you should have a field that points to the title textView (that's how a holder pattern should be anyway).

recyclerview onclicklistener java.lang.IndexOutOfBoundsException: Invalid index 0, size is 0

when I dynamic remove an item, or when I refresh the adapter(swipe to fresh) i get these erros:
recyclerview onclicklistener java.lang.IndexOutOfBoundsException: Invalid index 0, size is 0
Really can't figure out why this is happening, Really Appreciate any feed back.
MainActivity:
adapter.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(View view, int position) {
GroupModel selectedList = mGroupModels.get(position);
if (selectedList != null) {
Log.d(TAG, "setAdpterListner > view.getId: " + view.getId() +
" | P: " + position +
" | data ID: " + selectedList.getGroupName()
//" | viewID: " + viewID
);
Intent intent = new Intent(this, DetailsActivity.class);
String listId = selectedList.getGroupID();
String listName = selectedList.getGroupName();
intent.putExtra(Constant.KEY_LIST_ID, listId);
intent.putExtra(Constant.KEY_LIST_NAME, listName);
startActivity(intent);
}
}
});
Adapter:
public class GroupListAdapter extends RecyclerView.Adapter<GroupListAdapter.StatusViewHolder> {
Context context;
private List<GroupModel> mGroupModels;
private static OnItemClickListener listener;
public GroupListAdapter(Context context, List<GroupModel> groupList) {
this.context = context;
this.mGroupModels = groupList;
}
public void setOnItemClickListener(OnItemClickListener listener) {
GroupListAdapter.listener = listener;
}
#Override
public StatusViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.single_group_list, parent, false);
return new StatusViewHolder(view);
}
#Override
public void onBindViewHolder(StatusViewHolder holder, int position) {
final GroupModel data = mGroupModels.get(position);
holder.text_view_list_name.setText(data.getGroupName());
}//end onBindViewHolder
#Override
public int getItemCount() {
return mGroupModels.size();
}
public class StatusViewHolder extends RecyclerView.ViewHolder {
public TextView text_view_list_name;
public TextView created_by;
public StatusViewHolder(final View itemView) {
super(itemView);
text_view_list_name = (TextView) itemView.findViewById(R.id.text_view_list_name);
created_by = (TextView) itemView.findViewById(R.id.created_by);
// Setup the click listener
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (listener != null)
listener.onItemClick(itemView, getLayoutPosition());
}
});
}
}//end StatusViewHolder
}//end GroupListAdapter
UPDATE:
I taken into consideration Yurii Tsap Feedback. I check the code again. I think the problem is somewhere below:
Whenever I swipe to Fresh, and If i click on the list straight way, the app Crash with the error from above.
mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
// Refresh items
mRecyclerView.invalidate();
adapter = null;
initGetGroupList();
mSwipeRefreshLayout.setRefreshing(false);
}
});
In the API call
...
GroupModel groupModel = new GroupModel(groupID, groupName, groupCreatedBy);
mGroupModels.add(groupModel);
}
updateUI(true);
if (adapter == null) {
adapter = new GroupListAdapter(MainActivity.this, mGroupModels);
mRecyclerView.setAdapter(adapter);
setAdapterListener(adapter);
}
The problem is definitely not in the static listener. And also the listener is just an interface callback(related to the comment above) not a AdapterView.OnItemClickListener(). I think the problem is somewhere behind this code, maybe you are clearing the item list somewhere else or something like that?
And also as for me in your case it's better to use getAdapterPosition() instead of getLayoutPosition().
As mentioned in docs :
If LayoutManager needs to call an external method that requires the adapter position of the item, it can use getAdapterPosition() or RecyclerView.Recycler.convertPreLayoutPositionToPostLayout(int).
Make OnItemClickListener non static .Like
private OnItemClickListener listener;
your code have alot of problem
i will explain my way to handle recycle view
very simple adapter
package com.pentavalue.ongo.transportway.adapter;
import android.app.Activity;
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.LinearLayout;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import com.pentavalue.ongo.R;
import com.pentavalue.ongo.Utilts.ImageLoaderHelper;
import com.pentavalue.ongo.register.model.Vechiles;
import com.pentavalue.ongo.widget.ArabicTextView;
import java.util.ArrayList;
/**
* Created by hamada on 19/09/2015.
*/
public class TransportTypeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
public LayoutInflater inflater = null;
Activity activity;
ArrayList<Vechiles> vechileList;
ImageLoaderHelper imageLoaderHelper;
public TransportTypeAdapter(Activity activity, ArrayList<Vechiles> vechileList) {
this.activity = activity;
this.vechileList = vechileList;
imageLoaderHelper = new ImageLoaderHelper(activity, null);
inflater = LayoutInflater.from(activity);
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View vi = inflater.inflate(R.layout.single_transport_item, parent, false);
RecyclerView.ViewHolder vh = new VechileListHolder(vi);
return vh;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int pos) {
VechileListHolder mHolder = (VechileListHolder) viewHolder;
mHolder.renderDate(vechileList.get(pos));
}
#Override
public int getItemCount() {
if (vechileList != null)
return this.vechileList.size();
else
return 0;
}
public class VechileListHolder extends RecyclerView.ViewHolder implements
View.OnClickListener {
ArabicTextView vecName;
RelativeLayout img_layout;
ProgressBar progress;
ImageView imgView;
public VechileListHolder(View vi) {
super(vi);
vi.setOnClickListener(this);
img_layout = (RelativeLayout) vi.findViewById(R.id.img_layout);
vecName = (ArabicTextView) vi.findViewById(R.id.TVVecName);
progress = (ProgressBar) vi.findViewById(R.id.progress);
imgView = (ImageView) vi.findViewById(R.id.imgView);
}
public void renderDate(Vechiles item) {
imageLoaderHelper.loadImage(imgView, progress, item.getImg());
vecName.setText(item.getVecName());
}
#Override
public void onClick(View v) {
if (mItemClickListener != null)
mItemClickListener.onItemClickListener(getPosition(), v);
}
}
public void setOnItemClickListener(ItemClickListener itemClick) {
this.mItemClickListener = itemClick;
}
public ItemClickListener mItemClickListener;
public interface ItemClickListener {
public void onItemClickListener(int pos, View v);
}
public void updateList(ArrayList<Vechiles> vechileList) {
this.vechileList = vechileList;
notifyDataSetChanged();
}
public void removeItem(int pos){
this.vechileList.remove(pos);
notifyItemRemoved(pos);
}
}
and in Fragment or activity can
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
initListView();
}
private void initRecycleView(){
listView = (RecyclerView) v.findViewById(R.id.listView);
listView.getItemAnimator().setAddDuration(1000);
listView.getItemAnimator().setChangeDuration(1000);
listView.getItemAnimator().setMoveDuration(1000);
listView.getItemAnimator().setRemoveDuration(1000);
listView.setLayoutManager(new GridLayoutManager(getActivity(), 3));
listView.setAdapter(new TransportTypeAdapter(getActivity(), vecList));
}
then after data back from API can update adapter with new data by use method update
((VechileListHolder ) listView.getAdapter).updateList( vechileList);
in case went to remove any item by using Pos can do call method that in adapter removeItem(pos)
((VechileListHolder ) listView.getAdapter).removeItem(1);
hope this code help you

GridviewLayoutManager with headers

I am working on an app
I have implemented a working recycler view that receives a jsonarray, passes the data to a string array.
I now want to add section headers to the layout manager.
I have read two schools of thought on this:
- Change the spansize of the view to match the total columns of the grid
- create a custom adapter that loads a different view if the item is a section header.
Im not sure which way to go with this and its starting to confuse me
I have a list of data in an array which includes both headers and grid data (myDataset), i have also created another array with the mapping for the dataset in (myDatamap). In myDatamap i have a list of field types (1 for header and 0 for griddata. I was hoping to pass both arrays to the adaptor and for it decide if its a header or a griditem and then load the appropriate view.
I am leaning more towards loading a different view for the header items, allowing for me to customise the layout of the header easier.
Here is my adaptor code
package com.example.alex.recyclerview2;
import java.util.ArrayList;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.squareup.picasso.Picasso;
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
private ArrayList<String> mDataset;
private ArrayList<Integer> mDatamap;
private Context context;
// Provide a reference to the views for each data item
// Complex data items may need more than one view per item, and
// you provide access to all the views for a data item in a view holder
public class ViewHolder extends RecyclerView.ViewHolder {
// each data item is just a string in this case
public TextView txtHeader;
public TextView txtFooter;
public ImageView imgImage;
public ViewHolder(View v) {
super(v);
txtHeader = (TextView) v.findViewById(R.id.firstLine);
txtFooter = (TextView) v.findViewById(R.id.secondLine);
imgImage = (ImageView) v.findViewById(R.id.icon);
}
}
public void add(int position, String item) {
mDataset.add(position, item);
notifyItemInserted(position);
}
public void remove(String item) {
int position = mDataset.indexOf(item);
mDataset.remove(position);
notifyItemRemoved(position);
}
// Provide a suitable constructor (depends on the kind of dataset)
public MyAdapter(ArrayList<String> myDataset, ArrayList<Integer> myDatamap) {mDataset = myDataset;myDatamap=mDatamap; }
// Create new views (invoked by the layout manager)
#Override
public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
// create a new view
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.sub_layout, parent, false);
context = v.getContext();
// set the view's size, margins, paddings and layout parameters
ViewHolder vh = new ViewHolder(v);
return vh;
}
// Replace the contents of a view (invoked by the layout manager)
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
// - get element from your dataset at this position
// - replace the contents of the view with that element
final String name = mDataset.get(position);
Picasso.with(context).load("http://www.500kgiveaway.co.uk/" + name).resize(200,200).into(holder.imgImage);
// holder.txtHeader.setText(mDataset.get(position));
holder.txtHeader.setText(name);
holder.txtHeader.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
remove(name);
}
});
holder.txtFooter.setText("Footer: " + mDataset.get(position));
}
// Return the size of your dataset (invoked by the layout manager)
#Override
public int getItemCount() {
return mDataset.size();
}
}
ive not had much interest in this post but here is the answer
i hope this help someone else
What i have done is implemented a custom view adaptor to manage the item types
import android.content.Context;
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 com.squareup.picasso.Picasso;
import java.util.ArrayList;
public class ElementsAdapter extends RecyclerView.Adapter<ElementsAdapter.ViewHolder> {
private ArrayList<String> mDataset;
private ArrayList<Integer> mDatamap;
public Context context;
private static final int VIEW_HEADER = 0;
private static final int VIEW_NORMAL = 1;
private View headerView;
private int datasetSize;
public class ViewHolder extends RecyclerView.ViewHolder {
// each data item is just a string in this case
public TextView txtHeader;
public TextView txtFooter;
public ImageView imgImage;
//header
public TextView headertext;
public ViewHolder(View v, int viewType) {
super(v);
switch (viewType){
case 1:
txtHeader = (TextView) v.findViewById(R.id.firstLine);
txtFooter = (TextView) v.findViewById(R.id.secondLine);
imgImage = (ImageView) v.findViewById(R.id.icon);
case 0:
headertext = (TextView) v.findViewById(R.id.headertext);
}
}
}
public ElementsAdapter(ArrayList<String> myDataset, ArrayList<Integer> myDatamap) {
mDataset = myDataset;
mDatamap = myDatamap;
}
#Override
public int getItemViewType(int position) {
return isHeader(position) == 1 ? VIEW_HEADER : VIEW_NORMAL;
}
#Override
public int getItemCount() {
return mDataset.size();
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == VIEW_HEADER) {
// create a new view
View sub_view = LayoutInflater.from(parent.getContext()).inflate(R.layout.header, parent, false);
Context context = sub_view.getContext();
// set the view's size, margins, paddings and layout parameters
ViewHolder vh = new ViewHolder(sub_view,viewType);
return vh;
// return new HeaderViewHolder(headerView);
} else {
// create a new view
View sub_view = LayoutInflater.from(parent.getContext()).inflate(R.layout.sub_layout, parent, false);
context = sub_view.getContext();
// set the view's size, margins, paddings and layout parameters
ViewHolder vh = new ViewHolder(sub_view, viewType);
return vh;
}
}
#Override
public void onBindViewHolder(ViewHolder viewHolder, int position) {
if (isHeader(position) == 1) {
// - get element from your dataset at this position
// - replace the contents of the view with that element
final String name = mDataset.get(position);
// holder.txtHeader.setText(mDataset.get(position));
viewHolder.headertext.setText(name);
} else {
// - get element from your dataset at this position
// - replace the contents of the view with that element
final String name = mDataset.get(position);
Picasso.with(context).load("http://www.500kgiveaway.co.uk/"+name).resize(200,200).into(viewHolder.imgImage);
// holder.txtHeader.setText(mDataset.get(position));
viewHolder.txtHeader.setText(name);
viewHolder.txtHeader.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick (View v){
//remove(name);
}
}
);
viewHolder.txtFooter.setText("Footer: "+mDataset.get(position));
}
//ViewHolder holder = (ViewHolder) viewHolder;
//holder.textView.setText("Position " + (position - 1));
}
public int isHeader(int position) {
return mDatamap.get(position) ==1 ? 1:0;}
}
Why don't you use both solutions? If you set the span size you can easily set a textview or whatever you want the header to be.
gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
#Override
public int getSpanSize(int position) {
return adapter.isHeader(position) ? gridLayoutManager.getSpanCount() : 1;
}
});
Then in the adapter have a general class Item that says if the item is a header and has some information about the real item that should be shown, in my case since I have image paths for showing images and titles for headers I just use a attribute text but you can use something like int realPositionInTheirLists since headers titles and images paths are in two separate lists:
private static class Item {
public boolean isHeader;
public String text;
public Item(String text, boolean isHeader) {
this.isHeader = isHeader;
this.text = text;
}
}
Then you have something like this on the methods that tell which type of item it is:
#Override
public int getItemViewType(int position) {
return mItems.get(position).isHeader ? VIEW_TYPE_HEADER : VIEW_TYPE_CONTENT;
}
public boolean isHeader(int position) {
return mItems.get(position).isHeader;
}
Then finally on the two methods that inflate the view and bind the data you inflate the view that you want depending on whether it is a header or not and bind the data using the Item class:
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view;
if (viewType == VIEW_TYPE_HEADER) {
view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.grid_header, parent, false);
} else {
view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.grid_item, parent, false);
}
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
final Item item = mItems.get(position);
holder.bindItem(item, position);
}
Being the holder.bindItem a method of the ViewHolder class. There you can choose however you want to separate both views.

How do you use an OnClickListener in a recycler view? [duplicate]

This question already has answers here:
RecyclerView onClick
(49 answers)
Closed 7 years ago.
What i'm basically trying to do is make the objects that show up in the recycler view clickable to a certain TextView id because i'm making a program that shows an album cover and its title next to it in a list. I need to be able to click on each one of the boxes that the recycler view makes and have a TextView pop up with the other information (author, published date, hit songs, etc) when its clicked on and then a back button (if possible) to go back to the album list. I've been looking at this for hours and cant figure out how to make an OnclickListener work for it. If you know how or have any suggestions id be glad to hear them. Thank you!
package com.albumlist.albumlist;
import android.content.Context;
import android.content.Intent;
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 android.widget.Toast;
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
private AlbumData[] itemsData;
public MyAdapter(AlbumData[] itemsData){
this.itemsData = itemsData;
}
public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private TextView txtViewTitle;
private ImageView imgViewIcon;
public ViewHolder(View itemLayoutView) {
super(itemLayoutView);
itemLayoutView.setOnClickListener(this);
txtViewTitle = (TextView) itemLayoutView.findViewById(R.id.album_title);
imgViewIcon = (ImageView) itemLayoutView.findViewById(R.id.album_icon);
}
#Override
public void onClick(View v) {
}
}
#Override
public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,int viewType) {
View itemLayoutView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.data_layout, null);
ViewHolder viewHolder = new ViewHolder(itemLayoutView);
return viewHolder;
}
#Override
public void onBindViewHolder(ViewHolder viewHolder, int position) {
viewHolder.txtViewTitle.setText(itemsData[position].getTitle());
viewHolder.imgViewIcon.setImageResource(itemsData[position].getImageUrl());
}
#Override
public int getItemCount() {
return itemsData.length;
}
}
The concept is well summed up by Xaver Kapeller in the comments. If you are looking for a simple way to manage your RecyclerView interaction similar to the traditional interactions of a ListView, check out BigNerdRanch's recyclerview-multiselect library on GitHub. They have a sample app that you can explore, which implements series of OnClickListeners and OnLongClickListeners with added capabilities of multi-selection.
Here's a snippet of how BigNerdRanch implements listeners in a Fragment across an Adapter and a ViewHolder, which in this case is actually an extension of the library's own SwappingHolder.
public CrimeHolder(View itemView) {
super(itemView, mMultiSelector);
mTitleTextView = (TextView) itemView.findViewById(R.id.crime_list_item_titleTextView);
mDateTextView = (TextView) itemView.findViewById(R.id.crime_list_item_dateTextView);
mSolvedCheckBox = (CheckBox) itemView.findViewById(R.id.crime_list_item_solvedCheckBox);
itemView.setOnClickListener(this);
itemView.setLongClickable(true);
itemView.setOnLongClickListener(this);
}
public void bindCrime(Crime crime) {
mCrime = crime;
mTitleTextView.setText(crime.getTitle());
mDateTextView.setText(crime.getDate().toString());
mSolvedCheckBox.setChecked(crime.isSolved());
}
#Override
public void onClick(View v) {
if (mCrime == null) {
return;
}
if (!mMultiSelector.tapSelection(this)) {
selectCrime(mCrime);
}
}
#Override
public boolean onLongClick(View v) {
((AppCompatActivity) getActivity()).startSupportActionMode(mDeleteMode);
mMultiSelector.setSelected(this, true);
return true;
}
}
private class CrimeAdapter extends RecyclerView.Adapter<CrimeHolder> {
#Override
public CrimeHolder onCreateViewHolder(ViewGroup parent, int pos) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.list_item_crime, parent, false);
return new CrimeHolder(view);
}
#Override
public void onBindViewHolder(CrimeHolder holder, int pos) {
Crime crime = mCrimes.get(pos);
holder.bindCrime(crime);
Log.d(TAG, "binding crime" + crime + "at position" + pos);
}
#Override
public int getItemCount() {
return mCrimes.size();
}
}

Categories

Resources