The application has a BottomNavigationView for navigating between fragments. One of the Fragments related to the BottomNavigationView has a Fragment as a child containing a RecyclerView and each RecyclerView Item has a Button attached to it.
I would need to navigate the BottomNavigationView to another Fragment with an OnClick of the Button (Highlighted with the red) inside the RecyclerView Item. I have tried different ways but I have not gotten it to work so far.
The Click is handled inside the Adapter of the RecyclerView. (The code inside the OnClickListener is just to clarify what I am trying to do.)
#Override
public void onBindViewHolder(#NonNull LocationsViewHolder holder, int position) {
...
holder.showMarkerButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
BottomNavigationView navigation = (BottomNavigationView)v.findViewById(R.id.nav_view);
navigation.setSelectedItemId(R.id.navigation_map);
}
});
}
The easiest way is created an interface implemented by your Activity
First create an interface that i called OnItemClick :
public interface OnItemClick{
void onItemClick();
}
Following on your activity implement this interface like below :
public class MainActivity extends AppCompatActivity implements OnItemClick{
/*
rest of your code
*/
#Override
public void onItemClick() {
navigation.setSelectedItemId(R.id.navigation_map);
}
}
On your Fragment you need to pass the Activity into your Adapter
YourAdapter adapter = new YourAdapter(requireActivity());
And on your adapter you need to initialize the interface like below :
OnItemClick listener;
public YourAdapter(Activity activity) {
listener= ((MainActivity) activity);
}
And finaly to call the method on your activity just call it like below
#Override
public void onBindViewHolder(#NonNull LocationsViewHolder holder, int position) {
...
holder.showMarkerButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
listener.onItemClick();
}
});
}
Related
I have a listview in my tablayout. When I click on one of these elements, I want that element to be added to a list in the mainactivity. So that I can display this list on another fragment.
You can use interface when clicked on item
Create interface like this in one fragment
public interface OnClickListener{
void onClick(Item listItem);
}
and in fragment create object like:
OnClickListener onClickListener;
and in onAttach assign the object
#Override
public void onAttach(Context context) {
super.onAttach(context);
try {
onClickListener= (onClickListener) context;
} catch (ClassCastException e) {
}
}
and then implement this listener in your MainActivity
public class MainActivity extends AppCompatActivity implements onClickListener{}
and on button click in fragment pass the data to your MainActivity
button.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
onClickListener.onClick(YOUR_ITEM);
}
});
I have a layout where I use two RecyclerViews, each with its own Adapter.
On the Activity class of the layout I have the references of the RVs and I create them there. Then I dynamically create the buttons and insert them on one of the RecyclerViews.
The current problem I'm facing is that I'm setting the onClick listener inside the adapter itself but I want to hopefully set it through the activity class.
That's because the activity class has references to all the things I need to know when an object inside the recycler view is clicked and I want them to move between the RVs when clicked. From first RV to go to second and vice versa.
To create the view inside the first adapter I use.
for (Iterator<String> it = setList.iterator();it.hasNext();)
{
String str = it.next();
Object1 o = new Object1 (str, R.drawable.testicon);
objectList.add(o);
}
firstRVAdapter.notifyDataSetChanged();
Inside my adapter I set the onclick listener inside the OnBindViewHolder as such:
#Override
public void onBindViewHolder(LeftViewHolder holder,final int position) {
holder.imageView.setImageResource(verticalLeftList.get(position).getLogo());
holder.textView.setText(verticalLeftList.get(position).getName());
holder.imageView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String productName =
verticalLeftList.get(position).getName().toString();
Toast.makeText(context, productName + " is selected",
Toast.LENGTH_SHORT).show();
}
});
}
Any recommendations or help how to change this to allow me to do what I want would be really appreciated. Either searching for a way to access the second adapter through the first one or a way to set the listener for each item inside RV from the activity class.
You can create a callback for your adapter to pass data back to your activity.
public interface AdapterCallback {
void itemClicked(int position);
}
see Juan's answer for example
Pass the Activity to the adapter in the constructor as a callback listener, and then, in the onClick() method call a callback on the activity.
(...) means there is more code not relevant to the answer.
In the RV Adapter class:
public MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder>{
Listener listener;
public MyAdapter(Listener listener, ...){
this.listener = listener;
...
}
#Override
public void onBindViewHolder(LeftViewHolder holder,final int position) {
holder.imageView.setImageResource(verticalLeftList.get(position).getLogo());
holder.textView.setText(verticalLeftList.get(position).getName());
holder.imageView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String productName =
verticalLeftList.get(position).getName().toString();
Toast.makeText(context, productName + " is selected",
Toast.LENGTH_SHORT).show();
listener.onClick(productName);
}
});
}
...
public static interface Listener{
public void onRVClick(String aParamToIdWhatWasClicked);
}
}
And make the Activity implement the Listener interface and pass its instance to the RV Adapter constructor.
public class MyActivity extends AppCompatActivity implements MyAdapter.Listener {
private MyAdapter myRvAdapter;
#Override
public void onCreate(Bundle savedInstanceState){
...
myRvAdapter = new MyAapter(this, ...);
...
}
...
#Override
public void onRVClick(String what){
System.out.println(what + " was selected");
}
...
}
Note that the parameter of the onRVClick() interface method can be whatever you want. It could even be the data list item backing the selected recycler view item.
May i know why is it showing me the error of "Cannot resolve symbol ItemClickListener"? Do i need to add library or something in order to solve this issue or i shouldn't declare it in here?
public static class FoodViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
private ItemClickListener itemClickListener;
public void setItemClickListener(ItemClickListener itemClickListener) {
this.itemClickListener = itemClickListener;
}
View view;
public FoodViewHolder (View v){
super(v);
view= v;
}
public void setName(String title){
TextView post_title = (TextView)view.findViewById(R.id.Menu_Name);
post_title.setText(title);
}
public void setImage(Context ctx, String image){
ImageView menuImage = (ImageView) view.findViewById(R.id.Menu_Image);
Picasso.with(ctx).load(image).into(menuImage);
}
#Override
public void onClick(View v) {
}
}
In General for RecyclerView we create an Interface for handling the click events. Unlike a normal Button Click, the RecyclerView Click events cannot be handled directly. As the RecyclerView is the Adapter(Data Provider to the View), You cannot directly handle the item clicks from here and update the view. For this you need an Separate Interface which is ItemClickListener in your case (Create an Interface file separately in your project). In that Interface you need to declare a method for example something like this
public Interface ItemClickListener{
void onRecyclerViewItemClicked(int position);
}
Create a OnClickListener for your View(which is present over single row. Eg: image, text, etc);#Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.myText.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
itemClickListener.onRecyclerViewItemClicked(position);
//itemClickListener is the Interface Reference Variable
}
});
}
And in your Activity you need to implement this Interface like
public class YourActivity extends AppCompatActivity implements ItemClickListener {
....
....
protected void onCreate(Bundle savedInstanceState) {
...
...
}
#Override
public void onRecyclerViewItemClicked(int position) {
//You will get the position of the Item Clicked over recycler view
//You can handle as per your requirement
}
}
Upon doing this you will listen the click event of recyclerview to the activity. Then you can handle it accordingly.
If you have further doubt follow the references:
https://stackoverflow.com/a/40584425/8331006
https://stackoverflow.com/a/28304164/8331006
you can set the click listener to any view you want you don't need to declare it as a seperate
yourView.setOnClickListener(this);
and in your onClick(View v) add the code that you want whenever you click the view you want for example :
if(v==imageView){
//write your code here
}
I've got stuck with an issue about setting an OnItemClickListener to my RecyclerView items. I tried to set a listener the way described in the RecyclerView sample of Android Studio. So a listener is set in the ViewHolder class for my RecyclerView.
public class ProgramViewHolder extends RecyclerView.ViewHolder {
protected TextView vName;
protected ImageView vProgramImage;
public ProgramViewHolder(View v) {
super(v);
vName = (TextView) v.findViewById(R.id.programName);
vProgramImage = (ImageView) v.findViewById(R.id.programImage);
v.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// HERE PROBLEM !!
MainActivity.openSettings(1);
}
});
}
}
Now I want to call a method of my MainActivity openSettings(int ) to load a fragment:
public void openSettings(int layoutId) {
settingsFragment setFrag = new settingsFragment();
Bundle information = new Bundle();
information.putInt("layoutId", layoutId);
setFrag.setArguments(information);
getFragmentManager().beginTransaction()
.replace(R.id.fragmentContainer, setFrag)
.commit();
}
But now the problem. When I try to compile, it says "Non-static method 'openSettings(int )' cannot be referenced from a static context."
I quite not understand this error. Why is it a static context? The class ProgramViewHolder ist not declared static.
And the most important part: How can I fix it? I want to set a OnClickListener to every item of RecyclerView and call a public method of MainActivity.
Thanks a lot to you, for your time spending to help me.
It's not that ProgramViewHolder is static, it's because attempting to call your activity from a static context (you aren't calling a specific instance of the activity).
What you should do is pass the activity into your recyclerViewAdapter so that you have access to it.
For example
MainActivity mainActivity;
public CustomRecyclerViewAdapter(MainActivity mainActivity) {
this.mainActivity = mainActivity;
}
And to create the recyclerViewAdapter from MainActivity
CustomRecyclerView recyclerViewAdapter = new CustomRecyclerViewAdapter(this);
recyclerViewAdapter.setAdapter(recyclerViewAdapter);
You should then be able to access your method like this
mainActivity.openSettings(1);
Let me know if you have any trouble
//Edit
Here's how you would set onClick from bindViewHolder. You want to set up any onClickListeners here due to the way RecyclerView "recycles" data. For example, if each row should perform a different action on click, you need to make sure the click listener is tied to the specific row. Creating this in onBindViewHolder ensures this. If you want an entire row to be clickable, rather than elements inside, just create an outer view that fills the entire row. Then tie the onClickListener to that.
// 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
ProgramViewHolder programViewHolder = (ProgramViewHolder) holder;
programViewHolder.vName.setOnClicklistener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mainActivity.openSettings(1);
}
});
}
if you have context of the activity containing recyclerView, then you can simply do this:
your_view_holder.v.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// HERE SOLUTION!!
((MainActivity)context).openSettings(1);
}
});
You can place this in onBindViewHolder(...)
How to get context:
Create another parameter of context in your Adapter's constructor , and pass the context from your activity once instantiating Adapter .
why pass the context:
i would recommend you to always pass context and assign it to any adapter's variable because this is something you would require every now and then while working with your adapter, so instead of using a workaround every time for context, just save it once .
i am creating two java file 1st main activity.java file 2nd fragment.java file create button on fragment.java how to click listener written on activity.java help me
fragment.java
public class fragment extends fragment{
Button btn;
// some code
btn = (Button)layout.findviewbyid(R.id.btn1);
}
}
activity.java
public class activity extends Activity
{
// how to access the click action btn here
btn.setOnclicklistner(new View.OnClickLisitner(){
public OnClick(){
}
To use the button in activity from the fragment, you have to use getActivity()
In your fragment,
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_item_select, container, false);
btn = (Button) getActivity().findViewById(R.id.btn);
}
btn is the button in activity
getActivity() in a Fragment returns the Activity the Fragment is currently associated with. (see http://developer.android.com/reference/android/app/Fragment.html#getActivity()).
You can define custom clickListener class and create it's instance in fragment and set listener instance there. Now you can write code in that class. Hope it will help you.
public class MyCustomListener implements OnClickListener{
#override
public void onClick(View v){
// you stuff
}
}
then in your fragment call this
MyCustomListener listener=new MyCustomListener();
btn.setOnClickListener(listener);
Here is my take on the issue, both in Java and Kotlin.
Java:
public final class YourActivity extends AppCompatActivity {
/***/
public final void yourMethod() {
printIn("Printing from yourMethod!")
}
}
public final class YourFragment extends Fragment {
/***/
#Override
public void onViewCreated(View v, Bundle savedInstanceState) {
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
YourActivity yourActivity = (YourActivity) getActivity();
yourActivity.yourMethod();
}
}));
}
}
Kotlin:
class YourActivity : AppCompatActivity() {
/***/
fun yourMethod() {
print("Printing from yourMethod!")
}
}
class YourFragment: Fragment() {
/***/
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
button.setOnClickListener {
val yourActivity = activity as YourActivity
yourActivity.yourMethod()
}
}
}
I hope it helps someone out there =)
If I understand your problem correctly, you want to delegate a button click inside a fragment back to its parent activity.
Keep a reference to the parent activity inside your fragment. Then set the listener to your button in your fragment like this:
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
parentActivity.doStuff();
}
};
In your parent Activity, define method doStuff():
public void doStuff() {
// handle button click event here
}