Fragment replacing in RecyclerView item
19,102
Solution 1
I finnaly found solution. The problem is I set a common container id. But in recycler view need to set unique container id for each item.
So, my code now this:
MyFragment fragment = MyFragment.newInstance("fragment1");
fragmentManager.beginTransaction().replace(UNIQUE_CONTAINER_ID, fragment).commit();
If someone will be useful, here is my complete code (implementation fragment in recycler view):
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position)
{
...
// Delete old fragment
int containerId = holder.mediaContainer.getId();// Get container id
Fragment oldFragment = fragmentManager.findFragmentById(containerId);
if(oldFragment != null) {
fragmentManager.beginTransaction().remove(oldFragment).commit();
}
int newContainerId = View.generateViewId();// Generate unique container id
holder.mediaContainer.setId(newContainerId);// Set container id
// Add new fragment
MyFragment fragment = MyFragment.newInstance("fragment1");
fragmentManager.beginTransaction().replace(newContainerId, fragment).commit();
...
}
Upd.: Instead of using your own method to generate a unique id, it is recommended to use View.generateViewId()
Solution 2
Thanks to Mikhali, I'm able to provide to you a complete running example. Pay special attention on the comments in onBindViewHolder()
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewLedgerAdapter.ViewHolder>{
private final String TAG = RecyclerViewAdapter.class.getSimpleName();
private final float FINAL_OPACITY = 0.3f;
private final float START_OPACITY = 1f;
private final int ANIMATION_TIME = 500;
private final int TYPE_ITEM = 0;
private final int TYPE_DATE = 1;
private final int TYPE_TRANSACTION = 2;
private final int TYPE_PENDING = 3;
private HashMap<Integer, Integer> mElementTypes;
private List<Operation> mObjects;
private Context mContext;
private Utils.CURRENCIES mCurrencySelected; // Which currency is already selected
private boolean mCurrencyFilter; // Defines if a currency is already selected to apply filter
private Animation mAnimationUp;
private Animation mAnimationDown;
public RecyclerViewLedgerAdapter(List<Operation> objects, Context context) {
mElementTypes = new HashMap<Integer, Integer>();
mObjects = objects;
mContext = context;
mCurrencyFilter = false;
mCurrencySelected = null;
mAnimationUp = AnimationUtils.loadAnimation(context, R.anim.slide_up);
mAnimationDown = AnimationUtils.loadAnimation(context, R.anim.slide_down);
}
...
...
Not needed methods
...
...
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.rv_element_ledger, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
Operation operation = mObjects.get(position);
holder.setAppUserActivity(userActivityOperation);
// Remember that RecyclerView does not have onClickListener, you should implement it
holder.getView().setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// Hide details
// iDetailsContainer object could be checked on inner class ViewHolder
if(holder.iDetailsContainer.isShown()){
holder.iDetailsContainer.setVisibility(View.GONE);
}else{
// Show details
// Get fragment manager inside our fragment
FragmentManager fragmentManager = ((UserActivity)mContext).getSupportFragmentManager();
// Delete previous added fragment
int currentContainerId = holder.iDetailsContainer.getId();
// Get the current fragment
Fragment oldFragment = fragmentManager.findFragmentById(currentContainerId);
if(oldFragment != null) {
// Delete fragmet from ui, do not forget commit() otherwise no action
// is going to be observed
ragmentManager.beginTransaction().remove(oldFragment).commit();
}
// In order to be able of replacing a fragment on a recycler view
// the target container should always have a different id ALWAYS
int newContainerId = getUniqueId();
// Set the new Id to our know fragment container
holder.iDetailsContainer.setId(newContainerId);
// Just for Testing we are going to create a new fragment according
// if the view position is pair one fragment type is created, if not
// a different one is used
Fragment f;
if(position%2 == 0) {
f = new FragmentCard();
}else{
f=new FragmentChat();
}
// Then just replace the recycler view fragment as usually
manager.beginTransaction().replace(newContainerId, f).commit();
// Once all fragment replacement is done we can show the hidden container
holder.iDetailsContainer.setVisibility(View.VISIBLE);
}
}
// Method that could us an unique id
public int getUniqueId(){
return (int)SystemClock.currentThreadTimeMillis();
}
});
}
public class ViewHolder extends RecyclerView.ViewHolder{
private View iView;
private LinearLayout iContainer;
public LinearLayout iDetailsContainer;
private ImageView iOperationIcon;
private ImageView iOperationActionImage;
private TextView iOperation;
private TextView iAmount;
private TextView iTimestamp;
private TextView iStatus;
private UserActivityOperation mUserActivityOperation;
public ViewHolder(View itemView) {
super(itemView);
iView = itemView;
iContainer = (LinearLayout) iView.findViewById(R.id.operation_container);
iDetailsContainer = (LinearLayout) iView.findViewById(R.id.details_container);
iOperationIcon = (ImageView) iView.findViewById(R.id.ledgerOperationIcon);
iOperationActionImage = (ImageView) iView.findViewById(R.id.ledgerAction);
iOperation = (TextView) iView.findViewById(R.id.ledgerOperationDescription);
iAmount = (TextView) iView.findViewById(R.id.ledgerOperationCurrencyAmount);
iTimestamp = (TextView) iView.findViewById(R.id.ledgerOperationTimestamp);
iStatus = (TextView) iView.findViewById(R.id.ledgerOperationStatus);
// This linear layout status is GONE in order to avoid the view to use space
// even when it is not seen, when any element selected the Adapter will manage the
// behavior for showing the layout - container
iDetailsContainer.setVisibility(View.GONE);
}
...
...
Not needed methods
...
...
}
}
Layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/operation_container_maximum"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="11dp"
android:layout_marginLeft="30dp"
android:layout_marginRight="30dp"
android:layout_marginTop="11dp"
android:orientation="vertical">
<LinearLayout
android:id="@+id/operation_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="14dp">
<ImageView
android:id="@+id/ledgerOperationIcon"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:src="@drawable/fondear" />
<ImageView
android:id="@+id/ledgerAction"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|right"
android:src="@drawable/operation_trade" />
</FrameLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical"
android:weightSum="2">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:orientation="horizontal">
<TextView
android:id="@+id/ledgerOperationDescription"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Descripcion"
android:textColor="@color/ledger_desc" />
<TextView
android:id="@+id/ledgerOperationCurrencyAmount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="2dp"
android:text="5000 BTC" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:orientation="horizontal">
<TextView
android:id="@+id/ledgerOperationTimestamp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Fecha/Hora"
android:textColor="@color/ledger_timestamp" />
<TextView
android:id="@+id/ledgerOperationStatus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Status" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/details_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="Something hidden" />
<ImageView
android:layout_marginTop="15dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/user_btc"
android:layout_gravity="center_horizontal"/>
</LinearLayout>
</LinearLayout>
Fragment
// This is one of the fragments used in the RecyclerViewAdapterCode, and also makes a HTTPRequest to fill the
// view dynamically, you could laso use any of your fragments.
public class FragmentCard extends Fragment {
TextView mTextView;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_card, container, false);
mTextView = (TextView) view.findViewById(R.id.tv_fragment_two);
new UserActivityAsyncTask().execute();
return view;
}
private UserActivityOperation[] asyncMethodGetPendingWithdrawals(){
BitsoWithdrawal[] userWithdrawals = HttpHandler.getUserWithdrawals(getActivity());
int totalWithDrawals = userWithdrawals.length;
UserActivityOperation[] appUserActivities = new UserActivityOperation[totalWithDrawals];
for(int i=0; i<totalWithDrawals; i++){
appUserActivities[i] = new UserActivityOperation(userWithdrawals[i], getActivity());
}
return appUserActivities;
}
private class UserActivityAsyncTask extends AsyncTask<String, Void, Integer> {
@Override
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected Integer doInBackground(String... strings) {
// Precess Compound balance
UserActivityOperation[] compoundBalanceProcessed = asyncMethodGetPendingWithdrawals();
return compoundBalanceProcessed.length;
}
@Override
protected void onPostExecute(Integer result) {
super.onPostExecute(result);
mTextView.setText(result.toString());
}
}
}
Author by
Mikhail
Updated on July 16, 2022Comments
-
Mikhail almost 2 years
In my RecyclerView I need replace part of my item to my fragment. But replacing only first item in recycler view. What I am doing is wrong?
My container (in recycler view item):
... <FrameLayout android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/container" /> ...
My update code in RecyclerView adapter:
... @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { ... MyFragment fragment = MyFragment.newInstance("fragment1"); fragmentManager.beginTransaction().replace(R.id.container, fragment).commit(); ... } ...
-
AkhilGite about 7 yearsCan you please explain me what is GetUniqueID();
-
AkhilGite about 7 yearsI have replace this line int newContainerId = GetUniqueID();// My method by int newContainerId = 111 + (int)(Math.random() * 9999);
-
Mikhail about 7 years@AkhilGite Yes, it will work. You can also use timestamp (to ensure that the Id will not be repeated).
-
AkhilGite about 7 yearsBut still m getting error. Its not working as expected.
-
Maher Nabil about 7 yearsman, you saved me. I've been searching for a solution for 3 days. thanks.
-
Damia Fuentes almost 7 yearsHow can you put and if inside onBindViewHolder?!!! Then things start going slow...
-
nimi0112 over 6 yearsHey! thanks for your amazing solution. I am able to do what I wanted but just facing 1 problem i.e I am getting 'Resources$NotFoundException' only on the last item in Recycler view note that it is coming on the last one. I have tried increasing and decreasing the number of items in rc view but the result is the same. Can you help me out please. ?
-
vicco over 6 years@nimi0112 In order to help you I need to know when you are getting this exception. I think there could be more than one place where you can get it. 1. Maybe you are not inflating correctly the view, so the layout element are not found. 2. Maybe the resource you are trying to set or find is not found so please just check if you resource is available. In order to help you please submit your stack trace if possible or please share where in the code the error is occurring.
-
nimi0112 over 6 yearshave a look here stackoverflow.com/questions/48202131/…
-
nimi0112 over 6 yearsHey! bro. I have made a sample app separated out of the main project can you help me out in this. Please give your email id so that I can send you the source code of sample app.
-
vicco over 6 yearsSure [email protected]
-
vicco over 6 yearsI have seen this reference stackoverflow.com/questions/48202131/… as far I can see as the new view needs to get another id, you need to create it and then assign it to the view you are creating. In the example code check this line ---- holder.iDetailsContainer.setId(newContainerId); ---- after that the error should not appear any more.
-
nimi0112 over 6 yearsThank you for your response buddy, but I already solved it a week/10 days ago.
-
vivek over 3 yearsHi @Mikhail i am not able to achieve the same thing. Its gives me view id not found after implemented in same way!
-
drmrbrewer almost 3 yearsThis is not working for me. I'm getting
No view found for id 0xd (unknown) for fragment TitleFragment
afteronBindViewHolder()
completes... note that it's forid 0xd
which is a validid
, generated byView.generateViewId()
and assigned to themediaContainer
view as per the suggested code, but for some reason it isunknown
immediately afteronBindViewHolder()
completes. -
sweet_vish over 2 yearsAfter scrolling, app gets crashes with error....No view found for id 0xd (unknown) for fragment ..........i have done same implementation