How to set an Activity's root view as fragment in Android? - android

I have a Fragment, and I want to set that whole fragment as root view of my activity. I have everything ready, and I'm instantiating my fragment programatically. I've tried (in my activity):
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FeedFragment fragment = [...];
setContentView(fragment.getView());
}
But I've got a null pointer exception. In other words, how can I make my fragment act like an activity? I only target ICS+, I don't need to support older versions, if it makes any difference.

Try this
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.all_lecturer_frag, container, false);
......
return rootView;
}

A Fragment, by design, is intended to be a tool to help you reuse screen space and as such, fragments have to be present inside a container. So while a fragment cannot technically be a root view, you can have a fragment be the only view inside the Activity. For this, you should inflate the view for your fragment programmatically inside the onCreateView() method of the fragment. then you could have something like this in your activity's layout xml:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/frame_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.package.fragment_name
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</FrameLayout>
And then, within your activity, all you have to do is:
setContentView(R.layout.main);
Since, the fragment is defined in the layout xml, it cannot be removed from the activity's layout (although the layout itself can be changed) and is tied to it.
Also, on a side note, notice that the root view is a FrameLayout and not the fragment itself. But in this manner, your fragment can be tied to the activity. But don't forget that the Fragment will still retain it's lifecycle separate from the activity's.
EDIT: If you need to create your fragment instance programmatically, you have to do:
getFragmentManager().beginTransaction().add(R.id.frame_layout, your_fragment).commit();
This is the only way to add your fragment programmatically. But also keep in mind that the Fragment's layout is not tied to the activity's layout. But you can use the Fragment's lifecycle to behave similarly as an Activity.

#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.xxx);
//initializations...
if (savedInstanceState == null) {
// During initial setup, plug in the fragment.
YourFragment details = new YourFragment();
getFragmentManager().beginTransaction().add(R.id.your_root_frame_layout, details).commit();
}
}

Related

How to add a fragment to an Activity without a container

Is that possible I can add a fragment view on the activity view without specifying "fragment" view component in activity's layout xml file? Which function should I look for?
Well, the UI of the fragment has to go somewhere. If you want the entire "content view" to be the fragment, add the fragment to android.R.id.content:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getSupportFragmentManager().findFragmentById(android.R.id.content)==null) {
getSupportFragmentManager().beginTransaction()
.add(android.R.id.content, new ToDoRosterListFragment())
.commit();
}
}
Otherwise, somewhere in the activity's view hierarchy, you need a container (usually a FrameLayout) in which to place the fragment's UI. Typically, we do that by putting the container in the layout resource.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getSupportFragmentManager().beginTransaction()
.add(android.R.id.content, MyFragment.newInstance())
.commit();
//Some of your code here
}
android.R.id.content is the container of entire app screen.
It can be used with Fragment:
The android.R.id.content ID value indicates the ViewGroup of the entire content area of an Activity.
The code above will insert the View created by Fragment into the ViewGroup identified by android.R.id.content.
Simply, while creating a fragment we have to replace or add fragment's view with a view present in our application. To replace or add a fragment's, we normally add a Framelayout or any other layout view(as a fragmentview container) in activity or in a fragment.
Now, If you want to replace or add a fragment's view without adding a extra view container in your activity. You can simply do it by accessing the view's provided by AppCompatActivity or Activity.
Now, you can create a fragment, without adding a view container in your activity you can create as,
YourFragment fragment = new YourFragment();
transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(android.R.id.content, fragment); //here, android.R.id.content is a view on which your fragment's view is replaced
transaction.commit();
You need to have a layout in your activity to contain the fragment (preferably a FrameLayout).
<FrameLayout 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/container"
android:name="com.gdevelopers.movies.movies.FragmentMoreMovies"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
Then in activity put this code.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getSupportFragmentManager().beginTransaction()
.replace(R.id.container, new YourFragment())
.commit();
}
}
If you don't want to go with #CommonsWare answer, then you'll have to provide a container by code. then function you need is....
setContentView(View)
Yep. If you check the activity class code, you'll see that setContentView can be called with an INT (layouts are identified with ints), or with Views. Therefore, you can create a viewgroup instance on the fly, keep a reference to it (you would need to do the same with an XML generated view), and add your fragments there. This is possible because XML files are just arguments which the view factory class, Inflater, uses to find which view subclasses has to instantiate, using a set of parameters provided in the XML. And obviously, you can do that by hand. Just pick whatever layout class you want to use, for example, FrameLayout, and:
public class Activity extends AppCompatActivity{
private FrameLayout root;
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
root = new FrameLayout(this);
root.setLayoutParams(new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT));
setContentView(root);
//go on
}
}
use android container instead of custom container like
fragmentTransaction.replace(android.R.id.content,yourFragment);
1.use getWindow().getDecorView() to get a DecorView(FramLayout)
2.add a container view to DecorView
3.add Fragment to the container view
LinearLayout llRoot = findViewById(R.id.parent);
FragmentManager fragMan = getSupportFragmentManager();
FragmentTransaction fragTransaction = fragMan.beginTransaction();
YourFragment yourFragment = (YourFragment)fragMan.findFragmentByTag("yourFragment");
if (yourFragment == null) {
yourFragment = new YourFragment();
}
fragTransaction.replace(llRoot.getId(), yourFragment, "yourFragment");
fragTransaction.commit();
llRoot is a LinearLayout which contains different view object of your activity
If you don't want to allocate a specific place in the view to the fragment container you can always use the RelativeLayour. I guess without a container we cant place a fragment in a view.
If you have any View or say root view from the activity window, get its Id using view.getId() (relevant to android:id) and pass that id to the fragmentTransaction.add() as the container id. Here's just a sample:
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
View view = new View(this);
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.add(view.getId(), new Fragment());
}

