change id of elements in a reusable xml layout - android

i have an xml file that contains a reusable layout that i want to be added when the user clicks a button.
inputs.xml
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:id="#+id/btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/add"
android:textColor="#color/text_color_blue"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="#+id/edittext"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="#string/amount"
android:textColor="#color/text_color_blue"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="#+id/btn"
app:layout_constraintStart_toEndOf="#+id/textview"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/textview"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:gravity=""
android:text="#string/category"
android:textColor="#color/text_color_blue"
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
This layout is loaded into a fragment budgetFragment.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.dashboard.fragments.BudgetFrag">
<LinearLayout
android:id="#+id/budget_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="17dp"
android:orientation="vertical">
</LinearLayout>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/floating"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|bottom"
android:layout_margin="10dp"
app:srcCompat="#android:drawable/ic_input_add"/>
</FrameLayout>
the elements get loaded as I need them to but only one problem, all the elements have the same id which comes from the last element loaded.
private BudgetViewModel mViewModel;
private LinearLayout layout = null;
private TextView textView;
private Button button;
private EditText editText;
private ViewGroup viewGroup;
private View viewer;
private LayoutInflater layoutInflater;
private static String TAG = "BudgetFrag :: ";
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container,
#Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.bugdet_fragment, container, false);
viewGroup = container;
return v;
}
public int findUnusedId(LinearLayout layout) {
int fID = 0;
while (layout.findViewById(++fID) != null) ;
return fID;
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mViewModel = ViewModelProviders.of(this).get(BudgetViewModel.class);
// TODO: Use the ViewModel
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
FloatingActionButton add_elements = view.findViewById(R.id.floating);
layout = view.findViewById(R.id.budget_layout);
add_elements.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
View view = getDialog(getActivity(), layout);
layout.addView(view);
}
});
}
public View getDialog(Context context, final LinearLayout layout) {
layoutInflater = LayoutInflater.from(getContext());
viewer = layoutInflater.inflate(R.layout.buget_input, viewGroup, false);
AlertDialog.Builder b = new AlertDialog.Builder(context);
b.setTitle("Select A Category");
String[] types = {"Food", "Entertainment"};
final String[] selected = {""};
b.setItems(types, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
textView = viewer.findViewById(R.id.textview);
switch (which) {
case 0:
textView.setText("Food");
break;
case 1:
textView.setText("Entertainment");
break;
}
editText = viewer.findViewById(R.id.edittext);
Log.d(TAG, "DialogInterface :: editText :: " + editText.getId());
editText.setId(findUnusedId(layout));
button = viewer.findViewById(R.id.btn);
button.setId(findUnusedId(layout));
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d(TAG, "setOnClickListener :: editText :: " + editText.getId());
if(!editText.getText().toString().trim().isEmpty()){
Toast.makeText(getContext(), "textView.getId()", Toast.LENGTH_LONG).show();
Log.d(TAG, "setOnClickListener :: "+ editText.getText().toString());
}
}
});
dialog.dismiss();
}
}).show();
return viewer;
}
the getDialog method is where the action happens.
All three elements have the same id as the last added input layout elements.
the question is how can i make each added input layout is unique to be able to get the edittext data? how do i change the ids dynamically as the elememnts are being added?
ps. the number of input layout that can be added is infinite.

This could be a tricky method to handle this problem. First create instance variable like
ArrayList<RootView> rootViews = new ArrayList(); Then we have to generate our own ID to each Root View and its corresponding child views and put it inside above rootViews list.
Look below :
LinearLayout linearLayout = findViewById(R.id.linear);
TextView textView = linearLayout.findViewById(R.id.tv);
EditText editText = linearLayout.findViewById(R.id.et);
Button button = linearLayout.findViewById(R.id.btn);
int uniqueLinearLayoutId = View.generateViewId();
int uniqueTextViewId = View.generateViewId();
int uniqueFirstEditTextId = View.generateViewId();
int uniqueBtnId = View.generateViewId();
ArrayList<Integer> childViews = new ArrayList<>();
childViews.add(uniqueTextViewId);
childViews.add(uniqueFirstEditTextId);
childViews.add(uniqueBtnId);
rootViews.add(new RootView(uniqueLinearLayoutId,childViews));
Now we have structured our view id's inside rootViews list. So, now we can identify each view as they have unique id's.

