美文网首页
Android JectPack之Navigation的简

Android JectPack之Navigation的简

作者: 小杨不想努力了 | 来源:发表于2021-09-24 00:02 被阅读0次

1. 导包

// Java language implementation
implementation("androidx.navigation:navigation-fragment:2.3.5")
implementation("androidx.navigation:navigation-ui:2.3.5")

// Kotlin
implementation("androidx.navigation:navigation-fragment-ktx:2.3.5")
implementation("androidx.navigation:navigation-ui-ktx:2.3.5")

// Feature module Support
implementation("androidx.navigation:navigation-dynamic-features-fragment:2.3.5")

// Testing Navigation
androidTestImplementation("androidx.navigation:navigation-testing:2.3.5")

// Jetpack Compose Integration
implementation("androidx.navigation:navigation-compose:2.4.0-alpha08")

2. 创建Activity和fragment

(1) 创建MainActivity和MessageActivity

package com.example.mvvmdemo.NavigationCourse.fragment

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.example.mvvmdemo.R

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_nav_main)
    }
}
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/fragment_container_view"
        android:name="androidx.navigation.fragment.NavHostFragment"
        app:defaultNavHost="true"
        app:navGraph="@navigation/nav_config"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</FrameLayout>
package com.example.mvvmdemo.NavigationCourse.Activity

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.example.mvvmdemo.R

class MessageActivity: AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_message)
    }
}

(2)创建Fragment

首先创建一个BaseFragment

package com.example.mvvmdemo.base

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

abstract class BaseFragment : Fragment() {
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        val rootView: View = inflater.inflate(getLayoutResId(), container, false)
        //初始化View
        initView(rootView)
        return rootView
    }
    //子类需要使用时,重写即可
    open fun initView(rootView: View) {

    }
    //抽象函数,子类必须继承 传入View
    abstract fun getLayoutResId(): Int
}

其他Fragment继承BaseFragment

package com.example.mvvmdemo.NavigationCourse.fragment

import android.view.View
import androidx.navigation.fragment.FragmentNavigatorExtras
import androidx.navigation.fragment.findNavController
import com.example.mvvmdemo.R
import com.example.mvvmdemo.base.BaseFragment
import kotlinx.android.synthetic.main.fragment_login.*
import kotlinx.android.synthetic.main.fragment_login.view.*

class LoginFragment : BaseFragment() {
    override fun getLayoutResId(): Int {
        return R.layout.fragment_login
    }

    override fun initView(rootView: View) {
        super.initView(rootView)
        rootView.toRegister.setOnClickListener {
            val imagePair = Pair<View, String>(loginCover, "coverTn")
            //可以传多个
            val extras = FragmentNavigatorExtras(imagePair)
            //跳转到注册页面
            findNavController().navigate(
                R.id.to_register_fragment,
                null,
                null,
                extras
            )
        }
        rootView.toForget.setOnClickListener {
            //跳转到忘记密码页面
            findNavController().navigate(R.id.to_forget_fragment)
        }
        rootView.toMessageActivity.setOnClickListener {
            //跳转到messageActivity
            findNavController().navigate(R.id.to_message_activity)
        }
    }
}
<?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">

    <TextView
        android:id="@+id/registerTv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="login"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/toRegister"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="跳转到注册页面"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.498"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.121" />

    <Button
        android:id="@+id/toForget"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="跳转到忘记密码页面"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.497"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.243" />

    <Button
        android:id="@+id/toMessageActivity"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="跳转到messageActivity"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.498"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.392" />

    <ImageView
        android:id="@+id/loginCover"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@mipmap/ic_launcher"
        android:transitionName="coverTn"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.498"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.828" />
</androidx.constraintlayout.widget.ConstraintLayout>
<?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">

    <TextView
        android:id="@+id/registerTv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="register"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <ImageView
        android:id="@+id/registerCover"
        android:layout_width="220dp"
        android:layout_height="221dp"
        android:transitionName="coverTn"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.497"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.109"
       android:src="@mipmap/ic_launcher"
       />
