jetpacknavigation(代码片段)

编程的平行世界 编程的平行世界     2023-02-25     761

关键词:

前言

如果文章排版有问题,或者图片无法显示,请到我的主运营博客阅读

🏀什么是Navigation?官方文档的话有点不容易让人理解。所以,这里用我自己的话来总结一下,我们在处理Fragment是需要通过写Fragment的事务去操作Fragment的,而Navigation的出现是为了解决我们之前开发的一些痛点。Navigation主要用于实现Fragment代替Activity的页面导航功能,让Fragment能够轻松的实现跳转与传递参数,我们可以通过使用Navigation,让Fragment代替android项目中绝大多数的Activity。但需要注意的是在使用Navigation切换页面生命周期的变化情况,避免开发过程中踩坑。

🌟官方文档:https://developer.android.google.cn/jetpack/androidx/releases/navigation

🌟navigation项目地址:https://github.com/googlecodelabs/android-navigation

💡本文Demo地址:https://github.com/taxze6/Jetpack_learn/tree/main/Jetpack_basic_learn/navigation

使用Navigation具有什么优势?

  • 处理Fragment事务
  • 默认情况下,能正确处理往返操作
  • 为动画和转换提供标准化资源
  • 实现和处理深层链接
  • 包括导航界面模式,例如抽屉式导航栏和底部导航,我们只需要完成少量的代码编写
  • Safe Args - 可在目标之间导航和传递数据时提供类型安全的Gradle插件
  • ViewModel支持 - 您可以将ViewModel的范围限定为导航图,以在图标的目标之间共享与界面相关的数据

如何使用Navigation呢?

Navigation目前仅AndroidStudio 3.2以上版本支持,如果您的版本不足3.2,请点此下载最新版AndroidStudio(2202年了应该没有人还在用3.2以下的版本吧!🐤)

在开始学习Navigation组件之前,我们需要先对Navigation主要组成部分有个简单的了解,Navigation由三部分组成:

  • Navigation graph:一个包含所有导航相关信息的 XML 资源
  • NavHostFragment:一种特殊的Fragment,用于承载导航内容的容器
  • NavController:管理应用导航的对象,实现Fragment之间的跳转等操作

下面我们正式开始学习Navigation啦

第一步:添加依赖

//project的Navigation依赖设置
dependencies 
  //文章发布时的最新稳定版本:
  def nav_version = "2.4.2"
​
  // 使用java作为开发语言添加下面两行:
  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版本:
implementation "androidx.navigation:navigation-compose:$nav_version"

第二步:创建导航图

右键点击res目录,然后依次选择NewAndroid Resource Directory。此时系统会显示 New Resource Directory对话框。Directory name输入你的文件夹名(一般为navigation),Resource type选择navigation

右键navigation文件夹,然后newNavigation Resource FileFile name中输入名称(常用nav_graph_main或nav_graph
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rv4ObFso-1657166276980)(https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/4f667ebfc2d242debcd50f9978baddb4~tplv-k3u1fbpfcp-watermark.image?)]

第三步:创建Fragment

为了让跳转更加的丰富,我们这里创建三个Fragment

我们可以自己手动创建:

FirstFragment:

<?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)
    

另外创建两个和FirstFragement一样的:SecondFragmentThirdFragment

我们也可以通过Navigation graph创建

我们在新建好的nav_graph_main.xml下,在右上角切换到Design模式,然后在Navigation Editor中,点击Create new destination,选择所需要的Fragment后,点击Finish,你就会发现Fragment已经出现在我们可以拖动的面板中了。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CCf67eXE-1657166276982)(https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/a863a4a9d78549e5b029e2c65e1b3e4a~tplv-k3u1fbpfcp-watermark.image?)]

第四步:将Fragment拖入面板并进行跳转配置

只需要在Navigation Editor中双击想要的Fragment就会被加入到面板中啦。

