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

运行效果

相关推荐
鸿蒙布道师1 小时前
鸿蒙NEXT开发动画案例2
android·ios·华为·harmonyos·鸿蒙系统·arkui·huawei
androidwork1 小时前
Kotlin Android工程Mock数据方法总结
android·开发语言·kotlin
xiangxiongfly9154 小时前
Android setContentView()源码分析
android·setcontentview
人间有清欢5 小时前
Android开发补充内容
android·okhttp·rxjava·retrofit·hilt·jetpack compose
人间有清欢6 小时前
Android开发报错解决
android
每次的天空7 小时前
Android学习总结之kotlin协程面试篇
android·学习·kotlin
每次的天空9 小时前
Android学习总结之Binder篇
android·学习·binder
峥嵘life9 小时前
Android 有线网开发调试总结
android
是店小二呀10 小时前
【算法-链表】链表操作技巧:常见算法
android·c++·算法·链表
zhifanxu12 小时前
Kotlin 遍历
android·开发语言·kotlin