</androidx.constraintlayout.widget.ConstraintLayout>
package com.example.mvvmdemo.NavigationCourse.fragment

import android.os.Bundle
import androidx.transition.TransitionInflater
import com.example.mvvmdemo.R
import com.example.mvvmdemo.base.BaseFragment

class RegisterFragment : BaseFragment() {
    override fun getLayoutResId(): Int {
        return R.layout.fragment_register
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        sharedElementEnterTransition = TransitionInflater.from(requireContext())
            .inflateTransition(R.transition.shared_image)
    }
}
<?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">

    <TextView
        android:id="@+id/registerTv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="register"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <ImageView
        android:id="@+id/registerCover"
        android:layout_width="220dp"
        android:layout_height="221dp"
        android:transitionName="coverTn"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.497"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.109"
       android:src="@mipmap/ic_launcher"
       />
</androidx.constraintlayout.widget.ConstraintLayout>
package com.example.mvvmdemo.NavigationCourse.fragment

import com.example.mvvmdemo.R
import com.example.mvvmdemo.base.BaseFragment

class ForgetFragment : BaseFragment() {
    override fun getLayoutResId(): Int {
        return R.layout.fragment_forget
    }
}
<?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">

    <TextView
        android:id="@+id/registerTv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="forget"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

3. 跳转

创建nav_config.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"
    android:id="@+id/nav_config"
    app:startDestination="@id/login_fragment">
    <fragment
        android:id="@+id/login_fragment"
        android:name="com.example.mvvmdemo.NavigationCourse.fragment.LoginFragment">
        <action
            android:id="@+id/to_register_fragment"
            app:destination="@+id/register_fragment"
            />
        <action
            android:id="@+id/to_forget_fragment"
            app:destination="@+id/forget_fragment"
            app:enterAnim="@anim/slid_from_right_to_left_in"
            app:exitAnim="@anim/slid_from_right_to_left_out"
            app:popEnterAnim="@anim/slid_from_left_to_right_in"
            app:popExitAnim="@anim/slid_from_left_to_right_out" />
        <action
            android:id="@+id/to_message_activity"
            app:destination="@+id/message_activity" />
    </fragment>
    <fragment
        android:id="@+id/forget_fragment"
        android:name="com.example.mvvmdemo.NavigationCourse.fragment.ForgetFragment"></fragment>
    <fragment
        android:id="@+id/register_fragment"
        android:name="com.example.mvvmdemo.NavigationCourse.fragment.RegisterFragment"></fragment>
    <activity
        android:id="@+id/message_activity"
        android:name="com.example.mvvmdemo.NavigationCourse.Activity.MessageActivity"></activity>
</navigation>

(1)Fragment之间的跳转

LoginFragment 跳转到 RegisterFragment

在nav_config.xml的login_fragment的<fragment>中设置action标签,设置id,destination(想要跳转的fragment),在LoginFragment中的toRegister按钮设置点击事件,实现跳转
<fragment
    android:id="@+id/login_fragment"
    android:name="com.example.mvvmdemo.NavigationCourse.fragment.LoginFragment">
    <action
        android:id="@+id/to_register_fragment"
        app:destination="@+id/register_fragment"/>
</fragment>
<fragment
android:id="@+id/register_fragment
android:name="com.example.mvvmdemo.NavigationCourse.fragment.RegisterFragment"></fragment>
rootView.toRegister.setOnClickListener {
    //跳转到注册页面
    findNavController().navigate(R.id.to_register_fragment)
}

(2)Activity之间的跳转

    与Fragment跳转类似
<fragment
    android:id="@+id/login_fragment"
    android:name="com.example.mvvmdemo.NavigationCourse.fragment.LoginFragment">
    <action
        android:id="@+id/to_message_activity"
        app:destination="@+id/message_activity" />
</fragment>
<activity
    android:id="@+id/message_activity"
    android:name="com.example.mvvmdemo.NavigationCourse.Activity.MessageActivity">

