Add fragment to list item

I want to have a snippet for each item in the list, because I want to separate some logic. I use a view holder for each item. If the view does not exist, I create a new fragment and add it to the container.

holder.mMyFragment = new MyFragment(mActivity, this); mActivity.getSupportFragmentManager().beginTransaction().add(R.id.my_container, holder.mMyFragment).commit(); 

Also for each element, I call owner.mMyFragment.setUi (dataSource, position) to set the fragment UI based on the source and source position.

The problem I am facing is initializing the UI elements in the onCreateView method of the fragment class, but it is not called when I add the fragment to the element. So later, when I call setUi (), which uses some user interface elements in the fragment, it complains about a NullPointerException. Anyone have a suggestion? Thanks!

+9
source share
6 answers

I want to have a snippet for each item in the list, because I want to separate some logic.

You cannot use a fragment as representations of a list item, because the API does not allow you - View and Fragment are not even related, so you cannot use it that way. Create custom views and use the getViewTypeCount and getView to use different list item behavior.

Fragment management is carried out using the Activity FragmentManager or other child fragments of the FragmentManager; while views of list items are managed by ListView & ListAdapter. You can use ListViews in fragments, but not vice versa.

+10
source

" FOR THIS DECISION .

The problem is that you cannot add the fragment directly to the container (FrameLayout) with the same "id" in the list as in the above code.

trick , create a listview (Recyclerview) for "LinearLayout". Then dynamically create a FrameLayout in the adapter and assign different id for each. Put a snippet on FrameLayout and this FrameLayout on LinearLayout.

 @Override protected void onBindBasicItemView(RecyclerView.ViewHolder holder, int position) { if (holder instanceof VideoHomeViewHolder) { VideoHomeViewHolder videoHomeViewHolder = (VideoHomeViewHolder) holder; FrameLayout frameLayout = new FrameLayout(mContext); frameLayout.setId(position+1); //since id cannot be zero FragmentHelper.popBackStackAndReplace(mFragmentManager, frameLayout.getId(), new ShowLatestVideosFragment(mShowLatestVideosItems.get(position))); videoHomeViewHolder.linearLayout.addView(frameLayout); } } 
+9
source

The easy way. One problem: you must maintain recovery recovery status.

 holder.mMyFragment = new MyFragment(mActivity, this); int id = View.generateViewId(); findViewByTag("abc").setId(id); mActivity.getSupportFragmentManager().beginTransaction().add(id, holder.mMyFragment).commit(); 
+3
source

Hi, I ran into the same problem and I found a way to do this.
My problem was like you:

"I want to have a snippet for each item in the list because I want to separate some logic"

In my application, I must provide the ability to display user elements in vertical (listView) and horizontal (ViewPager) modes. In addition, I had to deal with 18 user elements and each logic, so the best approach was to reuse the fragments that I used for the ViewPager in the ListView.

I got this, but not the way you tried, I mean, I used my snippets like "ViewHolders":

  • Define a fragment widget as class variables in each fragment.
  • Create a custom ArrayAdapter and redefine: getViewTypeCount(), getItemViewType(int position), getCount(), getItem(int position) getView(int position, View convertView, ViewGroup parent)

In getView I checked what type of layout I need before inflating the corresponding XML, creating a fragment, assigning a widget from XML to a fragment (using rootView.findViewById ), and setting a β€œtag” with a new fragment. <ears>
What you see at this stage is that the fragments in the ListView were never attached to the Activity, but you got what you wanted: the logic is distributed in several parts and all the advantages of ListView (reusing rows, scrolling, etc. d.).

If you need, I can post some of my code, but you need to deal with "spanglish";).



UPDATED

The whole problem is that when you create a snippet that will be used with the ViewPager, usually all the "layout" and "setup" code is inside the onCreateView method, I mean:

  • Get the view object that you are going to use ( View rootView = inflater.inflate(R.layout.fragment_question_horizontal_container, container, false); )
  • Get widgets from above, define behavior, fonts, etc.: ( answer = (EditText)rootView.findViewById(R.id.answer_question_text); )

Up to this point there is nothing strange.
If you intend to use a snippet with the behavior described above, you must "imitate" the onCreateView call, fill in the data, and attach it to the View list.

Here's the trick: split the code in onCreateView in some methods that don't care about who calls them. An example of my onCreateView :

 @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_pregunta_horizontal_container, container, false); addAnswerLayout(rootView, R.layout.fragment_pregunta_texto, getActivity()); setUpComponents(rootView); //those 2 methods are about my app logic so I'm not going to talk much about them setUpQuestionState(savedInstanceState); readSavedAnswer(); return rootView; } public void addAnswerLayout(View rootView, int optionId, Context context) { mContext = context; RelativeLayout relativeLayout = (RelativeLayout)rootView.findViewById(R.id.pregunta_container); LayoutInflater inflater = ((Activity)mContext).getLayoutInflater(); View newView = inflater.inflate(optionId, relativeLayout, false); relativeLayout.addView(newView); } public void setUpComponents(View rootView) { //next line: some heritage that you can ignore super.setUpComponents(rootView); respuesta = (EditText)rootView.findViewById(R.id.pregunta_respuesta_texto); respuesta.setTypeface(UiHelper.getInstance(getActivity()).typeface); respuesta.setTextColor(mContext.getResources().getColor(R.color.drs_gris)); ... } 