Related

After translating recyclerview, it stops to listen to touch events

Probably I am missing something here, but I am animating a recyclerview to outside of its container and when it is in the final position, the click events are not triggered, neither the scroll works...
I am using the ObjectAnimator to translate it, so I thought the clickable areas were also translated. Here is the relevant code:
The Fragment
public class SlideListFragment extends Fragment {
private Button slideButton;
private RecyclerView listToSlide;
private DummyListAdapter listAdapter;
private LinearLayout listContainer;
public static SlideListFragment newInstance() {
return new SlideListFragment();
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container,
#Nullable Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.slide_list_fragment, container, false);
slideButton = root.findViewById(R.id.slide_up_btn);
slideButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
slideUpRoomsList();
}
});
listToSlide = root.findViewById(R.id.list_to_slide);
listContainer = root.findViewById(R.id.list_container);
setupList();
return root;
}
private void setupList() {
GridLayoutManager layoutManager = new GridLayoutManager(this.getContext(), 1);
layoutManager.setReverseLayout(true);
listToSlide.setLayoutManager(layoutManager);
listAdapter = new DummyListAdapter(this.getContext());
listToSlide.setAdapter(listAdapter);
setListData(5);
}
private void setListData(int i) {
ArrayList<DummyModel> items = new ArrayList<>();
for (int j = 0; j < i; j++) {
items.add(new DummyModel(j, "TEXT" + j));
}
listAdapter.refreshItems(items);
}
private void slideUpRoomsList() {
float height = listContainer.getHeight();
ObjectAnimator showAnimation = ObjectAnimator.ofFloat(listContainer, "translationY", -height);
showAnimation.setDuration(500);
showAnimation.start();
}
}
The Fragment Layout
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/slidelist"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
android:clipToPadding="false"
tools:context=".ui.slidelist.SlideListFragment">
<android.support.constraint.Guideline
android:id="#+id/guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.8" />
<android.support.constraint.ConstraintLayout
android:layout_width="0dp"
android:layout_height="0dp"
android:background="#FF0000"
android:clipChildren="false"
android:clipToPadding="false"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/guideline">
<LinearLayout
android:id="#+id/list_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.RecyclerView
android:id="#+id/list_to_slide"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#00FF00"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</LinearLayout>
</android.support.constraint.ConstraintLayout>
<Button
android:id="#+id/slide_up_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:text="SlideUp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
The Adapter
public class DummyListAdapter extends RecyclerView.Adapter<DummyListAdapter.ViewHolder> {
private WeakReference<Context> mContext;
private ArrayList<DummyModel> data;
public DummyListAdapter(Context ctx) {
mContext = new WeakReference<>(ctx);
}
#NonNull
#Override
public DummyListAdapter.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
// create a new view
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.dummy_list_item, parent, false);
DummyListAdapter.ViewHolder vh = new DummyListAdapter.ViewHolder(v);
return vh;
}
#Override
public void onBindViewHolder(#NonNull DummyListAdapter.ViewHolder holder, int position) {
// get element from your dataset at this position
final DummyModel item = data.get(position);
// replace the contents of the view with that element
holder.labelTV.setText(item.getText());
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(mContext.get(), "Item Clicked: "+ item.getText(), Toast.LENGTH_SHORT).show();
}
});
}
#Override
public int getItemCount() {
return data != null ? data.size() : 0;
}
public void refreshItems(ArrayList<DummyModel> items) {
this.data = items;
notifyDataSetChanged();
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView labelTV;
public ViewHolder(View itemView) {
super(itemView);
this.labelTV = itemView.findViewById(R.id.label_tv);
}
}
}
The List Item Layout
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/label_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:text="TextView"
android:textSize="20sp"
android:textColor="#0000FF"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
What is happening in this case?
UPDATE
I am doing some debug and I noticed that the problem is because the end position is outside the list container. If I translate inside the container, it works properly. So my new question is: how can I translate a view outside of the container, while still having the click events triggered?
Basically, I just gave up on this approach. I changed my layout so it list has space to show up inside its container.

TextView doesn't display inside LinearLayout with RecycleView

