Navigation入门

Navigation

Navigation入门

概念

Navigation:实现应用内页面之间的切换

NavHost:容器,存放每一个页面,同时也是一个控制器

Fragment:碎片

NavController:控制导航的逻辑

NavGraph:工具,设置导航的路线

使用

  1. 创建两个Fragment:

    public class HomeFragment extends Fragment {
    
        public HomeFragment() {
            // Required empty public constructor
        }
    
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
            // Inflate the layout for this fragment
            return inflater.inflate(R.layout.fragment_home, container, false);
        }
        }
    }
    
    public class DetailFragment extends Fragment {
    
        public DetailFragment() {
            // Required empty public constructor
        }
    
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
            // Inflate the layout for this fragment
            return inflater.inflate(R.layout.fragment_detail, container, false);
        }
    }
    
    <?xml version="1.0" encoding="utf-8"?>
    <FrameLayout 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=".DetailFragment">
    
        <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">
    
            <androidx.constraintlayout.widget.Guideline
                android:id="@+id/guideline4"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:orientation="horizontal"
                app:layout_constraintGuide_begin="365dp" />
    
            <TextView
                android:id="@+id/textView3"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Detail"
                android:textSize="30sp"
                app:layout_constraintBottom_toTopOf="@+id/guideline4"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent" />
    
            <Button
                android:id="@+id/button2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Button"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="@+id/guideline4" />
        </androidx.constraintlayout.widget.ConstraintLayout>
    </FrameLayout>
    
    <?xml version="1.0" encoding="utf-8"?>
    <FrameLayout 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=".HomeFragment">
    
        <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">
    
            <TextView
                android:id="@+id/textView"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Home"
                android:textSize="30sp"
                app:layout_constraintBottom_toTopOf="@+id/guideline2"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent" />
    
            <androidx.constraintlayout.widget.Guideline
                android:id="@+id/guideline2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:orientation="horizontal"
                app:layout_constraintGuide_begin="365dp" />
    
            <Button
                android:id="@+id/button"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Button"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="@+id/guideline2" />
        </androidx.constraintlayout.widget.ConstraintLayout>
    </FrameLayout>
    
  2. 在res目录下创建navigation目录

  3. 然后创建一个Navigation文件,根节点为navigation,中间会提示添加依赖,点击确认就可以了

  4. 请添加图片描述添加我们创建的Fragment

  5. 进行两个Fragment连接,然后可以设置FragmentActionBar的名称、路线的默认动画等请添加图片描述

  6. 在activity_main.xml中添加NaviHostFragment的View请添加图片描述

  7. 分别在两个Fragemnt中添加方法:

    @Override
        public void onActivityCreated(@Nullable Bundle savedInstanceState) {
            super.onActivityCreated(savedInstanceState);
            Button button = getView().findViewById(R.id.button);
            button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    //创建NavController对象
                    NavController controller = Navigation.findNavController(v);
                   //设置路线
              controller.navigate(R.id.action_homeFragment_to_detailFragment);
                }
            });
        }
    

    或者是

        @Override
        public void onActivityCreated(@Nullable Bundle savedInstanceState) {
            super.onActivityCreated(savedInstanceState);
            getView().findViewById(R.id.button2).setOnClickListener(Navigation
                    .createNavigateOnClickListener(R.id.action_detailFragment_to_homeFragment));
        }
    
  8. 完成6之后就可以进行点击页面切换了,这里我们在MainActivity中来实现进入其他页面左上角的返回按钮

    1. 这里我们可以在onCreate方法里这样写,这里:
    NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager()
                    .findFragmentById(R.id.fragmentContainerView);
            NavController controller = navHostFragment.getNavController();
            NavigationUI.setupActionBarWithNavController(this,controller);
    
    1. 也可以在onStart方法里:
    NavController controller = Navigation
                    .findNavController(this,R.id.fragmentContainerView);
            NavigationUI.setupActionBarWithNavController(this,controller);
    
    1. 注意方法2中的方法不能直接写在onCreate方法内
  9. 重写onSupportNavigateUp方法:

    @Override
        public boolean onSupportNavigateUp() {
            NavController controller = Navigation
                    .findNavController(this,R.id.fragmentContainerView);
            return controller.navigateUp();
        }
    
  10. 至此就完成了整个Navigation的入门

