当前位置:网站首页>Navigation - are you sure you want to take a look at such an easy-to-use navigation framework?
Navigation - are you sure you want to take a look at such an easy-to-use navigation framework?
2022-07-07 14:26:00 【InfoQ】
Preface
Use Navigation What's the advantage ?
- Handle Fragment Business
- By default , Can correctly handle round-trip operations
- Provide standardized resources for animation and transformation
- Implement and handle deep links
- Including navigation interface mode , For example, drawer navigation bar and bottom navigation , We only need to complete a small amount of code
- Safe Args - Provides type safe navigation and data transfer between targets Gradle plug-in unit
- ViewModel Support - You can use ViewModel The scope of is limited to the navigation map , To share data related to the interface between the targets of the icon
How to use Navigation Well ?
NavigationNavigation- Navigation graph: One that contains all navigation related information
XMLresources
- NavHostFragment: A special kind
Fragment, Container used to hold navigation content
- NavController: Manage application navigation objects , Realization
FragmentBetween the jump and other operations
First step : Add dependency
//project Of Navigation Dependency settings
dependencies {
// The latest stable version when the article is released :
def nav_version = "2.4.2"
// Use java Add the following two lines as the development language :
implementation "androidx.navigation:navigation-fragment:$nav_version"
implementation "androidx.navigation:navigation-ui:$nav_version"
// Kotlin:
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
}
//Compose edition :
implementation "androidx.navigation:navigation-compose:$nav_version"
The second step : Create a navigation map
resNewAndroid Resource DirectoryNew Resource DirectoryDirectory namenavigationResource typenavigationnavigationnewNavigation Resource FileFile name
The third step : establish Fragment
Fragment<?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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".FirstFragment">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="hello world" />
</FrameLayout>
class FirstFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_first, container, false)
}
}
FirstFragementSecondFragmentThirdFragmentNavigation graphnav_graph_main.xmlDesignNavigation EditorCreate new destinationFragmentFinishFragment
Step four : take Fragment Drag into the panel and configure the jump
Navigation EditorFragmentFragmentFragmentFirstFragmentSecondFragmentThirdFragmentFirstFragment
nav_graph_main.xmlCodexml<?xml version="1.0" encoding="utf-8"?>
<navigation 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/nav_graph_main"
app:startDestination="@id/firstFragment">
<fragment
android:id="@+id/firstFragment"
android:name="com.taxze.jetpack.navigation.FirstFragment"
android:label="fragment_first"
tools:layout="@layout/fragment_first" >
<action
android:id="@+id/action_firstFragment_to_secondFragment2"
app:destination="@id/secondFragment" />
</fragment>
<fragment
android:id="@+id/secondFragment"
android:name="com.taxze.jetpack.navigation.SecondFragment"
android:label="fragment_second"
tools:layout="@layout/fragment_second" >
<action
android:id="@+id/action_secondFragment_to_thirdFragment2"
app:destination="@id/thirdFragment" />
</fragment>
<fragment
android:id="@+id/thirdFragment"
android:name="com.taxze.jetpack.navigation.ThirdFragment"
android:label="fragment_third"
tools:layout="@layout/fragment_third" >
<action
android:id="@+id/action_thirdFragment_to_firstFragment"
app:destination="@id/firstFragment" />
</fragment>
</navigation>
navigationIt's a label , adoptstartDestinationConfigure the first page launched by default , The configuration here isfirstFragment, We can change it manually in the codemainFragment( The first one at startup Fragment), You can also clickFragment, Click againAssign Start Destination, You can also modifymainFragment

