在哪里添加工具栏和导航栏
Where to add toolbar and navigation bar
我正在使用 android 导航控制器。
我的主 activity 包含一个导航片段,但工具栏和导航底部栏等其他组件应该放在哪里,在主 activity 或子片段中?
activity_main.xml
<?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"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:popupTheme="@style/AppTheme.PopupOverlay" />
<fragment
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
app:defaultNavHost="true"
app:navGraph="@navigation/navigation" />
<android.support.design.widget.BottomNavigationView
android:id="@+id/bottom_nav_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:menu="@menu/menu_bottom_nav" />
</LinearLayout>
fragment_home.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">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerList"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical" />
</RelativeLayout>
或者 ToolBar 和 BottomNavigationView 应该像这样 fragment_home.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">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:popupTheme="@style/AppTheme.PopupOverlay" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerList"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical" />
<android.support.design.widget.BottomNavigationView
android:id="@+id/bottom_nav_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:menu="@menu/menu_bottom_nav" />
</RelativeLayout>
我会给你举个例子。请记住,我正在为 SDK 28+ 使用最新的 androidx 进行编译,因此如果您使用的是旧版本,您的命名空间会略有不同。
我也在使用数据绑定和 Kotlin,所以如果您不使用数据绑定,请不要使用布局和数据标签。
工具栏
<layout 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">
<data>
PUT BINDING VARIABLES HERE
</data>
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/SSTheme.AppBarOverlay">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?android:attr/actionBarSize"
android:theme="@style/ToolbarTextAppearance">
</androidx.appcompat.widget.Toolbar>
</com.google.android.material.appbar.AppBarLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
主要ACTIVITY
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable name="activity" type="com.a35.activities.MainActivity"/>
<variable name="iBindingRecyclerView" type="com.a35.interfaces.IBindingRecyclerView"/>
</data>
<androidx.drawerlayout.widget.DrawerLayout
android:id="@+id/drawerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="false"
tools:openDrawer="start">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!--TOP TOOLBAR-->
<include
android:id="@+id/toolbarMain"
layout="@layout/toolbar_main"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<!--TOP BLACK LINE-->
<View
android:id="@+id/vRedLine"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_2"
android:background="@color/black" />
<!-- FrameLayout is used to insert fragments to display -->
<FrameLayout
android:id="@+id/fragPlaceholder"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</LinearLayout>
<com.google.android.material.navigation.NavigationView
android:id="@+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
android:background="@color/colorPrimary">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="@layout/nav_drawer_header"
android:id="@+id/navHeader"/>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/lstMenuItems"
android:layout_below="@+id/navHeader"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:bindRcvInterface="@{iBindingRecyclerView}"
app:bindRcvList="@{activity.getDrawerItemList}"/>
<ImageView
android:id="@+id/imgBottomLogo"
android:layout_width="@dimen/dp_160"
android:layout_height="@dimen/dp_35"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="@dimen/dp_35"
android:src="@drawable/scott_logo" />
</RelativeLayout>
</com.google.android.material.navigation.NavigationView>
</androidx.drawerlayout.widget.DrawerLayout>
</layout>
注意 Main Activity 包含位于抽屉布局内的导航视图,其中包含用于构建抽屉内容的 Recycler 视图。
除此之外,您还会看到名为 fragPlaceHolder 的片段内容占位符。
最后请注意,父布局是一个 LinearLayout,第一个元素是我们认为合适的工具栏包含项。
接下来是您的样式。如果您打算将工具栏用作操作栏,则需要使用不依赖于操作栏的样式。 (为了记录,您应该使用工具栏)
风格
<!--Full Screen-->
<style name="A35.FullScreen">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
<item name="android:windowFullscreen">true</item>
</style>
清单
<application
android:name=".application.A35Application"
android:allowBackup="true"
android:icon="@mipmap/a35_logo"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/A35.FullScreen">
如果更适合您的需要,您也可以将其放在单独的活动中。
现在你还剩两步。
您需要调用 setActionToolbar 并传递您找到的 UI 或者如果您使用的是简单易行的 kotlin 和数据绑定,则使用合成视图。所以在你的 onCreate AFTER 添加视图。
setSupportActionBar(toolbar)
你没有问这个,但我也会提供。当你需要改变你的片段时,我通常有一个 BaseActivity 和一个像这样的辅助方法。
protected fun swapFragment(fragment: BaseFragment, @Nullable bundle: Bundle?, hideCurrentFrag: Boolean = false) {
if (fragment.isVisible) {
A35Log.e(mClassTag, "swapFragment called on already visible fragment")
return
}
A35Log.v(mClassTag, "swapFragment( ${fragment.javaClass.simpleName} )")
val currentFragBundle = fragment.arguments
if (currentFragBundle == null && bundle != null) {
fragment.arguments = bundle
A35Log.v(mClassTag, "current bundle is null, so setting new bundle passed in")
} else if (bundle != null) {
fragment.arguments?.putAll(bundle)
A35Log.v(mClassTag, "current fragment bundle was not null, so add new bundle to it")
}
val fragmentManager = supportFragmentManager
fragmentManager.executePendingTransactions()
val fragmentTransaction = fragmentManager.beginTransaction()
//Make sure the requested fragment isn't already on the screen before adding it
if (fragment.isAdded) {
A35Log.v(mClassTag, "Fragment is already added")
if (fragment.isHidden) {
A35Log.v(mClassTag, "Fragment is hidden, so show it")
fragmentTransaction.show(fragment)
if(hideCurrentFrag) {
A35Log.v(mClassTag, "hideCurrentFlag = true, hiding current fragment $mSelectedFragment")
fragmentTransaction.hide(mSelectedFragment!!)
}else{
A35Log.v(mClassTag, "hideCurrentFlag = false, removing current fragment $mSelectedFragment")
fragmentTransaction.remove(mSelectedFragment!!)
}
}else{
A35Log.v(mClassTag, "Fragment is already visible")
}
}else if(mSelectedFragment == null){
A35Log.v(mClassTag,"mSelectedFragment = null, so replacing active fragment with new one ${fragment.javaClass.simpleName}")
fragmentTransaction.replace(R.id.fragPlaceholder, fragment)
}else{
A35Log.v(mClassTag, "Fragment is not added, so adding to the screen ${fragment.javaClass.simpleName}")
fragmentTransaction.add(R.id.fragPlaceholder, fragment)
if(hideCurrentFrag) {
A35Log.v(mClassTag, "hideCurrentFlag = true, hiding current fragment $mSelectedFragment")
fragmentTransaction.hide(mSelectedFragment!!)
}else{
A35Log.v(mClassTag, "hideCurrentFlag = false, removing current fragment $mSelectedFragment")
fragmentTransaction.remove(mSelectedFragment!!)
}
}
A35Log.v(mClassTag, "committing swap fragment transaction")
fragmentTransaction.commit()
A35Log.v(mClassTag, "mSelectedFragment = ${fragment.javaClass.simpleName}")
mSelectedFragment = fragment
}
注意* 虽然交换片段相当普遍,但您需要确保正确处理您的需求。应该隐藏还是删除。它应该处理捆绑包还是忽略它们。我提供给您的方法基本上是显示不存在和隐藏片段,而不是在被告知隐藏片段时将其删除。
处理为导航抽屉构建适配器和列表以及连接侦听器点击这些项目的过程未在此处显示,因为这不是您的问题并且超出了此问题的范围。我不想让我的回答过于臃肿,所以希望这就是你需要开始的全部内容。
快乐编码。
我正在使用 android 导航控制器。
我的主 activity 包含一个导航片段,但工具栏和导航底部栏等其他组件应该放在哪里,在主 activity 或子片段中?
activity_main.xml
<?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"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:popupTheme="@style/AppTheme.PopupOverlay" />
<fragment
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
app:defaultNavHost="true"
app:navGraph="@navigation/navigation" />
<android.support.design.widget.BottomNavigationView
android:id="@+id/bottom_nav_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:menu="@menu/menu_bottom_nav" />
</LinearLayout>
fragment_home.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">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerList"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical" />
</RelativeLayout>
或者 ToolBar 和 BottomNavigationView 应该像这样 fragment_home.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">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:popupTheme="@style/AppTheme.PopupOverlay" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerList"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical" />
<android.support.design.widget.BottomNavigationView
android:id="@+id/bottom_nav_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:menu="@menu/menu_bottom_nav" />
</RelativeLayout>
我会给你举个例子。请记住,我正在为 SDK 28+ 使用最新的 androidx 进行编译,因此如果您使用的是旧版本,您的命名空间会略有不同。
我也在使用数据绑定和 Kotlin,所以如果您不使用数据绑定,请不要使用布局和数据标签。
工具栏
<layout 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">
<data>
PUT BINDING VARIABLES HERE
</data>
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/SSTheme.AppBarOverlay">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?android:attr/actionBarSize"
android:theme="@style/ToolbarTextAppearance">
</androidx.appcompat.widget.Toolbar>
</com.google.android.material.appbar.AppBarLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
主要ACTIVITY
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable name="activity" type="com.a35.activities.MainActivity"/>
<variable name="iBindingRecyclerView" type="com.a35.interfaces.IBindingRecyclerView"/>
</data>
<androidx.drawerlayout.widget.DrawerLayout
android:id="@+id/drawerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="false"
tools:openDrawer="start">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!--TOP TOOLBAR-->
<include
android:id="@+id/toolbarMain"
layout="@layout/toolbar_main"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<!--TOP BLACK LINE-->
<View
android:id="@+id/vRedLine"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_2"
android:background="@color/black" />
<!-- FrameLayout is used to insert fragments to display -->
<FrameLayout
android:id="@+id/fragPlaceholder"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</LinearLayout>
<com.google.android.material.navigation.NavigationView
android:id="@+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
android:background="@color/colorPrimary">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="@layout/nav_drawer_header"
android:id="@+id/navHeader"/>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/lstMenuItems"
android:layout_below="@+id/navHeader"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:bindRcvInterface="@{iBindingRecyclerView}"
app:bindRcvList="@{activity.getDrawerItemList}"/>
<ImageView
android:id="@+id/imgBottomLogo"
android:layout_width="@dimen/dp_160"
android:layout_height="@dimen/dp_35"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="@dimen/dp_35"
android:src="@drawable/scott_logo" />
</RelativeLayout>
</com.google.android.material.navigation.NavigationView>
</androidx.drawerlayout.widget.DrawerLayout>
</layout>
注意 Main Activity 包含位于抽屉布局内的导航视图,其中包含用于构建抽屉内容的 Recycler 视图。
除此之外,您还会看到名为 fragPlaceHolder 的片段内容占位符。
最后请注意,父布局是一个 LinearLayout,第一个元素是我们认为合适的工具栏包含项。
接下来是您的样式。如果您打算将工具栏用作操作栏,则需要使用不依赖于操作栏的样式。 (为了记录,您应该使用工具栏)
风格
<!--Full Screen-->
<style name="A35.FullScreen">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
<item name="android:windowFullscreen">true</item>
</style>
清单
<application
android:name=".application.A35Application"
android:allowBackup="true"
android:icon="@mipmap/a35_logo"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/A35.FullScreen">
如果更适合您的需要,您也可以将其放在单独的活动中。
现在你还剩两步。
您需要调用 setActionToolbar 并传递您找到的 UI 或者如果您使用的是简单易行的 kotlin 和数据绑定,则使用合成视图。所以在你的 onCreate AFTER 添加视图。
setSupportActionBar(toolbar)
你没有问这个,但我也会提供。当你需要改变你的片段时,我通常有一个 BaseActivity 和一个像这样的辅助方法。
protected fun swapFragment(fragment: BaseFragment, @Nullable bundle: Bundle?, hideCurrentFrag: Boolean = false) {
if (fragment.isVisible) {
A35Log.e(mClassTag, "swapFragment called on already visible fragment")
return
}
A35Log.v(mClassTag, "swapFragment( ${fragment.javaClass.simpleName} )")
val currentFragBundle = fragment.arguments
if (currentFragBundle == null && bundle != null) {
fragment.arguments = bundle
A35Log.v(mClassTag, "current bundle is null, so setting new bundle passed in")
} else if (bundle != null) {
fragment.arguments?.putAll(bundle)
A35Log.v(mClassTag, "current fragment bundle was not null, so add new bundle to it")
}
val fragmentManager = supportFragmentManager
fragmentManager.executePendingTransactions()
val fragmentTransaction = fragmentManager.beginTransaction()
//Make sure the requested fragment isn't already on the screen before adding it
if (fragment.isAdded) {
A35Log.v(mClassTag, "Fragment is already added")
if (fragment.isHidden) {
A35Log.v(mClassTag, "Fragment is hidden, so show it")
fragmentTransaction.show(fragment)
if(hideCurrentFrag) {
A35Log.v(mClassTag, "hideCurrentFlag = true, hiding current fragment $mSelectedFragment")
fragmentTransaction.hide(mSelectedFragment!!)
}else{
A35Log.v(mClassTag, "hideCurrentFlag = false, removing current fragment $mSelectedFragment")
fragmentTransaction.remove(mSelectedFragment!!)
}
}else{
A35Log.v(mClassTag, "Fragment is already visible")
}
}else if(mSelectedFragment == null){
A35Log.v(mClassTag,"mSelectedFragment = null, so replacing active fragment with new one ${fragment.javaClass.simpleName}")
fragmentTransaction.replace(R.id.fragPlaceholder, fragment)
}else{
A35Log.v(mClassTag, "Fragment is not added, so adding to the screen ${fragment.javaClass.simpleName}")
fragmentTransaction.add(R.id.fragPlaceholder, fragment)
if(hideCurrentFrag) {
A35Log.v(mClassTag, "hideCurrentFlag = true, hiding current fragment $mSelectedFragment")
fragmentTransaction.hide(mSelectedFragment!!)
}else{
A35Log.v(mClassTag, "hideCurrentFlag = false, removing current fragment $mSelectedFragment")
fragmentTransaction.remove(mSelectedFragment!!)
}
}
A35Log.v(mClassTag, "committing swap fragment transaction")
fragmentTransaction.commit()
A35Log.v(mClassTag, "mSelectedFragment = ${fragment.javaClass.simpleName}")
mSelectedFragment = fragment
}
注意* 虽然交换片段相当普遍,但您需要确保正确处理您的需求。应该隐藏还是删除。它应该处理捆绑包还是忽略它们。我提供给您的方法基本上是显示不存在和隐藏片段,而不是在被告知隐藏片段时将其删除。
处理为导航抽屉构建适配器和列表以及连接侦听器点击这些项目的过程未在此处显示,因为这不是您的问题并且超出了此问题的范围。我不想让我的回答过于臃肿,所以希望这就是你需要开始的全部内容。
快乐编码。