Following XML is a test layout for my view. It shows a NavigationDrawer on the left side with a toolbar on top of the view. The toolbar shows a title and a hamburger-Icon on the top left to toggle the NavigationDrawer. Everything works fine:
My XML (I removed all height/width attributes because it's better readable):
<?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:fitsSystemWindows="true">
<LinearLayout
android:orientation="vertical">
<android.support.v7.widget.Toolbar
android:id="#+id/my_awesome_toolbar"
android:minHeight="?attr/actionBarSize"
android:background="?attr/colorPrimary" />
<!-- ** MY VIEW ELEMENTS **-->
</LinearLayout>
<LinearLayout
android:id="#+id/drawer_leftpane"
android:orientation="vertical"
android:layout_gravity="left|start"
android:background="#FFFFFF"
android:fitsSystemWindows="true">
<TextView
android:text="Test string on top of list" />
<android.support.v7.widget.RecyclerView
android:id="#+id/drawer_menulist"
android:scrollbars="vertical"
android:choiceMode="singleChoice"
android:divider="#null" />
</LinearLayout>
</android.support.v4.widget.DrawerLayout>
In the section <!-- ** MY VIEW ELEMENTS **--> I insert the view Elements for the different views (that's the only thing who changes between all views).
I have many views which need this layout above. I know about includes, merges and compound views and read many articles about these. But I am not able to create a layout for this special case and I would like to avoid copy paste the whole layout throughout all my views.
In the end I want something like this for all my views:
<?xml version="1.0" encoding="utf-8"?>
<MyDrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/drawer_layout"
android:fitsSystemWindows="true">
<!-- ** MY VIEW ELEMENTS **-->
</MyDrawerLayout>
Is that even possible? Or is there another way to achive this? Thanks in advance
Well, I would just use LayoutInflater.
First of all I would create FrameLayout as a container for my layouts.
Then I would inflate required layout.
And if I would need to inflate another layout, I would just do view_container.removeAllViews( ) and inflate that another layout.
Everything in action
main.xml
<!-- it's not full layout, I've just taken a fragment from your example -->
<LinearLayout
android:orientation="vertical" >
<android.support.v7.widget.Toolbar
android:id="#+id/my_awesome_toolbar"
android:minHeight="?attr/actionBarSize"
android:background="?attr/colorPrimary" />
<!-- This is where you hold required layout -->
<FrameLayout
android:id="#+id/view_container"
android:layout_width = "match_parent"
android:layout_height = "match_parent" />
</LinearLayout>
Main.java
public class Main extends AppCompatActivity
{
#Override public void onCreate( Bundle savedInstaceBundle )
{
super.onCreate( );
setContentView( R.layout.main );
FrameLayout view_container = ( FrameLayout ) findViewById( R.id.view_container );
/** To inflate layout **/
LayoutInflater inflater = getApplicationContext.getSystemService( Context.LAYOUT_INFLATER_SERVICE );
inflater.inflate( /*R.layout.my_layout */, view_container );
/** To remove layout in 'view_container' **/
view_container.removeAllViews( );
/** To change layout in 'view_container' **/
// 1. Remove all views
// 2. Inflate required layout
}
}
P.S. I wrote it all in here, so I may have made some mistakes but the idea is still the same!
You need to remove this. This is the wrong idea:
<LinearLayout
android:orientation="vertical">
<android.support.v7.widget.Toolbar
android:id="#+id/my_awesome_toolbar"
android:minHeight="?attr/actionBarSize"
android:background="?attr/colorPrimary" />
<!-- ** MY VIEW ELEMENTS **-->
</LinearLayout>
Just use this:
<android.support.v7.widget.Toolbar
android:id="#+id/my_awesome_toolbar"
android:minHeight="?attr/actionBarSize"
android:background="?attr/colorPrimary" />
Find the View in Java, and then add views you inflate into it.
Then you can have separate XML layouts for the different Toolbar configurations you have and inflate them dynamically.
E.G.
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
orientation:horizontal>
<TextView
android:id="#+id/action_bar_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:singleLine="true"
android:ellipsize="end"
android:layout_marginRight="#dimen/dp_fortytwo"
android:text="#string/app_name"
android:textColor="#color/primary_text"
android:textSize="#dimen/dp_eighteen"/>
</LinearLayout>
It's convenient to keep a Singleton class for your navigation that has a reference to a ViewGroup in the Toolbar. You could inflate an "actionbar" into the Toolbar:
toolBar = (Toolbar) drawerLayout.findViewById(R.id.toolbar);
context.setSupportActionBar(toolBar);
actionBar = (ViewGroup) LayoutInflater.from(context()).inflate(R.layout.actionbar, toolBar, false);
toolBar.addView(actionBar);
Then add views as needed dynamically:
LayoutInflater.from(context).inflate(R.layout.actionbar_home_icon, actionBar, true);
Related
My fragment contains lots of different views. Some views are already in the XML files like imageview,drawables, etc. and other views get filled with data after a successful response from Retrofit. The XML file also contains a toolbar and progressbar.
When data is coming from the server I want only toolbar and Progressbar to be shown and other content hidden. but the problem is I can't hide the whole view because it contains a toolbar and progress bar itself.
What should I do?
<RelativeLayout 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">
<androidx.appcompat.widget.Toolbar...>
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="#+id/swiperefresh_open_post"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="#id/bottom_sec">
<!-- this contains all Content I want to hide this -->
<ScrollView...>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
<!-- this contains content which is fixed at the bottom I also want to hide this -->
<FrameLayout...>
<include layout="#layout/progressbar_item" />
</RelativeLayout>
Just put the views to other places. If you use for example FrameLayout, you can have pretty flat structure, where Toolbar and ProgressBar are on the same hierarchy level as inner FrameLayout which contains the rest of the layout. So you can do something like this:
<FrameLayout
android:id="#+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="56dp" />
<FrameLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="56dp" >
<!-- Put your layout here -->
</FrameLayout>
<ProgressBar
android:id="#+id/progressbar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="gone" />
</FrameLayout>
and then just call
container.visibility = View.GONE
progressbar.visibility = View.VISIBLE
or
container.visibility = View.VISIBLE
progressbar.visibility = View.GONE
I have adopted the "one activity, multiple fragments" way of defining layouts for my Android (Xamarin) application. All views (fragments) share the same BottomNavigationView managed by MainActivity that adds each fragment to the same FrameLayout. But, as some fragments need to define their own AppBarLayouts, to for example create a CollapsingToolbarLayout, I can not just create a FragmentTransaction and put those fragments in the same FrameLayout container, as the Toolbar is part of the Activity's layout and thus not managed by the fragments. It would also seem counterproductive having to add and manage a Toolbar for each Fragment.
What I have tried so far:
Having a FrameLayout for each variation and then show/hide
accordingly (in layout for MainActivity) when making a
FragmentTransaction.
Use a fullscreen DialogFragment to show contents
above the active fragment.
Convert the "offending" fragment into an
Activity (makes it hard to handle the BottomNavigationView).
MainActivity currently looks like this (with some details omitted):
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
android:id="#+id/coordinator"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<include
android:id="#+id/appbar_main"
layout="#layout/toolbar_main"/>
<FrameLayout
android:id="#+id/fragment_container"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
<include
android:id="#+id/bottombar"
layout="#layout/toolbar_nav" />
</android.support.design.widget.CoordinatorLayout>
appbar_main layout (used by MainActivity)
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.AppBarLayout
android:id="#+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true">
<!-- logo layout -->
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="?attr/actionBarSize"
android:orientation="horizontal"
android:layout_gravity="center"
android:paddingTop="10dp"
android:paddingBottom="10dp">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
</android.support.v7.widget.Toolbar>
</android.support.design.widget.AppBarLayout>
appbar_collapsing layout (for example used to show a profile page)
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.AppBarLayout
android:id="#+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true">
<android.support.design.widget.CollapsingToolbarLayout
android:id="#+id/collapsing_toolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
app:contentScrim="#drawable/toolbar_app_bg"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">
<ffimageloading.views.ImageViewAsync
android:id="#+id/imageViewCover"
android:layout_width="match_parent"
android:layout_height="200dp"
app:layout_collapseMode="parallax"
app:layout_collapseParallaxMultiplier="0.9" />
<ffimageloading.views.ImageViewAsync
android:id="#+id/imageViewProfile"
android:layout_width="100dp"
android:layout_height="100dp"/>
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"/>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
The appbar_main layout provided above is quite simple and also the primary way of showing the Toolbar. appbar_collapsing differs from the main layout in that the Toolbar is nested within a CollapsingToolbarLayout to make it collapsible when scrolling while also collapsing two ImageView.
Any examples and advaree is much appreciated!
In fragments with bottom layout with changing needs for toolbars.
After testing different methods i concluded with this:
private void createMenus(Toolbar actionBarToolBar, #MenuRes int menu){
((MainActivity) Objects.requireNonNull(getActivity())).setSupportActionBar(actionBarToolBar);
actionBarToolBar.setTitle("");
actionBarToolBar.inflateMenu(menu);
}
Call this method here:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
mRootView = inflater.inflate(R.layout.fragment_profile, container, false);
createMenus(mToolbar,R.menu.profile_menu);
setHasOptionsMenu(true);
//add fragments to adapter
//...
return mRootView;
}
Then override this:
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
menu.clear();
inflater.inflate(R.menu.profile_menu, menu);
super.onCreateOptionsMenu(menu, inflater);
}
I want to have 3 layouts in my ScrollView but when I add them it actually doesn't scroll. I tried to put all layouts in different files, then include them, tried to put them in ListView and it doesn't work too. In this option, when I put in ScrollView the LinearLayout and there include the rest of the layouts the application show nothing. That's probably becouse I don't know how to refer to that nested layouts... This is my XML:
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<ScrollView android:layout_width="match_parent" android:layout_height="match_parent">
<LinearLayout android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
>
<include layout="#layout/first"/>
<include layout="#layout/second"/>
<include layout="#layout/third"/>
</LinearLayout>
</ScrollView>
</LinearLayout>
#EDIT views included (all are the same so I put just one):
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/first"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
>
</RelativeLayout>
And in the main activity I put the objects into layouts like this:
setContentView(R.layout.activity_main);
RelativeLayout first = (RelativeLayout) findViewById(R.id.first);
RelativeLayout second = (RelativeLayout) findViewById(R.id.second);
RelativeLayout third = (RelativeLayout) findViewById(R.id.third);
...some code creating views...
first.addView(myView1);
second.addView(myView2);
third.addView(myView3);
Need to put fix size in included layout, for example:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/first"
android:layout_width="match_parent"
android:layout_height="300dp"
/>
I don`t understand why do you need to add view manually when you already added it to the layout.
You should also eliminate top Linear Layout since there is no use of it.
Okay, I've been going through several StackOverflow posts now, but I'm still confused as to where this xml for my Toolbar goes.
<android.support.v7.widget.Toolbar
android:id=”#+id/my_awesome_toolbar”
android:layout_height=”wrap_content”
android:layout_width=”match_parent”
android:background=”#styles/colorPrimary” />
Does it go in my /layout/activity_main.xml?
Toolbar is a generalization of Action bars for use within app layouts, now to answer your question there are two practices:
Bad practice:
Bad practice is to define the Toolbar in every layouts.
Standard practice:
Standard practice is to define a layout and reference it in a base activity. You just need to include this Toolbar layout in whichever layout you want (by using <include>) and extend the defined base activity in whichever activity.
This standard practice will help you keeping a single code base for Toolbar and save your time from defining Toolbar every time.
Example: Google I/O 2014 android app
toolbar_actionbar_with_headerbar.xml
<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:iosched="http://schemas.android.com/apk/res-auto"
style="#style/HeaderBar"
iosched:theme="#style/ActionBarThemeOverlay"
iosched:popupTheme="#style/ActionBarPopupThemeOverlay"
android:id="#+id/toolbar_actionbar"
iosched:titleTextAppearance="#style/ActionBar.TitleText"
iosched:contentInsetStart="?actionBarInsetStart"
android:layout_width="match_parent"
android:layout_height="?actionBarSize" />
This toolbar layout is referenced in settings activity as given below:
activity_settings.xml
<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="match_parent"
android:orientation="vertical"
tools:context=".ui.SettingsActivity">
<include layout="#layout/toolbar_actionbar_with_headerbar" />
<FrameLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout>
As for me, I usually make a ToolbarActivity. Next, if you want your activity to have a toolbar, you just need to YourActivity extends ToolbarActivity.
public class ToolbarActivity extends AppCompatActivity {
#Override
public void setContentView(int layoutResID) {
super.setContentView(R.layout.activity_toolbar);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
LayoutInflater inflater = LayoutInflater.from(this);
View contentView = inflater.inflate(layoutResID, null);
LinearLayout layout = (LinearLayout) findViewById(R.id.layout);
layout.addView(contentView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
}
}
XML:
<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="match_parent"
android:orientation="vertical"
android:id="#+id/layout"
tools:context=".ToolbarActivity" >
<android.support.v7.widget.Toolbar
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:minHeight="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:id="#+id/toolbar" />
</LinearLayout>
I want to show a custom view as empty view in my list view in Drawer Layout!
I create a view in xml like this and called it view_custom_empty.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFff0000">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:text="NO RESULT"
android:textColor="#FFffffff" />
</RelativeLayout>
in my activity i set list view emptyview like this:
View emptyView = getLayoutInflater().inflate(R.layout.view_custom_empty, null);
ViewGroup viewGroup = (ViewGroup) drawerLayout.getParent();
viewGroup.addView(emptyView, 0);
drawerListview.setEmptyView(emptyView);
drawerListview.setAdapter(mDrawerAdapter);
But my custom empty view does not appear in my listview when it's empty!
I had the same Problem and finally found a solution to it.
You could actually set a separate layout.xml as an empty view, but then it won't be in the drawer, but inside the activity itself.
The activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<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"
android:fitsSystemWindows="false"
tools:openDrawer="start">
<!-- Your activity content here-->
<android.support.design.widget.NavigationView
android:id="#+id/navigation_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start">
<!-- Your ListView you want to be shown if not empty-->
<ListView
android:id="#+id/left_drawer"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="#android:color/white"/>
<!-- Here starts the empty view Layout-->
<RelativeLayout
android:id="#+id/empty_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFff0000"
android:visibility="gone">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:text="NO RESULT"
android:textColor="#FFffffff" />
</RelativeLayout>
</android.support.design.widget.NavigationView>
</android.support.v4.widget.DrawerLayout>
Add the empty_view to your list like this:
drawerListview.setAdapter(mDrawerAdapter);
drawerListview.setEmptyView(findViewById(R.id.empty_view));
Step by step on how to add an EmptyView to your list in the Navigation Drawer
Add your EmptyView (Layout) as a child of <android.support.design.widget.NavigationView inside the layout of your Navigation Drawer.
Set the Layouts/ Views visibility which holds the EmptyView to gone. In your case RealtiveLayout android:visibility="gone"
Add a Id to the Layout/View from point 2, you refer to in the activity
Add the EmptyView to your list like this: drawerListview.setAdapter(mDrawerAdapter);
drawerListview.setEmptyView(findViewById(R.id.empty_view));
Explanation:
The whole Navigation drawer actually works without <android.support.design.widget.NavigationView. But adding your list and the empty view as a child, makes sure the child items are inside the navigation drawer and not inside your content area. It also sets the Navigation drawer width automatically to match the Material design guidelines on all screen sizes.
As soon as you set your adapter to something not null, the empty view will be dismissed. You need to setAdapter when it's ready to be shown.