In first place this is the code of the fragment:
public class MyFragment extends Fragment {
private View FragmentView;
public static Fragment newInstance() {
MyFragment NewFragment = new MyFragment();
return NewFragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
FragmentView = inflater.inflate(
R.layout.tasks,
new LinearLayout(MainActivity.MainContext)
);
FragmentView.setLayoutParams(
new LayoutParams(
LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT
)
);
addText();
return FragmentView;
}
private void addText() {
TasksView.setBackgroundResource(R.drawable.bg_image);
TextView MyTitle = new TextView(MainActivity.MainContext);
MyTitle.setLayoutParams(
new LayoutParams(
LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT
)
);
MyTitle.setText(R.string.mytitle);
((LinearLayout) FragmentView).addView(MyTitle );
}
}
MainActivity.MainContext is stored as public static in the main activity's class and is retrieved when creating the activity by getApplicationContext().
Now, the problem lays here:
FragmentView = inflater.inflate(
R.layout.tasks,
new LinearLayout(MainActivity.MainContext)
);
Because of this, the MyTitle text view is not displayed inside the fragment. If I do this:
FragmentView = inflater.inflate(R.layout.tasks, null);
it is displayed but I get a warning:
Avoid passing null as the view root (needed to resolve layout parameters on the inflated layout's root element)
I would like do it properly and not get any warnings and I don't find a way. I also tried:
FragmentView = inflater.inflate(R.layout.tasks, container);
but the application crashes.
You should pass container as a parent.
FragmentView = inflater.inflate(
R.layout.tasks,
container,
false
);
Also you should specify false, so LayoutInflater does not attach the inflated view to parent. The inflated view is attached to parent by FragmentManager.
Related
Inside a fragment I try to inflate two layouts besides the root layout:
View a, b;
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.list_fragment, container, false);
//..
a = inflater.inflate(R.layout.empty_list_view, container);
b = inflater.inflate(R.layout.progress_list_view, container);
//..
return root;
}
public void showB() {
a.setVisibility(GONE);
b.setVisibility(VISIBLE);
}
So I just return a single layout from the onCreateView method. However I inflate two more, a and b.
However when I display b actually a will be displayed. So progress_list_view never shows up. Can someone explain this strange behavior?
I suspect that a and b are both added to the container (ViewGroup). And since a is added first, it will be displayed first.
edit:
The point is, you're doing a huge mess and there is no good reason why you're doing it.
What happens there is that you inflate root, but not attach it to the container with this line View root = inflater.inflate(R.layout.list_fragment, container, false);
Then you inflate two views and add them directly to the container with those lines a = inflater.inflate(R.layout.empty_list_view, container);, which is a wrong thing to do as per Fragment documentation:
The fragment should not add the view itself, but this can be used to generate the LayoutParams of the view
also both a and b are the same object, which is the container object as per documentation for the LayoutInflater
If root was supplied, this is the root
and root was supplied by you and it's the container, so what you have is basically the same asa=container; b=container;
and then you return root, at which point I really don't know what is happening anymore due to this mess. I decribed.
Lucky to fix is easy:
create another XML layout like this (shortened):
<FrameLayout>
<include layout="#layout/empty_list_view"/>
<include layout="#layout/progress_list_view"/>
</FrameLayout>
then you inflate this new XML:
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.new_xml, container, false);
a = root.findViewById( .. ID of the root of empty_list_view.. )
b = root.findViewById( .. ID of the root of progress_list_view.. )
return root;
}
then the code will work.
original answer:
There's no strange behavior. You inflated those layouts and you have 2 View objects that are representative of them. But nothing attached those Views to the UI.
Only the view that you return from the onCreateView method that will be attached to the device UI.
For example:
the following code will show a:
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
//..
View a = inflater.inflate(R.layout.empty_list_view, container);
View b = inflater.inflate(R.layout.progress_list_view, container);
//..
return a;
}
the following code will show b:
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
//..
View a = inflater.inflate(R.layout.empty_list_view, container);
View b = inflater.inflate(R.layout.progress_list_view, container);
//..
return b;
}
if you want to have them both togeher you should put them together in the XML layout file. Maybe using an include tag if you need it re-usable.
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LinearLayout layoutMain = new LinearLayout(this);
layoutMain.setOrientation(LinearLayout.HORIZONTAL);
setContentView(layoutMain);
LayoutInflater inflate = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
// 1st Layout
RelativeLayout layoutLeft = (RelativeLayout) inflate.inflate(
R.layout.main, null);
// 2nd Layout
RelativeLayout layoutRight = (RelativeLayout) inflate.inflate(
R.layout.row, null);
RelativeLayout.LayoutParams relParam = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT);
layoutMain.addView(layoutLeft, 100, 100);
layoutMain.addView(layoutRight, relParam);
}
You can only return one view from the onCreateView. The view that is returned is the view that is displayed. Looks like you always return view a.
R.layout.list_fragment should look something like this:
<FrameLayout>
<include
android:id="#+id/a"
layout="#layout/empty_list_view"/>
<include
android:id="#+id/b"
layout="#layout/progress_list_view"/>
</FrameLayout>
Your code will look something like this:
View a, b;
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.list_fragment, container, false);
a = root.findViewById(R.id.a);
b = root.findViewById(R.id.b);
return root;
}
public void showB() {
a.setVisibility(GONE);
b.setVisibility(VISIBLE);
}
Why don't you inflate new view in the container.
Try this
LayoutInflater mInflater = null;
ViewGroup mContainer = null;
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
mInflater = inflater;
mContainer = container;
View root = inflater.inflate(R.layout.list_fragment, container, false);
return root;
}
public void showB() {
mInflater.inflate(R.layout.progress_list_view, mContainer, false);
}
public void showA() {
mInflater.inflate(R.layout.empty_list_view, mContainer, false);
}
Let's say following is my fragment.
public class FieldsFragment extends Fragment {
LinearLayout linearLayout;
ScrollView scrollView;
ViewGroup rootView;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
rootView = (ViewGroup) inflater.inflate(
R.layout.single_field_fragment ,null);
scrollView = (ScrollView) rootView.findViewById(R.id.single_field_scrollView);
return rootView;
}
public void setLinearLayout(LinearLayout linearLayout){
scrollView.removeAllViews();
scrollView.addView(linearLayout);
}
public LinearLayout getLinearLayout(){
return linearLayout;
}
}
What I want to do is ...
ArrayList<FieldsFragment> fragmentList = new ArrayList<FieldsFragment>();
fragment = new FieldsFragment();
fragment.setLinearLayout(lL);
fragmentList.add(fragment);
just want to parse my linear layouts to the fragment from other activity in order to use in FragmentStatePagerAdapter...
the problem is I can't setLinearLayout(myLayout1) without initiating the scrollView (findViewByID).
My work flow is so simple...
(1) to pull linearLayout's from server..
(2) set them to each FieldsFragment and add them to ArrayList
(3) and use that ArrayList to put FragmentStatePagerAdapter.
The purpose is to slide all linearlayout got from server.
I got a solution and it's quite simple.
Following is the way I put linearlayout to fragment and it works.
public class MyFragment extends Fragment {
ScrollView scrollView;
private LinearLayout linearLayout;
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
ViewGroup rootView = (ViewGroup) inflater.inflate(
R.layout.my_fragment , container, false);
scrollView = (ScrollView) rootView.findViewById(R.id.svMyFragment);
scrollView.addView(linearLayout);
return rootView;
}
public static final MyFragment newInstance(LinearLayout linear_Layout){
MyFragment myfragment = new MyFragment();
myfragment.setLinearLayout(linear_Layout);
return myfragment;
}
public void setLinearLayout(LinearLayout linearLayout) {
this.linearLayout = linearLayout;
}
}
In FragmentActivity class, instantiate like this
MyFragment fooFragment = MyFragment.newInstance(myLinearLayout);
I am getting a Null Pointer Exception when trying to add a textView programmatically to a fragment.
I think the context is coming back null but I could be wrong. The crash is happening at startMenu.addView(tv);
public class TabFragment1 extends Fragment {
View inflatedView;
Context context = null;
private Bundle mBundle;
private LinearLayout startMenull ;
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (container == null) {
return null;
}
if (inflatedView != null) {
ViewGroup parent = (ViewGroup) inflatedView.getParent();
if (parent != null)
parent.removeView(inflatedView);
}
try {
inflatedView = inflater.inflate(R.layout.start_menu, container,
false);
context = getActivity().getApplicationContext();
//startMenu = (LinearLayout) getActivity().findViewById(R.id.start_menull);
startMenu = (LinearLayout) getLayoutInflater(mBundle).inflate(R.id.start_menull, null);
TextView tv = new TextView(context);
tv.setId(1);
tv.setText("Here is the text Box");
startMenu.addView(tv);
} catch (InflateException e) {
}
return inflatedView;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mBundle = savedInstanceState;
}
}
Updated above code 9/16 3:48
Solved:
in the try/catch
inflatedView = inflater.inflate(R.layout.start_menu, container,
false);
context = getActivity().getApplicationContext();
startMenull =((LinearLayout) inflatedView.findViewById(R.id.start_menull));
TextView tv = new TextView(context);
tv.setId(1);
tv.setText("Here is the text Box");
startMenull.addView(tv);
context cant be null at that point, since he is using applicationContext.
but start Menu IS! null since onCreate is called before onCreateView. So you would have to inflate the View first, which you should do in onCreateView not onCreate.
Just Noticed you are inflating the View in onCreateView, but still you cant Access it in onCreate as it is called before onCreateView.
See Android Life Cycle. http://developer.android.com/images/fragment_lifecycle.png
public class TabFragment1 extends Fragment {
View inflatedView;
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
inflatedView = inflater.inflate(R.layout.start_menu, container,false);
LinearLayout startMenu = (LinearLayout) inflatedView.findViewById(R.id.start_menu);
TextView tv = new TextView(getActivity());
tv.setId(1);
tv.setText("Here is the text view");
startMenu.addView(tv);
return inflatedView;
}
}
If i wanted to do something like you are doing, this would b how i'd do it. Why would u check if container is null? or why would you assume that inflatedView is != null?
onCreate calls before onCreateView. Read about lifecycle.
In PageFragment; I inflate a layout in onCreateView. But I want to inflate this layout before onCreateView loads. It could be inflated one time / or for every fragment; not important.
How can I achieve it ?
public class PageFragment extends Fragment {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.page_quiz, container, false);
tv = (TextView) view.findViewById(R.id.Text);
LinearLayout ll = (LinearLayout) view.findViewById(R.id.questionList);
return view;
}
}
You just have to provide a layout as the return parameter in onCreateView(), that does not means you have to inflate it there. Layout can come from anywhere. You can Inflate the layout in onAttach() or in onCreate().
use getActivity() to get a LayoutInflater instance:
View layout = LayoutInflater.from(getActivity()).inflate(........);
I'm making a downloader app, and i got child's parents error after the onCreateView return section.
I tried a lots of things, but nothing help. I tried:
((ViewGroup)dlistView.getParent()).removeView(dlistView);
after that the compiler says:
01-12 12:05:15.558: E/AndroidRuntime(10740): java.lang.RuntimeException: Your content must have a ListView whose id attribute is 'android.R.id.list'
or remove the container/ i got an npe/ or remove the V but the V.getParent() is null.
Which view is the parent, and which is the child?
The code:
public static class DownloadingFragment extends ListFragment {
public static final String ARG_SECTION_NUMBER = "section_number";
public DownloadingFragment() {
}
#Override
public View onCreateView (LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View V = inflater.inflate (R.layout.list, null);
ListView dlistView = (ListView) V.findViewById(R.id.dlist);
List<DownloadInfo> downloadInfo = new ArrayList<DownloadInfo>();
downloadInfo.add(new DownloadInfo("File", 1000));
DownloadInfoArrayAdapter diaa = new DownloadInfoArrayAdapter(
getActivity().getApplication(),R.layout.list, downloadInfo);
dlistView.setAdapter(diaa);
return dlistView; // throw exception
}
}
//...
}
Thank you in advance for your help.
EDIT:
the new code:
public static class DownloadingFragment extends Fragment {
public static final String ARG_SECTION_NUMBER = "section_number";
public DownloadingFragment() {
}
#Override
public View onCreateView (LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View V = inflater.inflate (R.layout.list, null);
return V;
}
#Override
public void onStart() {
// TODO Auto-generated method stub
super.onStart();
ListView dlistView = (ListView) getView().findViewById(R.id.dlist);
List<DownloadInfo> downloadInfo = new ArrayList<DownloadInfo>();
downloadInfo.add(new DownloadInfo("File", 1000));
DownloadInfoArrayAdapter diaa = new DownloadInfoArrayAdapter(
getActivity().getApplication(),R.layout.list, downloadInfo);
dlistView.setAdapter(diaa);
}
}
//...
}
that's because you return the listview which has a parent (somewhere in V's layout tree) .
for any type of fragment , onCreateView should return a view that doesn't have any parent .
in this case , since it's a listFragment , create the listview (either using xml or programmatically ) , and then return it . do not allow it to have any parents since it needs to have a parent as a fragment .
read here for more information :
The system calls this when it's time for the fragment to draw its
user interface for the first time. To draw a UI for your fragment, you
must return a View from this method that is the root of your
fragment's layout. You can return null if the fragment does not
provide a UI.
Note that the third argument of inflate is false.
so replace this line
View V = inflater.inflate (R.layout.list, null);
with this
View V = inflater.inflate (R.layout.list, null,false);
and you are done.hope this helps.