is it possible to have an abstract activity which defines the layout (navigation and so on) and a subclasses that define content of the activity? How about xml layout files?
I mean I have an xml
<xxx.DefaultNavigationDrawer xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/navigation_drawer"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<FrameLayout
android:id="#+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<!-- Fragment contents go in here -->
</FrameLayout>
<ListView
android:id="#+id/navigation_drawer_list"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:layout_weight="1"
android:background="#drawable/calendar"
android:choiceMode="singleChoice"
android:divider="#color/calendar_divider"
android:dividerHeight="1dp" />
</xxx.DefaultNavigationDrawer>
and I'd like all my activities to have such layout. The only thing which would change is marked.
You can set your layout in your base Activity class and then in your derived Activity's onCreate you can call FragmentManager.replace() to replace the contents of your FrameLayout with your fragment.
Related
My app consists of multiple activities, they all have a common layout in the sense that they are drawer layout, have a tool bar, but they have different main content. Specifically, their complete layouts are as follows
<?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">
<RelativeLayout
android:id="#+id/relative_layout"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<android.support.v7.widget.Toolbar
android:id="#+id/action_bar"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
/>
.......main content, this is different for each activity..........
</RelativeLayout>
</android.support.v4.widget.DrawerLayout>
Since the shared components are defined at "parent level", I'm not sure how to structure these layouts so that the generic layout is only defined once. Is it possible to achieve that? Thanks.
Two options:
1. ViewStub
Define the main layout with a ViewStub where you will have different sub-layouts.
A ViewStub is an invisible, zero-sized View that can be used to lazily
inflate layout resources at runtime. When a ViewStub is made visible,
or when inflate() is invoked, the layout resource is inflated. The
ViewStub then replaces itself in its parent with the inflated View or
Views.
In each Activity you set the same layout and then inflate the specific sub-layout onto the ViewStub.
2. Fragments
If you want to avoid having massive quantities of code on a single Activity you might want to think about using Fragments.
Some other topics to guide you:
How to use View Stub in android
Loading Views On Demand
Yes it is possible by using Fragment. For this structure first you need to define a FrameLayout in your activity_main.xml . This framelayout will be replaced by the contents of the fragments over the time.
<android.support.v4.widget.DrawerLayout 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/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:id="#+id/container_toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<include
android:id="#+id/toolbar"
layout="#layout/toolbar" />
</LinearLayout>
<FrameLayout
android:id="#+id/container_body"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1" >
</FrameLayout>
</LinearLayout>
<fragment
android:id="#+id/fragment_navigation_drawer"
android:name="com.safallwa.zahan.oreader.FragmentDrawer"
android:layout_width="#dimen/nav_drawer_width"
android:layout_height="match_parent"
android:layout_gravity="start"
app:layout="#layout/fragment_navigation_drawer"
tools:layout="#layout/fragment_navigation_drawer" />
</android.support.v4.widget.DrawerLayout>
Then you can create your layouts as you want and classes as those extends Fragment . Set these new layouts as contentView of Fragment classes. Now these fragments can replace that FrameLayout of activity_main. Suppose we have a Framgent class name First_Fragment.Java then we can show that fragment by replacing activity_main framelayout by below code
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.container_body, fragment);//container_body is the id of the framelayout
fragmentTransaction.commit();
For full featured example with navigation drawer also we can follow below link
http://www.codedisect.com/?p=134
This is my .xml for the current view:
<!-- A DrawerLayout is intended to be used as the top-level content view using match_parent for both width and height to consume the full space available. -->
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".nav">
<!-- As the main content view, the view below consumes the entire
space available using match_parent in both dimensions. -->
<FrameLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="com.google.android.gms.maps.MapFragment"/>
<ImageButton
android:text="Center"
android:onClick="centerMap"
android:id="#+id/center_button"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:src="#drawable/center_button_iconn"
android:layout_width="45dp"
android:layout_height="55dp"
android:layout_gravity="start|bottom" />
<fragment android:id="#+id/navigation_drawer"
android:layout_width="#dimen/navigation_drawer_width"
android:layout_height="match_parent"
android:layout_gravity="start"
android:name="nuathackmit.yo.NavigationDrawerFragment"
tools:layout="#layout/fragment_navigation_drawer" />
</FrameLayout>
<!-- android:layout_gravity="start" tells DrawerLayout to treat
this as a sliding drawer on the left side for left-to-right
languages and on the right side for right-to-left languages.
If you're not building against API 17 or higher, use
android:layout_gravity="left" instead. -->
<!-- The drawer is given a fixed width in dp and extends the full height of
the container. -->
</android.support.v4.widget.DrawerLayout>
Originally, my fragments (and ImageButton) existed outside of the framelayout. However, since I wanted the organize which object appeared above which, I moved them into the framelayout.
However:
mMap = ((MapFragment) getFragmentManager().findFragmentById(R.id.map)).getMap();
Where this code originally worked, it now returns an NPE.
How do I get the fragment by ID when moved into a FrameLayout?
I created my own DrawerLayout here is the XML:
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<!-- The main content view -->
<LinearLayout
android:id="#+id/content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" />
<!-- The navigation drawer -->
<ListView
android:id="#+id/navigation"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:choiceMode="singleChoice"
android:divider="#android:color/white"
android:dividerHeight="1dp"
android:background="#FFF"/>
</android.support.v4.widget.DrawerLayout>
Instead of FrameLayout like you get by default I chose LinearLayout because it allows me to set margins/paddings and automatically adding elements bellow each other. Anyhow when I call:
LinearLayout layout = (LinearLayout) findViewById(R.id.content);
I get an exception saying cannot cast from FrameLayout to LinearLayout but I don't have LinearLayout defined anywhere.
You have stumbled on an interesting quirk on how Android creates Layouts.
The top-most layout is a FrameLayout that the system puts your layout in to. Its id is android.R.id.content. You probably importing the android.R file into your app so you're referencing android.R.id.content instead of your project's R file which would have the correct ID.
I am new to android, I follow this tutorial to create Navigation Drawer here
I make the navigation drawer successfully but I dont know how to change framelayout to my custom layout with button, textview....My app just show menu and blank framelayout, how can I solve this ?
<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" >
<FrameLayout
android:id="#+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="asdsadsad" />
<ListView
android:id="#+id/left_drawer"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="#color/purple_dark"
android:choiceMode="singleChoice"
android:divider="#android:color/darker_gray"
android:dividerHeight="0.1dp"
android:listSelector="#drawable/ic_drawer"/>
</android.support.v4.widget.DrawerLayout>
you can use a RelativeLayout on LinearLayout instead of FrameLayout and you can build your whole layout inside that
If you need to add another layout you need to gie it to your closeDrawerand drawerOpen.
Please refer my answer here
I want to show two fragments (one listfragment and other is details fragment) in the main contentview of navigation drawer like below:
But AFAIK, there can be only one view in the main contentview of drawerLayout. So how can achieve this?
Anything you put inside the FrameLayout will be in the main content view.
You can put whatever you want (including multiple Fragments) inside this FrameLayout:
<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">
<!-- The main content view -->
<FrameLayout
android:id="#+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- YOUR CONTENT HERE -->
<!-- Could be layout with multiple views or fragments -->
</FrameLayout
<!-- The navigation drawer -->
<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>