I am creating an Android app right now and I have a Frame which shell contain fragments. Till now all works fine, but I have come to a question which I cannot fully understand.
I have a Frame which is the entire screen (FrameLayout - should i use a FrameLayout as the main Frame?) and inside this Frame there are fragments that change, depending on the users interaction. These fragments are in the .xml files FrameLayouts. I am wondering now whether they can or should be FrameLayouts or fragments... I created a Google Maps frgment which is a fragment ideed and that made me thinking.
So my question ist: Does it make a difference or has it any impact on the perfomance or can I simple use whatever serves it's purpose?
To show what I mean, here are some code samples:
(Inside the FrameLayout inside the Framelayout are all fragments put)
MainFrame (activity_main.xml):
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
tools:ignore="MergeRootFrame" >
<FrameLayout
android:id = "#+id/mainFrame"
android:layout_width = "match_parent"
android:layout_height = "match_parent"
android:layout_marginBottom = "#dimen/bottom_Main_Tabs">
</FrameLayout>
<LinearLayout
android:layout_width = "match_parent"
android:layout_height = "#dimen/bottom_Main_Tabs"
android:layout_gravity = "bottom"
android:background="#color/grey2"
>
<ImageButton
android:id = "#+id/bottomButton_home"
android:layout_height = "match_parent"
android:layout_width = "0dp"
android:layout_weight = "1.0"
android:layout_marginLeft = "2dp"
android:layout_marginRight = "2dp"
android:background = "#drawable/ic_home_white"
android:onClick = "openHome"
/>
[...]
</LinearLayout>
<RelativeLayout
android:id = "#+id/TopBar"
android:layout_width = "match_parent"
android:layout_height = "#dimen/top_Bar_Hight"
android:layout_gravity="top"
android:background="#color/grey_transparentBy50"
>
<ImageView
android:id= "#+id/TopBarLogo"
android:layout_width = "#dimen/top_Bar_Hight"
android:layout_height = "#dimen/top_Bar_Hight"
android:background="#drawable/ic_launcher"
/>
[...]
</RelativeLayout>
</FrameLayout>
One Fragment (FrameLayout:)
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/home_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/blue"
tools:context="com.domain.app.HomeFragment">
<!-- TODO: Update blank fragment layout -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="50dp"
android:textSize="100sp"
android:text="Home" />
</FrameLayout>
Another Frament (fragment)
<fragment 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:id="#+id/map"
tools:context="com.domain.app.MapsActivity"
android:name="com.google.android.gms.maps.MapFragment"
tools:layout = "#layout/activity_main"
/>
Is too hae problems with the GoogleMaps implementation but I have not spent enough time on it yet to ask about help here.
Thanks in advance.
John
If you are attaching fragments in xml like GoogleMapFragment or by using FrameLayout(or any other ViewGroup like LinearLayout or RelativeLayout) in xml. Both ways are same. It is more likely creating a textview programmatically (i.e. in Java) or defining it in xml.
Using fragment in Java:
FragmentManager fragmentManager = getFragmentManager()
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
ExampleFragment fragment = new ExampleFragment();
fragmentTransaction.add(R.id.fragment_container, fragment);
fragmentTransaction.commit();
and in xml
<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" />
Here R.id.fragment_container is id of your Frame Layout.
Using fragment in XML:
<fragment android:name="com.example.ExampleFragment"
android:id="#+id/fragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
In case of Fragment in XML your fragment will be defined by <fragment/> xml tag and on the other side when we are using fragments programmatically, your FrameLayout will work as a container for your fragment.
Conclusion: Using FrameLayout will increase a hierarchy by one but it will not effect your performance very much.
See: http://developer.android.com/guide/components/fragments.html#Adding
The android:name attribute in the specifies the Fragment
class to instantiate in the layout. When the system creates this
activity layout, it instantiates each fragment specified in the layout
and calls the onCreateView() method for each one, to retrieve each
fragment's layout. The system inserts the View returned by the
fragment directly in place of the element.
Related
Since I only changed from buttons to RecyclerView (and it worked just fine with the buttons), I know my java code is working fine, so now I face a problem because clicking a cards in the RecyclerView calls the fragment with the FragmentManager, but not showing it.
Here is my activity.xml code.
<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:orientation="vertical">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".mainSearch"
android:background="#f2f2f2">
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/recyclerView"
android:orientation="horizontal" />
</androidx.constraintlayout.widget.ConstraintLayout>
<fragment
android:name="com.diamcom.blue.StoneCodeFragment"
android:id="#+id/fragment_place"
android:layout_width="match_parent"
android:layout_height="match_parent">
</fragment>
</LinearLayout>
I wonder what am I doing wrong ?
I think the issue you have here is having both the recyclerview and the fragment as match_parent for both width and height. A way I think you can do that is by wrapping the containerview which holds the recyclerview and the fragment in a framelayout and making the containerview to be gone when you click on any of the cards in the recyclerview.
I'm using the layout below, The CoordinatorLayout holds inside it AppBarLayout (With Toolbar) and the fragment layout.
I'm using app:layout_scrollFlags in my Toolbar and app:layout_behavior="#string/appbar_scrolling_view_behavior" in the fragment, so the Toolbar appear and disappear (hide/show) with scrolling my fragment content.
My problem: when I scroll in fragment A and therefore the toolbar disappear, then I use the BottomNavigationView to go to fragment B the toolbar remains hidden.
I want the toolbar to appear every time I open new fragment.
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/containerMain"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="#+id/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/AppBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_gravity="top"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:layout_scrollFlags="scroll|enterAlways"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light"
app:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar" />
</com.google.android.material.appbar.AppBarLayout>
<fragment
android:id="#+id/nav_host_fragment"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:navGraph="#navigation/mobile_navigation" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/nav_view"
android:layout_width="0dp"
android:layout_height="#dimen/nav_bar"
android:layout_marginStart="0dp"
android:layout_marginEnd="0dp"
android:background="?android:attr/windowBackground"
app:itemIconTint="#drawable/bottom_color_nav"
app:itemTextColor="#drawable/bottom_color_nav"
app:layout_constraintBottom_toBottomOf="#id/main_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:menu="#menu/bottom_nav_menu" />
</androidx.constraintlayout.widget.ConstraintLayout>
I would assume that the xml you posted is your layout for your MainActivity(), if so create a reference to your Toolbar in your MainActivty and create a function in your MainActivty() to access/change your Toolbar collapse states.
In your Fragments, create a reference to your MainActivity to then access the function to change the state of your Toolbar.
I cannot test as from work, but I have used same code flow to do the same stuff when using only MainActivity with Inner Fragments as the navigation flow of the app.
Below not exact working or tested code, but same idea/flow
//my fragment function to access MainActivity().changeToolbarState(boolean)
changeToolbar(state: boolean) {
if(state){
//true
//show toolbar
MainActivty().changeToolbarState(true)
}else{
//false
//collapse/hidetoolbar
MainActivty().changeToolbarState(false)
}
}
The best alternative could be enabling setExpanded property of app bar layout to true with the following code inside the fragment. Here, MainActivity.appBarLayout is the static variable defined in Main Activity referenced to App Bar Layout.
#Override
public void onPause() {
super.onPause();
MainActivity.appBarLayout.setExpanded(true);
}
My Android app is a fullscreen OpenGL ES 2.0 app, so the main content is a custom extension of GLSurfaceView.
The activity layout looks like this:
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/drawer_layout">
<FrameLayout android:id="#+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ListView android:id="#+id/left_drawer"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:choiceMode="singleChoice"
android:divider="#android:color/transparent"
android:dividerHeight="0dp"
android:background="#111" />
</android.support.v4.widget.DrawerLayout>
I then add my GLSurfaceView using the addView method of the FrameLayout.
If i don't do this, the Drawer works as expected.
The ListView seems to be pulled out correctly when i swipe it in, as i can't interact with the GLSurfaceView anymore until i swipe it back to the left. But it's not displayed at all, like the GLSurfaceView is allways rendered ontop of it.
How do i get a DrawerLayout working with a GLSurfaceView as its content?
I've just faced the same problem, and I've found quite a silly workaround for it. This issue seems to only affect DrawerLayouts, and not regular Views. So simply place an empty View over your GLSurfaceView, to mask it away from the Drawer.
Here's my stripped down layout file as a sample for you:
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/drawerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<GLSurfaceView
android:id="#+id/glSurfaceView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<View
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
<FrameLayout
android:id="#+id/frameLayoutDrawer"
android:layout_width="#dimen/navigation_drawer_width"
android:layout_height="match_parent"
android:layout_gravity="end"
android:background="#android:color/white" />
</android.support.v4.widget.DrawerLayout>
The submit button in the activity layout floats to the top left of the phone screen even after the fragment has been added resulting in it obscuring some of the fragment's content. should it not be pushed down when the following code is called:
currentFragment = MyFragment.newInstance();
getSupportFragmentManager().beginTransaction()
.replace(R.id.my_fragment, currentFragment).commit();
Activity Layout:
<?xml version="1.0" encoding="UTF-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<fragment android:name="com.mycompany.myapp.MyFragment"
android:id="#+id/my_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:layout="#layout/my_fragment_layout"/>
<Button
android:id="#+id/submit_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/submit_button_text"
/>
</FrameLayout>
Fragment layout (my_fragment_layout.xml):
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/question_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/text"/>
<RadioGroup android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/radio_buttons"></RadioGroup>
</LinearLayout>
What am I missing about fragments and layouts here?
As per your requirement , your Activity parent layout should be LinearLayout or RelativeLayout not FrameLayout. Also set a layout weight for Fragment layout, so that it will occupy the remaining space, used by the Button
Change your activity layout like this
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<fragment
android:id="#+id/my_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:layout="#layout/my_fragment_layout"
android:layout_weight="100"/>
<Button
android:id="#+id/submit_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="submit_button_text"/>
</LinearLayout>
One more suggestion here. If your adding your Fragment using Fragment Manager programmatically you can just define the Fragment container as FrameLayout in XML (Any way your creating the instance of fragment in code).
<FrameLayout
android:id="#+id/my_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="100"/>
Hope this helps to fix your issue.
I am trying to add a navigation drawer to an activity which will contain one or two fragments. I would like this activity to have a navigation drawer associated with it regardless of how many fragments are displayed. To do this i figured I'd need two xml files, one for the activity and one for the fragment. This seems to work except for the fact that the when the navigation drawer is opened, it is "under" the normal content view. Am I doing something wrong? or is there a way to increase the z index of the drawer?
Here is my onCreate() in the activity,
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_alarm_list);
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(android.R.id.content, new AlarmListFragment());
fragmentTransaction.commit();
}
and here are my xml layouts:
Activity:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<ListView
android:id="#+id/alarm_list"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</ListView>
</LinearLayout>
<ListView android:id="#+id/left_drawer"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:choiceMode="singleChoice"
android:divider="#android:color/transparent"
android:dividerHeight="0dp"
android:background="#111"/>
</android.support.v4.widget.DrawerLayout>
Fragment:
<?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="match_parent"
android:orientation="vertical" >
<ListView
android:id="#id/android:list"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</ListView>
</LinearLayout>
I'd appricate any suggestions on how to go about this! Thanks!
I wonder how the code is working for you. The above code should not work. You put the fragment at android.R.id.content. But I don't see that inside the DrawerLayout your Activity XML. Furthermore, the Drawer Layout should only have a FrameLayout (with id 'content' in your case) and a ListView as mentioned here. So you need to have add a FrameLayout as below in your Activity XML for which you are implementing the navigation drawer.
<FrameLayout
android:id="#+id/content"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Also you will have to move the xml into another fragment which you can load when the activity starts or when desired.