I just started with Android and I have a problem. I have Recycler View with training list and in this view, I want to make header which will be in a static place regardless of the scrolling. However, the header or text view is not visible in the linear layout which is over the recycler view.
I have no idea how to solve my problem, anybody have any solutions or idea?
Below I present the individual elements of the code.
My recycler view:
<android.support.v7.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/training_recycler"
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
My example linear layout
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
tools:context=".TrainingFragment">
<TextView
android:id="#+id/anything"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="40sp"
android:text="#string/monia"/>
</LinearLayout>
Inside RecyclerView I have card view which looks:
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="#+id/card_view"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_margin="15dp"
card_view:cardCornerRadius="10dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<TextView
android:id="#+id/info_text"
android:layout_marginLeft="15dp"
android:layout_marginBottom="15dp"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:textSize="20sp"/>
</LinearLayout>
</android.support.v7.widget.CardView>
When I look to design window I see my textView with text but when I turn on emulator TextView wasn't display.
Thanks for any suggestions.
Edit:
TrainingMaterialFragment.java
public class TrainingMaterialFragment extends Fragment {
RecyclerView trainingRecycler;
public TrainingMaterialFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
RecyclerView trainingRecycler = (RecyclerView)inflater.inflate(
R.layout.fragment_training_material, container, false);
int userNo = 1;
String[] nameArray = new String[0];
int[] idArray= new int[0];
try {
SQLiteOpenHelper myFitnessAppDatabaseHelper = new MyFitnessAppDatabaseHelper(inflater.getContext());
View view = inflater.inflate(R.layout.fragment_training, container, false);
SQLiteDatabase db = myFitnessAppDatabaseHelper.getReadableDatabase();
Cursor cursor = db.query("TRAINING_DIARY",
new String[]{"TRAINING_NAME", "DATE",
"DISTANCE","_id"},
"USER = ?",
new String[]{Integer.toString(userNo)},
null, null, null);
int count = cursor.getCount();
nameArray = new String[count];
idArray=new int[count];
if (cursor.moveToFirst()) {
String nameText = cursor.getString(0);
TextView name = (TextView) view.findViewById(R.id.training_name);
name.setText(nameText);
nameArray[0] = nameText;
idArray[0]=cursor.getInt(3);
int i = 1;
while(i < count) {
cursor.moveToNext();
nameText = cursor.getString(0);
nameArray[i] = nameText;
idArray[i]=cursor.getInt(3);
i++;
}
}
cursor.close();
db.close();
} catch (SQLiteException e) {
Toast toast = Toast.makeText(inflater.getContext(), "Baza danych jest niedostępna", Toast.LENGTH_SHORT);
toast.show();
}
TrainingAdapter adapter =
new TrainingAdapter(nameArray);
trainingRecycler.setAdapter(adapter);
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
trainingRecycler.setLayoutManager(layoutManager);
adapter.setListener(new TrainingAdapter.Listener() {
public void onClick(int position) {
Intent intent = new Intent(getActivity(), TrainingDetailActivity.class);
intent.putExtra(TrainingDetailActivity.EXTRA_TRAINING, position);
getActivity().startActivity(intent);
}
});
return trainingRecycler;
}
}
Adapter
public class TrainingAdapter extends RecyclerView.Adapter<TrainingAdapter.ViewHolder> {
private String[] captions;
private Listener listener;
public TrainingAdapter(String[] captions){
this.captions = captions;
}
public static class ViewHolder extends RecyclerView.ViewHolder {
private CardView cardView;
public ViewHolder(CardView v) {
super(v);
cardView = v;
}
}
#Override
public TrainingAdapter.ViewHolder onCreateViewHolder(
ViewGroup parent, int viewType){
CardView cv = (CardView) LayoutInflater.from(parent.getContext())
.inflate(R.layout.training_card_view, parent, false);
return new ViewHolder(cv);
}
#Override
public void onBindViewHolder(ViewHolder holder, final int position){
CardView cardView = holder.cardView;
TextView textView = (TextView)cardView.findViewById(R.id.info_text);
textView.setText(captions[position]);
cardView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (listener != null) {
listener.onClick(position);
}
}
});
}
#Override
public int getItemCount(){
return captions.length;
}
public static interface Listener {
public void onClick(int position);
}
public void setListener(Listener listener) {
this.listener = listener;
}
}
Try this way.
As you said LinearLayout in fragment_training.xml so put recylerview inside linearlayout.
Your fragment_training.xml code become like below
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
tools:context=".TrainingFragment">
<TextView
android:id="#+id/anything"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="40sp"
android:text="#string/monia"/>
<android.support.v7.widget.RecyclerView
android:id="#+id/training_recycler"
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<LinearLayout/>
Then finally changes in java class.
Change this line
RecyclerView trainingRecycler = (RecyclerView)inflater.inflate(
R.layout.fragment_training_material, container, false);
To
View rootview = inflater.inflate(
R.layout.fragment_training, container, false);
.....
.....
return rootview;
Then you can find recylerview using rootview.
trainingRecycler = rootview.findViewById(R.id.training_recycler);
and make sure return rootview added..
Your OnCreateView method look like below
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootview = inflater.inflate(
R.layout.fragment_training, container, false);
trainingRecycler = rootview.findViewById(R.id.findViewById);
.....
...
..
return rootview;
Correct me if i am wrong but you are not putting your Recycler inside the LinearLayout.Your LinearLayout should look like this and then you will be able to get what you want:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
tools:context=".TrainingFragment">
<TextView
android:id="#+id/anything"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="40sp"
android:text="#string/monia"/>
<android.support.v7.widget.RecyclerView
android:id="#+id/training_recycler"
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<LinearLayout/>
I did this same thing in this project.
This is the link to the XML file
https://github.com/ShowYoungg/JournalApp/blob/master/app/src/main/res/layout/activity_main.xml. and the link to the java file;
https://github.com/ShowYoungg/JournalApp/blob/master/app/src/main/java/com/example/android/journalapp/MainActivity.java.
You can download the entire app and run to see that I put not just TexView but also button and others on the RecyclerView

