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) {  
  
    }  
}

运行效果

相关推荐
tracyZhang7 分钟前
NativeAllocationRegistry----通过绑定Java对象辅助回收native对象内存的机制
android
vv啊vv14 分钟前
使用android studio 开发app笔记
android·笔记·android studio
冯浩(grow up)1 小时前
使用vs code终端访问mysql报错解决
android·数据库·mysql
_一条咸鱼_4 小时前
Android Fresco 框架工具与测试模块源码深度剖析(五)
android
QING6184 小时前
Android Jetpack Security 使用入门指南
android·安全·android jetpack
顾林海4 小时前
Jetpack LiveData 使用与原理解析
android·android jetpack
七郎的小院4 小时前
性能优化ANR系列之-BroadCastReceiver ANR原理
android·性能优化·客户端
QING6184 小时前
Android Jetpack WorkManager 详解
android·kotlin·android jetpack
今阳5 小时前
鸿蒙开发笔记-14-应用上下文Context
android·华为·harmonyos
东莞梦幻科技6 小时前
体育直播系统趣猜功能开发技术实现方案
android