I am trying to display a Fragment Dialog when a user clicks on an item on my recycler view.
The bit I am stuck on is how to use a FragmentDialog in a class that extends RecyclerView.ViewHolder?
This is what I have so far:
public class FinalHolder extends RecyclerView.ViewHolder{
public FinalHolder(View view){
super(view);
TextView username= (TextView)view.findViewById(R.id.username);
TextView address = (TextView)view.findViewById(R.id.address);
view.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
ViewFragmentDialog viewFragmentDialog = new ViewFragmentDialog();
viewFragmentDialog.show() // THIS IS WHERE I AM HAVING TROUBLE. THE `show` METHOD EXPECTS A FRAGMENTACTIVITY
}
});
}
}
The viewFragmentDialog.show() method is where I am having some difficulty - because it is expecting Fragment Activity but I am using RecyclerView.ViewHolder
I won't use a DialogFragment in this case, if you want explicitly call it from RecyclerView.ViewHolder. The main reason is that you need access to the FragmentManager to show() your DialogFragment's subclass, and you don't. I see two possible solution. The easiest one is to use a normal AlertDialog. You need a context to access it that you can easily retrieve with itemView.getContext(), or use a Delegate (aka Listener) to communicate with the Activity/Fragment, and show the DialogFragment from there
Related
In my app I have one activity which has a RecyclerView adapter using a List of OrderItems
When a user clicks on an item, I pass the object from my RecyclerAdapter to my MainActivity to inflate a BottomSheetDialog
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
. . .
int position;
ViewHolder(#NonNull View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View v) {
. . .
adapterCallback.onOrderItemClick(orderItem);
}
}
public interface OrdersAdapterCallback {
void onOrderItemClick(OrderItem orderItem);
}
In the implemented interface callback method inside my MainActivity, I inflate the BottomSheetDialog using the object from my adapter (First time the object is passed)
MainActivity
#Override
public void onOrderItemClick(OrderItem orderItem) {
//Object passed from adapter
BottomSheetDialogFragment dialogFragment = BottomSheetOrderFragment.newInstance(orderItem);
dialogFragment.show(getSupportFragmentManager(), Constants.FRAGMENT_BOTTOMSHEET_ORDER);
}
When the BottomSheetDialog is inflated, there is a button that dismisses this current dialog, and inflates a FragmentDialog that passes that OrderItem (but after using some setters on it) object again (second time the object is passed).
Inside the BottomSheetDialog:
private BottomSheetOrderFragment(OrderItem orderItem){
this.orderItem = orderItem;
this.orderItem.setNewOrder("New order string here");
}
#OnClick(R.id.btn_edit_order)
void onEditOrderBtnClick(){
dismiss();
mainActivity.editOrder(this.orderItem);
}
So currently we have passed the OrderItem object to two different fragments inside the MainActivity. I then have to pass this object to the MainViewModel, and then to the MainRepo where the RoomDatabase class inserts that object into the local db.
This ends up having the OrderItem to be passed through 4 different classes through their constructors, and on the way a few setters are applied to that object. My question is, is this a bad practice in Android / OOP in general? Or is there a better way of doing what I'm trying to achieve?
My question is, is this a bad practice in Android / OOP in general?
Yes.
Or is there a better way of doing what I'm trying to achieve?
Probably.
What that is is hard to say since it's not fully clear what you're trying to achieve and how this code is structured.
But I would advise you check out this documentation on sharing data between fragments. With that in mind, consider keeping this OrderItem object in one place - the ViewModel - then accessing the one shared view model from each Fragment or Activity that needs to work with / on the order item.
Its not a bad practice but however a good one will be to use a shared viewmodel from which the fragments can access the data they need
This is my ImageViewHolder that I have mentioned in my adapter class
public static class ImageTypeViewHolder extends RecyclerView.ViewHolder {
TextView imageCard_Title,imageCard_Description;
public ImageView imageCardView;
public ImageTypeViewHolder(View itemView) {
super(itemView);
imageCard_Title=itemView.findViewById(R.id.imagecard_title);
imageCard_Description=itemView.findViewById(R.id.imagecard_description);
imageCardView=itemView.findViewById(R.id.imagecard_picture);
}
}
This is the segment of code written in my onBindViewHolder
((ImageTypeViewHolder) viewHolder).imageCard_Title.setText(modelObject.getImageCardTitle());
((ImageTypeViewHolder) viewHolder).imageCard_Description.setText(modelObject.getImageCardDescription());
((ImageTypeViewHolder) viewHolder).imageCardView.setImageResource(modelObject.getImageCardUrl());
I want to create an option which creates a fullscreen view of the imageview which is a part of the RecyclerView item.
This is the code segment in the activity where i'm adding the imagecard element :
chatList.add(new OustChatModel(1,
"Sample Image Card",
R.drawable.app_icon,
"sample description"));
I would like to know what do I do to add a operation that allows the imagecard view to open in a full screen view.
Thanks in advance
Create full screen image Fragment or Activity and simply use shared element transition on click to get nice animated full screen image.
It is easy to accomplish with Android SharedElementTransitions.
Please read :
SharedElementTransition Guide
In the case of a custom adapter, where you populate your activity/fragment with multiple viewholders, you can make use of an interface to pass data from a fragment to activity.
I provided a interface in the adapter class with a method defined :
public interface onImageClick
{ void onClickImageView(Drawable image);}
Define an object of this interface in this adapter class
onImageClick mObject;
and also declare it in the constructor of the adapter class :
mObject = (onImageClick) this.mCtx;
Now, setup a OnClickListener in the onBindViewHolder()
((ImageTypeViewHolder) viewHolder).imageCardView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mObject.onClickImageView(((ImageTypeViewHolder) viewHolder).imageCardView.getDrawable());
}
});
Write the interface method declared in the activity/fragment where you access Recycler view items :
#Override
public void onClickImageView(Drawable image) {
//Your operation here
}
let's say you have a listview with custom xml-objects on it in a row.
But you want to address specifically the textview, if it's press in the OnItemClickListener. What's the way - or bette - the best practise to do so? If i check in the OnItemClick method, the specifically element in the row (e.g. the textview, doesn't get recognized.
You can add onClickListener to that textView in the getView method of your adapter like this.
viewHolder.myTextView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d(TAG,"item= "+data.get(position).getTitle());
}
});
For this to work create a class which extends BaseAdapter class and implements all its method
1.Now in the getView() method of this class initialize all the required views in a single item of listview
2.After that attach onClickListener() to the desired textView.
3.After that select your custom adapter class in the listView.setAdapter() method
This should help you if it doesn't work use RecyclerView instead and do all the above task in the onCreateViewHolder() method of RecyclerView.adapter Class
if you have model class name **User** now you can get user info by using
viewHolder.tv.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
User user = data.get(pos);
user.getTitle();
Log.d(TAG,"item= "+data.get(position).getTitle());
}
});
I want to get all the value of a single item on recyclerview and pass it to a dialog. a dialog comes when I click that single item.
Create own callback. Example:
public interface OnItemClicked {
onItemClicked(Item item);
}
Your activity or fragment could implement that interface. In implementation you can show a dialog.
Next you need provide a reference of object which implement that interface first to the adapter ( can be by constructor) and then to the viewHolder ( can be by method in bindingView() method)
Then, when you pass a reference to viewHolder.
You can register views in your viewholder to listen onClickEvent. Your ViewHolder will implement OnClickListener.
Example:
public static class MyViewHolder extends ViewHolder implements OnClickListener{
OnItemClicked listener;
Item item;
public void methodWhereYouCreateView(){
view.setOnClickListener(this);
}
public void onClick(View view){
listener.onItemClicked(item);
}
}
I finally solve this with setTag() and getTag(). Thank you for your answer guys.
This is a my use case. I have an activity with a listview and a textview. The textview is the sum of all numbers on the listview, the listview has all the numbers.I have a custom adapter for this case.
On each row of the listview, I have a button. This button will change the number on this row.
what I want to do is this:
when user clicks the button, the value on each row is changed - doable.
the sum on the textview also changes accordingly.
This is a simplified example. In reality, I also have a constraint that I have a data model to represent the data on each role. I am not able to extend the data model to DataSetObserver.
any help?
You should create a listener, which listens for touch on your increment button and inside it call a method of the class extending an interface you created.
To make it easy, in your adapter you will have:
public interface OnIncrementListener{
onNumberIncremented();
}
private OnIncrementListener mListener;
//This is inside getView method of your adapter
myButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
mListener.onNumberIncremented();
}
});
Then your activity
public class MyActivity extends Activity implements OnIncrementListener {
//inside onCreate
myAdapter.setOnIncrementListener(this);
//end onCreate
#Override
public void onNumberIncremented() {
//Change value of your TextView here
}
}