zoukankan      html  css  js  c++  java
  • Android开发笔记(十七)——Fragment详解

    Fragment基本介绍和使用

    • Fragment有自己的生命周期。
    • Fragment依赖于Activity。
    • Fragment通过 getActivity() 可以获取所在的Activity;Activity通过FragmentManager的 findFragmentById() 或者 findFragmentByTag() 获取Fragment。
    • Fragment和Activity是多对多的关系。

    新建一个package名为 fragment ,在这个包内创建一个Activity ContainerActivity 作为Fragment演示界面,对应会创建好布局 activity_container.xml ,之后在该包内创建两个Fragment分别为 AFragmentBFragment ,创建相对应的布局 fragment_afragment_b

    在布局 fragment_a 的布局如下: fragment_b 类似。

    AFragment.java 中的代码如下: BFragment.java 类似。

    public class AFragment extends Fragment {
    
        private TextView mTvTitle;
    
        //设置布局文件
        @Nullable
        @Override
        public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
            //相当于Activity中setContentView的作用
            View view = inflater.inflate(R.layout.fragment_a, container, false);
            return view;
        }
    
        //设置findViewById
        @Override
        public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
            super.onViewCreated(view, savedInstanceState);
    
            mTvTitle=view.findViewById(R.id.tv_title);
        }
    }
    

    布局 activity_container.xml 如下:其中 FrameLayout帧布局,这个布局直接在屏幕上开辟出一块空白的区域,当我们往里面添加控件的时候,会默认把他们放到这块区域的左上角。

    MainActivity 进入 ContainerActivity ,想要把AFragment放到 ContainerActivity 中, ContainerActivity.java 中的代码如下:

    当前效果展示:

    想要点击按钮,FrameLayout 中显示的内容从AFragment变成BFragment, 在 ContainerActivity.java 中的代码如下:替换的实现使用replace()函数

    效果如下:

    Fragment中getActivity()为null的问题

    Fragment中获取当前所在的Activity可以使用 getActivity() 方法,切换到后台或者横竖屏去转换的时候,可能会出现 getActivity() 为null的问题。

    向Fragment传递参数

    之前添加Fragment的时候实例化是直接new一个Fragment,如果在实例化Fragment的时候希望传参,可以这样做:在 AFragment.java 中添加 newInstance 方法:在这个方法中实例化一个AFragment,并且给这个fragment setArguments,通过getArguments得到具体的值:

    之后在 ContainerActivity.java 中改变一下实例化的方法:调用AFragment的一个静态的方法 newInstance

    Fragment回退栈

    更改之前的布局,activity_container.xml 的整个界面是一个FrameLayout

    布局 fragment_a 更改如下:

    ContainerActivity 中代码修改如下:在MainActivity上点击Button进入整个屏幕都是AFragment。

    AFragment中的Button "更换为BFragment" 实现的是点击按钮,当前界面显示为BFragment的内容,button “更改TextView的文字内容” 实现的是点击按钮,AFragment中TextView的内容更改。

    此时效果如下:

    当点击按钮 "更换为BFragment" ,当前界面显示为BFragment的内容,返回时会直接返回到MainActivity中,如果想要返回上一届界面也就是AFragment时,可以如下操作:在commit之前把Fragment添加到回退栈当中去

    此时效果如下:

    日志如下:

    尽管AFragment没有被重新实例化,但是 onCreateView 方法还是会重新运行,也就是说实例还是同一个实例,但是视图会被重新创建,从显示效果可以看到,在AFragment中,先更换TextView的文字内容,再更换为BFragment,这时返回的时候可以发现,显示的文字依旧是之前的文字,这就验证了Activity还是之前的实例,但是 onCreateView 方法还是会重新调用,所以他的视图还又重新刷新了一遍,TextView回到了最开始设置的文字。

    那么如果希望从BFragment返回的时候,AFragment中的TextView是之前更换过的状态,可以如下操作:先将AFragment隐藏掉,再add一个新的Fragment,之后再添加一个BFragment,接着添加到回退栈当中,最后commit,而不是直接replace(会导致前一个Fragment的视图没有被保存下来)

    此时效果如下:

    可以看到此时视图并没有被重新创建,而是保持了之前的视图状态,

    Fragment和Activity的通信

    希望在AFragment中点击Button,把ContainerActivity中的TextView设置文字(从Fragment中发出消息,通知Activity去执行的环节)

    在ContainerActivity中写一个公共的方法:实现当调用这个方法的时候可以给TextView设置文字

        public void setData(String text){
            mTvTitle.setText(text);
        }
    

    在AFragment中添加点击事件如下:把getActivity()转换成ContainerActivity,然后调用ContainerActivity中的setData方法

            mBtnMessage.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    ((ContainerActivity)getActivity()).setData("你好!");
                }
            });
    

    该方法可行但是并不推荐。更推荐下面的方法:

    通过回调接口来实现Fragment和Activity的通信

    在Activity中去实现一个在Fragment中声明好的接口,通过回调接口来实现数据的传递

    首先在Fragment中写一个接口:

        public interface IOnMessageClick{
            void onClick(String text);
        }
    
    

    让Activity去实现这个接口:

        @Override
        public void onClick(String text) {
            mTvTitle.setText(text);
        }
    

    在AFragment中声明接口:

    private IOnMessageClick listener;
    

    当Fragment依附到Activity中时候,Fragment会调用一个方法 onAttach() :把context强制转换成接口,如果转换失败,则Activity没有实现这个接口IOnMessageClick,就抛出异常。

        @Override
        public void onAttach(Context context) {
            super.onAttach(context);
            try {
                listener = (IOnMessageClick) context;
            }catch (ClassCastException e){
                throw new ClassCastException("Activity 必须实现IOnMessageClick接口");
            }
        }
    

    添加点击事件如下:

            mBtnMessage.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
    //                ((ContainerActivity)getActivity()).setData("你好!");
                    listener.onClick("你好呀!");
                }
            });
    

    这时候可以正常通信。

  • 相关阅读:
    使用JS实现网页动态换肤
    数据库更新Sql脚本总结
    Javascript无刷新获取当前时间
    ASP.NET将网页设为桌面图标实现
    解决在IE浏览器中resize事件执行多次
    linux编译安装gcc5.3.0
    JAVA抽象类和接口
    JAVA内部类
    推测竞赛中测试集的正负比例
    Codeforces Round #742 (Div. 2) 题解
  • 原文地址:https://www.cnblogs.com/yangdd/p/13357096.html
Copyright © 2011-2022 走看看