Is it possible to access fragment's UI elements from activitiy's onCreate

As the headline says: Is it possible to get the currently visible fragment with all UI elements initialized within the onCreate() method of the activity?
I am implementing a separation into model, view and controller with separate controller classes that handle business logic and UI events. Therefore they need a reference to the current fragment. These controllers are initialized in the onCreate() method of the activity hence I need the initialized fragment within that method.
I welcome any kind of advice :)
EDIT:
Adding some code for better understanding:
I'm using dagger for dependency injection and would like to do this in the onCreate() method. As I said before my controller needs an the mapView element. And that is why I would like to have a fragment with the mapView element initialized.
MapActivity#onCreate(Bundle):
public void onCreate(Bundle savedInstance) {
super.onCreate(savedInstance);
setContentView(R.layout.activity_layout);
MyMapFragment fragment = new MyMapFragment();
getFragmentManager().beginTransaction()
.add(R.id.activity_container, fragment, "fragment")
.commit();
ObjectGraph.create(new Module(fragment.getMapView())).inject(this);
}
activity_layout.xml
<android.support.v4.widget.DrawerLayout>
<FrameLayout
android:id="#+id/activity_container"
... />
<ListView .../>
</android.support.v4.widget.DrawerLayout>
fragment_layout.xml
<RelativeLayout>
<org.osmdroid.map.MapView
android:id"#+id/mapview"
... />
<Button .../>
</RelativeLayout>
2ND EDIT:
So it seems like that is not possible... Yay for the downvote ^^
By default, no. At the time activity onCreate() runs, the fragment is not attached to the activity yet.
Right place to access a fragment's views is in the fragment itself. Consider putting the controller assignments in the fragment within its lifecycle such as onCreateView() or onViewCreated().
It is possible to explicitly run queued up fragment transactions using executePendingTransactions(), or implicitly after super.onStart() has been run in the activity lifecycle. After that the fragment views are accessible in the activity view hierarchy.
in your onCreate method add the following (I used a textview as an example):
while (fragment.getView() == null) {
}
rootView = fragment.getView();
TextView myView = (TextView) rootView.findViewById(R.id.text_view);
Make sure to return the rootView in your fragment's onCreateView method as follows:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_activity,
container, false);
return rootView;
}
I know that the idea of getting your fragment to access its views from the main activity is bad. Yet, this solution may give you what you want.

Use view from fragment xml file

I have an activity with several tabs (using the 'fixed tabs + swipe' style). Each tab layout is defined as a fragment xml file.
Eg, my activity is called ModifyCustActivity. This uses an almost-empty xml file called activity_modify_cust.xml. Each tab on this page is represented by various xml files such as fragment_modify_cust_basic and fragment_modify_cust_address etc etc. Each of these fragment xml files contains EditTexts, Spinners and more.
When the activity starts, I need to be able to access these views from the activity code, as I need to pre-populate them, and get their results once they are edited. However, because these views exist in a fragment xml file, I don't seem to be able to reach them in code. Is there a way to access a view contained in a fragment xml file?
Is there a way to access a view contained in a fragment xml file?
Yes it is, but your fragment should be declared in the XML layout file, which seems to be your case.
For example:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
...">
<fragment
android:name="com.example.MyFragment"
android:id="#+id/my_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
And you would access the fragment like this:
FragmentManager manager = getSupportFragmentManager();
MyFragment fragment = (MyFragment)manager.findFragmentById(R.id.my_fragment);
Then using the fragment instance you could further access your views, for example by calling a public method from the fragment which updates some particular view.
UPDATE:
Suppose you have a TextView that appears in layout of the fragment, and need to update from the activity.
Let this be the fragment class:
public class MyFragment extends Fragment{
private TextView textView;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_layout, null, false);
textView = (TextView)view.findViewById(R.id.textView);
return view;
}
public void updateTextView(String text){
textView.setText(text);
}
}
Then you would update the TextView by calling in your activity the updateTextView() method:
fragment.updateTextView("text");
You can reach fragments views from activity. If you want to send a data from fragment to another fragment. Your sender fragment must communicate with activity and your activity can manipulate the view in other fragment
http://developer.android.com/training/basics/fragments/communicating.html

Trying to add a fragment to my fragment container FrameLayout

