Android Fragment

Android Fragment

01 Fragment 的产生

我们一般认为 Fragment 是小的 activity

3.0 产生 Fragment

手机 底部 Item 点一个 Item 出现一个 Fragment

什么是 Fragment

和其他view 不同

  • 具备生命周期
    • 在一个activity中组合使用多个 Fragment ,从而构造多窗格的界面。
    • 在多个activity中重复使用,重复利用
    • 可以自己去接受输入事件,同样可以动态的增加和移除某一些Fragment
  • 必须委托在activity中才能运行 。
    • fragment 生命周期依赖于 activity activity暂停,fragment也暂停
    • activity运行的时候,fragment可以独立的运行和操作

可以将 Fragment 片段 视为activity 模块化组成部分 ,变成一个部分(子activity)。

Fragment 使用方法

  • 新建一个Fragment

    • public class BlankFragment1 extends Fragment 
      
  • 定义一个 Fragment xaml

    • <TextView
          android:id="@+id/tv"
          android:layout_width="match_parent"
          android:layout_height="40dp"
          android:text="@string/hello_blank_fragment" />
      
      <Button
          android:layout_width="match_parent"
          android:layout_height="40dp"
          android:text="how are you?"
          android:id="@+id/btn"
          />
      
  • fragment 并不和 activity 一样

    • 通过inflater 解析成一个 view

    • activity 通过 setContentView 解析

      • //生命周期函数
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
            if (root == null) {
                root = inflater.inflate(R.layout.fragment_blank_fragment1, container, false);
            }
        
    • Fragment 就是小型 activity 可以直接操作组件

      • textView = root.findViewById(R.id.tv);
        button = root.findViewById(R.id.btn);
        
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                textView.setText("good,how u  doing?");
            }
        });
        
    • 把 创建好的 fragment 放进 mainactivity

      • 必须 加 id,

      • <fragment
            android:name="com.example.myapplication.BlankFragment1"
            android:layout_width = "match_parent"
            android:layout_height = "match_parent"
            android:id="@+id/fragment1"/>
        

在 activity 增加两个 fragment

<fragment android:name="com.example.myapplication.BlankFragment1"
    android:layout_width = "match_parent"
    android:layout_height = "match_parent"
    android:layout_weight = "1"
    android:id="@+id/fragment1"/>

<fragment android:name="com.example.myapplication.BlankFragment2"
    android:layout_width = "match_parent"
    android:layout_height = "match_parent"
    android:layout_weight = "1"
    android:id="@+id/fragment2"/>

动态添加 Fragment

  1. 创建一个待处理的fragement
  2. 获取FragmentManger,一般都是通过getSupportfragmentManager()
  3. 开启一个事务transaction,一般调用fragmentManger 的 beginTransaction
  4. 使用transaction 进行 fragment 的替换
  5. 提交事务
  • 创建 两个 Button 和 FrameLayout(点击按钮,fragment 替换 Frame Layout)

    • main_activity 布局

      • <Button
                android:id="@+id/btn1"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="@string/change" />
        
            <Button
                android:id="@+id/btn2"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="@string/replace"/>
        
            <FrameLayout
                android:id="@+id/frameLayout"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@color/colorAccent"/>
        
    • 设置按钮点击事件

      • 实现按钮点击事件有两种

        • 匿名内部类(就像前面实现的那样,传输 new View.OnClickListener 对象 )

        • 实现接口

          • public class MainActivity extends AppCompatActivity implements View.OnClickListener
            
      • Button button = findViewById(R.id.btn1);
                button.setOnClickListener(this);
        
                Button button2 = findViewById(R.id.btn2);
                button2.setOnClickListener(this);
        
         @Override
            public void onClick(View view) {
                switch (view.getId()){
                    case R.id.btn1:
                        replaceFragment(new BlankFragment());
                        break;
                    case R.id.btn2:
                        replaceFragment(new ItemFragment());
                }
            }
        
    • 实现 动态切换 fragment

      • //获得 fragment 管理类
                FragmentManager fragmentManager = getSupportFragmentManager();
        // 获得事务
        FragmentTransaction transaction = fragmentManager.beginTransaction();
               transaction.replace(R.id.frameLayout,fragment);
        // fragment 压入栈,返回的时候,一个一个弹出
        transaction.addToBackStack(null);
        // 提交之后才能运行
        transaction.commit();
        
        • beginTransaction 开始事务

