Use same Recycler Adapter for inflating different activities - android

I have the following adapter
public class CardAdapter extends RecyclerView.Adapter<CardAdapter.ViewHolder>{
List<String> list;
int id;
Context context;
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view= LayoutInflater.from(parent.getContext()).inflate(id,parent,false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
holder.textView.setText(list.get(position));
holder.textView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Handler handler=new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
Intent intent = new Intent(context, BESyllabus.class);
context.startActivity(intent);
}
},500);
}
});
}
#Override
public int getItemCount() {
return list.size();
}
public static class ViewHolder extends RecyclerView.ViewHolder{
public TextView textView;
public CardView cardView;
public ViewHolder(View v){
super(v);
textView=(TextView)v.findViewById(R.id.text);
cardView=(CardView)v.findViewById(R.id.card_view);
}
}
public CardAdapter(List<String> list, int id,Context context){
this.list=list;
this.id=id;
this.context=context;
}
}
I use the same layout file which has a recyclerView which uses the above adapter,id is the resource id for layout file which i use as rows for recycler view`
<?xml version="1.0" encoding="utf-8"?>
<TextView
android:id="#+id/text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textColor="#000000"
android:alpha="0.87"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginTop="8dp"
android:textSize="35dp" />
What i want to do is inflate multiple activities using the same row structure using the same adapter. It works fine while displaying the rows but the same onClickListener is used in every activity relaunching the same activity every time i click. Is there a way to use the same adapter where i can assign listeners based on the activity.Or should i create new adapter for every activity? I am new to android development so any help will be appreciated.Thanks in advance.

Use the interface :
public class CardAdapter extends RecyclerView.Adapter<CardAdapter.ViewHolder>{
private IOnItemClickListener mListener;
public CardAdapter(IOnItemClickListener mListener) {
this.mListener = mListener;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view= LayoutInflater.from(parent.getContext()).inflate(id,parent,false);
return new ViewHolder(v, new CardAdapter.ViewHolder.IMyViewHolderClicks() {
public void onClick(View v, int position) {
mListener.onItemClick(v, position);
};
});
}
public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public TextView textView;
public CardView cardView;
public IMyViewHolderClicks mListener;
public ViewHolder(View v, IMyViewHolderClicks listener) {
super(itemView);
mListener = listener;
textView=(TextView)v.findViewById(R.id.text);
cardView=(CardView)v.findViewById(R.id.card_view);
}
#Override
public void onClick(View v) {
mListener.onClick(v, getPosition());
}
public interface IMyViewHolderClicks {
public void onClick(View v, int position);
}
}
}
public interface IOnItemClickListener {
public void onItemClick(View v, int position);
}

You should pass an OnClickListener to the CardAdapter (on its constructor maybe) and implement it on the activity working with this Adapter.
public class ActivityX extends Activity implements View.OnClickListener {
CardAdapter adapter;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
adapter = new CardAdapter(this)
}
public void onClick(View v) {
// Handle click here
String string = (String) v.getTag();
}
}
Your Adapter may then look like this:
public class CardAdapter extends RecyclerView.Adapter<CardAdapter.ViewHolder> {
View.OnClickListener onClickListener;
public CardAdapter(View.OnClickListener onClickListener) {
this.onClickListener = onClickListener;
}
#Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
// Saving object from list at given position in View tag
holder.setTag(list.get(position));
holder.textView.setText(list.get(position));
holder.textView.setOnClickListener(onClickListener);
}
}

You can pass the listener as a constructor argument to the Adapter

In this answer there's an implementation of a onItemClickListener for a recycler view. You could move the code from your onClickListener to a diferent onItemClickListener for each diferent activity you need.

First of all, what is a reason to use handler delay in setOnClickListener? This code will lead to an NullPointerException in cases when context was destroyed before.
On the subject of the question you could pass onClickListener via constructor as in previous answers, pass only Class variable of target activity, make broadcast event. It depends on your needs. But the most appropriate in most cases i think is not make onClickListener inside adapter, setting onItemClickListener of recycler view instead (as #tinuviel answer). In this case pressed state of recycle view item will be animated automatically

Related

Handle click item in Recycleview

I have a horizontal recycleview inside vertical recycleview.
and i add list cardview inside horizontal recycleview.
How to get the item information when click on the item on main activity?
Thank you
public class MainActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private AlbumsVerticalAdapter adapter;
private List<Album> albumList;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
initCollapsingToolbar();
recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
albumList = new ArrayList<>();
adapter = new AlbumsVerticalAdapter(this, albumList);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
recyclerView.setAdapter(adapter);
}
private void initCollapsingToolbar() {}
private void prepareAlbums() {}
}
public class AlbumsVerticalAdapter extends RecyclerView.Adapter<AlbumsVerticalAdapter.MyViewHolder> {
private Context mContext;
private List<Album> albumList;
//.............
#Override
public void onBindViewHolder(final MyViewHolder holder, int position) {
Album album = albumList.get(position);
holder.title.setText(album.getName());
AlbumsHorizontalAdapter itemListDataAdapter = new AlbumsHorizontalAdapter(mContext, albumList);
holder.recycler_view_list.setHasFixedSize(true);
holder.recycler_view_list.setLayoutManager(new LinearLayoutManager(mContext, LinearLayoutManager.HORIZONTAL, false));
holder.recycler_view_list.setAdapter(itemListDataAdapter);
}
#Override
public int getItemCount() {
return albumList.size();
}
}
It would be better to implement OnClickListener on your ViewHolder class and add the listener to your desired views.
Just in onBindViewHolder(...) add setOnClickListener(...) like this:
#Override
public void onBindViewHolder(WordViewHolder holder, final int position) {
//...
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(v.getContext(), position + "", Toast.LENGTH_SHORT).show();
}
});
}
Looking at your code the VerticalRecyclerViewAdapter has a List<Albums> and each Album in this list will require a HorizontalRecyclerViewAdapter to hold another List<Albums>.
In your VerticalRecylerViewAdapter create VerticalClickListener which will be implemented by your activity. Inside HorizontalRecyclerViewAdapter create HorizontalClickListener which will be implemented by your VerticalRecyclerViewAdapter for each Album. When creating the HorizontalRecyclerViewAdapter for each Album, pass in the vertical position as well. Then, when a cardview is clicked, the HorizontalClickListener can return the vertical position of the adapter and also the horizontal position of the cardview. The VerticalRecyclerViewAdapter will return the vertical and horizontal positions to your activity.
First, you create an interface like :
public interface OnItemClickListener{
void onItemClick(View view, int position)
}
Declare on global :
private OnItemClickListener mOnItemClickListener;
Next, you need a contructor like :
public MyAdapter(Context context, List data, OnItemClickListener mOnItemClickListener){
//...
this.mOnItemClickListener= mOnItemClickListener;
}
And in onBindViewHolder
#Override
public void onBindViewHolder(final FolderViewHolder holder, final int position) {
//....
holder.image.setOnClickListener(new View.OnItemClickListener){
#Override
public void onClick(View v) {
mOnItemClickListener.onItemClick(v,position);
}
});
}
Finally, you can implement Callback in class use adapter like :
public class A extends AppCombatActivity implements MyAdapter.OnItemClickListener{
//exist code
#Override
onItemClick(View view, int position){
// Do something with view + position
}
}
/Just try to implement the below code Snippet/
First make an Interface Class "RecyclerView_ItemClickListener"
public interface RecyclerView_ItemClickListener
{
void onClick(View view, int position);
void onItemClick(View view, int position);
}
Then use this class in your Activity/Fragment and inside Adapter.
How to Implement in Adapter class:
private RecyclerView_ItemClickListener clickListener;
public void setClickListener(RecyclerView_ItemClickListener itemClickListener)
{
this.clickListener = itemClickListener;
}
public void SetOnItemClickListener(final RecyclerView_ItemClickListener mItemClickListener)
{
this.clickListener = mItemClickListener;
}
Implement implements View.OnClickListener inside MyViewHolder Method
of Adapter
Example like this: class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener
itemView.setOnClickListener(this);
Then put the below code
#Override
public void onClick(View view)
{
if (clickListener != null)
{
clickListener.onClick(view, getAdapterPosition());
clickListener.onItemClick(view,getAdapterPosition());
}
}
After that implements RecyclerView_ItemClickListener inside your
Activity/Fragment
in OnCreate:
your_Adapter.setClickListener(this);
your_Adapter.SetOnItemClickListener(this);
#Override
public void onClick(View view, int position)
{}
#Override
public void onItemClick(View view, int position)
{
}
Create an inteface
public interface OnItemClickListener{
void onItemClick(View view, int position)
}
Add a parametrized constuctor in your adapter AlbumsVerticalAdapter
private OnItemClickListener mOnviewItemClickListener;
public AlbumsVerticalAdapter(Context context, List data, OnItemClickListener mOItemClickListener){
//...
this.mOnItemClickListener= mOnItemClickListener;
Now add this line in your in OnBinderViewHolder method inside adapter class
#Override
public void onBindViewHolder(final FolderViewHolder holder, final int position) {
//....
mholder.mimageview.setOnClickListener(new View.OnItemClickListener){
#Override
public void onClick(View v) {
mOnItemClickListener.onItemClick(v,position);
}
});
}
Implement this interface in your Activity and use onClick of the item
public class MainActivity extends AppCombatActivity implements AlbumsVerticalAdapter.OnItemClickListener{
#Override
onItemClick(View view, int position){
// write your code
}
}

Update ArrayList for RecyclerView.Adapter from RecyclerView.ViewHolder?

In my MainActivity I have something like this:
recyclerAdapter = new RecyclerAdapter(this, arrayList);
recyclerView.setAdapter(recyclerAdapter);
To update my RecyclerView, I do: (in MainActivity, too)
Item item = new Item();
item.setId(id);
item.setMessage(message);
arrayList.set(position, item);
recyclerAdapter.notifyItemChanged(position);
I want to have a button within every RecyclerView list item which can enable/disable the current entry. Therefore I need to get the current toggle state.
My problem is, how can I update the RecyclerView in MainActivity from within my ViewHolder?
RecyclerView.ViewHolder:
public class SetViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{//, View.OnLongClickListener{
public ImageView toggle;
public SetViewHolder(View itemView){
super(itemView);
toggle = (ImageView) itemView.findViewById(R.id.img_main_card_toggle);
toggle.setOnClickListener(this);
}
#Override
public void onClick(View v) {
if (v.getId() == toggle.getId()) {
int clicked_position = getAdapterPosition();
//TODO update Item of RecyclerView of MainActivity
}
}
My Recycler.Adapter:
public class RulesAdapter extends RecyclerView.Adapter<SetViewHolder>{
private Activity activity;
List<Item> items = Collections.emptyList();
private OnTapListener onTapListener;
public RulesAdapter(Activity activity, List<Item> items){
this.activity = activity;
this.items = items;
}
#Override
public SetViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.rules_list_item,parent,false);
return new SetViewHolder(view);
}
#Override
public void onBindViewHolder(SetViewHolder holder, final int position) {
holder.recevied_message.setText(items.get(position).getReceived_message());
holder.reply_message.setText(items.get(position).getReply_message());
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if(onTapListener != null){
onTapListener.OnTapView(position);
}
}
});
}
#Override
public int getItemCount() {
return items.size();
}
public void setOnTapListener(OnTapListener onTapListener){
this.onTapListener = onTapListener;
}
}
Define an Interface.
public interface OnRecyclerItemToggleClickListener {
void onToggleClick(int adapterPosition);
}
Implement this in your adapter. And pass the adapter instance to the ViewHolder through a setter method in the onCreateViewHolder callback.
public class SetViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{//, View.OnLongClickListener{
public ImageView toggle;
private OnRecyclerItemToggleClickListener listener;
public SetViewHolder(View itemView){
super(itemView);
toggle = (ImageView)
itemView.findViewById(R.id.img_main_card_toggle);
toggle.setOnClickListener(this);
}
public void setRecyclerItemToggleClickListener( OnRecyclerItemToggleClickListener listener) {
this.listener = listener;
}
#Override
public void onClick(View v) {
if (v.getId() == toggle.getId()) {
int clicked_position = getAdapterPosition();
//TODO update Item of RecyclerView of MainActivity
listener.onToggleClick(clicked_position);
}
}
In your adapter:
#Override
public SetViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.rules_list_item,parent,false);
SetViewHolder holder = new SetViewHolder(view);
holder.setOnRecyclerItemToggleClickListener(this);
return holder;
}
#Override public void onToggleClick(int adapterPosition) {
// you will get the callback here when the toggle button is clicked.
// you can update the ArrayList here.
// Or similarly, call an interface method to Activity.
}
And call this onToggleClick method from ViewHolder when the toggle is clicked. You will get a callback to adapter, where you can update the ArrayList. Otherwise you can have another similar Interface to give callback to Activity from the adapter.
You just have to add a static function and make items static too:
public static ArrayList<Items> getAreayList()
{
return items;
}
And get this function in MainActivity:
onStart()

Recycle Item Click issue and never go into function

I'm new on Android material design and wanna use Recycle View instead of List View but having problem on implement OnClickListener.
I find out that RecyclerView.Adapter a bit different from ListView.Adapter.
first I impelement OnClick listener in onBindViewHolder but it returns wrong item numbers and lead to out of-bound after some removing.
#Override
public void onBindViewHolder(PersonViewHolder personViewHolder, int i) {
final int index = i ;
personViewHolder.cv.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
... items.get(index).gettext();
}
so I find out that I should implement OnClikListener in my ViewHolder class as this link.
but in this case never inter to OnClick.
public static class PersonViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
#Override
public void onClick(View v) {
Log.i("log","position="+getAdapterPosition());
}
}
public CardViewAdapter(List<MessageTO> persons) {
this.items = persons;
}
#Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
}
#Override
public PersonViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.deposite_card_view, viewGroup, false);
PersonViewHolder pvh = new PersonViewHolder(v);
return pvh;
}
#Override
public void onBindViewHolder(PersonViewHolder personViewHolder, int i) {
...
}
also I find out that I should do my Initializing item values all in onBindViewHolder is it right or not? I am very confused.
First you need to set the onclicklistener as shown below. Then it should work.
public static class PersonViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public ViewHolder(View itemView) {
super(itemView);
.
.
.
itemView.setOnClickListener(this);
}
#Override
public void onClick(View v) {
Log.i("log","position="+getAdapterPosition());
}
}
You need to call viewHolder.itemView.setOnClickListener(viewHolder) somewhere to make it work

How do I set up a specific button in the recyclerView to send back the info to the MainActivity?

I have a RecyclerView that has a button that creates a TimePickerDialog, and I need send back the time picked to the MainActivity.
How do I send it back?(Not trough clicking the entire view, just from that button/dialog)
Make your RecyclerView's adapter implement a custom interface. It's the only reasonable and adequate way.
CODE:
RecyclerViewAdapter.java:
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> {
private ButtonListener mListener;
public interface ButtonListener {
void onButtonClick(View view, String yourInfo);
}
public void setButtonListener(ButtonListener listener) {
mListener = listener;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
.....
}
#Override
public void onBindViewHolder(ViewHolder viewHolder, int i) {
.....
}
public class ViewHolder extends RecyclerView.ViewHolder {
private final Button mButton;
ViewHolder(View v) {
super(v);
mButton = (Button)v.findViewById(R.id.favouriteButton);
mButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(mListener != null)
mListener.onButtonClick(v, "Your info");
}
});
}
}
}
Activity.java:
private RecyclerViewAdapter mAdapter;
...
...
mAdapter = new RecyclerViewAdapter(yourParams...);
mAdapter.setButtonListener(new RecyclerViewAdapter.ButtonListener() {
#Override
public void onButtonClick(View view, String yourInfo) {
// Do stuff with yourInfo
}
});
Define the interface callback with the parameters that you need & that shall do it. This way you can intercept the RecyclerView items' click event and handle it in your Activity (the proper way) instead of the adapter.

Handling clicks for recyclerview's internal item

I have a recyclerview to show facebook like newsfeed with a comment button. I cant figure out how to show a dialog when user clicks on comment button. All the solutions I found here were to handle the entire item's click but not its internal view. I tried this soultion also. How to handle multiple layout clicks in recyclerView in Android
Here is my adapter class.
public class NewsfeedAdapter extends RecyclerView.Adapter<NewsfeedAdapter.NewsfeedViewHolder> {
private final LayoutInflater inflater;
private Context context;
ArrayList<NewsfeedItem> data= new ArrayList<NewsfeedItem>();
public NewsfeedAdapter(Context context,ArrayList<NewsfeedItem> data){
inflater= LayoutInflater.from(context);
this.data=data;
this.context = context;
}
#Override
public NewsfeedViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = inflater.inflate(R.layout.custom_newsfeed_row, parent, false);
NewsfeedViewHolder holder = new NewsfeedViewHolder(view);
return holder;
}
#Override
public void onBindViewHolder(NewsfeedViewHolder newsfeedViewHolder, int i) {
NewsfeedItem current = data.get(i);
newsfeedViewHolder.username.setText(current.username);
newsfeedViewHolder.icon.setImageResource(current.iconid);
newsfeedViewHolder.timestamp.setText((CharSequence) current.timestamp);
newsfeedViewHolder.news.setText(current.news);
}
#Override
public int getItemCount()
{
return data.size();
}
class NewsfeedViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView news, username, timestamp, comment_btn, like_btn;
ImageView icon;
private NewsfeedClickInterface clickListener;
public NewsfeedViewHolder(View itemView) {
super(itemView);
news = (TextView) itemView.findViewById(R.id.news);
timestamp = (TextView) itemView.findViewById(R.id.timestamp);
username = (TextView) itemView.findViewById(R.id.username);
icon = (ImageView) itemView.findViewById(R.id.profile_img);
comment_btn = (TextView) itemView.findViewById(R.id.comment_btn);
comment_btn.setTag("comment");
comment_btn.setOnClickListener(this);
}
#Override
public void onClick(View v) {
if (clickListener != null) {
clickListener.onItemClicked(getPosition(), v.getTag().toString());
}
}
}
public interface NewsfeedClickInterface {
public void onItemClicked(int position, String tag);
}
}
First define an interface in your viewholder. And when button is clicked, call this interface.
public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
public interface ViewHolderClickListener {
public void onItemClick(View caller, int position);
}
public ViewHolderClickListener mListener;
public ViewHolder(View itemView, ViewHolderClickListener listener) {
super(itemView);
mListener = listener;
//other initializations...
}
#Override
public void onClick(View v) {
mListener.onItemClick(v, getPosition());
}
}
Then create another interface in a separate file, let's say you create this interface in a class called Commons:
public class Commons {
public interface OnRecyclerItemClickedListener{
public void onRecyclerItemClicked(String parameter);
}
}
Then let your fragment/activity implement that interface. And pass this interface to your adapter's constructor as a parameter.
public class MyFragment extends Fragment implements Commons.OnRecyclerItemClickedListener{
#Override
public void onRecyclerItemClicked(String productId) {
//do whatever you want on click
}
}
Pass this interface to your adapter's constructor:
//here "this" parameter is your listener since your fragment implements
//the interface you defined
MyRecyclerViewAdapter adapter = new MyRecyclerViewAdapter(items, R.layout.yourlayout, getContext(), this);
and in your adapter, create an instance of the interface you defined in Commons class and set it in your constructor. Then create your viewholder in onCreateViewHolder method. Finally, call the interface you defined in your Commons class in your Viewholder's click interface:
public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.ViewHolder>{
private OnRecyclerItemClickedListener onRecyclerItemClickedListener;
public MyRecyclerViewAdapter(List<Item> items, int rowLayout, Context context, OnRecyclerItemClickedListener onRecyclerItemClickedListener){
this.items = items;
this.rowLayout = rowLayout;
this.mContext = context;
this.onRecyclerItemClickedListener = onRecyclerItemClickedListener;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(rowLayout, parent, false);
ViewHolder holder = new ViewHolder(v, new ViewHolder.ViewHolderClickListener() {
#Override
public void onItemClick(View caller, int position) {
onRecyclerItemClickedListener.onRecyclerItemClicked(put_parameters_if_you_want);
}});
return holder;
}
}
It is a little complicated, but here is the explanation of what you do: When button is clicked, your button click listener calls another listener(which was defined in your viewholder), and that listener calls another listener which was implemented in your fragment.
That is all you need to do.
Inside
#Override
public void onClick(View v) {
if(view.getId() == comment_btn.getId()){
Log.d("LOGTAG","Bingo !!! Your view Clicked.");
}
if (clickListener != null) {
clickListener.onItemClicked(getPosition(), v.getTag().toString());
}
}
you can check the Id's of the views and fire different click listeners according to which view was clicked.
like
comment_btn.setOnClickListener(this);
anotherButton.setOnClickListener(this);
switch (v.getId())
case R.id.comment_btn:
code goes here
case R.id.another_button:
hope this helps.

Categories

Resources