I have created an xml file called editor.xml which contains a FrameLayout. In my main activity I am trying to add my custom fragment to my FrameLayout.
The error I receive when trying to add my fragment is:
The method add(int, Fragment) in the type FragmentTransaction is not applicable for the arguments (int, editorFrag)
However my editorFrag extends Fragment so I am confused on why this is happening. Below is my code for the files I have mentioned. Any help is appreciated.
Editor.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
editorFrag.java
public class editorFrag extends Fragment
{
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
// Inflate the layout for this fragment
return inflater.inflate(R.layout.newlevel, container, false);
}
}
MainActivity.java
public class editorActivity extends FragmentActivity
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.editor);
// Check that the activity is using the layout version with the fragment_container FrameLayout
if(findViewById(R.id.fragment_container) != null)
{
// if we are being restored from a previous state, then we dont need to do anything and should
// return or else we could end up with overlapping fragments.
if(savedInstanceState != null)
return;
// Create an instance of editorFrag
editorFrag firstFrag = new editorFrag();
// add fragment to the fragment container layout
getSupportFragmentManager().beginTransaction().add(R.id.fragment_container, firstFrag);
}
}
}
Answered:
Luksprog answered this problem for me below by telling me to check my imports. Eclipse chose to import the SDK version of Fragment instead of the support version that I needed. Thank you for the help.
You forgot to commit() your transaction.
You also forgot to call the addtoBackStack() method, otherwise your app closes when you hit the back button.
add commit() like this
getSupportFragmentManager().beginTransaction().add(R.id.fragment_container, firstFrag).commit();
1- //Add fragment container in xml file
<androidx.fragment.app.FragmentContainerView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/fragment_container_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
</androidx.fragment.app.FragmentContainerView>
2- //Implementation of BackStack
fragmentTransaction.setReorderingAllowed(true);
fragmentTransaction.addToBackStack("name");

findViewById returns NULL when using Fragment

I'm new to Android developing and of course on Fragments.
I want to access the controls of my fragment in main activity but 'findViewById' returns null.
without fragment the code works fine.
Here's part of my code:
The fragment:
<?xml version="1.0" encoding="utf-8"?>
<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="wrap_content"
android:orientation="vertical"
tools:ignore="HardcodedText" >
<EditText
android:id="#+id/txtXML"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:ems="10"
android:scrollbars="vertical">
</EditText>
</LinearLayout>
the onCreate of MainActivity:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
super.setContentView(R.layout.main);
this.initialisePaging();
EditText txtXML = (EditText) findViewById(R.id.txtXML);}
on this point the txtXML is null.
What's Missing in my code or what should I do?
Try like this on your fragments on onCreateView
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if (container == null) {
return null;
}
LinearLayout ll = (LinearLayout )inflater.inflate(R.layout.tab_frag1_layout, container, false);
EditText txtXML = (EditText) ll.findViewById(R.id.txtXML);
return ll;
}
You should inflate the layout of the fragment on onCreateView method of the Fragment then you can simply access it's elements with findViewById on your Activity.
In this Example my fragment layout is a LinearLayout so I Cast the inflate result to LinearLayout.
public class FrgResults extends Fragment
{
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
//some code
LinearLayout ll = (LinearLayout)inflater.inflate(R.layout.frg_result, container, false);
//some code
return ll;
}
}
I'm late, but for anyone else having this issue. You should be inflating your view in the onCreateView method. Then override the onCreateActivity method and you can use getView().findViewById there.
#Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
return inflater.inflate(R.layout.fragment, container, false);
}
You can't access the the view of fragment in activity class by findViewById instead what you can do is...
You must have an object of Fragment class in you activity file, right? create getter method of EditText class in that fragment class and access that method in your activity.
create a call back in Fragment class on the event where you need the Edittext obj.
1) Try this:
Eclipse menu -> Project -> Clean...
update
2) If you have 2 or more instances of 'main' layout, check if all of them have a view with 'txtXML' id
3)
A Fragment is a piece of an application's user interface or behavior that can be placed in an Activity. Interaction with fragments is done through FragmentManager, which can be obtained via Activity.getFragmentManager() and Fragment.getFragmentManager().
The Fragment class can be used many ways to achieve a wide variety of results. It is core, it represents a particular operation or interface that is running within a larger Activity. A Fragment is closely tied to the Activity it is in, and can not be used apart from one. Though Fragment defines its own lifecycle, that lifecycle is dependent on its activity: if the activity is stopped, no fragments inside of it can be started; when the activity is destroyed, all fragments will be destroyed.
Study this. you must use FragmentManager.
If you want use findViewById as you use at activities onCreate, you can simply put all in overrided method onActivityCreated.
All the answers above tell you how you should "return the layout" but don't exactly tell you how to reference the layout that was returned so I was unable to use any of the solutions given. I used a different approach to solve the problem. In the Fragment class that handles the fragment, got to the onViewCreated() class and create a context variable in it that saves the context of the parent activity (main activity in my case).
public void onViewCreated(#NonNull View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Context fragmentContext = (MainActivity) view.getContext();
}
Once that is done, you can use the new context to access items on your fragment from inside the onViewCreated() method.
EditText editText = context.findViewById(R.id.textXML);

Categories

Resources