自己做个Android框架-Dialog

代码地址:

TJFramework - -TJDialog.java

文章索引

  1. List item

序言

任何封装都不是一蹴而就的,需要有一定的时间和经验的积累,去挖掘深层次的需求。我看过很多人的封装,有一种风格是在一个大的封装里集成了各种各样的弹窗,是或否弹窗-进度条弹窗-加载弹窗-等等等,但后来我发现,面对日益多变的设计需求,任何指定UI的封装都是活不不长久的,所以我从一开始做,就是打算让每一个弹窗的创建都能自由化、简单化,能真正对得起Base角色。

弹窗需求设计

  • 简单、快捷、一目了然的调用逻辑
  • 支持自定义页面
  • 支持弹窗动画自定义。
  • 支持自动响应关闭、取消、确认等通用事件
  • 支持统一化、能面对任何UI的事件回调机制
  • 支持内存回收,处理内存泄漏问题

弹窗开做

构造方法

这里的设计是,全程通过布局文件来初始化弹窗,需要什么UI,直接新建一个布局就行了。至于怎么自动响应关闭、取消、确认等通用事件,我这里用的是通过在布局内指定特定的id,即可添加相关的功能。里入你需要确认按钮和取消按钮,只需要分别设置fw_dialog_win_bt_continue和fw_dialog_win_bt_cancel为其id即可。

public TJDialog(@NonNull Context context, @LayoutRes int layoutId)
public TJDialog(@NonNull Context context, @LayoutRes int layoutId,@StyleRes int styleId)
public TJDialog(@NonNull Context context, @LayoutRes int layoutId, int width, int height)
public TJDialog(@NonNull Context context, @LayoutRes int layoutId, int width, int height,int styleId)
{
	super(context,styleId);
    this.width = width;//支持WRAP_CONTENT、MATCH_PARENT、自定义大小,用于后面设置弹窗的整体宽高
    this.height = height;
    //通过制定的id来寻找对应的组件,所以如果需要一个关闭按钮,则只需要
    VIEW_WIN_BG_ID = getViewWinBgId();//通过方法获取id,如有需要可以重写该方法二次封装,改变其中默认的id。
    VIEW_WIN_BOX_ID = getViewWinBoxId();
    VIEW_WIN_TITLE_ID = getViewWinTitleId();
    VIEW_WIN_BT_CONTINUE_ID = getViewWinBtContinue();
    VIEW_WIN_BT_CANCEL_ID = getViewWinBtCancel();
    VIEW_WIN_BT_CLOSE_ID = getViewWinBtClose();
    baseView = LayoutInflater.from(context).inflate(layoutId, null);
    setContentView(baseView);
    initView();//初始化组件,设置点击事件
}    
private void initView()
    {
        //初始化组件
        winBgView = baseView.findViewById(VIEW_WIN_BG_ID);
        winBoxView = baseView.findViewById(VIEW_WIN_BOX_ID);
        winTitleView = baseView.findViewById(VIEW_WIN_TITLE_ID);
        winBtContinue = baseView.findViewById(VIEW_WIN_BT_CONTINUE_ID);
        winBtCancel = baseView.findViewById(VIEW_WIN_BT_CANCEL_ID);
        winBtClose = baseView.findViewById(VIEW_WIN_BT_CLOSE_ID);
        //初始化点击事件
        setOnClickListener(winBgView);
        setOnClickListener(winBoxView);
        setOnClickListener(winBtContinue);
        setOnClickListener(winBtCancel);
        setOnClickListener(winBtClose);
        //这个方法是抽象方法,需要重写设置你想要监听其点击事件的组件
        int[] ids = onInitClick();
        if(ids!=null)
        {
            for(int id:ids)
            {
                View view = baseView.findViewById(id);
                setOnClickListener(view);
            }
        }
        //抽象方法,用户可以重写初始化自己的组件
        onInitView(baseView);
    }