fragmentThe label means this is a Fragment
actionTags define the behavior of page jumps , Each line in the above figure ,destinationDefine the target page for jump , You can also add animation during jump
Step five : Handle MainActivity
MainActivityNavHostFragmentNavigationActivityFragmentNavHostFragment<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<fragment
android:id="@+id/nav_host_fragment"
android:layout_width="0dp"
android:layout_height="0dp"
android:name="androidx.navigation.fragment.NavHostFragment"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:defaultNavHost="true"
app:navGraph="@navigation/nav_graph_main" />
</androidx.constraintlayout.widget.ConstraintLayout>
fragmentLabel underandroid:nameIs used to designateNavHostFragment
app:navGraphIs used to specify the Navigation view
app:defaultNavHost=trueEvery timeFragmentWhen switching , Save the click record in the stack , When you need to exit , After pressing the back key , You'll get it from the stack last timeFragmentDisplay . But in some cases , Such operation is not very friendly , But fortunately, we just need toapp:defaultNavHost=trueChange it toapp:defaultNavHost=falseOr delete this line . When it isfalseUnder the circumstances , No matter how you switchFragment, Click the back button again and exit directlyapp. Of course, we can also listen to its stack , So as to achieve , Click the back button once to return to the home page , Click the back button again to exitapp.
MainActivityonSupportNavigateUpActivitybackclass MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
override fun onSupportNavigateUp(): Boolean {
return findNavController(R.id.nav_host_fragment).navigateUp()
}
}
Step six : Handle Fragment Corresponding jump event of
FragmentTextViewFragment<?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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".FirstFragment">
<Button
android:id="@+id/firstButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text=" Click to jump to the second fragment" />
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="@string/hello_first_fragment" />
</FrameLayout>
//secondFragment Add :
<Button
android:id="@+id/firstButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text=" Click to jump to the third fragment" />
//thirdFragment Add :
<Button
android:id="@+id/firstButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text=" Return to the first fragment" />
class FirstFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_first, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
view.findViewById<Button>(R.id.firstButton).apply {
setOnClickListener {
it.findNavController().navigate(R.id.action_firstFragment_to_secondFragment2)
}
}
}
}
//secondFragment Add :
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
view.findViewById<Button>(R.id.firstButton).apply {
setOnClickListener {
it.findNavController().navigate(R.id.action_secondFragment_to_thirdFragment2)
}
}
}
//thirdFragment Add :
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
view.findViewById<Button>(R.id.firstButton).apply {
setOnClickListener {
it.findNavController().navigate(R.id.action_thirdFragment_to_firstFragment)
}
}
}
R.id.action_firstFragment_to_secondFragment2nav_graph_main.xmlaction<action
android:id="@+id/action_firstFragment_to_secondFragment2"
app:destination="@id/secondFragment" />

Jump animation & Custom animation
nav_graph_main.xmlDesignFragmentAnimationsenterAnimPick a Resourenav_default_enter_animexitAnimnav_default_exit_animaction<fragment
android:id="@+id/firstFragment"
android:name="com.taxze.jetpack.navigation.FirstFragment"
android:label="fragment_first"
tools:layout="@layout/fragment_first" >
<action
android:id="@+id/action_firstFragment_to_secondFragment2"
app:destination="@id/secondFragment"
app:enterAnim="@anim/nav_default_enter_anim"
app:exitAnim="@anim/nav_default_exit_anim"
/>
</fragment>

enterAnim: Animation of the target page when jumping
exitAnim: The original page animation when jumping
popEnterAnim: Animation of the target page when backing back
popExitAnim: Back to the original page animation
resNewAndroid Resource FileNew Resource FileFile nameslide_from_leftResource typeAnimationresanim// Left slide effect
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="300"
android:fromXDelta="-100%"
android:toXDelta="0%">
</translate>
</set>
// Right slide effect
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="300"
android:fromXDelta="0%"
android:toXDelta="100%">
</translate>
</set>
// Rotation effect
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<scale
android:duration="1000"
android:fromXScale="0.0"
android:fromYScale="0.0"
android:pivotX="50%"
android:pivotY="50%"
android:toXScale="1.0"
android:toYScale="1.0" />
<rotate
android:duration="1000"
android:fromDegrees="0"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="360" />
</set>

