I am trying to make a particular nested FrameLayout visible dynamically. However, i am getting NullPointerException when i try to access the view outside of my fragment's onCreateView() method. So here is my implementation.
private View myView;
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View fragmentView = inflater.inflate(R.layout.listView, container, false);
this.myView = fragmentView;
...
return fragmentView;
}
#Override
public void apiCompleted(ApiResult apiResult, HttpRequest httpRequest) {
if(myLocationManager.hasLocation()){
FrameLayout flayout = (FrameLayout) myView.findViewById(R.id.ldrawlayout);
flayout.setVisibility(View.VISIBLE);
}
}
listView.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/background_gray"
tools:context=".fragment.MallListFragment"
android:orientation="vertical">
<ListView
android:id="#+id/lv_malls"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</ListView>
</LinearLayout>
rowlist.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/row_mallx"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/white"
android:paddingBottom="7dp">
<FrameLayout
android:id="#+id/ldrawlayout"
>
...
</FrameLayout>
</RelativeLayout>
LOGCAT (onCreateView method is called first)
01-15 18:40:16.905 7633-7633/? V/onCreateView METHOD CALLED﹕ onCreateView
01-15 18:40:17.280 7633-7633/? V/APICOMPLETED METHOD CALLED﹕ apiCompleted
Ok, I see the problem. You want to access the row-layout, but your listview has multiple versions of this layout, that mean you can not access the row layout from the activity, you have to do it in your listadapter or you give your single rows in the listadapter an unique id such as row.setId(row.getId + positionOfRow)
LayoutInflater Inflater = (LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = Inflater.inflate(R.layout.row_mallx, null);
FrameLayout flayout = (FrameLayout) view .findViewById(R.id.ldrawlayout);
flayout.setVisibility(View.VISIBLE);
try this code in on apiCompleted
Are your sure that the onCreateView() method is called before the apiCompleted() method.
If yes, you should be able to access the view any where in your code as long as you hold the reference to it.
You can add some logs to see the order that the functions get called
Related
I am trying to create a View from code for a Fragment, where I had it inflate in the standard way. In the onCreateView from the Fragment I changed
View view = inflater.inflate(R.layout.list_layout, container, false);
mDragListView = (DragListView) view.findViewById(dlid); //R.id.drag_list_view
mDragListView.getRecyclerView().setVerticalScrollBarEnabled(true);
to
RelativeLayout rl = new RelativeLayout(getActivity());
DragListView dlv = new DragListView(getActivity());
int dlid = View.generateViewId();
dlv.setId(dlid);
rl.addView(dlv);
View view = rl;
mDragListView = (DragListView) view.findViewById(dlid);
mDragListView.getRecyclerView().setVerticalScrollBarEnabled(true);
with the list_layout being
<?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:background="#android:color/white"
android:id ="#+id/viewer_layout">
<com.woxthebox.draglistview.DragListView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/drag_list_view"
android:layout_width="match_parent"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_height="match_parent"/>
In the second version it throws the stated error, that getRecyclerView() returns a nullobject, where it worked in the first version.
Help is appreciated and cheers
EDIT: could it be possible via this, that I can load the layout, when I inflate it in the "method" in ClassToBeImported.class?
You are not calling
inflater.inflate(R.layout.list_layout, container, false);
in the new version. All layout elements will be null without it.
EDIT:
Since you already have a reference to the DragListView, you can use the instead of calling
view.findViewById(dlid);
Also return rl from onCreateView method.
EDIT2
If you have a local copy of DragListView implementation, try adding call to onFinishInflate in the constructor, so that it works when created from code as well.
public DragListView(Context context) {
super(context);
onFinishInflate();
}
I have the following fragment working in view pager:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/window_background"
android:id="#+id/font"
tools:context="com.cuentos.lib.cuentosmusicales.Libro">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp"
android:gravity="center"
android:id="#+id/titleBook"
android:textSize="25sp"
android:textColor="#2211CC"
android:text="#string/hello_blank_fragment" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/titleBook"
android:id="#+id/textBook"
android:textSize="15sp"
android:textColor="#44BB11"
android:text="#string/hello_blank_fragment" />
</RelativeLayout>
and i want to modify textview values from fragment class
public class Libro extends Fragment {
String titleLibro;
String text;
TextView title, text1;
public Libro() {}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_libro, container, false);
title = (TextView) view.findViewById(R.id.titleBook);
text1 = (TextView) view.findViewById(R.id.textBook);
title.setText("hi friends");
text1.setText("text");
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_libro, container, false);
}
}
So, I detect im not able to change data because there is no change, so how I can instanciate textview in fragment?
First, you're inflating your view two times. There's one on the first line of the onCreateView, which is the one that you modify the TextViews, but in the return statement you create and return another, you're not returning the one you modified, but a new one instead, so the view that will be presented in the UI is the not modified.
Also, you're calling the findViewById in the wrong lifecycle stage. Notice that onCreateView returns the view that will be present in your fragment. It's not possible to retrieve a view component like yours TextViews that way, because the view itself doesn't exists yet.
The right method to modify your view components is in the onViewCreated:
#Override
public void onViewCreated(View view, Bundle savedInstanceState)
{
title = (TextView) view.findViewById(R.id.titleBook);
text1 = (TextView) view.findViewById(R.id.textBook);
title.setText("hi friends");
text1.setText(text);
}
Try setting the text when overriding your Fragments onActivityCreated or onResume methods.
Hi there (and thanks in advance),
I have an application with a Google Play Store-like layout (using PagerTabStrip with 5 sub fragments). In some of those fragments I will need to display a little info regarding the last time the data was updated.
I immediately thought of creating a fragment (LastUpdatedFragment) which I would then add (nest) to the fragments I needed. At first, and since the last updated date was supposed to be the same for every screen, things were working (I simply added the fragment in the xml of the parent Fragments I needed and inside onCreateView I would put the date in the TextView), but after some changes I now need to send a specific date for each one of these LastUpdatedFragment instances.
I came up with one way - creating new custom attributes for my Fragment and then I would set the date I wanted. After some reading I stumbled across a easier way (Fragments within Fragments - dinamically adding the fragment using FragmentManager) - I simply needed the parent Fragment to handle the input parameters and pass it to the child fragment.
The problem is that, although I get no errors I also get no child fragment, it just does not display. I would be grateful if you could guide me in the right direction.
ScoreBoardFragment.java -> Parent Fragment
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.fragment_scoreboard, container,
false);
for (int i = 0; i < tvCount; i++) {
tvName = "f_scoreboard_header_tv" + String.valueOf(i);
resID = getResources().getIdentifier(tvName, "id",
_activity.getPackageName());
header = (TextView) rootView.findViewById(resID);
header.setTypeface(MyGlobalConfig.getInstance().getHeadersFont());
}
FragmentManager childFragMan = getChildFragmentManager();
FragmentTransaction childFragTrans = childFragMan.beginTransaction();
LastUpdatedFragment fragB = new LastUpdatedFragment();
childFragTrans.add(R.id.FRAGMENT_PLACEHOLDER, fragB);
childFragTrans.addToBackStack("B");
childFragTrans.commit();
return rootView;
}
fragment_scoreboard.xml (simplified but displaying everything else)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/FRAGMENT_PLACEHOLDER"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<LinearLayout
style="#style/ListView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:id="#+id/f_scoreboard_header_tv0"
style="#style/ListViewRowHeader"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="#" />
</LinearLayout>
<ListView
android:id="#+id/f_scoreboard_lvbody"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerHorizontal="true" >
</ListView>
</LinearLayout>
LastUpdatedFragment.java -> Child Fragment
public class LastUpdatedFragment extends Fragment{
private View rootView;
private TextView tv;
private Context ctx;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Thread.setDefaultUncaughtExceptionHandler(new ExceptionHandler(
getActivity()));
this.ctx = getActivity().getApplicationContext();
}
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.fragment_date, container,
false);
tv = (TextView) rootView.findViewById(R.id.f_date_tv);
tv.setTypeface(MyGlobalConfig.getInstance().getBodyFont());
tv.setText(getString(R.string.lastupdated) + ": " + Util.getLastUpdated(ctx));
return rootView;
}
}
fragment_date.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:id="#+id/f_date_tv"
style="#style/LastUpdatedTV"
android:layout_width="match_parent"
android:text="Data de última actualização: 27/12/2014 21:30" />
</LinearLayout>
Try to use FrameLayout instead of LinearLayout as Placeholder.
Following is a xml: welcome_view.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/root_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/white" >
<ImageView
android:id="#+id/welcome_bg"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.demo.src.WelcomeLayout
android:id="#+id/welcome_ad"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
This is the MainActivity, I setContentView with layout welcome_view.xml.
class MainActivity extends Activity
{
onCreate()
{
setContentView(R.layout.welcome_view);
ViewGroup view1 = findViewByID(R.id.ad_view);
}
}
WelcomeLayout has been contained in the welcome_view.xml. Please tell me the view in the following class is different with the one in above class??? Why, tell me some the inner mechanism.
class WelcomeLayout extends FrameLayout
{
onCreate()
{
super(context);
View.inflate(context, R.layout.welcome_view, null);
ViewGroup view2 = findViewById(R.id.ad_view);
}
}
Thanks!
reference:Difference between setContentView and LayoutInflater
setContentView is an Activity method only. Each Activity is provided with a FrameLayout with id "#+id/content" (i.e. the content view). Whatever view you specify in setContentView will be the view for that Activity. Note that you can also pass an instance of a view to this method, e.g. setContentView(new WebView(this)); The version of the method that you are using will inflate the view for you behind the scenes.
on the other hand, have a lifecycle method called onCreateView which returns a view (if it has one). The most common way to do this is to inflate a view in XML and return it in this method. In this case you need to inflate it yourself though. Fragments don't have a "setContentView" method
Note:link might be destroy so answer pasted.
How can I add a simple static header to my listview inside a listFragment? I want to create the header from an xml def and add it through inflation.
My onCreateView:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View detailList = inflater.inflate(R.layout.detail_fragment, container, false);
View detailListHeader = inflater.inflate(R.layout.daily_sales_header, null, false);
container.addView(detailListHeader, 0);
return detailList;
}
This creates the header, but it is not above the listview, rather the listview appears underneath the header, ie the header is overlaying the listview.
Any hints on the correct implementation?
Putting hackbod's description into code for you since his answer created more questions before the answers came. Sometimes I just want the fish. I don't always need to know how the net is made...
To start with, create a layout that looks like this:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/myListViewWithHeader"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="6dp"
android:textStyle="bold"
android:textSize="20sp" />
<ListView
android:id="#android:id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawSelectorOnTop="false" />
<TextView
android:id="#android:id/empty"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
Then, in your onCreateView method you do this:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.myListViewWithHeader, null);
return view;
}
The header can now be populated by doing this:
// get the header view
TextView headerView = (TextView) getView().findViewById(R.id.header);
headerView.setText("Header text goes here");
Notice that my header is a TextView, but it can be replaced with another view if you like. In that case you will need to do a getView().findViewById(R.id.xxxxx) for each view inside the header you want to work with
You should NEVER EVER be adding views directly to the container in onCreateView(). Please read the documentation: http://developer.android.com/reference/android/app/Fragment.html#onCreateView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle)
Also see the various sample code in the Fragment documentation, as well as the API demos: http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/app/index.html
There is nothing special about using a Fragment here. Just build a view hierarchy containing a ListView like you normally would in an Activity or elsewhere. You always need to return one View from onCreateView; this is the root of your hierarchy.
For example you could make the ListView and then use this to add a header to it: http://developer.android.com/reference/android/widget/ListView.html#addHeaderView(android.view.View)