点击其中一个Fragment,你会发现,在他的右边会有一个小圆点,拖曳小圆点指向想要跳转的那个Fragment,我们这里设置FirstFragmentSecondFragmentThirdFragmentFirstFragment

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-29JRH2s5-1657166276983)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/9034fe09af4f468380a6db6dbdc9a841~tplv-k3u1fbpfcp-watermark.image?)]
我们将nav_graph_main.xml切换到Code下,我们来解读一下xml

<?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>
  • navigation是根标签,通过startDestination配置默认启动的第一个页面,这里配置的是firstFragment,我们可以在代码中手动改mainFragment(启动时的第一个Fragment),也可以在可视化面板中点击Fragment,再点击Assign Start Destination,同样可以修改mainFragment

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6Oqt1Byf-1657166276984)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/cf5421b074df46d79ee9fcbe38c66721~tplv-k3u1fbpfcp-watermark.image?)]

  • fragment标签就代表这是一个Fragment
  • action标签定义了页面跳转的行为,就是上图中的每条线,destination定义跳转的目标页,还可以加入跳转时的动画

💡注意:在fragment标签下的android:name属性,其中的包名的是否正确声明

第五步:处理MainActivity

编辑MainActivity的布局文件,在布局文件中添加NavHostFragment。我们需要告诉NavigationActivity,我们的Fragment展示在哪里,所以NavHostFragment其实就是导航界面的容器

<?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>
  • fragment标签下的android:name是用于指定NavHostFragment
  • app:navGraph是用于指定导航视图的
  • app:defaultNavHost=true是在每一次Fragment切换时,将点击记录在堆栈中保存起来,在需要退出时,按下返回键后,会从堆栈拿到上一次的Fragment进行显示。但是在某些情况下,这样的操作不是很友好,不过好在我们只需要将app:defaultNavHost=true改为app:defaultNavHost=false或者删除这行即可。在其为false的情况下,无论怎么切换Fragment,再点击返回键就都直接退出app。当然我们也可以对其堆栈进行监听,从而来实现,点击一次返回键回到主页,再点击一次返回键退出app

修改MainActivity

我们重写了onSupportNavigateUp,表示我们将Activityback点击事件委托出去

class 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()
    

第六步:处理Fragment的对应跳转事件

Fragment布局:给一个按钮用于跳转,一个TextView用于标识,三个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"><Button
        android:id="@+id/firstButton"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:text="点击跳转到第二个fragment" /><TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:text="@string/hello_first_fragment" /></FrameLayout>
​
//secondFragment中加入:
<Button
        android:id="@+id/firstButton"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:text="点击跳转到第三个fragment" />
​
//thirdFragment中加入:
<Button
        android:id="@+id/firstButton"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:text="返回第一个fragment" />

②配置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中加入:
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中加入:
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_secondFragment2这样的标识,是在nav_graph_main.xmlaction标签下配置的。

<action
    android:id="@+id/action_firstFragment_to_secondFragment2"
    app:destination="@id/secondFragment" />

③最后的效果图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ogs53lc9-1657166276986)(https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/74bc27f878394383ad52f8f972c2b3f7~tplv-k3u1fbpfcp-watermark.image?)]

跳转动画&自定义动画

我们会发现,刚刚的例子中,我们在跳转界面时,没有左滑右滑进入界面的动画,显得很生硬,所以我们要给跳转过程中添加上动画。

添加默认动画:

nav_graph_main.xml文件中的Design模式下,点击连接两个Fragment的线。然后你会发现在右侧会出现一个Animations的面板,然后我们点击enterAnim这些选项最右侧的椭圆点,然后就会弹出Pick a Resoure的面板,我们可以在这里选择需要的动画,这里我们就设置nav_default_enter_anim。同理exitAnim我们也设置一个动画,nav_default_exit_anim。然后运行代码你就发现一个渐变的跳转动画。然后配置动画后会发现action多了动画相关的属性

<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>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YjFcKytn-1657166276987)(https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/d08632a0d1d442e4857165b30a720a8b~tplv-k3u1fbpfcp-watermark.image?)]

  • enterAnim: 跳转时的目标页面动画
  • exitAnim: 跳转时的原页面动画
  • popEnterAnim: 回退时的目标页面动画
  • popExitAnim:回退时的原页面动画

