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.
Related
I want to add a popup menu when I click on the dots inside a RecyclerView row, this menu will show many options include (delete, update and more) and want to do the logic of this popup menu outside the adapter activity not inside it.
How can I do it?
here is my Adapter Code
public class JobAdapter extends RecyclerView.Adapter<JobAdapter.ViewHolder> {
private List<JobModel> mData;
private LayoutInflater mInflater;
private JobAdapter.ItemClickListener mClickListener;
// data is passed into the constructor
public JobAdapter(Context context, List<JobModel> mData) {
this.mInflater = LayoutInflater.from(context);
this.mData = mData;
}
// inflates the row layout from xml when needed
#NonNull
#Override
public JobAdapter.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = mInflater.inflate(R.layout.job_item, parent, false);
return new JobAdapter.ViewHolder(view);
}
// binds the data to the TextView in each row
#Override
public void onBindViewHolder(final JobAdapter.ViewHolder holder, final int position) {
holder.Name.setText(mData.get(position).getName());
holder.HeadLine.setText(mData.get(position).getHeadLine());
holder.Time.setText(mData.get(position).getTime());
}
// total number of rows
#Override
public int getItemCount() {
return mData.size();
}
// stores and recycles views as they are scrolled off screen
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener {
TextView Name;
TextView HeadLine;
TextView Time;
View MyJobOptions;
ViewHolder(View itemView) {
super(itemView);
Name = itemView.findViewById(R.id.employer_name);
HeadLine = itemView.findViewById(R.id.head_line);
Time = itemView.findViewById(R.id.date_of_job);
MyJobOptions = itemView.findViewById(R.id.textViewOptions);
// these are used when the click on the whole view not on item inside view
itemView.setOnClickListener(this);
itemView.setOnLongClickListener(this);
MyJobOptions.setOnClickListener(this); // new
}
#Override
public void onClick(View view) {
if (mClickListener != null) {
mClickListener.onItemClick(view, getAdapterPosition());
// mClickListener.onMyJobOptionsClick(view, getAdapterPosition()); // new
}
}
#Override
public boolean onLongClick(View view) {
if (mClickListener != null) mClickListener.onItemLongClick(view, getAdapterPosition());
return true;
}
}
// convenience method for getting data at click position
JobModel getItem(int id) {
return mData.get(id);
}
// allows clicks events to be caught
void setClickListener(JobAdapter.ItemClickListener itemClickListener) {
this.mClickListener = itemClickListener;
}
// parent activity will implement this method to respond to click events
public interface ItemClickListener {
void onItemClick(View view, int position);
void onItemLongClick(View view, int position);
// void onMyJobOptionsClick(View view, int position); //new
}
}
Thank you in Advance
Inside the class viewholder you have a view, you can access the elements of the item with the itemView. it would be something like this:
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener {
YourInterface interface;
TextView Name;
TextView HeadLine;
TextView Time;
View MyJobOptions;
ViewHolder(View itemView) {
super(itemView);
Name = itemView.findViewById(R.id.employer_name);
HeadLine = itemView.findViewById(R.id.head_line);
Time = itemView.findViewById(R.id.date_of_job);
MyJobOptions = itemView.findViewById(R.id.textViewOptions);
// these are used when the click on the whole view not on item inside view
itemView.setOnClickListener(this);
itemView.setOnLongClickListener(this);
MyJobOptions.setOnClickListener(this);
itemView.findViewById(R.id.TheITEMTHATYOUWANTOCLICK).setOnClickListener{
interface.yourMethod()
}
}
In Activity
class YourActivity implements YourInterface{
override void yourMethod(){
//the logic of what you want to be done
}
}
In Interface
public interface YourInterface{
void yourMethod()
}
Let me know if it works for you!
I Have a ListView in a Fragment, in my ListView's Item, i have a Button How can i call another Fragment a custom DialogFragment from clicking on the button and keep the item information?
you can Use interface ,
Create an Interface in Adapter class , then set it from owner fragment and when user click on Button call interface Method
Adapter class :
public class TestAdapter extends RecyclerView.Adapter<TestAdapter.ViewHolder> {
private ArrayList<AddressModel> dataset;
private WeakReference<Activity> activity;
private onChecked listener;
public TestAdapter(Activity activity, ArrayList<AddressModel> datasett) {
this.dataset = datasett;
this.activity = new WeakReference<Activity>(activity);
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View rootView = LayoutInflater.from(activity.get()).inflate(R.layout.item_popup_change_address_step_two, null);
TextView tv = (TextView) rootView.findViewById(R.id.title_itemPopUp_ChangeAddress_TV);
tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);
tv.setBackground(ContextCompat.getDrawable(parent.getContext(), R.drawable.edittext_style));
RecyclerView.LayoutParams lp = new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
rootView.setLayoutParams(lp);
return new ViewHolder(rootView);
}
#Override
public void onBindViewHolder(ViewHolder holder, final int position) {
holder.title.get().setText(dataset.get(position).getTitle());
holder.rootView.get().setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (listener != null) //call interface
listener.chekedListener(dataset.get(position));
}
});
}
#Override
public int getItemCount() {
if (dataset == null)
return 0;
return dataset.size();
}
public void setListener(onChecked listener) {
this.listener = listener;
}
public interface onChecked {
void chekedListener(AddressModel addressClass_serialized);
}
public class ViewHolder extends RecyclerView.ViewHolder {
private WeakReference<TextView> title;
private WeakReference<LinearLayout> rootView;
public ViewHolder(View itemView) {
super(itemView);
title = new WeakReference<TextView>((TextView) itemView.findViewById(R.id.title_itemPopUp_ChangeAddress_TV));
rootView = new WeakReference<LinearLayout>((LinearLayout) itemView.findViewById(R.id.rootCardView_addressItemPopUP_cd));
}
}
}
in fragment :
adapter.setListener(new TestAdapter.onChecked() {
#Override
public void chekedListener(AddressModel addressClass_serialized) {
//Call Dialog Here
}
});
Logic/Steps
Set the Click Listener in List Items.
Step 1:- Make Constructor in DialogFragment/CustomDialog to pass the Information from OnClick of ListItem.
Step 2:- Do whatevet u want in Dialog Class.
Everything works well and my onClick in my recyclerView is working in getting the positions of my items, but what my design calls for is to be able to click an item of the recyclerView and open up a new activity (as a popover or pop up). I can achieve this but my problems comes with the information I need to display on the popover. The information comes like this inside the activity (inside a Firebase value call)
attributeList.removeAll(attributeList);
for (DataSnapshot child : dataSnapshot.child("Attribute").getChildren()){
Attribute attribute = child.getValue(Attribute.class);
attribute_list newAttributeList = new attribute_list( attribute.Name + ": " + attribute.Value);
attributeList.add(newAttributeList);
}
attributeAdapter = new attribute_list_adapter(attributeList, getContext());
recyclerAttribute.setAdapter(attributeAdapter);
This works perfectly for displaying the information, but there's more then just a "value" and a "name" associated with the click.
Basically when I select an item, I need to get the position of the item clicked (which I have) and compare it to the position inside attributeList so I can call a Firebase call (or pass the data somehow) to the popover to display values from the "Attribute" class (such as Name, Value, Description, and another list (recyclerView).
My recyclerView:
public class attribute_list_adapter extends RecyclerView.Adapter<attribute_list_adapter.ViewHolder> {
private List<attribute_list> listItems;
private Context context;
public attribute_list_adapter(List<attribute_list> listItems, Context context) {
this.listItems = listItems;
this.context = context;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.attribute_list, parent, false);
return new ViewHolder(v);
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
attribute_list listItem = listItems.get(position);
holder.txtTitle.setText(listItem.getTxtTitle());
}
#Override
public int getItemCount() {
return listItems.size();
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public TextView txtTitle;
public ViewHolder(View itemView) {
super(itemView);
itemView.setOnClickListener(this);
txtTitle = (TextView) itemView.findViewById(R.id.txtTitle);
}
#Override
public void onClick(View v) {
}
}
}
This is example:
public class attribute_list_adapter extends RecyclerView.Adapter<attribute_list_adapter.ViewHolder> {
private List<attribute_list> listItems;
private Context context;
public attribute_list_adapter(List<attribute_list> listItems, Context context) {
this.listItems = listItems;
this.context = context;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.attribute_list, parent, false);
return new ViewHolder(v);
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.itemView.setOnClickListener(new View.onClickListener() {
#Override
public void onClick(View v) {
onItemClickListener.onItemClick(position);
}
});
}
#Override
public int getItemCount() {
return listItems.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView txtberita;
ImageView imgberita;
TextView txtnama;
public ViewHolder(View itemView) {
super(itemView);
txtnama = (TextView) itemView.findViewById(R.id.txtnama);
txtberita = (TextView) itemView.findViewById(R.id.txtberita);
imgberita = (ImageView) itemView.findViewById(R.id.imgberita);
}
}
public void setOnItemClickListener(OnItemClickListener onItemClickListener){
this.onItemClickListener = onItemClickListener;
}
OnItemClickListener onItemClickListener;
public interface OnItemClickListener{
void onItemClick(int position);
}
}
your Activity. in Oncreate()
public class TestActivity extends AppCompatActivity implements attribute_list_adapter.OnItemClickListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
attribute_list_adapter adapter = new attribute_list_adapter(listItems, this);
adapter.setOnItemClickListener(this);
}
#Override
public void onItemClick(int position) {
// code here
}
}
Create an interface something like
public interface OnSingleItemClickListener{
void onSingleItemClick(int position);
}
Then implement it on your ViewHolder like this
public class ViewHolder extends RecyclerView.ViewHolder implements OnSingleItemClickListener {
public ViewHolder(View itemView) {
super(itemView);
}
#Override
void onSingleItemClick(int position){
if(listItems.get(position) == listItems.get(getAdapterPosition)){
// TODO do something here
}
}
now on your OnBindViewHolder inside your adapter you must do this.
holder.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View view) {
holder.onSingleItemClick(position);
}
}):
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()
I've been trying to follow the following guide to implement an onClickListener on a RecyclerView
http://blog.lovelyhq.com/creating-lists-with-recyclerview-in-android-part-2/
However, I can't seem to get any context to call setOnClickListener or getPosition.
Here is my code (errors have comments next to them):
public class CategoryDataAdapter extends RecyclerView.Adapter<CategoryDataAdapter.DataViewHolder> implements View.OnClickListener
{
private List<CategoryData.Category> dataList;
private static Context con;
private ClickListener clickListener;
public CategoryDataAdapter(Context context, List<CategoryData.Category> list)
{
this.dataList = list;
con = context;
}
#Override
public int getItemCount()
{
return dataList.size();
}
#Override
public void onBindViewHolder(DataViewHolder dataViewHolder, int i)
{
CategoryData.Category item = dataList.get(i);
Picasso.with(con).load(item.getImage()).into(dataViewHolder.categoryImage);
dataViewHolder.categoryText.setText(item.getName());
}
#Override
public DataViewHolder onCreateViewHolder(ViewGroup viewGroup, int i)
{
View itemView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.tile_category, viewGroup, false);
DataViewHolder dvh = new DataViewHolder(itemView);
return dvh;
}
public static class DataViewHolder extends RecyclerView.ViewHolder
{
protected ImageView categoryImage;
protected TextView categoryText;
public DataViewHolder(View v)
{
super(v);
categoryImage = (ImageView) v.findViewById(R.id.categoryImage);
categoryText = (TextView) v.findViewById(R.id.categoryName);
v.setOnClickListener(this); // here, can't put in 'this'
}
}
public interface ClickListener
{
/**
* Called when the view is clicked.
*
* #param v view that is clicked
* #param position of the clicked item
* #param isLongClick true if long click, false otherwise
*/
public void onClick(View v, int position, boolean isLongClick);
}
public void setClickListener(ClickListener clickListener)
{
this.clickListener = clickListener;
}
#Override
public void onClick(View v)
{
clickListener.onClick(v, getPosition(), false); // here, get position
}
}
What can I do to fix this? I only need a click listener for the entire view, not one particular item (already implemented that)
Instead of making RecyclerView.Adapter implement View.OnClickListener, make DataViewHolder implement that. then also save the rootview at your DataViewHolder variable (like ImageView and TextView) and at onBindViewHolder use something like below:
dataViewHolder.rootView.setOnClickListener(dataViewHolder);
Add interface for detect click listener in recyclerAdapter
public class DeviceAdapter extends ArrayAdapter<Blablah>{
private OnClickItemListener listener;
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
................
holder.button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(listener != null){
listener.click(int position)
}
}
});
.............
return convertView;
}
public interface OnClickItemListener {
public void click(int position);
}
public void setOnClickItemListener(OnClickItemListener listener) {
this.listener = listener;
}
}
And set adapter Listener to your fragment/activity
adapterRecycler.setOnsetOnClickItemListener(new ....{
});