Android 一些基础-05-导航与 Tab

导航

导航结构,是一个栈结构,每进入一级页面,压入栈中一级,返回一级,栈中弹出一级

实操

先安装依赖,在 Android 中使用导航需要先安装这两个依赖

arduino 复制代码
implementation 'androidx.navigation:navigation-fragment-ktx:2.8.7'  
implementation 'androidx.navigation:navigation-ui-ktx:2.8.7'

拖拽 要在 Activity 的 xml 文件中处理导航 Fragment,不能缺少这两个属性 如果不存在可以通过这两种方式创建 然后可以看到这个页面 点击创建 host 和目标页面,注意:至少要搞两个,否则也没用 然后连线 连线之后的效果 xml 文件就会变成这个样子

html 复制代码
<?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/mobile_navigation.xml"  
    app:startDestination="@id/navHostFragment">  
    <fragment  
        android:id="@+id/navHostFragment"  
        android:name="com.example.basepractice.NavHostFragment"  
        android:label="NavHostFragment" >  
        <action  
            android:id="@+id/action_navHostFragment_to_secondFragment"  
            app:destination="@id/secondFragment" />  
    </fragment>  
    <fragment  
        android:id="@+id/secondFragment"  
        android:name="com.example.basepractice.SecondFragment"  
        android:label="fragment_second"  
        tools:layout="@layout/fragment_second" />  
</navigation>

接下来需要实现 Fragment 的 OnFragmentInteractionListener 接口,注意:默认情况下有可能没有这个接口,根据提示在 Fragment 中定义一个即可。

java 复制代码
package com.example.basepractice;  
  
import android.net.Uri;  
import android.os.Bundle;  
  
import androidx.fragment.app.Fragment;  
  
import android.view.LayoutInflater;  
import android.view.View;  
import android.view.ViewGroup;  
  
/**  
 * A simple {@link Fragment} subclass.  
 * Use the {@link SecondFragment#newInstance} factory method to  
 * create an instance of this fragment. */public class SecondFragment extends Fragment {  
  
    // TODO: Rename parameter arguments, choose names that match  
    // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER  
    private static final String ARG_PARAM1 = "param1";  
    private static final String ARG_PARAM2 = "param2";  
  
    // TODO: Rename and change types of parameters  
    private String mParam1;  
    private String mParam2;  
  
    public SecondFragment() {  
        // Required empty public constructor  
    }  
  
    /**  
     * Use this factory method to create a new instance of     * this fragment using the provided parameters.     *     * @param param1 Parameter 1.  
     * @param param2 Parameter 2.  
     * @return A new instance of fragment SecondFragment.  
     */    // TODO: Rename and change types and number of parameters  
    public static SecondFragment newInstance(String param1, String param2) {  
        SecondFragment fragment = new SecondFragment();  
        Bundle args = new Bundle();  
        args.putString(ARG_PARAM1, param1);  
        args.putString(ARG_PARAM2, param2);  
        fragment.setArguments(args);  
        return fragment;  
    }  
  
    @Override  
    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        if (getArguments() != null) {  
            mParam1 = getArguments().getString(ARG_PARAM1);  
            mParam2 = getArguments().getString(ARG_PARAM2);  
        }  
    }  
  
    @Override  
    public View onCreateView(LayoutInflater inflater, ViewGroup container,  
                             Bundle savedInstanceState) {  
        // Inflate the layout for this fragment  
        return inflater.inflate(R.layout.fragment_second, container, false);  
    }  
  
    public interface OnFragmentInteractionListener {  
        void onFragmentInteraction(Uri uri);  
    }  
}
java 复制代码
package com.example.basepractice;  
  
import android.net.Uri;  
import android.os.Bundle;  
import android.os.PersistableBundle;  
import android.util.Log;  
import android.view.View;  
import android.widget.TextView;  
  
import androidx.activity.EdgeToEdge;  
import androidx.annotation.NonNull;  
import androidx.appcompat.app.AppCompatActivity;  
import androidx.constraintlayout.widget.ConstraintSet;  
import androidx.core.graphics.Insets;  
import androidx.core.view.ViewCompat;  
import androidx.core.view.WindowInsetsCompat;  
import androidx.fragment.app.FragmentActivity;  
import androidx.fragment.app.FragmentManager;  
import androidx.fragment.app.FragmentTransaction;  
import androidx.lifecycle.ViewModelProvider;  
  
import com.example.basepractice.databinding.ActivityMainBinding;  
  
