Currently, I'm developing support for different orientations. I have a viewpager and tablayout for my landscape layout and only a single fragment for my portrait layout. When I launch the application in whichever orientation, the layouts work fine. However, when the orientation is changed during runtime, in this case from portrait to landscape, the viewpager and tablayout completely disappears from the screen, leaving only the fragment at parent height and width even though a weight is allocated.
This led me to believe that the layout is not changing properly. I do not have android:configurations applied to my manifest as well. Otherwise, other activities and fragments work fine when I have their orientation changed. For some reason, only this does not work. I'll attach the XML code below.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/drawer"
tools:context=".HomeActivity">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
tools:ignore="UselessParent">
<fragment
android:id="#+id/none"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:tag="fragment_tag"
android:name="com.example.trackeths.HomeFragment" />
</FrameLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:layout_weight="1">
<com.google.android.material.tabs.TabLayout
android:id="#+id/tabLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabGravity="fill"
app:tabMode="fixed"
app:tabTextColor="#fff"
app:tabIndicatorColor="#fff"
android:background="#color/colorPrimaryDark"
/>
<androidx.viewpager.widget.ViewPager
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/viewPager"/>
</LinearLayout>
After posting this question, suddenly had an epiphany that it could be a persistent fragment that overwrites my layouts (i.e. fragment from portrait mode stacks on landscape mode due to savedInstanceState).
Hence, changed the super call to null.
super.onCreate(null);
Got the idea from Fool-proof way to handle Fragment on orientation change if anyone's interested or is new to fragments like I am.
Related
My app uses a tabLayout which is defined in the main_activity layout. I then have a separate layout file per tab to place all the views for that tab.
In the tab layout files, I’d like to constrain a view to the bottom edge of the tabs. I don’t know how to do this as the tabLayout is defined in another layout file, and it doesn’t have a fixed height (and I don't really want it to), so I can’t just use the same dimension in the tab layout file.
I’ve seen that there’s an tag that you can use to pull content in from other layouts, but this doesn’t feel right, I don’t need the whole layout to be duplicated within the tab, I essentially just need to know the height of it.
Here’s my main_activity layout which contains the tabLayout.
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/backgroundColour"
tools:context=".MainActivity">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize"
android:theme="?attr/actionBarTheme"
app:layout_constraintTop_toTopOf="parent"/>
<android.support.design.widget.TabLayout
android:id="#+id/tabMenu"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="#id/toolbar">
<android.support.design.widget.TabItem
android:id="#+id/CostTab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/cost" />
<android.support.design.widget.TabItem
android:id="#+id/costTab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/distance" />
</android.support.design.widget.TabLayout>
<android.support.v4.view.ViewPager
android:id="#+id/viewPager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="#id/tabMenu"
/>
</android.support.constraint.ConstraintLayout>
You should populate the adapter for ViewPager with Fragments for each tabLayout you have or use plain views as adapter items. You can find more info in developer guide here: https://developer.android.com/guide/navigation/navigation-swipe-view
My app adds fragments with values to the main activity at runtime but I need to be able to change the screen orientation without losing those values. The main issue is my adding of android:configChanges="orientation|screenSize" to the manifest works, but a large amount of extra space is added to the top of the app, so at either orientation after the first change, about a fourth of the screen is inaccessible white space.
activity_main.xml
<android.support.design.widget.AppBarLayout
android:id="#+id/app_bar"
android:layout_width="match_parent"
android:layout_height="50dp"
android:fitsSystemWindows="true"
android:theme="#style/MyAppTheme">
</android.support.design.widget.AppBarLayout>
<include layout="#layout/content_main" />
</android.support.design.widget.CoordinatorLayout>
content_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.NestedScrollView 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:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="25dp"
android:fillViewport="true"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:context=".MainActivity"
tools:showIn="#layout/activity_main">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="60dp"
android:layout_marginTop="8dp">
<TextView
android:id="#+id/manu_label"
android:layout_width="wrap_content"
android:layout_height="20dp"
android:text="Manufacturer:"
android:textSize="12sp"
android:gravity="center"
android:layout_marginBottom="4dp"
android:layout_marginLeft="8dp"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"/>
<Spinner
android:id="#+id/manu_spinner"
android:theme="#style/SpinnerStyle"
android:layout_width="80dp"
android:layout_height="20dp"
android:dropDownWidth="150dp"
android:layout_marginLeft="8dp"
android:background="#drawable/cell_background"
android:layout_toRightOf="#id/manu_label"
android:layout_alignParentTop="true">
</Spinner>
<LinearLayout
android:id="#+id/panels_container"
android:orientation="vertical"
android:layout_below="#id/manu_spinner"
android:layout_alignParentLeft="true"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</LinearLayout>
</RelativeLayout>
</android.support.v4.widget.NestedScrollView>
My java code does not manipulate the view except to add fragments to a linear layout:
private View.OnClickListener cableListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
FragmentTransaction ft = manager.beginTransaction();
PanelsFragment frag = PanelsFragment.newInstance();
cables.add(frag);
ft.add(R.id.panels_container, frag, Integer.toString(trans.indexOf(frag)));
ft.commit();
}
};
Is there a way to prevent the extra space between my app bar and the scrollview, or do I need a different strategy? I did try overriding the onSaveInstanceState and onRestoreInstanceState, but my methods supposedly required a higher API than my minimum of 14. Any suggestions would be appreciated.
EDIT: Due to the nature of the project, I cannot provide a picture of the issue. When the app first starts, there is almost no space between the label and spinner with "manu" id's and the app bar. However, when the screen goes from portrait to landscape, at least 60dp of inaccessible space is between the app bar and the label and spinner. I noted that the 25dp of top margin for the content view was needed otherwise its contents started behind the app bar.
My problem was unexpectedly solved by specifying the height, width and margins for the content view in activity_main.xml:
<include
layout="#layout/content_main"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:layout_marginTop="0dp" />
i want to create fixed navigation layout, but there is a problem when i rotate device, margin-top of this layout is more than it has to be, so the question - how can i find height of this dark-blue header ( to use it as margin ), or maybe there is another way
<RelativeLayout
android:layout_width="match_parent"
android:layout_marginTop="55dp"
android:layout_height="80dp"
android:background="#drawable/panel_border"
android:layout_alignParentTop="true">
If I were you, I would go with this:
android:layout_marginTop="?attr/actionBarSize"
This attribute indicates correct height of the ActionBar / Toolbar.
The Toolbars height may be different for different APIs and that's the reason you should use ?android:attr or ?attr (when using support library).
? means that it comes from internal Android resources.
Let the android support library do it for you. Like this
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<! -- Your View -->
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/panel_border"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_scrollFlags="scroll|enterAlways">
</android.support.design.widget.AppBarLayout>
</android.support.design.widget.CoordinatorLayout>
take a look at this
I'm working on an android app and am using a toolbar at the top of the screen and a navigation bar at the bottom of the screen. I'm using a single activity to create the top and bottom toolbars and fragments to change the content between the toolbars. However, when the contents in the fragment go beyond the size of the screen, the bottom bar disappears.
Here is my home activity xml:
<?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:id="#+id/activity_home"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.rentables.testcenter.HomeActivity">
<include
android:id="#+id/toolbar_main"
layout="#layout/toolbar_main"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<fragment android:name="com.rentables.testcenter.HomeFragment"
android:id="#+id/fragment_place"
android:layout_weight="0"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:layout="#layout/fragment_home" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="bottom">
<include
android:id="#+id/toolbar_navigate"
layout="#layout/toolbar_navigate"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center|bottom"/>
</LinearLayout>
</LinearLayout>
Im guessing it's because of the inner linear layout I have, but I wasn't sure how else to get the nav bar to stay static at the bottom. Any help would be awesome. Thanks
Figured it out. I just changed the whole thing to a relative layout, got rid of the inner linear layout, and instead of gravity I used alignParentBottom="true".
I have an Activity that shows a video using VideoView with a custom MediaController. The system UI is hidden until the user taps the screen to show the MediaController (just like in YouTube or Photos app).
The following method takes care of hiding the system UI:
private void hideSystemUi() {
int flags = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
View.SYSTEM_UI_FLAG_FULLSCREEN |
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
getWindow().getDecorView().setSystemUiVisibility(flags);
}
And the layout of the Activity:
<FrameLayout android:id="#+id/root"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:focusable="true"
android:keepScreenOn="true">
<com.google.android.exoplayer.AspectRatioFrameLayout
android:id="#+id/video_frame"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center">
<SurfaceView
android:id="#+id/surface_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"/>
</com.google.android.exoplayer.AspectRatioFrameLayout>
</FrameLayout>
I then add the MediaController to video_frame via code like so:
mMediaController.setAnchorView(findViewById(R.id.video_frame));
Testing with Nexus 5, I noticed that when showing the MediaController, the soft navigation bar is overlapping the MediaController UI. I managed to fix it by adding the following attribute to the root of MediaController layout:
android:fitsSystemWindows="true"
So far so good. This worked perfectly fine as long as my Activity theme was Theme.AppCompat.NoActionBar. Now that I'm refactoring the app, getting it as per Material design guidelines for featuring, I have to show the ActionBar.
So I changed the theme to Theme.AppCompat and guess what? The system UI once again overlaps the MediaController. It seems that android:fitsSystemWindows="true" has absolutely no affect anymore.
I've tried to set android:fitsSystemWindows="true" directly to the Activity theme itself and it seemed to solve the overlapping issue, but then I got another issue where the VideoView was padded in a totally weird way from random direction, instead of scaling to fit the screen as it used to be.
I've spent hours on that and still can't figure out a clean solution.
Please note that I need a solution that works for Tablets and Phones together.
And as you probably know, on tablets, the soft navigation bar appears at the bottom of the screen while in landscape mode.
I prefer to solve the issue via XML if possible.
After examining Android Studio's Fullscreen Activity template, I noticed that in the FullscreenActivity layout they are using android:fitsSystemWindows="true" in a little bit different way than me.
Here's the layout that comes with the template (activity_fullscreen.xml):
<FrameLayout 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="#0099cc"
tools:context=".FullscreenActivity">
<!-- The primary full-screen view. This can be replaced with whatever view
is needed to present your content, e.g. VideoView, SurfaceView,
TextureView, etc. -->
<TextView android:id="#+id/fullscreen_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:keepScreenOn="true"
android:textColor="#33b5e5"
android:textStyle="bold"
android:textSize="50sp"
android:gravity="center"
android:text="#string/dummy_content"/>
<!-- This FrameLayout insets its children based on system windows using
android:fitsSystemWindows. -->
<FrameLayout android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<LinearLayout android:id="#+id/fullscreen_content_controls"
style="?metaButtonBarStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center_horizontal"
android:background="#color/black_overlay"
android:orientation="horizontal"
tools:ignore="UselessParent">
<Button android:id="#+id/dummy_button"
style="?metaButtonBarButtonStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="#string/dummy_button"/>
</LinearLayout>
</FrameLayout>
</FrameLayout>
I noticed that they have an additional FrameLayout container set with android:fitsSystemWindows="true" that wraps the actual layout container (in my case this was the MediaController) at the bottom of the screen.
Once I added a FrameLayout to wrap my MediaController layout as shown in the above code snippet my problem is gone! Really weird that I need to have additional layout container to solve this issue. Especially when Android Studio is saying now that I have "Useless Parent".
So to summarize, here is the fully working solution of how my Activity layout looks like:
<FrameLayout android:id="#+id/root"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:focusable="true"
android:keepScreenOn="true">
<com.google.android.exoplayer.AspectRatioFrameLayout
android:id="#+id/video_frame"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center">
<SurfaceView
android:id="#+id/surface_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"/>
</com.google.android.exoplayer.AspectRatioFrameLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<LinearLayout android:id="#+id/controller_frame"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center_horizontal"
android:orientation="horizontal">
</LinearLayout>
</FrameLayout>
</FrameLayout>
and I hook up the MediaController to controller_frame instead of video_frame as I did previously:
mMediaController.setAnchorView(findViewById(R.id.controller_frame));