</activity>
rootView.toMessageActivity.setOnClickListener {
    //跳转到messageActivity
    findNavController().navigate(R.id.to_message_activity)
}

(3)跳转之间的动画实现

创建slid_from_left_to_right_in.xml ,

        slid_from_left_to_right_out.xml ,

        slid_from_right_to_left_in.xml,

        slid_from_right_to_left_out.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="400"
        android:fromXDelta="-100%p"
        android:toXDelta="0" />
</set>
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="400"
        android:fromXDelta="0"
        android:toXDelta="100%p" />
</set>
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="400"
        android:fromXDelta="100%p"
        android:toXDelta="0" />
</set>
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="400"
        android:fromXDelta="0"
        android:toXDelta="-100%p"/>
</set>

然后添加在相应的action后面

<action
    android:id="@+id/to_forget_fragment"
    app:destination="@+id/forget_fragment"
    app:enterAnim="@anim/slid_from_right_to_left_in"
    app:exitAnim="@anim/slid_from_right_to_left_out"
    app:popEnterAnim="@anim/slid_from_left_to_right_in"
    app:popExitAnim="@anim/slid_from_left_to_right_out" />

还有就是Activity的全局配置如下的动画跳转

在themes.xml文件中配置

<resources xmlns:tools="http://schemas.android.com/tools">
    <!-- Base application theme. -->
    <style name="Theme.MVVMDemo" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
     
        <item name="android:windowAnimationStyle">@style/activityAnimation</item>
 
    </style>
    <style name="activityAnimation" parent="@android:style/Animation">
        <item name="android:activityOpenEnterAnimation">@anim/slid_from_right_to_left_in</item>
        <item name="android:activityOpenExitAnimation">@anim/slid_from_right_to_left_out</item>
        <item name="android:activityCloseEnterAnimation">@anim/slid_from_left_to_right_in</item>
        <item name="android:activityCloseExitAnimation">@anim/slid_from_left_to_right_out</item>
    </style>
</resources>

在AndroidManifest.xml文件中添加,不过一般创建项目时就已经添加了

android:theme="@style/Theme.MVVMDemo">

4. 返回

(1)返回到上一页

//一般用于左上角的返回箭头back
findNavController().navigateUp()
//类似手机底部返回按钮,退栈
findNavController().popBackStack()

在RegisterFragment的布局文件中添加一个按钮

<Button
    android:id="@+id/back2Login"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="返回"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    tools:layout_editor_absoluteY="482dp"
    tools:ignore="MissingConstraints" />
找到控件设置事件
override fun initView(rootView: View) {
    rootView.back2Login.setOnClickListener {
        findNavController().navigateUp()
       // findNavController().popBackStack()
    }

(2)跳页返回

    从loginFragment(登录) 到 registerFragment(注册) 到 verifyFragment (认证)

    直接从verifyFragment 到 loginFragment 
//跳页的实现
app:popUpTo="@id/to_login_fragment"
app:popUpToInclusive="true" 
<?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"
    android:id="@+id/nav_config"
    app:startDestination="@id/login_fragment">
    <fragment
        android:id="@+id/login_fragment"
        android:name="com.example.mvvmdemo.NavigationCourse.fragment.LoginFragment">
        <action
            android:id="@+id/to_register_fragment"
            app:destination="@+id/register_fragment" />
    </fragment>
    <fragment
        android:id="@+id/register_fragment"
        android:name="com.example.mvvmdemo.NavigationCourse.fragment.RegisterFragment">
        <action
            android:id="@+id/to_verify_fragment"
            app:destination="@id/avatar_verify_fragment" />
    </fragment>
    <fragment
        android:id="@+id/avatar_verify_fragment"
        android:name="com.example.mvvmdemo.NavigationCourse.fragment.AvatarVerifyFragment">
        <action
            android:id="@+id/to_login_fragment"
            app:destination="@id/login_fragment"
            app:popUpTo="@id/login_fragment"
            app:popUpToInclusive="true" />
    </fragment>
</navigation>

5. Fragment实现元素共享

在loginFragment中创建布局

<Button
    android:id="@+id/toRegister"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="跳转到注册页面" />
<ImageView
    android:id="@+id/loginCover"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@mipmap/ic_launcher"
    android:transitionName="coverTn" />
    按钮注册响应事件
rootView.toRegister.setOnClickListener {
    val imagePair = Pair<View, String>(loginCover, "coverTn")
    //可以传多个
    val extras = FragmentNavigatorExtras(imagePair)
    //跳转到注册页面
    findNavController().navigate(
        R.id.to_register_fragment,
        null,
        null,
        extras
    )
}
在registerFragment创建布局
<ImageView
    android:id="@+id/registerCover"
    android:layout_width="220dp"
    android:layout_height="221dp"
    android:transitionName="coverTn"
    android:src="@mipmap/ic_launcher"
   />
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    sharedElementEnterTransition = TransitionInflater.from(requireContext())
        .inflateTransition(R.transition.shared_image)
}