Fragment replacing in RecyclerView item

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();
...
}
...
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()
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());
}
}
}

Dynamically adding elements to already created relativelayout

In my fragment, I want each custom item in my listview to look as follows:
Name
SetsXReps
[][][][][] ---> array of textviews
[][][][][] ---> array of checkboxes
The number of textviews and checkboxes depends upon the item in the adapter, so I need to create that part dynamically. I am having trouble adding these elements dynamically to my relativelayout that I partially define in my xml. Here is my fragment class followed by my xml for the custom list item. The id for the layout is list_item_exercise_in_workout.
public class WorkoutFragment extends Fragment
{
public static final String EXTRA_ALREADYCREATED_ID = "shake2lift.nickdelnano.com";
private ExAdapter adapter;
private ListView listView;
private ArrayList<Set> sets;
private Workout w;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
UUID workoutId = (UUID) getArguments().getSerializable(EXTRA_ALREADYCREATED_ID);
w = WorkoutMASTER.get(getActivity()).getWorkout(workoutId);
}
public View onCreateView(LayoutInflater inflater, ViewGroup parent,Bundle savedInstanceState)
{
View v = inflater.inflate(R.layout.fragment_workout, parent, false);
adapter = new ExAdapter(getActivity(), R.layout.fragment_create_workout, R.id.list, sets);
listView.setAdapter(adapter);
return v;
}
public static WorkoutFragment newInstance(UUID workoutId)
{
Bundle args = new Bundle();
args.putSerializable(EXTRA_ALREADYCREATED_ID, workoutId);
WorkoutFragment fragment = new WorkoutFragment();
fragment.setArguments(args);
return fragment;
}
private class ExAdapter extends ArrayAdapter<Set>
{
public ExAdapter(Context c, int resource, int textViewResourceId, ArrayList<Set> sets ) {
super(c, 0, sets);
}
public View getView(final int position, View convertView, ViewGroup parent)
{
//if we werent given a view, inflate one
if(convertView == null)
{
convertView = getActivity().getLayoutInflater().inflate(R.layout.list_item_exercise_in_workout, null);
}
Set s = getItem(position);
//RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(
// RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT );
TextView name = (TextView) convertView.findViewById(R.id.exName);
name.setText(s.getName());
TextView setsReps = (TextView) convertView.findViewById(R.id.setsXreps);
setsReps.setText(s.getSets() + "X" + s.getReps());
CheckBox[] checkBoxes = new CheckBox[s.getSetsInt()];
EditText[] weightBoxes = new EditText[s.getSetsInt()];
//initialize weightBoxes's text to the inputted weight
for(int i = 0; i < weightBoxes.length; i++)
{
//code to add dynamically here
}
return convertView;
}
}
}
and my XML:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/relativeLayoutEx"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="Name"
android:id="#+id/exName"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="SetsXReps"
android:id="#+id/setsXreps"
android:layout_below="#id/exName"
android:layout_alignParentLeft="true"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="New Button"
android:id="#+id/button2"
android:layout_below="#+id/setsXreps"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginTop="112dp" />
I appreciate any help or advice.
You need to first get a pointer to your RelativeLayout like this
RelativeLayout container = (RelativeLayout) view.findViewById(R.id.relativeLayoutEx);
Then in your for loop, create the Text Boxes (and Check Boxes) dynamically and add them to the layout:
TextView text = new TextView(getActivity());
text.setText("Hello");
container.addView(text);

