11、JetPack之Navigation

1、背景

为什么要使用Navigation呢,因为使用它切换、跳转Fragment,Activity更加的方便

Navigation在androidx.navigation下

2、基本使用方法

2.1创建项目

11、JetPack之Navigation_第1张图片

在activity_main中的布局采用FrameLayout,使用 androidx.fragment.app.FragmentContainerView

其中必须要提供id、name、navGraph

android:name="androidx.navigation.fragment.NavHostFragment"  name指代这个包下的NavHostFragment,整个FragmentContainerView指代的便是NavHostFragmentapp:navGraph="@navigation/nav_config" 表示在res下创建navigation文件夹,里面nav_config是对应切换跳转的fragment和activity




    
    

 2.2 创建res/navigation/xxx.xml文件




    
    

        
        

        
        

        
        

    

    
    

    

    
    

        
        
    

    
    

        
        
    

    
    

表示切换的fragment 

11、JetPack之Navigation_第2张图片

 表示可以切换的activity,需要定义id、name,name指的是对应的fragment或activity的路径11、JetPack之Navigation_第3张图片

 app:startDestination="@id/login_fragment" 表示默认选中的fragment是login_fragment

如果你想从当前的activity或fragment跳转到其他的fragment或activity,那么你需要在当前的fragment或activity下面添加相应的action行为

 表示可以在登录界面跳转到注册界面的fragment11、JetPack之Navigation_第4张图片

 然后在login_fragment中找到对应的控件,设置点击事件,通过findNavController().navigate(R.id.to_forget_fragment)便可点击跳转到忘记密码的fragment界面

11、JetPack之Navigation_第5张图片

 其中这个id是在nav_config中登录界面frament中的action的id,指代的是从登录界面跳转到忘记密码界面的action的id11、JetPack之Navigation_第6张图片

 这样便可以实现跳转和切换了,是不是十分的方便

 下面先看一下这个循环,我们从登录界面点击进行到注册界面,在注册界面点击进行头像认证,认证完成后又回到了登录界面11、JetPack之Navigation_第7张图片

 这里面需要注意一下两个属性

app:popUpTo="@id/login_fragment"  表示把login_fragment移到栈顶,其他内容全部出栈,如果设置的话其他fragment,activity还在栈中

app:popUpToInclusive="true" true  表示是否新建一个栈顶对象,true表示的只有一个对象,false表示会有两个login_fragment

11、JetPack之Navigation_第8张图片

 在切换fragment的时候我们还可以添加切换动画,通过下面四个属性进行配置

app:enterAnim="@anim/slide_in_from_right_to_left" 进入-从右到左 app:exitAnim="@anim/slide_out_from_right_to_left" 退出- 从右到左

app:popEnterAnim="@anim/slide_in_from_left_to_right" 进入-从左到右 app:popExitAnim="@anim/slide_out_from_left_to_right" 退出-从左到右

11、JetPack之Navigation_第9张图片

 屏幕及即将显示的view11、JetPack之Navigation_第10张图片

 app:enterAnim="@anim/slide_in_from_right_to_left" 进入-从右到左



    

11、JetPack之Navigation_第11张图片

app:exitAnim="@anim/slide_out_from_right_to_left" 退出- 从右到左 



    

11、JetPack之Navigation_第12张图片

app:popEnterAnim="@anim/slide_in_from_left_to_right" 进入-从左到右 



    

11、JetPack之Navigation_第13张图片

app:popExitAnim="@anim/slide_out_from_left_to_right" 退出-从左到右 



    

11、JetPack之Navigation_第14张图片 这样便可以实现进入和退出fragment的过渡动画效果

那么对于activity进入和退出的动画效果,我们可以设置一个全局的style来控制,通过设置主题就可以实现了

设置style



    

 主题中使用该style即可11、JetPack之Navigation_第15张图片

 这样我们便实现了切换fragment和activity的过渡动画效果

2.3 切换fragment、activity实现元素共享

实现例如下图的功能

11、JetPack之Navigation_第16张图片

 实际上这已经是跳转到另外一个fragment或者activity了,这个数据并不在当前的view之上了,那么,我们要怎么去实现切换的时候元素的共享呢?

首先来看一下fragment的元素共享,在登录界面,点击注册,实现图片头像的共享

11、JetPack之Navigation_第17张图片

 login_fragment登录界面的view,包含上述图片,需要设android:transitionName="userAvatarTn"




    

    

    

    

同样的,在注册界面也要定义该控件,这里的transitionName必须保持一致才可以

11、JetPack之Navigation_第18张图片




    

    
    

    

 跳转的时候可以携带数据,通过bundle来实现

 这样早login_fragment找到对应的控件,设置点击事件

1、设置Pair,这个Pair是kotlin.Pair路径下面的,参数是控件的id和共享元素的transitionName

2、FragmentNavigatorExtras()可以设置多个控件的Pair

3、可以携带数据,通过Bundle来实现

4、调用findNavController().navigate