public class MainActivity extends FragmentActivity implements DemoFragment.OnFragmentInteractionListener, SecondFragment.OnFragmentInteractionListener {  
    public ActivityMainBinding binding;  
    private DataViewModel dataViewModel;  
  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
  
        dataViewModel = new ViewModelProvider(this).get(DataViewModel.class);  
        dataViewModel.setData("来自Activity的数据");  
  
        binding = ActivityMainBinding.inflate(getLayoutInflater());  
        View view = binding.getRoot();  
        setContentView(view);  
  
        FragmentManager fragmentManager = getSupportFragmentManager();  
        DemoFragment demoFragment = (DemoFragment) fragmentManager.findFragmentById(R.id.fragment1);  
  
        if (demoFragment == null) {  
            Log.i("Tag", "onCreate: 空");  
        } else {  
            // 传递数据给fragment  
            demoFragment.receiveDataFromActivity("Activity 的数据");  
        }  
  
    }  
  
    void fragmentData2Activity() {  
        // 第一步:获取fragment实例  
        DemoFragment demoFragment = new DemoFragment();  
        getSupportFragmentManager().beginTransaction()  
                .add(R.id.fragment1, demoFragment)  
                .commitNow();  
  
        // 第三步:调用接口方法  
        demoFragment.buttonClick();  
    }  
  
    // 第二步:实现接口方法  
    @Override  
    public void onDataFromFragment(String str) {  
        Log.i("TAG", "onDataFromFragment: " + str);  
    }  

	// 实现导航目标页面接口方法
    @Override  
    public void onFragmentInteraction(Uri uri) {  
  
    }  
}

在 host Fragment 中做这个操作

scss 复制代码
Navigation.findNavController(rootView).navigate(R.id.secondFragment);
java 复制代码
package com.example.basepractice;  
  
import android.os.Bundle;  
  
import androidx.fragment.app.Fragment;  
  
import android.view.LayoutInflater;  
import android.view.View;  
import android.view.ViewGroup;  
import android.widget.Button;  
import androidx.navigation.Navigation;  
  
/**  
 * A simple {@link Fragment} subclass.  
 * Use the {@link NavHostFragment#newInstance} factory method to  
 * create an instance of this fragment. */public class NavHostFragment extends Fragment {  
  
    // TODO: Rename parameter arguments, choose names that match  
    // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER  
    private static final String ARG_PARAM1 = "param1";  
    private static final String ARG_PARAM2 = "param2";  
  
    // TODO: Rename and change types of parameters  
    private String mParam1;  
    private String mParam2;  
  
    private Button navButton;  
  
    public NavHostFragment() {  
        // Required empty public constructor  
    }  
  
    /**  
     * Use this factory method to create a new instance of     * this fragment using the provided parameters.     *     * @param param1 Parameter 1.  
     * @param param2 Parameter 2.  
     * @return A new instance of fragment NavHostFragment.  
     */    // TODO: Rename and change types and number of parameters  
    public static NavHostFragment newInstance(String param1, String param2) {  
        NavHostFragment fragment = new NavHostFragment();  
        Bundle args = new Bundle();  
        args.putString(ARG_PARAM1, param1);  
        args.putString(ARG_PARAM2, param2);  
        fragment.setArguments(args);  
        return fragment;  
    }  
  
    @Override  
    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        if (getArguments() != null) {  
            mParam1 = getArguments().getString(ARG_PARAM1);  
            mParam2 = getArguments().getString(ARG_PARAM2);  
        }  
    }  
  
    @Override  
    public View onCreateView(LayoutInflater inflater, ViewGroup container,  
                             Bundle savedInstanceState) {  
        // 加载片段布局  
        View rootView = inflater.inflate(R.layout.fragment_nav_host, container, false);  
        navButton = rootView.findViewById(R.id.nav_btn);  
        navButton.setOnClickListener(new View.OnClickListener() {  
            @Override  
            public void onClick(View v) {  
                Navigation.findNavController(rootView).navigate(R.id.secondFragment);  
            }  
        });  
        // Inflate the layout for this fragment  
        return rootView;  
    }  
}

测试效果

添加导航栏

通过ToolBar