Activity 与 Fragment 通信

  • 两个相互独立的类

  • 都是用来展示 UI的

  • 独立的类 怎么进行 通信呢?

    • Activity 与 Fragment 通信
    • Activity 与 Activity 通信
    • Fragment 与 Activity 通信
    • Fragment 与 Fragment 通信
  • 先学习 Activity 与 Fragment 通信

    • 原生方案 Bundle n. 束;捆

      • 创建 Bundle 对象

        • Bundle bundle = new Bundle();
                         bundle.putString("message","你好呀Fragment,我是activity,");
          BlankFragment blankFragment = new BlankFragment();
                         blankFragment.setArguments(bundle);
          replaceFragment(blankFragment);
          
      • 你可以在 fragement 任何地方获取 message,以生命周期为例

        • public void onCreate(Bundle savedInstanceState) {
                 super.onCreate(savedInstanceState);
                 // 返回 activity传进去的 bundle
                 Bundle bundle = this.getArguments();
                 String string = bundle.getString("message");
                 Log.e("leo","传进来的string:"+string);
                 if (getArguments() != null) {
                     mParam1 = getArguments().getString(ARG_PARAM1);
                     mParam2 = getArguments().getString(ARG_PARAM2);
                 }
             }
          
  • 另一种通信方案 : 接口(Java 语言中类与类自己通信的方案)

    1. 定义一个接口类(面向对象原则:面向接口编程)

      • public interface IFragmentCallback {
            void sentMsgToActivity(String string);
            String getMsgFromActivity(String msg);
        }
        
      • 通过接口 对象 实现弱关联

  1. 在 Fragment里面定义一个承接 接口类型对象的函数,接口类型对象的值来自 Avtivity,在Activity 里面创建 Fragment对象,调用Fragment 里面的接口方法里 new 接口类型对象(匿名内部类),把值赋值给 Fragment 里面的变量

    • Fragment

      • //定义一个callback函数  activity 给他赋值
            private IFragmentCallback fragmentCallback;
            // activity 调用这个函数赋值
            public void setFragmentCallback(IFragmentCallback callback){
                fragmentCallback = callback;
            }
        
    • Activity

      • // 通过对象 调用 callback 方法赋值
                        //调用接口对象,new 匿名内部类
                        blankFragment.setFragmentCallback(new IFragmentCallback() {
                            @Override
                            public void sentMsgToActivity(String string) {
        
                            }
        
                            @Override
                            public String getMsgFromActivity(String msg) {
                                return null;
                            }
                        });
        
      • mainactivity里面

        • // 通过对象 调用 callback 方法赋值
                          //调用接口对象,new 匿名内部类
                          blankFragment.setFragmentCallback(new IFragmentCallback() {
                              @Override
                              public void sentMsgToActivity(String msg) {
                                  Toast.makeText(MainActivity.this,msg,Toast.LENGTH_LONG).show();
          
                              }
          
  2. 实现fragment 发布消息 给 activity

    • fragment 里面

      • @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
            if(rootView == null) {
                rootView = inflater.inflate(R.layout.fragment_blank, container, false);
            }
            Button button = rootView.findViewById(R.id.btn3);
            button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    fragmentCallback.sentMsgToActivity("hello,I'm from fragment");
                }
            });
            // Inflate the layout for this fragment
            return rootView;
        }
        

观察者设计模式,发布订阅

fragment 可以 观测activity 的变化,activity发布的消息是我感兴趣的消息,我就接受到

封装好的方案 : eventBus, LiveData

Fragment 生命周期

fragment 执行 依托 activity 执行。

  • onAttach() 和 activity 捆绑

  • onCreat() fragment 创建 对 activity 传来的bundle进行解析就要在oncreat里面进行

  • onCreatView 对fragmentUI的设计

  • onActivityCreated() Activity 创建

  • onStart

  • onResume 重新开始,继续;重新回到

  • onPause 暂停;间歇 UI 状态复位

  • onStop

  • onDestoryView

  • onDestory fragment 销毁

  • onDetach() 和 activity 解绑