Navigation信息传递

  1. 在navigation的配置文件中的可以通过在Fragment界面的Arguments参数添加,类型是键值对进行参数传递,在该Fragment中直接通过如下方法获取值

    getArguments().getString("key")
    
  2. 同样在navigation的配置文件中的路线中,可以修改Fragment的Arguments值,注意这里需要使用路线来进行跳转:

    controller.navigate(R.id.action_homeFragment_to_detailFragment)
    

    如果是通过Fragment的Id来进行跳转的话,跳转后Fragment中Arguments的值是不会变化的。

    controller.navigate(R.id.detailFragment);
    
  3. 还可以在出发点通过Bundle来进行值传递,

    Bundle bundle = new Bundle();
    bundle.putString("my_name","Rose");
    

    这里我们进行跳转时,带着这个Bundle就可以进行传递了

    controller.navigate(R.id.action_homeFragment_to_detailFragment,bundle);
    

Navigation的跳转动画

这里我们可以通过自定义动画,然后在跳转路线中进行enter或者exit的动画引用即可

Navigation结合ViewModel使用

  1. 首先创建一个MyViewModel类继承ViewModel,然后进行变量定义,和方法的添加

    public class MyViewModel extends ViewModel {
        private MutableLiveData<Integer> mNumber;
    
        public MutableLiveData<Integer> getNumber() {
            if (mNumber == null) {
                mNumber = new MutableLiveData<>();
                mNumber.setValue(0);
            }
            return mNumber;
        }
    
        public void add(int num) {
            mNumber.setValue(mNumber.getValue() + num);
            if (mNumber.getValue() < 0) {
                mNumber.setValue(0);
            } else if (mNumber.getValue() >= 10){
                mNumber.setValue(10);
            }
        }
    }
    
  2. 然后创建两个Fragment,然后修改XML文件的格式

    <?xml version="1.0" encoding="utf-8"?>
    <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>
            <variable
                name="viewModel"
                type="com.ts.navigationviewmodel.MyViewModel" />
        </data>
    
        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            tools:context=".HomeFragment">
    
            <androidx.constraintlayout.widget.ConstraintLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent">
    
                <TextView
                    android:id="@+id/textView"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="@{String.valueOf(viewModel.number)}"
                    android:textSize="30sp"
                    android:gravity="center"
                    app:layout_constraintBottom_toTopOf="@+id/seekBar"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toTopOf="parent" />
    
                <Button
                    android:id="@+id/button"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="跳转"
                    app:layout_constraintBottom_toBottomOf="parent"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toBottomOf="@+id/seekBar" />
    
                <SeekBar
                    android:id="@+id/seekBar"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:max="10"
                    android:saveEnabled="false"
                    app:layout_constraintBottom_toBottomOf="parent"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toTopOf="parent" />
    
            </androidx.constraintlayout.widget.ConstraintLayout>
        </FrameLayout>
    </layout>
    
    <?xml version="1.0" encoding="utf-8"?>
    <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>
            <variable
                name="viewModel"
                type="com.ts.navigationviewmodel.MyViewModel" />
        </data>
    
        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            tools:context=".DetailFragment">
    
            <androidx.constraintlayout.widget.ConstraintLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent">
    
                <TextView
                    android:id="@+id/textView3"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="@{String.valueOf(viewModel.number)}"
                    android:textSize="30sp"
                    app:layout_constraintBottom_toBottomOf="parent"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintHorizontal_bias="0.541"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toTopOf="parent"
                    app:layout_constraintVertical_bias="0.179" />
    
                <Button
                    android:id="@+id/button2"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="-"
                    android:onClick="@{()->viewModel.add(-1)}"
                    app:layout_constraintBottom_toBottomOf="parent"
                    app:layout_constraintEnd_toStartOf="@+id/button4"
                    app:layout_constraintHorizontal_bias="0.5"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toTopOf="parent" />
    
                <Button
                    android:id="@+id/button4"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="+"
                    android:onClick="@{()->viewModel.add(1)}"
                    app:layout_constraintBottom_toBottomOf="@+id/button2"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintHorizontal_bias="0.5"
                    app:layout_constraintStart_toEndOf="@+id/button2"
                    app:layout_constraintTop_toTopOf="@+id/button2" />
    
                <Button
                    android:id="@+id/button5"
                    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.743" />
    
            </androidx.constraintlayout.widget.ConstraintLayout>
        </FrameLayout>
    </layout>
    

    这里我们只做了一个简单的功能,在Home页面使用SeekBar来变换数据,通过跳转在Detail界面加减数据并显示

    public class HomeFragment extends Fragment {
    
        public HomeFragment() {
            // Required empty public constructor
        }
    
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
            // Inflate the layout for this fragment
            final MyViewModel viewModel = new ViewModelProvider(requireActivity(),
                    new ViewModelProvider.NewInstanceFactory()).get(MyViewModel.class);
            FragmentHomeBinding fragmentHomeBinding = DataBindingUtil.inflate(inflater,
                    R.layout.fragment_home,container,false);
            fragmentHomeBinding.setViewModel(viewModel);
            fragmentHomeBinding.setLifecycleOwner(requireActivity());
    
            fragmentHomeBinding.button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    NavController controller = Navigation.findNavController(v);
                    controller.navigate(R.id.action_homeFragment_to_detailFragment);
                }
            });
            //SeekBar初始化
            fragmentHomeBinding.seekBar.setProgress(viewModel.getNumber().getValue());
            //监听SeekBar的宾欢,并改变界面显示的值
            fragmentHomeBinding.seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
                @Override
                public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                    viewModel.getNumber().setValue(progress);
                }
                @Override
                public void onStartTrackingTouch(SeekBar seekBar) {
                }
                @Override
                public void onStopTrackingTouch(SeekBar seekBar) {
                }
            });
            return fragmentHomeBinding.getRoot();
        }
    }
    
    public class DetailFragment extends Fragment {
    
        public DetailFragment() {
            // Required empty public constructor
        }
    
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
            MyViewModel viewModel = new ViewModelProvider(requireActivity(),
                    new ViewModelProvider.NewInstanceFactory()).get(MyViewModel.class);
            FragmentDetailBinding fragmentDetailBinding = DataBindingUtil.inflate(inflater,
                    R.layout.fragment_detail,container,false);
            fragmentDetailBinding.setViewModel(viewModel);
            fragmentDetailBinding.setLifecycleOwner(requireActivity());
            fragmentDetailBinding.button5.setOnClickListener(v->{
                NavController navController = Navigation.findNavController(v);
                navController.navigate(R.id.action_detailFragment_to_homeFragment);
            });
            // Inflate the layout for this fragment
            return fragmentDetailBinding.getRoot();
        }
    }
    
  3. Navigation的使用就不在赘述了,但是注意这里的SeekBar,如果我们跳转界面,并在Detail界面修改值,然后通过系统的返回键来返回时,会出现SeekBar的值还是我们跳转之前的值的情况,这是由于我们返回时,相当于把DetailFragment在栈中给弹出来,系统会把资源恢复为之前的状态,然后触发SeekBar变化的监听,导致值不会变化,这里我们可以通过在Xml文件中修改请添加图片描述seekbar的saveEnable为false即可;还有一个问题是反复跳转的话,我们通过返回键返回会出现反复返回的情况,这与我们的实际不符,我们可以在DetailFragment返回的路线中设置popUpToclusive为True即可。

    请添加图片描述

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

立花泷える宫水三叶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值