Now go to the CustomArrayAdapter to view the list:

  • Define your customArrayAdapter like this: PreguntasVerticalArrayAdapter extends ArrayAdapter<Pregunta> where "Pregunta" is a common fragment with logic at the top.
  • Override getViewTypeCount(), getItemViewType(int position), getCount(), getItem(int position) getView(int position, View convertView, ViewGroup parent) .

getView follow the same behavior: get the object for a given position in the parameters, reuse the "viewer" and fill in the data. Here is my getView :

 @Override public View getView(int position, View convertView, ViewGroup parent) { View rowView = convertView; Pregunta pregunta = mData.get(position); if (rowView == null) rowView = createQuestionUI(pregunta, parent, position); fillDataInRow((PreguntaUI)rowView.getTag(), pregunta, position); return rowView; } private View createPreguntaUI(Pregunta pregunta, ViewGroup parent, int position) { View rootView = null; LayoutInflater inflater = (mPreguntasVerticalFragment.getActivity()).getLayoutInflater(); //you can ignore this part of the code ralted to Bundle. Bundle args = new Bundle(); args.putLong(PreguntaUI.PREGUNTAUI_ID, pregunta.getIdpregunta()); args.putInt(PreguntaUI.PREGUNTAUI_INDEX, position); args.putInt(PreguntaUI.PREGUNTAUI_TOTAL_QUESTIONS, getCount()); //internal method of "pregunta" to know what kind of question it is. String tipo = pregunta.getTipo(); if (tipo.equalsIgnoreCase(PreguntaType.TEXT.toString())) { rootView = inflater.inflate(R.layout.fragment_pregunta_vertical_container, parent, false); Pregunta_texto pregunta_texto = new Pregunta_texto(); pregunta_texto.setArguments(args); //LOOK AT THIS POINT!!!: I'm calling the same methods that I called in onCreateView fragment method. pregunta_texto.addAnswerLayout(rootView, R.layout.fragment_pregunta_texto, mPreguntasVerticalFragment.getActivity()); pregunta_texto.setUpComponents(rootView); pregunta_texto.setUpQuestionState(null); pregunta_texto.readSavedAnswer(); //I'm adding the fragment to reuse it when I can rootView.setTag(pregunta_texto); } else if ... return rootView; } 



That's all ... for now, if you have enough experience with CustomArrayAdapters and Fragments, you probably got it !: D

+1
source

From the Android Documentation: β€œA Fragment represents a behavior or part of a user interface in an Activity. You can combine multiple fragments in one action to create a multi-level user interface and reuse a fragment in multiple actions.”

For your activity, you want to add 2 fragments, where the first displays listView ( = ListFragment , and the other on the right) and is displayed only when the user clicks on an element (from the first fragment or listView)?

0
source

Instead of using ListFragment, you can use RecyclerView, Android has documentation on this:

enter image description here

https://developer.android.com/training/basics/fragments/creating.html#AddInLayout

0
source

Source: https://habr.com/ru/post/953272/


All Articles