Android Activity 与 DialogFragment通信传递数据

前言:

本篇文章讲解的是 Activity 与 DialogFragment 如何传递数据进行通信,在项目中经常要用

到,然后自己在做项目的过程中,梳理了一下,基本可以当做模板来使用。供参考

基本原理:

Activity 向 Fragment 传递数据: 在Activity中创建Bundle数据包,并调用Fragment的

setArguments(Bundle bundle) 方法即可将Bundle数据包传给Fragment。

Fragment 向Activity传递数据: 在Fragment中定义一个内部回调接口,在让包含该Fragment的Activity实现该回调接口,这样子Fragment即可调用该回调方法将数据传给Activity。

Activity代码如下:

        1. 实现 Fragment中的 自定义CallBackListener接口

        2.  通过setArguments(bundle)方法传递数据给Fragment

public class MainActivity extends AppCompatActivity implements CustomFragment.CallBackListener {
    private Button button;

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

        button = findViewById(R.id.test_btn);

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                CustomFragment customfragment = new CustomFragment();
                Bundle bundle = new Bundle();
                bundle.putString("transfer_data", "Activity 传递给 Fragment数据");
                //通过setArguments(bundle)方法传递数据
                customfragment.setArguments(bundle);
                customfragment.show(getSupportFragmentManager(), "test");
            }
        });
    }


    //接收从Fragment 返回给Activity 的数据
    @Override
    public void returnFragmentData(String message) {
        Log.e("test", "打印 Actvity data : " + message);
    }
}

DialogFragment 的代码,我这里做一个父类封装,子类只需要复写加载自定义的layout文件的方法即可,然后UI控件的事件也可以在里面处理

1. 父类DialogFragment的代码

public abstract class CustomDialogFragment extends DialogFragment {

    private static final String TAG = "test";

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        Dialog dialog = new AlertDialog.Builder(getActivity())
                .setView(getCustomView())
                .create();

        return dialog;
    }

    //只需要复写这个方法即可,处理事件也在这个方法中
    protected abstract View getCustomView();

    @Override
    public void onStart() {
        super.onStart();
        //在横竖屏情况下设置dialog对话框的宽和高, 设置DialogFragment的宽和高,需要在
        //onCreateDialog 生命周期方法之后才能设置成功
        Configuration newConfig = getResources().getConfiguration();
        Dialog dialog = getDialog();
        if (dialog != null) {
            DisplayMetrics dm = new DisplayMetrics();
            getActivity().getWindowManager().getDefaultDisplay().getMetrics(dm);
            //横屏和竖屏的宽高
            if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
                dialog.getWindow().setLayout((int) (dm.widthPixels*0.4), ViewGroup.LayoutParams.WRAP_CONTENT);
            } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
                dialog.getWindow().setLayout((int) (dm.widthPixels*0.64), ViewGroup.LayoutParams.WRAP_CONTENT);
            }
            //点击dialog外部,不关闭
            dialog.setCanceledOnTouchOutside(false);
        }
    }

    @Override
    public void onCancel(DialogInterface dialog) {
        dialogFinsih();
    }

    private void dialogFinsih(){
        try {
            getActivity().finish();
        } catch (Exception e) {
            Log.e(TAG, "father activity is destoryed "+ e);
        }
    }

}

    在使用DiaglogFragment 有三个注意的地方:

  第一点: 设置Dialog的宽和高的时候,一定要在生命周期onCreateDialog() 方法之后才可以设置成功,这里自定义宽高我写在onStart()方法中

  第二点: dialog.getWindow().setLayout((int) (dm.widthPixels*0.4), ViewGroup.LayoutParams.WRAP_CONTENT) ,通过查看源码,setLayout()的宽高参数,实质是这个Dialog的 DecorView 的宽高, 显示出来的Dialog宽高要比你设置的宽高要小一点,所以UI适配的时候,要适当去调整一下,比如UI给的设计图Dialog 的宽度是400dp, 你设置这个参数的时候需要设置大一点(估计432dp左右),宽高都是可以通过Layout inspector工具去查看,然后适配调整

 /**
     * Set the width and height layout parameters of the window.  The default
     * for both of these is MATCH_PARENT; you can change them to WRAP_CONTENT
     * or an absolute value to make a window that is not full-screen.
     *
     * @param width The desired layout width of the window.
     * @param height The desired layout height of the window.
     *
     * @see ViewGroup.LayoutParams#height
     * @see ViewGroup.LayoutParams#width
     */
    public void setLayout(int width, int height) {
        final WindowManager.LayoutParams attrs = getAttributes();
        attrs.width = width;
        attrs.height = height;
        dispatchWindowAttributesChanged(attrs);
    }


#最终调用的是 Dialog.java 中的onWindowAttributesChanged 方法,是给mDecor设置宽高

    @Override
    public void onWindowAttributesChanged(WindowManager.LayoutParams params) {
        if (mDecor != null) {
            mWindowManager.updateViewLayout(mDecor, params);
        }
    }

Dialog设置宽高参数效果图:

Dialog呈现给用户宽高效果图:

 第三点:

        如果你的DialogFragment,导入包为:android.app.DialogFragment;

       那么显示的时候调用的方法为:

        xxxxx.show(getFragmentManager(),    "testFragment");

       如果你的DialogFragment 导入包为 :androidx.fragment.app.DialogFragment

       那么显示的时候调用的方法为:

       xxxxx.show(getSupportFragmentManager(),  "testFragment");

2. 子类DialogFragment的代码

     

public class CustomFragment extends CustomDialogFragment {

    private CallBackListener mFragmentListener;


    public interface CallBackListener {
        //回调方法
        void returnFragmentData(String message);
    }


    //当该Fragent被添加显示到Activity时,回调该方法
    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        try{
            //把该activity当成 实现CallBackListener接口的对象
            mFragmentListener = (CallBackListener)activity;
        }catch (ClassCastException e) {
            throw new ClassCastException(activity.toString() + " must implementon CallBackListener");
        }
    }


    //当该Fragment 从它所属的activity 中被移除的时候,回调此方法
    @Override
    public void onDetach() {
        super.onDetach();
        //将 mFragmentListener 置为空
        mFragmentListener = null;
    }

    //设置dialogFragment 的自定义布局 ,然后获取子View 设置响应事件
    @Override
    protected View getCustomView() {

        View view = getActivity().getLayoutInflater().inflate(R.layout.dialog_main, null);

        Button button = view.findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //子View的响应事件
                if (null != mFragmentListener) {
                    mFragmentListener.returnFragmentData("从 Fragment 返回给 Actvity的数据");
                }
            }
        });
        return view;
    }


    //接收从Activity传递过来的数据
    @Override
    public void onResume() {
        super.onResume();
        Bundle receiveBundler = getArguments();
        String data = receiveBundler.getString("transfer_data");
        Log.e("test", " 打印 fragment data: " + data);
    }
}

       代码解读: 

第一点:子类DialogFragment 只需要复写 getCustomView() 方法, 实现设置dialogFragment 的自定义布局 ,然后获取子View 设置响应事件

第二点: 定义一个内部回调接口CallBackListener ,在onAttach方法中把 Activity转换成实现CallBackListener接口的对象,然后在需要的地方调用。这样子就把DialogFragment中的数据传递到Activity中了。

总结:

        Activity 与 Fragment 的通信基本是一个固定模板,在项目使用中根据需求再稍微调整即可。

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值