自定义动画

💡 在真正的业务需求中是会有很多不同的跳转动画的,官方提供的默认动画是不够的,所以我们要学会自定义动画。

⑴创建Animation资源文件

右键点击res目录,然后依次选择NewAndroid Resource File。此时系统会显示 New Resource File对话框。File name输入你的文件夹名(这里设置为slide_from_left),Resource type选择Animation,然后我们就可以发下在res目录下多了一个anim目录,里面存放着我们自定义的动画。

⑵编写我们的动画代码

这里举几个常用的例子:

//左滑效果
<?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>
//右滑效果
<?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>
//旋转效果
<?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>

常用的属性:

属性介绍
alpha透明度设置效果
scale大小缩放效果
rotate旋转效果
translate位移效果

常用设置:

属性介绍
android:duration动画时长
fromXX开始状态
toXX结束状态

⑶使用自定义动画文件

使用自定义动画也是和使用默认动画是一样的。

旋转效果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-25BfCEKe-1657166276988)(https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/e7978e5abe9445e8b5219ba79c9ddca5~tplv-k3u1fbpfcp-watermark.image?)]

如何传递数据?

💡Navigation 支持您通过定义目的地参数将数据附加到导航操作。一般情况下,建议传递少量数据。例如传递userId,而不是具体用户的信息。如果需要传递大量的数据,还是推荐使用ViewModel。

nav_graph_main.xml文件中的Design模式下。点击选中其中的Fragment。在右侧的Attributes 面板中,点击Arguments选项右侧的加号。添加需要的参数。添加参数后,在箭头 Action 上点击,会在右边的 Argument Default Values中显示这个userId变量,在xml中也可以看到

//伪代码,请勿直接cv
<fragment
   ... 
   >
   ...
    <argument
        android:name="userId"
        android:defaultValue="1"
        app:argType="integer" />
</fragment>

代码处理:

查看详情  

jetpacknavigation(代码片段)

前言如果文章排版有问题,或者图片无法显示,请到我的主运营博客阅读🏀什么是Navigation?官方文档的话有点不容易让人理解。所以,这里用我自己的话来总结一下,我们在处理Fragment是需要通过写Fragment... 查看详情

jetpacknavigation真香预警(代码片段)

1.Navigation到底该如何正确的使用相信大家对Navigation都有所耳闻,我不细说怎么用了,官方的讲解也很详细。我是想说一下到底该如何更好的使用这个组件。这个组件其实是需要配合官方的MVVM架构使用的,ViewModel+Li... 查看详情

如何使用 JetpackNavigation 组件从 BottomSheetDialogFragment 导航到另一个 Fragment

】如何使用JetpackNavigation组件从BottomSheetDialogFragment导航到另一个Fragment【英文标题】:HowtonavigatefromBottomSheetDialogFragmenttoanotherFragmentusingJetpackNavigationcomponent【发布时间】:2021-11-0821:59:49【问题描述】:如果我尝试从底部工作表对... 查看详情

来自 JetpackNavigation 库中通知的隐式深层链接

】来自JetpackNavigation库中通知的隐式深层链接【英文标题】:AnimplicitdeeplinkfromanotificationinJetpackNavigationlibrary【发布时间】:2020-08-1603:08:45【问题描述】:我正在尝试在我的应用程序中实现隐式深层链接处理,但以下代码不起作用... 查看详情

未解决的参考:使用自定义 Parcelable 参数时:Jetpack Navigation

】未解决的参考:使用自定义Parcelable参数时:JetpackNavigation【英文标题】:UnresolvedReference:WhenCustomParcelableArgumentUsed:JetpackNavigation【发布时间】:2021-10-1416:04:33【问题描述】:这是我第一次使用JetpackNavigation和Safeargs。使用自定义P... 查看详情

导航到 Jetpack Navigation 中的另一个 Fragment 后将 DialogFragment 保留在 backstack 中

】导航到JetpackNavigation中的另一个Fragment后将DialogFragment保留在backstack中【英文标题】:KeepingDialogFragmentinbackstackafternavigationtoanotherFragmentinJetpackNavigation【发布时间】:2021-09-1607:50:42【问题描述】:我正在为应用程序中的对话框使... 查看详情