How to pass data ?
nav_graph_main.xmlDesignFragmentAttributesArgumentsActionArgument Default ValuesuserId// Pseudo code , Do not directly cv
<fragment
...
>
...
<argument
android:name="userId"
android:defaultValue="1"
app:argType="integer" />
</fragment>
// By default arrow Action Pass the parameters set in
it.findNavController().navigate(R.id.action_firstFragment_to_secondFragment2)
Transfer data dynamically
// Pseudo code , Do not directly cv
view.findViewById<Button>(R.id.firstButton).setOnClickListener {
val bundle = Bundle()
bundle.putString("userId", "1")
val navController = it.findNavController()
navController.navigate(R.id.action_firstFragment_to_secondFragment2, bundle)
}
val tv = view.findViewById<TextView>(R.id.textView)
tv.text = arguments?.getString("userId")
stay Activity Use setGraph Switch between different Navigation
navigationsetGraphNavigationactivity_mainfragmentapp:navGraph<fragment
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:defaultNavHost="true"/>
setGraphapp:navGraphclass MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
initNav(1)
}
private fun initNav(id: Int) {
var controller = Navigation.findNavController([email protected], R.id.nav_host_fragment)
if (id == 1) {
// Set the corresponding app:navGraph
controller.setGraph(R.navigation.first)
}
if (id == 2) {
controller.setGraph(R.navigation.second)
}
[email protected]()
}
}
NavigationNavController
NavigationFragmentfindNavControllerNavigationNavControllerapiNavControllerNavigationFragmentFragmentFragmentTabLayoutNavigationHow to get
NavController
What's the example? ?
// Pseudo code , Do not directly cv
//activity:
//Activity.findNavController(viewId: Int)
findNavController(R.id.nav_host_fragment).navigateUp()
//Fragment:
//Fragment.findNavController()
//View.findNavController()
findNavController().navigate(R.id.action_thirdFragment_to_firstFragment)
Navigation Common operations :
①popBackStack eject Fragment
oneFragmentsecondFragmentthirdFragmentthirdFragmentsecondFragmentpopBackStackoverride fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
.....
btn.setOnClickListener{
// eject Fragment
controller.popBackStack()
}
}
② Pop up to the specified Fragment
popBackStack//xxxFragment Pop up to the specified Fragment.
// If the Boolean value of the second parameter is true It means that our parameter one Fragment Pop up together , It means that if it is false Just popBackStack To
//xxxFragment, If it is true, It's just xxxFragment stay popBackStack() once
controller.popBackStack(xxxFragment,true)
③navigateUp() Up Navigation
findNavController(R.id.nav_host_fragment).navigateUp()
navigateUpFragmentpopBackStacknavigateUppopBackStacknavigateUpNavigationFragmentpopBackStack()navigateUp()④ Add navigation monitoring
val listener: NavController.OnDestinationChangedListener =
object : OnDestinationChangedListener() {
fun onDestinationChanged(
controller: NavController,
destination: NavDestination,
@Nullable arguments: Bundle?
) {
Log.d(TAG, "onDestinationChanged: id = ${destination.getId()}")
}
}
// Add listening
controller.addOnDestinationChangedListener(listener)
// Remove monitor
controller.removeOnDestinationChangedListener(listener)
⑤ Get the current navigation destination
getCurrentDestination// obtain
val destination = controller.getCurrentDestination()
Log.d(TAG, "onCreate: NavigatorName = ${destination.getNavigatorName()}")
Log.d(TAG, "onCreate: id = ${destination.getId()}")
Log.d(TAG, "onCreate: Parent = ${destination.getParent()}")
⑥ Judge what is displayed on the current page Fragment Is it a goal Fragment
// Directly cv
fun <F : Fragment> isActiveFragment(fragmentClass: Class<F>): Boolean {
val navHostFragment = this.supportFragmentManager.fragments.first() as NavHostFragment
navHostFragment.childFragmentManager.fragments.forEach {
if (fragmentClass.isAssignableFrom(it.javaClass)) {
return true
}
}
return false
}
Use Safe Args Make sure the type is safe
Safe Argsbuild.gradle// Put it on plugins{} Before
buildscript {
repositories {
google()
}
dependencies {
def nav_version = "2.4.2"
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version"
}
}
appmodulebuild.gradleJavaJavaKotlinJavaapply plugin: "androidx.navigation.safeargs"
KotlinKotlinapply plugin: "androidx.navigation.safeargs.kotlin"
android.useAndroidX=true
android.enableJetifier=true
// Pseudo code , Do not directly cv
<fragment
android:id="@+id/blankFragment"
android:name="com.taxze.jetpack.navigation.BlankFragment"
android:label="fragment_blank"
tools:layout="@layout/fragment_blank" >
<action
android:id="@+id/toSecond"
Modify here id
app:destination="@id/blankFragment2" />
</fragment>
BlankFragmentBlankFragment2var action = BlankFragment.actionJump("111")
action.setParam("222")
adopt Navigation imitation WeChat Bottom jump