难点 每次调用并不严格按照顺序

  1. 打开界面
    • onCreate() -> onCreateView -> onActivityCreated() -> onStart -> onResume
  2. 按下主屏键
    • onPause -> onStop
  3. 重新打开界面
    • onStart -> onResume()
  4. 按下退键
    • onPause() -> onStart -> onDestoryView -> onDestory -> onDetach()

生命周期总结

  • 将来开发者会围绕fragment生命周期花很多时间来解决问题

  • Fragment 的使用一定需要在生命周期函数onAttach 和 onDetach之间

  • Fragment 的使用一定要遵守生命周期管理的规划,在正确的地方写恰当的代码

Fragment 与 ViewPager的联合应用

ViewPager + Fragment 形成翻页效果

减少用户的操作:点击层面越少越好

viewPager1 和 viewPager2 的区别

  • viewpager1 是使用完全自定义的 group

  • viewPager2 也是group 对 recycleView 的封装 说白了就是 recyleview 自带 懒加载 功能

  • 设置viewpager 布局

    • <androidx.viewpager.widget.ViewPager
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:id="@+id/viewPager"
              android:background="@color/colorAccent"/>
      
  • viewpager 是一个容器,需要适配很多不同的参数,所以在 activity 创建 viewpager对象还需要setAdapter()

    • ViewPager2 viewPager = findViewById(R.id.viewPager);
      ViewPagerAdapter viewPagerAdapter = new ViewPagerAdapter();
      viewPager.setAdapter(viewPagerAdapter);
      
  • 创建Adaptor类

    • class ViewPagerAdapter extends RecyclerView.Adapter {
      
          @NonNull
          @Override
          public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
              return null;
          }
      
          @Override
          public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
      
          }
      
          @Override
          public int getItemCount() {
              return 0;
          }
      }
      
  • 适配的内容是一个单独界面,创建界面

    • <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          android:id="@+id/action_container">
      
          <TextView
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:id="@+id/tvTitle"
              android:layout_centerInParent="true"
              android:textColor="#ff4532"
              android:textSize="32dp"
              android:text="Hello"/>
      
      </RelativeLayout>
      
  • adapter 解析item_pager 组件

    • // 解析 item_pager
          class ViewPagerViewHolder extends RecyclerView.ViewHolder{
      
              TextView mtv;
              RelativeLayout mContainer;
              public ViewPagerViewHolder(@NonNull View itemView) {
                  super(itemView);
                  mContainer = itemView.findViewById(R.id.container);
                  mtv = itemView.findViewById(R.id.tvTitle);
              }
          }
      
  • 把 组件加到 view上 先解析 Item_pager .xml 成 一个 view

    public ViewPagerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        //解析 xml 返回 view
        return new ViewPagerViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_pager,parent,false));
    }
    
  • 设置文字和颜色

    • public ViewPagerAdapter(){
              titles.add("Hello");
              titles.add("Kity");
              titles.add("A");
              titles.add("B");
              titles.add("C");
              titles.add("D");
              titles.add("E");
              titles.add("F");
              titles.add("G");
              titles.add("H");
          }
      colors.add(R.color.white);
              colors.add(R.color.red);
              colors.add(R.color.colorAccent);
              colors.add(R.color.colorPrimary);
              colors.add(R.color.balck);
              colors.add(R.color.colorPrimary);
              colors.add(R.color.red);
              colors.add(R.color.white);
              colors.add(R.color.balck);
      
  • 设置页数

    • @Override
      public int getItemCount() {
          return 10;
      }
      
  • 传入文字和颜色

    • @Override
      public void onBindViewHolder(@NonNull ViewPagerViewHolder holder, int position) {
      
          holder.mtv.setText(titles.get(position));
      
      }
      holder.mContainer.setBackgroundResource(colors.get(position));
      

总结

一般流程:

  • 定义 ViewPager
  • 为Viewpager 构建 Adapter
  • 创建Adapter 并继承RecyclerView.Adapter
  • 构建ViewPager 要展示页面的 ViewHolder
  • 实现必须的方法

Fragment 与 ViewPager 的联合应用

ViewPager + Fragment 形成翻页效果‘

  • activity是数组,fragment是数组之上的结构

MV VM : jetpack 扩展

模拟微信页面

方案1 :ButtomNavigationView

原文地址:https://www.cnblogs.com/AronJudge/p/14621179.html