在res中创建transition包创建share_image.xml文件 设置时间

<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
    <autoTransition android:duration="400" />
</transitionSet>

6. Activity实现元素共享

loginFragment给相关按钮设置事件

rootView.toMessageActivity.setOnClickListener {
    //跳转到messageActivity
    val pair = androidx.core.util.Pair<View, String>(loginCover, "coverTn")
    val options = ActivityOptionsCompat.makeSceneTransitionAnimation(requireActivity(), pair)
    val extras: ActivityNavigator.Extras = ActivityNavigator.Extras.Builder()
        .setActivityOptions(options)
        .build()
    findNavController().navigate(
        R.id.to_message_activity, null, null, extras
    )
}

messageActivity布局 注意:android:transitionName="coverTn" transitionName要一样

<ImageView
    android:id="@+id/messageCover"
    android:layout_width="219dp"
    android:layout_height="204dp"
    android:src="@mipmap/ic_launcher"
    android:transitionName="coverTn"/>

7. 传参

(1)Fragment传参

创建Bundle,传入navigate()的args参数

rootView.toRegister.setOnClickListener {
    //图像
    val imagePair = Pair<View, String>(loginCover, "coverTn")
    //账号
    val userNamePair = Pair<View, String>(userNameEt, "userNameTn")
    val extras = FragmentNavigatorExtras(imagePair, userNamePair)
    //数据
    val bundle = Bundle()
    bundle.putString("userName", userNameEt.text.toString())
    //跳转到注册页面
    findNavController().navigate(
        R.id.to_register_fragment,
        //传入args
        bundle,
        null,
        extras
    )
}

在另一个Fragment中通过arguments获取

注意:在布局中保证transitionName属性的值一致

var userName: String? = arguments?.getString("userName")
rootView.registerTv.setText(userName)
(2)Activity传参
rootView.toMessageActivity.setOnClickListener {
    //跳转到messageActivity
    //两个参数
    //图像
    val imagePair = androidx.core.util.Pair<View, String>(loginCover, "coverTn")
    //账号
    val userNamePair = androidx.core.util.Pair<View, String>(userNameEt, "userNameTn")
    val options = ActivityOptionsCompat.makeSceneTransitionAnimation(
        requireActivity(),
        imagePair,
        userNamePair
    )
    //数据
    val bundle = Bundle()
    bundle.putString("userName", userNameEt.text.toString())
    val extras: ActivityNavigator.Extras = ActivityNavigator.Extras.Builder()
        .setActivityOptions(options)
        .build()
    findNavController().navigate(
        R.id.to_message_activity, bundle, null, extras
    )
}

在Activity中,通过Intent获取

private fun initView() {
    val userName = intent.getStringExtra("userName")
    messageTv.text = userName
}

相关文章

网友评论

      本文标题:Android JectPack之Navigation的简

      本文链接:https://www.haomeiwen.com/subject/exuagltx.html