resNewAndroid Resource FileNew Resource FileFile namemenuResource typeMenuresmenuitem
menu.xmlDesignItemidtitleicon
FragmentNavigation<?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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".HomeFragment">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="Home" />
</FrameLayout>
class HomeFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_home, container, false)
}
}
nav_graph_main.xmlFragmentidmenu.xmlid
activity_mainBottomNavigationViewdrawableselector_menu_text_color.xmlItem<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="#818181" android:state_checked="false"/>
<item android:color="#45C01A" android:state_checked="true"/>
</selector>
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<fragment
android:id="@+id/nav_host_fragment"
android:layout_width="0dp"
android:layout_height="0dp"
android:name="androidx.navigation.fragment.NavHostFragment"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:defaultNavHost="true"
app:navGraph="@navigation/nav_graph_main" />
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/nav_view"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:itemIconTint="@drawable/selector_menu_text_color"
app:labelVisibilityMode="labeled"
app:itemTextColor="@drawable/selector_menu_text_color"
app:menu="@menu/menu" />
</androidx.constraintlayout.widget.ConstraintLayout>
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Remove the title bar
supportRequestWindowFeature(Window.FEATURE_NO_TITLE)
setContentView(R.layout.activity_main)
val navController: NavController = Navigation.findNavController(this, R.id.nav_host_fragment)
val navigationView = findViewById<BottomNavigationView>(R.id.nav_view)
NavigationUI.setupWithNavController(navigationView, navController)
}
}
GitEpilogue
About me
边栏推荐
- bashrc与profile
- Take you to master the three-tier architecture (recommended Collection)
- 最长上升子序列模型 AcWing 1012. 友好城市
- gvim【三】【_vimrc配置】
- Analysis of arouter
- 今日睡眠质量记录78分
- FCOS3D label assignment
- JS get the current time, month, day, year, and the uniapp location applet opens the map to select the location
- Leetcode——剑指 Offer 05. 替换空格
- AI talent cultivation new ideas, this live broadcast has what you care about
猜你喜欢

【愚公系列】2022年7月 Go教学课程 005-变量

GAN发明者Ian Goodfellow正式加入DeepMind,任Research Scientist

小米的芯片自研之路

一个简单LEGv8处理器的Verilog实现【四】【单周期实现基础知识及模块设计讲解】

内部排序——插入排序

js 获取当前时间 年月日,uniapp定位 小程序打开地图选择地点

STM32CubeMX,68套组件,遵循10条开源协议

Equipment failure prediction machine failure early warning mechanical equipment vibration monitoring machine failure early warning CNC vibration wireless monitoring equipment abnormal early warning

Transferring files between VMware and host

【立体匹配论文阅读】【三】INTS
随机推荐
Notes de l'imprimante substance: paramètres pour les affichages Multi - écrans et multi - Résolutions
Reverse non return to zero code, Manchester code and differential Manchester code of common digital signal coding
Mrs offline data analysis: process OBS data through Flink job
Parsing of XML files
IP and long integer interchange
Transferring files between VMware and host
杭电oj2054 A == B ? ???
Vscode configuration uses pylint syntax checker
CSMA/CD 载波监听多点接入/碰撞检测协议
请问,redis没有消费消息,都在redis里堆着是怎么回事?用的是cerely 。
PERT图(工程网络图)
找到自己的价值
[AI practice] Application xgboost Xgbregressor builds air quality prediction model (II)
Csma/cd carrier monitoring multipoint access / collision detection protocol
Search engine interface
内部排序——插入排序
低代码平台中的数据连接方式(下)
Realization of search box effect [daily question]
Substance Painter筆記:多顯示器且多分辨率顯示器時的設置
IP address home location query full version