Android - Fragment

文章详细介绍了Fragment的生命周期,包括onAttach、onCreate、onCreateView等关键方法的调用时机。同时,讲解了如何静态和动态地将Fragment添加到Activity中,以及FragmentManager的使用,如事务处理、添加、移除和替换Fragment。此外,还提到了Fragment之间的数据通信方式和常见问题,如重叠显示及点击穿透的解决方案。

一、声明周期

通常情况下只需要重写 onCreateView() 提供自定义界面就行,重写其它生命周期方法第一行都要返回 super 实现。

onAttach( )

Fragment与Activity关联时回调,只会调用一次。

onCreate( )

创建该Fragment实例时回调,只会回调一次。用于除视图外的初始化,以保障它们在pause或stop状态时仍可用。

onCreateView( )

绘制视图时回调,会将显示的View返回,用于视图组件的初始化。不显示视图可返回null。

onActivityCreated( )

已弃用。初始化用上面两个。

onStart( )

可见时回调。

onResume( )

可以交互时回调。

onPause( )

失去焦点时回调。可能是可见但无法交互,例如被dialog遮挡。也可能是用户离开,可以做一些数据持久化。

onStop( )

完全不可见时回调,可以用来关闭一些资源。

onDestroyView( )

当视图被销毁时回调。

onDestroy( )

被销毁时回调。

onDetach( )

该Fragment从Activity上移除/替换时回调,只会调用一次。

二、将Fragment添加到Activity中

Fragment 1.2.0版本官方建议无论使用哪种方式添加,容器都建议使用 FragmentContainerView。

2.1 静态添加(xml)

把Fragment当作View一样使用。
  1. 编写Fragment布局,继承Fragment重写onCreatedView()设置布局。

  1. Activity布局中,通过对 FragmentContainerView 设置 name 引用 Fragment的全类名路径,在Activity代码中 findViewById 去使用。

//Activity布局中
<androidx.fragment.app.FragmentContainerView
    android:id="@+id/fragmentLeft"
    android:name="com.example.LeftFragment"    //指定Fragment的类名
    />

2.2 动态添加(代码)

  1. 编写Fragment布局,继承Fragment重写onCreatedView()设置布局。

  1. Activity布局中,添加 FragmentContainerView 用来占位。在Activity代码中实例化Fragment,通过 FragmentManager 开启 FragmentTransaction 将 Fragment 对象替换到占位容器中。

//Activity布局中
<androidx.fragment.app.FragmentContainerView
    android:id="@+id/fragmentContainerView"    //只是个用来占位的容器
    />
//activity

三、FragmentManager

用来管理Fragment返回栈,每一组操作称为事务 FragmentTransaction,一个事务只能被提交一次,只能再开启后提交。
  • 在 Activity 中通过 getSupportFragmentManager( ) 来获取。

  • 若是存在 Fragment 中嵌套 Fragment 的场景:

  • 在父片段中通过 getChildFragmentManager( ) 来获取子片段的管理器。

  • 在子片段中通过 getParentFragmentManager( ) 来获取父片段的管理器。

FragmentManager

beginTransaction( )

开启事务,返回一个FragmentTransaction。

findFragmentById( )

findFragmentByTag( )

通过 id 或 tag 获取对应的Fragment。

popBackStack( )

栈顶出栈。

getBackStackEntryCount( )

获取栈内Fragment数目。

FragmentTransaction

add( )

往容器中添加一个Fragment。

remove( )

从容器中移除一个Fragment并销毁。

replace( )

用指定的Fragment替换当前显示的(本质先remove再add)。

hide( )

隐藏当前Fragment(设为不可见,不会销毁)。

show( )

显示指定被隐藏的Fragment。

commit( )

提交事务,一个事物只能被提交一次,只能再开启后提交。

addToBackStack( )

将Fragment加入回退栈,按返回键的时候就会退到上一个。

attach( )

只销毁视图不销毁实例,Fragment状态仍旧由FragmentManager维护。

detach( )

重建视图并显示。

设置唯一标识

设置后,便可通过 FragmentManager 来获取对应的Fragment。
  • 通过 android:id 属性设置唯一id。

  • 通过 android:tag 属性设置唯一字符串标识。

  • 都为设置,默认为父容器view的id。

四、数据通信

更推荐使用ViewModel。

4.1 Fragment → Fragment

Fragment2 f2 = getActivity().getFragmentManager().findFragmentByTag("f2");
TextView textView = (TextView) getActivity().findViewById(R.id.fragment1_text);

4.2 Fragment → Activity

接口回调,或getActivity()并调用Activity中的方法。

4.3 Activity → Fragment

通过Fragment.setArguments方法向Fragment传递参数值,并且通过Fragment.getArguments方法获取传递的参数值。
MyFragment myFragment = new MyFragment();
Bundle bundle = new Bundle();
bundle.putString("DATA",values);//这里的values就是我们要传的值
myFragment.setArguments(bundle);

五、使用

最新版本

implementation("androidx.fragment:fragment-ktx:1.6.2")

5.1 结合 ViewPager

  • onHiddenChanged(boolean hidden):用 if 对 hidden 进行判断,true不在前端显示了,false在前端显示。

  • setUservisibleHint(boolean isVisibleToUser):fragment结合viewpager时候,FragmentStateAdapter设置为BEHAVIOR_SET_USER_VISIBLE_HINT时候调用,同上。

5.2 结合 RadioGroup

hide()、show() 对 Fragment 生命周期没有任何影。
public class MainActivity extends Activity {

    private Fragment mCurrentFragment;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final Fragment one = new OneFragment();
        final Fragment two = new TwoFragment();
        final Fragment three = new ThreeFragment();

        //默认显示第一个fragment,一个事物只能提交一次
        getFragmentManager().beginTransaction().add(R.id.container,one).commit();
        mCurrentFragment = one;

        RadioGroup rg = findViewById(R.id.rg);
        rg.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(RadioGroup group, int checkedId) {
                switch (checkedId){
                    case R.id.one:
                        switchContent(one);
                        break;
                    case R.id.two:
                        switchContent(two);
                        break;
                    case R.id.three:
                        switchContent(three);
                        break;
                }
            }
        });
    }

    public void switchContent(Fragment fragment) {
        FragmentTransaction transaction = getFragmentManager().beginTransaction();
        if (mCurrentFragment != fragment) {
            //先判断是否被添加过
            if (!fragment.isAdded()) {
                transaction.hide(mCurrentFragment).add(R.id.container, fragment).commit(); // 隐藏当前的fragment,添加要显示的fragment
            } else {
                transaction.hide(mCurrentFragment).show(fragment).commit(); // 隐藏当前的fragment,显示下一个
            }
            mCurrentFragment = fragment;
        }
    }

}

5.3 结合 Dialog(DialogFragment)

class Demo : DialogFragment() {
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        inflater.inflate(R.layout.fragment_chat, container, false)
        return super.onCreateView(inflater, container, savedInstanceState)
    }
}

class DemoActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val demo = Demo()
        supportFragmentManager
        demo.show(supportFragmentManager, "FragmentChat")  //显示
        demo.dismiss()  //隐藏
        if (demo.isVisible){}   //监听可见
    }
}

六、常见问题

6.1 重叠显示

fragment根布局节点设置android:background,除transparent都行。

6.2 点击穿透

fragment根布局节点设置设置android:clickable="true"。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值