html 复制代码
<?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:id="@+id/frameLayout"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent"  
    tools:context=".MainActivity"  
    android:background="#FFFFFF"  
    >  
  
    <androidx.appcompat.widget.Toolbar  
        android:id="@+id/toolbar"  
        android:layout_width="match_parent"  
        android:layout_height="?attr/actionBarSize"  
        android:background="?attr/colorPrimary"  
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"  
        app:popupTheme="@style/ThemeOverlay.AppCompat.Light"  
        app:layout_constraintTop_toTopOf="parent"  
        app:layout_constraintStart_toStartOf="parent"  
        app:layout_constraintEnd_toEndOf="parent"  
        >  
         
            <TextView  
                android:layout_width="wrap_content"  
                android:layout_height="40dp"  
                android:textSize="25sp"  
                android:textColor="@color/white"  
                android:text="首页"  
                android:textAlignment="center"  
                android:layout_gravity="center"  
                >  
            </TextView>  
          
  
    </androidx.appcompat.widget.Toolbar>  
  
  
    <!-- TODO: Update blank fragment layout -->  
    <Button  
        android:id="@+id/nav_btn"  
        android:layout_width="0dp"  
        android:layout_height="50dp"  
        android:text="跳转下一页"  
        app:layout_constraintEnd_toEndOf="parent"  
        app:layout_constraintStart_toStartOf="parent"  
        app:layout_constraintTop_toTopOf="parent"  
        android:layout_marginTop="180dp"  
        />  
</androidx.constraintlayout.widget.ConstraintLayout>

TabLayout 和 ViewPager2

选项卡交互方式,就类似于头条这类新闻 App 顶部的标签的交互方式,这些标签可以是固定的也可以是滚动的。 ViewPager2 的主要作用是允许用户翻阅不同的信息页面,其中每个页面通常由布局 Fragment 表示。与 ViewPager2 关联的 Fragment 由 FragmentStateAdapter 类的实例管理。 分配给 ViewPager2 的 adapter 必须实现至少两个方法:

第一个:getItemCount()必须返回可供用户显示的页面片段总数。

第二个:createFrament()传递一个页码,并且必须返回准备呈现给用户的相应 Fragment 对象。

附加小知识点:

在 Fragment 中开启 Activity 一般使用这个方法

java 复制代码
startActivity(new Intent(navContext, Demo2Activity.class));

这其中 context 是必不可少的,在 Activity 中可以定义进行直接调用,在 Fragment 中需要通过 onAttach() 方法获取

java 复制代码
/**  
 * 在 Fragment 的生命周期里,onAttach 方法会在 Fragment 与 Activity 关联时被调用,  
 * 此时可以获取到 Activity 的 Context。  
 * @param context  
 */  
@Override  
public void onAttach(@NonNull Context context) {  
    super.onAttach(context);  
    // navContext 是在 Fragment 中自定义的
    navContext = context;  
}

TabLayoutViewPager2 组合使用 第一步:准备用于切换页面的多个 Fragment 第二步:在 Activity 布局文件中创建 TabLayoutViewPager2

html 复制代码
<?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:id="@+id/main"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent"  
    tools:context=".baseUI.demo2.Demo2Activity">  
  
    <com.google.android.material.tabs.TabLayout  
        android:id="@+id/tab_layout"  
        android:layout_width="match_parent"  
        android:layout_height="wrap_content"  
        app:layout_constraintTop_toTopOf="parent"  
        app:layout_constraintStart_toStartOf="parent"  
        app:layout_constraintEnd_toEndOf="parent"  
        android:layout_marginTop="30dp"  
        >  
  
    </com.google.android.material.tabs.TabLayout>  
      
    <androidx.viewpager2.widget.ViewPager2  
        android:id="@+id/view_pager2"  
        android:layout_width="match_parent"  
        android:layout_height="0dp"  
        app:layout_constraintTop_toBottomOf="@id/tab_layout"  
        app:layout_constraintStart_toStartOf="parent"  
        app:layout_constraintEnd_toEndOf="parent"  
        app:layout_constraintBottom_toBottomOf="parent"  
        app:layout_behavior="@string/appbar_scrolling_view_behavior"  
        >  
  
    </androidx.viewpager2.widget.ViewPager2>  
  
  
</androidx.constraintlayout.widget.ConstraintLayout>

第三步:创建 adapter 并继承 FragmentStateAdapter 并重写相关方法

java 复制代码
package com.example.basepractice.baseUI.demo2.adapter;  
  
import androidx.annotation.NonNull;  
import androidx.fragment.app.Fragment;  
import androidx.fragment.app.FragmentActivity;  
import androidx.viewpager2.adapter.FragmentStateAdapter;  
  
import com.example.basepractice.baseUI.demo2.tab.Tab1Fragment;  
import com.example.basepractice.baseUI.demo2.tab.Tab2Fragment;  
import com.example.basepractice.baseUI.demo2.tab.Tab3Fragment;  
import com.example.basepractice.baseUI.demo2.tab.Tab4Fragment;  
  