show()和dismiss()
@Override
    public void show() {
        if(!isShow)//防止重复显示
        {
            super.setOnShowListener(dialog -> {
        		super.setOnShowListener(null);
            	if(onShowListener!=null) {
                	onShowListener.onShow(dialog);
            	}
            	//统一事件监听器,支持若干个常用事件监听,和所有自定义按钮的点击事件监听
            	if(onTJDialogListener!=null) {
                	onTJDialogListener.onShow(dialog,state);
            	}
        	});
            baseView.setVisibility(View.VISIBLE);
            if(winBgView!=null&&isShowWinBgAnim)
            {
            	//显示背景动画,可自定义,当然默认的动画也很美了
                if(animationWinBgEnter==null) {
                    animationWinBgEnter = AnimationUtils.loadAnimation(getContext(), windowAnimEnterId);
                } else {
                    animationWinBgEnter.reset();
                }
                winBgView.startAnimation(animationWinBgEnter);
            }
            if (winBoxView != null&&isShowWinBoxAnim) {
            	//显示窗体动画,可自定义,当然默认的动画也很美了
                if(animationWinBoxEnter==null) {
                    animationWinBoxEnter = AnimationUtils.loadAnimation(getContext(), contentAnimEnterId);
                } else {
                    animationWinBoxEnter.reset();
                }
                winBoxView.startAnimation(animationWinBoxEnter);
            }
            Window window = getWindow();
            if(window!=null)
            {
                window.setWindowAnimations(-1);
            }
            //拦截一些意外的报错(popupWindows继承过来的做法)
            try {
                super.show();
                isShow = true;
            }catch (Exception e){
                LogUtil.exception(e);
            }
            //设置弹窗动画
            WindowManager.LayoutParams layoutParams = getWindow().getAttributes();
            if (layoutParams != null) {
                layoutParams.width = width;
                layoutParams.height = height;
            }
            this.getWindow().setAttributes(layoutParams);
        }
    }
@Override
    public void dismiss() {
        if(isShow)
        {
        	super.setOnDismissListener(dialog -> {
        	super.setOnDismissListener(null);
            if(onDismissListener!=null) {
                onDismissListener.onDismiss(dialog);
            }
            //统一事件监听器,支持若干个常用事件监听,和所有自定义按钮的点击事件监听
            if(onTJDialogListener!=null) {
                onTJDialogListener.onDismiss(dialog,state);
            }
        	});
            isShow = false;
            if(winBoxView!=null&&isShowWinBoxAnim)
            {
            	//执行窗体关闭动画-默认的是渐变消失
                if(animationWinBoxExit==null) {
                    animationWinBoxExit = AnimationUtils.loadAnimation(getContext(), contentAnimExitId);
                } else {
                    animationWinBoxExit.reset();
                }
                winBoxView.startAnimation(animationWinBoxExit);
            }
            if(winBgView!=null)
            {
            	//执行背景关闭动画-默认的是渐变消失
                if(animationWinBgExit==null) {
                    animationWinBgExit = AnimationUtils.loadAnimation(getContext(), windowAnimExitId);
                } else {
                    animationWinBgExit.reset();
                }
                winBgView.startAnimation(animationWinBgExit);
                animationWinBgExit.setAnimationListener(new Animation.AnimationListener() {
                    @Override
                    public void onAnimationStart(Animation animation) {

                    }

                    @Override
                    public void onAnimationEnd(Animation animation) {
                    	//在动画执行完成之后dismiss弹窗。请放心,并不会造成内存泄漏。
                        TJDialog.super.dismiss();
                        baseView.setVisibility(View.INVISIBLE);
                    }

                    @Override
                    public void onAnimationRepeat(Animation animation) {

                    }
                });
            }
            else
            {
                super.dismiss();
            }
        }
    }
destroy()

这里回收了所有的对象,完全不存在任何内存泄漏的可能。

@Override
    public void destroy() {
        setOnDismissListener(null);
        setOnShowListener(null);
        setOnTJDialogListener(null);
        super.setOnDismissListener(null);
        super.setOnShowListener(null);
        onShowListener = null;
        onDismissListener = null;
        baseHandler.removeMessages(DISMISS);
        baseHandler.removeCallbacksAndMessages(null);
        baseView = null;
        winBgView = null;
        winBoxView= null;
        winTitleView= null;
        winBtContinue= null;
        winBtCancel= null;
        winBtClose= null;
    }

整个类492行代码,但主体代码并不多,就上面这些。其实整个封装的逻辑是很清晰的,并不复杂,但这样之后确实为我去掉了很多弹窗调用的烦恼。而且如果有需要的话,二次封装一些通用的弹窗也是可以的。

个人知识有限,不敢托大,如有遗漏缺陷的地方,欢迎大家指正。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值