5

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?

android.weasel
  • 3,343
  • 1
  • 30
  • 41
Goddchen
  • 4,459
  • 4
  • 33
  • 54

3 Answers3

21

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.

Prudhvi
  • 2,276
  • 7
  • 34
  • 54
android.weasel
  • 3,343
  • 1
  • 30
  • 41
  • 1
    answer accepted, but I think the addition FrameLayout isn't needed since you can use the ViewGroup container and getView() directly. – Goddchen Jun 12 '13 at 17:44
  • @Godchen: You're saying to feed the 'container' object to populateView() instead of the new FrameLayout object, and feed it getView().getParent() in onConfigurationChanged()? That seems to contradict the documentation: container: If non-null, this is the parent view that the fragment's UI should be attached to. *The fragment should not add the view itself, but this can be used to generate the LayoutParams of the view.* – android.weasel Jun 17 '13 at 10:15
  • This seems to be changed in Android 21. Seems that a fragment's layout gets re-inflated automatically upon rotation (in this new API version). But it's really annoying that this lack of management of rotation is not documented in previous API versions, especially when Google recommends to use fragments instead of activities. – Javad Feb 11 '15 at 10:19
  • This answer is very much applicable for pre lollipop devices. – Saraschandraa Mar 17 '15 at 05:53
  • Are view listeners going to be lost by this practice? – Tamim Attafi Nov 18 '19 at 15:07
  • The answer is no, all the callbacks are dead – Tamim Attafi Nov 18 '19 at 16:12
0

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.

D-Dᴙum
  • 7,689
  • 8
  • 58
  • 97
  • 1
    i know how all this works, but this only seems to apply for Activities, not for Fragments! – Goddchen Sep 16 '11 at 14:52
  • Does implementing onCreateView method [ http://developer.android.com/guide/topics/fundamentals/fragments.html#UI] in your Fragment class not achieve the same thing? – D-Dᴙum Sep 16 '11 at 19:28
  • it doesn't get called again on orientation change, only once – Goddchen Sep 16 '11 at 20:10
  • But does not Android handle selecting the appropriate layout? Just as with Activity, you set the layout once and Android takes care of orientation changes. If you want to handle it yourself there is the onConfigurationChange() method in the Fragment class too – D-Dᴙum Sep 16 '11 at 20:20
  • apparently it doesn't :( So you would suggest to inflate and populate the layout again in the onConfigurationChange method? – Goddchen Sep 16 '11 at 21:04
  • If android doesn't handle resources for Fragments sounds as though that might be a bug in the package. I would then indeed try as you suggested, handle the orientation change in the app. – D-Dᴙum Sep 17 '11 at 06:58
  • this doesn't work for me either. Because Android won't recreate the back stack, i will loose everything the user has done when orientation changes :( – Goddchen Sep 18 '11 at 21:09
  • i am now performing a FragmentTransaction to readd the Fragment. but this only works for the currently visible Fragment. Please see http://stackoverflow.com/questions/7464919/android-fragments-orientation-problem – Goddchen Sep 19 '11 at 09:45
0

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()
}
Emre Memil
  • 233
  • 3
  • 5