11、JetPack之Navigation_第19张图片

 在注册界面,可以设置共享元素的过渡动画,这个时候会和前文切换fragment的动画冲突,可以删除切换fragment的过渡动画

11、JetPack之Navigation_第20张图片

 可以通过arguments,这个arguments指的就是Bundle来获取到传输的数据11、JetPack之Navigation_第21张图片

 这样便实现了fragment中元素的共享

对于activity中的元素共享大同小异

在登录界面我们同样跳转到头像验证界面,对头像和用户名进行元素共享

1、创建Pair, 注意,这里的Pair是 androidx.core.util.包下面的,和上面的fragment的不一样

2、ActivityOptionsCompat.makeSceneTransitionAnimation创建options

3、创建extras

4、使用Bundle携带数据

11、JetPack之Navigation_第22张图片

 在AgreeActivity中通过intent获取到Bundle携带的数据

11、JetPack之Navigation_第23张图片

 这样便实现了activity的元素共享以及携带参数

Tips:在fragmnet如果在当前界面中设置控件进行返回,可以使findNavController().navigateUp()方法,popBackStack() 这个方法直接出栈,一般是系统导航栏返回键调用的

11、JetPack之Navigation_第24张图片

 案例:使用BottomNavigationView和navigation实现下面功能,点击导航栏切换fragment

11、JetPack之Navigation_第25张图片

 主页面:TaoBaoActivity

package com.example.taobao

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.ui.setupWithNavController
import com.example.navigation.R
import kotlinx.android.synthetic.main.activity_tao_bao.*

/**
 * Project_name:JetPackBySob
 * Created by:ChenFuXu.
 * Date: 2022/5/22 11:05
 */
class TaoBaoActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_tao_bao)
        initView()
    }

    private fun initView() {
        // 需要将上面的navigationFragment和底部的BottomNavigationView联系起来
        /**
         * 方法1
         */
        // 1.首先找到navigationFragment,通过fragment管理器
        var navigateHostFragment = supportFragmentManager.findFragmentById(R.id.navigate_host_fragment) as NavHostFragment
        // 2.设置BottomNavigationView的setupWithNavController
        bottomNavigationView.setupWithNavController(navigateHostFragment.navController)

        /**
         * 方法2
         * 把navigate_host_fragment控件由androidx.fragment.app.FragmentContainerView改为fragment
         */
        // bottomNavigationView.setupWithNavController(findNavController(R.id.navigate_host_fragment))

    }

    override fun onDestroy() {
        super.onDestroy()
    }
}

布局




    
    

    
    

 app:navGraph="@navigation/nav_tao_bao" 用来配置切换的fragment




    
    
    
    
    

 app:menu="@menu/navigation_items" 用来配置底部的导航栏



    
    

    
    

    
    

    
    

为了导航栏和上面的fragment能够对应的上,menu的item的id和navigation/nav_tao_bao.xml中fragment的id要保持一致

BaseFragment

package com.example.navigation.base

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment

/**
 * Project_name:JetPackBySob
 * Created by:ChenFuXu.
 * Date: 2022/5/18 23:16
 */
abstract class BaseFragment : Fragment() {
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        val rootView = inflater.inflate(getLayoutResId(), container, false)
        // 初始化view
        initView(rootView)
        return rootView
    }

    open fun initView(rootView: View) {

    }

    abstract fun getLayoutResId(): Int
}

首页fragment

package com.example.taobao.fragment

import com.example.navigation.R
import com.example.navigation.base.BaseFragment

/**
 * Project_name:JetPackBySob
 * Created by:ChenFuXu.
 * Date: 2022/5/22 11:07
 */
class HomeFragment : BaseFragment() {
    override fun getLayoutResId(): Int {
        return R.layout.fragment_home
    }
}

精选fragment

package com.example.taobao.fragment

import com.example.navigation.R
import com.example.navigation.base.BaseFragment

/**
 * Project_name:JetPackBySob
 * Created by:ChenFuXu.
 * Date: 2022/5/22 11:08
 */
class SelectedFragment : BaseFragment() {
    override fun getLayoutResId(): Int {
        return R.layout.fragment_on_sell
    }
}

特惠界面fragment

package com.example.taobao.fragment

import com.example.navigation.R
import com.example.navigation.base.BaseFragment

/**
 * Project_name:JetPackBySob
 * Created by:ChenFuXu.
 * Date: 2022/5/22 11:11
 */
class RedPocketFragment : BaseFragment() {
    override fun getLayoutResId(): Int {
        return R.layout.fragment_red_pocket
    }
}

搜索界面的fragment

package com.example.taobao.fragment

import com.example.navigation.R
import com.example.navigation.base.BaseFragment

/**
 * Project_name:JetPackBySob
 * Created by:ChenFuXu.
 * Date: 2022/5/22 11:13
 */
class SearchFragment : BaseFragment() {
    override fun getLayoutResId(): Int {
        return R.layout.fragment_search
    }
}

即可完成底部导航栏和上面fragment完成联动

你可能感兴趣的:(JetPack,android,android,studio,kotlin)