Can Fragments use XML to define their layout? - android

Looking at the Android tutorial on:
http://developer.android.com/guide/topics/fundamentals/fragments.html
... it seems fragments have their layouts defined programmatically. Is there a way to use the usual XML files instead?
Thank you

You just missed it, this is the first code snippet in the fragment documentation:
public static class ExampleFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.example_fragment, container, false);
}
}
It uses a (supplied) LayoutInflater to inflate a layout, in this case named example_fragment.xml (inflate means parse XML and generate a layout structure out of it). So yes, certainly possible.
Basically all you have to do is return your fragment layout from onCreateView(). How you generate it inside is up to you, and since you get an inflater supplied, it's intended to use XML too.

Related

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

Assign Content to Tabs in a Fragment - Android

Just created a new project in the newest ADT release in Eclipse and found that it will setup up certain environments for you to get things started. I choose Tabs + Swipe.
It has this code I have question on:
public static class DummyFragment extends Fragment {
public DummyFragment () {
}
public static final String ARG_SECTION_NUMBER = "section_number";
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
TextView textView = new TextView(getActivity());
textView.setGravity(Gravity.CENTER);
Bundle args = getArguments();
textView.setText(Integer.toString(args.getInt(ARG_SECTION_NUMBER)));
return textView;
}
}
Both tabs refer to this same fragment. All it does is switch the content on the TextView that has the tab position number on it (1,2, or 3).
The more advanced question first: I want two different Fragments that the tab switches to. In the example code, it points to the same fragment. Where does this change take place? and can I see brief code example?
Easier question: I have two pre-defined XML layouts I'd like to set each tab (or Fragment) with. Do I do this in the actual Fragment? And if so, where? setContentView does't seem to be working in the onCreateView method?
Not really sure what this question is asking exactly, but if I understand correctly the TabHost (or whatever you are using to manage the Fragment tabs) is instantiating multiple instances of the DummyFragment and then attaching each to the screen when a tab is clicked. This is all done behind the scenes... all you need to worry about is implementing the Fragment and telling the TabHost when it should be instantiated/displayed.
Fragments don't have a setContentView method. You should inflate your Fragment's layout from xml in onCreateView. For instance with,
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_layout, container, false);
}

Using Fragments in ActionBar Tabs to have widgets

I made a program that uses FragmentTabs for implementing ActionBar Tabs.
I was wondering how it is possible to add a widget to a inflated Fragments in Tabs. It's more complicated than normal because the fragment is returning only an onCreateView to the TabListener, so how would I add in functioning widgets? I don't need specific code, just the logic please!
Here is a sample Fragment being inflated when a Tab is clicked (inside of which I need widgets):
public class IdFragment extends Fragment{
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
// Inflate the layout for this fragment
return inflater.inflate(R.layout.id_layout, container, false);
}
}

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);

Change Fragment layout on orientation change

I have the following problem:
I have a TabActivity that shows a FragmentActivity in one of its tabs.
That FragmentActivity adds a ListFragment, when clicked on the item of that ListFragment, a Fragment is added (also to the backstack) and displayed.
Now I need to change the layout of that Fragment to change when going to landscape orientation.
But I'm totally clueless where to implement that change. I have already created to correct layout in the layout-land folder. But where is the correct point to set it?
Warning: this may be a pre-Lollipop answer.
A Fragment doesn't get re-inflated on configuration change, but you can achieve the effect as follows by creating it with a FrameLayout and (re)populating that manually:
public class MyFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
FrameLayout frameLayout = new FrameLayout(getActivity());
populateViewForOrientation(inflater, frameLayout);
return frameLayout;
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
LayoutInflater inflater = LayoutInflater.from(getActivity());
populateViewForOrientation(inflater, (ViewGroup) getView());
}
private void populateViewForOrientation(LayoutInflater inflater, ViewGroup viewGroup) {
viewGroup.removeAllViewsInLayout();
View subview = inflater.inflate(R.layout.my_fragment, viewGroup);
// Find your buttons in subview, set up onclicks, set up callbacks to your parent fragment or activity here.
}
}
I'm not particularly happy with the getActivity() and related calls here, but I don't think there's another way to get hold of those things.
Update: Removed cast of ViewGroup to FrameLayout and used LayoutInflater.from(), and the third parameter of inflate() instead of adding the view explicitly.
I believe that if you have layouts that are for specific device orientations then all you need do is give them the same name but place them in the appropriate resource directory. This link gives some explanation. The Android system then takes care of selecting the appropriate resource but you can handle this yourself if needs be.
You need two different xml designs with the same name within the layout and layout-land packages under the res package.
When the orientation changes, override the onConfigurationChanged() function and edit the function as follows to load the xml file suitable for the orientation.
override fun onConfigurationChanged(newConfig: Configuration) {
val fragmentManager: FragmentManager = requireActivity().supportFragmentManager
fragmentManager.beginTransaction().detach(this).commitAllowingStateLoss()
super.onConfigurationChanged(newConfig)
fragmentManager.beginTransaction().attach(this).commitAllowingStateLoss()
}

Categories

Resources