public class TabPageAdapter extends FragmentStateAdapter {  
    int tabCount;  
    public TabPageAdapter(@NonNull FragmentActivity fragmentActivity, int numberOfTabs) {  
        super(fragmentActivity);  
        this.tabCount = numberOfTabs;  
    }  
  
    @NonNull  
    @Override    
    public Fragment createFragment(int position) {  
        switch (position){  
            case 0:  
                return new Tab1Fragment();  
            case 1:  
                return new Tab2Fragment();  
            case 2:  
                return new Tab3Fragment();  
            case 3:  
                return new Tab4Fragment();  
            default:  
                return null;  
        }  
    }  
  
    @Override  
    public int getItemCount() {  
        return tabCount;  
    }  
}

第四步:回到 Activity 中进行 TabLayoutViewPager2 的配置

java 复制代码
package com.example.basepractice.baseUI.demo2;  
  
import android.net.Uri;  
import android.os.Bundle;  
  
import androidx.activity.EdgeToEdge;  
import androidx.appcompat.app.AppCompatActivity;  
import androidx.core.graphics.Insets;  
import androidx.core.view.ViewCompat;  
import androidx.core.view.WindowInsetsCompat;  
import androidx.viewpager2.widget.ViewPager2;  
  
import com.example.basepractice.R;  
import com.example.basepractice.baseUI.basic.BasicActivity;  
import com.example.basepractice.baseUI.demo2.adapter.TabPageAdapter;  
import com.example.basepractice.baseUI.demo2.tab.Tab1Fragment;  
import com.example.basepractice.baseUI.demo2.tab.Tab2Fragment;  
import com.example.basepractice.baseUI.demo2.tab.Tab3Fragment;  
import com.example.basepractice.baseUI.demo2.tab.Tab4Fragment;  
import com.google.android.material.tabs.TabLayout;  
import com.google.android.material.tabs.TabLayoutMediator;  
  
public class Demo2Activity extends BasicActivity implements Tab1Fragment.OnFragmentInteractionListener,  
        Tab2Fragment.OnFragmentInteractionListener, Tab3Fragment.OnFragmentInteractionListener,  
        Tab4Fragment.OnFragmentInteractionListener {  
    private TabLayout tabLayout;  
    private ViewPager2 viewPager2;  
  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        EdgeToEdge.enable(this);  
        setContentView(R.layout.activity_demo2);  
        tabLayout = findViewById(R.id.tab_layout);  
        viewPager2 = findViewById(R.id.view_pager2);  
        configureTabLayout();  
    }  
  
    protected void configureTabLayout() {  
        // 1、通过 addTab 方法添加Tab,for循环添加4个 Tab        for (int i = 0; i < 4; i++) {  
            tabLayout.addTab(tabLayout.newTab());  
        }  
        // 2、创建 adapter 并设置 Tab 个数  
        TabPageAdapter adapter = new TabPageAdapter(this, tabLayout.getTabCount());  
        // 3、viewPager2 设置 adapter        viewPager2.setAdapter(adapter);  
        // 4、创建 TabLayoutMediator 将 TabLayout 和 ViewPager2 关联  
        new TabLayoutMediator(tabLayout, viewPager2, (tab, position) -> {  
            tab.setText("Tab " + (position + 1));  
        }).attach();  
    }  
  
    @Override  
    public void onFragmentInteraction(Uri uri) {  
  
    }  
}

运行效果

相关推荐
雨白12 小时前
Android 快捷方式实战指南:静态、动态与固定快捷方式详解
android
hqk12 小时前
鸿蒙项目实战:手把手带你实现 WanAndroid 布局与交互
android·前端·harmonyos
LING13 小时前
RN容器启动优化实践
android·react native
恋猫de小郭15 小时前
Flutter 发布官方 Skills ,Flutter 在 AI 领域再添一助力
android·前端·flutter
Kapaseker20 小时前
一杯美式搞懂 Any、Unit、Nothing
android·kotlin
黄林晴20 小时前
你的 Android App 还没接 AI?Gemini API 接入全攻略
android
恋猫de小郭1 天前
2026 Flutter VS React Native ,同时在 AI 时代 VS Native 开发,你没见过的版本
android·前端·flutter
冬奇Lab1 天前
PowerManagerService(上):电源状态与WakeLock管理
android·源码阅读
BoomHe2 天前
Now in Android 架构模式全面分析
android·android jetpack
二流小码农2 天前
鸿蒙开发:上传一张参考图片便可实现页面功能
android·ios·harmonyos