The specified child already has a parent. You must call removeView() on the child's parent first showing error

When I run my program I get the error E/AndroidRuntime(27275): java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first. where is the problem??
My list fragment class
package com.zaa.yhgj;
public class HomeFragment extends ListFragment {
private List<ListViewItem> mItems; // ListView items list
View myFragmentView;
ArrayList<View> chart_view = new ArrayList<View>();
List<Integer> onedimen = new ArrayList<Integer>();
List<List> aa = new ArrayList<List>();
///
List<List> statuslistoflist = new ArrayList<List>();
List<String> statusonedimen = new ArrayList<String>();
private List<DialogInterface.OnClickListener> nItems;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
myFragmentView = inflater.inflate(R.layout.dashboardlist, container, false);
HashMap<String,Integer> myhash=new HashMap<String, Integer>() ;
myhash.put("Pending",0);
myhash.put("In Progress",0);
myhash.put("Limitation",0);
myhash.put("Needs Research",0);
myhash.put("In Testing",0);
myhash.put("Issue Not Clear",0);
myhash.put("Unassigned",0);
int mainclasssize = Constants.listuserprojectMain.getMainListClass().size();
int[] listsize = new int[mainclasssize];
String[] projectname = new String[mainclasssize];
int[] openissuecount = new int[mainclasssize];
for (int k = 0; k < mainclasssize; k++) {
listsize[k] = Constants.listuserprojectMain.getMainListClass().get(k).getProjectIssue().size();
projectname[k] = Constants.listuserprojectMain.getMainListClass().get(k).getName();
openissuecount[k] = Constants.listuserprojectMain.getMainListClass().get(k).getOpenIssueCount();
}
for (int w = 0; w < mainclasssize; w++) {
onedimen = new ArrayList<Integer>();
for (int x = 0; x < listsize[w]; x++) {
myhash.put(Constants.listuserprojectMain.getMainListClass().get(w).getProjectIssue().get(x).getStatus(),Constants.listuserprojectMain.getMainListClass().get(w).getProjectIssue().get(x).getIssueCount());
}
Set keys = myhash.keySet();
Iterator itr = keys.iterator();
String key;
int value;
while(itr.hasNext())
{
key = (String)itr.next();
onedimen.add((Integer)myhash.get(key));
value = (Integer)myhash.get(key);
// System.out.println(key + " - "+ value);
}
aa.add(onedimen);
statuslistoflist.add(statusonedimen);
}
for (int v = 0; v < aa.size(); v++) {
chart_view.add(openChart(aa.get(v)));
}
mItems = new ArrayList<ListViewItem>();
nItems = new ArrayList<DialogInterface.OnClickListener>();
Resources resources = getResources();
for (int f = 0; f < aa.size(); f++) {
mItems.add(new ListViewItem(projectname[f], openissuecount[f], chart_view.get(f)));
}
nItems.add(new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
}
});
// initialize and set the list adapter
setListAdapter(new ListViewDemoAdapter(getActivity(), mItems));
return myFragmentView;
}
private View openChart(List<Integer> chartvaluedd) {
return v;
}
}
my adapter class is
public class ListViewDemoAdapter extends ArrayAdapter {
public ListViewDemoAdapter(Context context, List<ListViewItem> items) {
super(context, R.layout.dashboardlistview_item, items);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder= new ViewHolder();
if(convertView == null) {
// inflate the GridView item layout
LayoutInflater inflater = LayoutInflater.from(getContext());
convertView = inflater.inflate(R.layout.dashboardlistview_item, parent, false);
// initialize the view holder
// viewHolder.ivIcon = (ImageView) convertView.findViewById(R.id.ivIcon);
viewHolder.graphView = (LinearLayout) convertView.findViewById(R.id.ll_chart);
viewHolder.tvCreateIssue = (TextView) convertView.findViewById(R.id.tvCreateissue);
viewHolder.tvDetails = (TextView) convertView.findViewById(R.id.tv_details);
viewHolder.tvIssue = (TextView) convertView.findViewById(R.id.tv_issues);
viewHolder.tvProjectTitle = (TextView) convertView.findViewById(R.id.tv_projectTitle);
viewHolder.tvOpenIssueCount = (TextView) convertView.findViewById(R.id.tv_openissues);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
// recycle the already inflated view
///error when scrolling graph
viewHolder.graphView.removeAllViews();
}
// update the item view
final ListViewItem item = getItem(position);
viewHolder.tvCreateIssue.setText("Create Issue");
viewHolder.tvProjectTitle.setText(item.title);
viewHolder.graphView.addView(item.chartview);
viewHolder.tvOpenIssueCount.setText("Open Issues "+item.openissuecount);
viewHolder.tvCreateIssue.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(getContext(), item.title, Toast.LENGTH_SHORT).show();
}
});
/////
viewHolder.tvIssue.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Toast.makeText(getContext(),"issue",Toast.LENGTH_LONG).show();
}
});
return convertView;
}
private static class ViewHolder {
// ImageView ivIcon;
LinearLayout graphView;
TextView tvCreateIssue;
TextView tvDetails;
TextView tvProjectTitle;
TextView tvOpenIssueCount;
TextView tvIssue;
}
}
my xml layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<include layout="#layout/top" />
<ListView
android:id="#android:id/list"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:scrollbars="none" >
</ListView>
</LinearLayout>
my listview item is
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:gravity="center_vertical"
android:background="#color/list_background"
android:padding="5dp"
android:id="#+id/ww"
>
<!-- the innner view - provides the white rectangle -->
<RelativeLayout android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="5dp"
android:background="#drawable/frame"
android:id="#+id/jhhh">
<!-- the icon view -->
<TextView
android:id="#+id/tv_projectTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Project name"
android:textSize="16dp"
android:textStyle="bold"
android:layout_centerHorizontal="true"
/>
<LinearLayout android:id="#+id/ll_chart"
android:orientation="vertical"
android:layout_below="#+id/tv_projectTitle"
android:layout_width="wrap_content"
android:layout_height="230dp"
android:background="#ffffff"
android:padding="5dp"
android:scaleType="fitXY" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#id/ll_chart"
android:id="#+id/tv_openissues"
android:text="Open Issues 24"/>
<LinearLayout
android:layout_width="wrap_content"
android:id="#+id/ll_textview"
android:padding="5dp"
android:layout_alignParentRight="true"
android:layout_below="#id/tv_openissues"
android:orientation="horizontal"
android:layout_height="wrap_content">
<TextView android:id="#+id/tvCreateissue"
android:drawableLeft="#drawable/bug6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Create Issue"
/>
<!-- the description view -->
<TextView android:id="#+id/tv_details"
android:layout_below="#id/tvCreateissue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableLeft="#drawable/bars64"
android:layout_marginLeft="5dp"
android:text="Details"
/>
<TextView android:id="#+id/tv_issues"
android:layout_below="#id/tvCreateissue"
android:layout_marginLeft="5dp"
android:drawableLeft="#drawable/bug6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Issues"
/>
</LinearLayout>
</RelativeLayout>
</RelativeLayout>
I might be wrong, but the error seems to reside here:
viewHolder.graphView.addView(item.chartview);
Once the view item.chartview is added to graphView, it has a parent. However ListView is known to call some getView on some positions multiple times for caching.
It would seem that the same view is being added to multiple parents which in return throws the error you get. Before adding the chartview you could try removing it from its parent if it exists:
// Remove from parent (if exists)
ViewGroup parent = item.chartview.getParent();
if (parent != null) {
parent.removeView(item.chartview);
}
// Add to another parent
viewHolder.graphView.addView(item.chartview);
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
myFragmentView = inflater.inflate(R.layout.dashboardlist, container, false);
instead of container use null
(I'm not an android geek but faced the problem before)

Categories

Resources