说到jetpack路由组件熟悉的只有arouter框架?今天带你深入理解功能强大的navigation架构(代码片段)

1.前言不管你之前用没用过JetpackNavigation组件,但是或多或少你也可能听说过它。它是Jetpack库中的一个路由组件。此刻你的脑海中可能会浮现阿里ARouter框架。如果你熟悉ARouter但是对Navigation比较陌生,那么你先简单把它们... 查看详情

说到jetpack路由组件熟悉的只有arouter框架?今天带你深入理解功能强大的navigation架构(代码片段)

1.前言不管你之前用没用过JetpackNavigation组件,但是或多或少你也可能听说过它。它是Jetpack库中的一个路由组件。此刻你的脑海中可能会浮现阿里ARouter框架。如果你熟悉ARouter但是对Navigation比较陌生,那么你先简单把它们... 查看详情

后堆栈在 Jetpack Navigation 中无法正常工作

】后堆栈在JetpackNavigation中无法正常工作【英文标题】:BackstacknotworkingproperlyinJetpackNavigation【发布时间】:2021-12-2622:54:01【问题描述】:我创建了一个简单的演示项目来测试AndroidJetpackNavigation组件的默认回栈功能。我有一个主要... 查看详情

如何完成活动? (喷气背包导航)

...活动?(喷气背包导航)【英文标题】:Howtofinishactivity?(jetpacknavigation)【发布时间】:2020-03-2409:55:42【问题描述】:我有带有片段数量的导航图,比如A、B和C。在C中,我想完成当前活动(AA)并跳转到新的活动(BB,使用自己的图... 查看详情

深入理解composenavigation实现原理(代码片段)

...大家学习,那么本文就带大家深挖一下其实现原理从JetpackNavigation说起JetpackNavigatioin是一个通用的页面导航框架,navigation-compose只是其针对Compose的的一个具体实现。抛开具体实现,Navigation在核心公共层定义了以下重... 查看详情

android jetpack 导航仪器测试在返回导航上失败

...tpack导航仪器测试在返回导航上失败【英文标题】:androidjetpacknavigationinstrumentedtestfailonbacknavigation【发布时间】:2021-06-1023:02:01【问题描述】:我使用jetpackNavigation组件(androidx.navigation)创建了一个简单的两个片段示例应用程序。... 查看详情

带有 Jetpack Navigation 的 BottomNavigationView 未正确显示活动菜单指示器

】带有JetpackNavigation的BottomNavigationView未正确显示活动菜单指示器【英文标题】:BottomNavigationViewwithJetpackNavigationnotcorrectlyshowingtheactivemenuindicator【发布时间】:2021-12-2207:44:34【问题描述】:我正在尝试使用JetpackNavigation解决BottomNa... 查看详情

使用喷气背包导航始终按返回返回起始目的地

...的地【英文标题】:Pressingbackalwaysreturntostartdestinationusingjetpacknavigation【发布时间】:2021-12-1712:58:18【问题描述】:所以,我将BottomNavigationView与JetpackNavigation绑定在一起。假设我有4个底部导航菜单,片段A、B、C和D和A作为起始目... 查看详情

与 Jetpack 导航一起使用时,TextField 会中断组合吗?

...中断组合吗?【英文标题】:TextFieldbreakscomposingwhenusedwithJetpacknavigation?【发布时间】:2021-09-0809:37:50【问题描述】:我一直在尝试使用Compose1.0.0-beta09、Kotlin1.5.10和JetpackNavigation2.3.4组合一个简单的应用程序。该应用有一个活动和... 查看详情

如果应用程序关闭,深层链接不会正确重定向

...【发布时间】:2021-09-0113:59:09【问题描述】:我正在使用JetpackNavigation进行深度链接。如果之前未打开应用程序,则深层链接不会正确重定向。但是,如果应用程序存在于内存中,则应用程序将进入前台并且深度链接正确打开。... 查看详情

markdowngit代码片段(代码片段)

查看详情