部分开发日志(二) | 青训营笔记

115 阅读5分钟

这是我参与「第四届青训营 」笔记创作活动的第3天

前言:

这是第二篇开发日志,主要实现了向用户申请权限的功能(通过自定义Dialog),下面我将讲述实现的过程

自定义Dialog

因为系统自带的Dialog实在是不好看,所以在这个项目中依旧来实现一下和项目UI设计风格一致的自定义Dialog

1. 定制Style

在这里丢出几个常用的Dialog的Style:

  1. 这个是Dialog的背景颜色和透明度这里我选择默认的
<item name="android:windowBackground">@android:color/transparent</item>
  1. 下面这个item可以设置Dialog是否显示标题,因为我的标题需要适配项目整体的UI风格,所以我把默认的标题隐藏掉了,之后可以在Layout文件中进行设置
<item name="android:windowNoTitle">true</item>
  1. 下面这个是设置边框的,和上面一样为了自定义UI,所以设置成了“@null”(无边框)
<item name="android:windowFrame">@null</item>
  1. 设置是否浮现在Activity上(如果选false的话根据个人经验:Dialog会单独占用整个窗口,即可以自定义Dialog显示在任何位置,并无法通过点击空白处关闭——设置了也不行)
<item name="android:windowIsFloating">true</item>
  1. 是否实现背景模糊(模糊了好看点)
<item name="android:backgroundDimEnabled">true</item>

下面是完整的style代码,样式继承自系统的Dialog

<!--DialogP-->
<style name="DialogP" parent="android:style/Theme.Dialog">
    <!--背景颜色及和透明程度-->
    <item name="android:windowBackground">@android:color/transparent</item>
    <!--去除标题 -->
    <item name="android:windowNoTitle">true</item>
    <!--去除边框-->
    <item name="android:windowFrame">@null</item>
    <!--浮现在activity之上-->
    <item name="android:windowIsFloating">true</item>
    <!--模糊-->
    <item name="android:backgroundDimEnabled">true</item>
</style>

2. 自定义layout文件

既然选择放弃安卓默认提供的Dialog,就要自己写一个更好看的来代替原来的Dialog布局,这里新建一个布局文件,根据项目的UI进行设计,代码我就不贴上来了,写一下比较重要的几个点:

  1. 可以根据不同的应用场景设计多个布局文件,因为之后Dialog的布局是通过onCreate()来绑定的,所以可以在构造方法中对使用哪一个布局进行设置,然后在onCreate方法中进行布局的绑定。当然也可以选择把控件都放到一个布局文件中,根据应用场景对需要的控件进行展示也是可以的

  2. 还有一点需要注意的是如果需要设计圆角或者其它边框的Dialog的话需要在布局文件中最外层的layout中设置background,当然使用其它方法设置边框也是没有问题的

3. 继承Dialog类,自定义属于自己的Dialog

既然是自定义的Dialog,而且应用场景也不算复杂,继承系统原有的Dialog类进行代码逻辑的修改是一个既轻松又不失水准的做法。

  1. 首先我们需要重写onCreate方法,这里可以对布局文件进行设置,也可以进行一些Dialog的初始化,这里初始化的方法我省略了
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.dialog_p);
    //可从空白处关闭
    setCanceledOnTouchOutside(false);
}
  1. 因为不重写方法会报错,所以我先把重写的事说一遍,但是最先加载的其实是构造方法,所以上面就有提到说通过构造方法来设置使用哪一种布局,再在onCreate中通过if等手段做出判断的事情。除此之外,我们还需要再构造方法中绑定Style,可以看见这里调用父类构造方法设置了Style,具体代码如下:
//构造方法,绑定style
public DialogP(@NonNull Context context, int dialogType) {
   super(context,R.style.DialogP);
   this.context=context;
   this.dialogType=dialogType;
}
  1. 本来想说接下来可以即兴发挥的,但还是把剩下的思路讲了:

首先是通过findviewbyid来找到控件,这样就可以在类中自己编写类似于setTitle()的方法对Dialog中的控件进行操作了

private void initView() {
    title=findViewById(R.id.tv_dialog_p_title);
    message=findViewById(R.id.tv_dialog_p_message);
    positiveButton=findViewById(R.id.bt_dialog_p_confirm);
    negativeButton=findViewById(R.id.bt_dialog_p_cancel);
    textInputLayout=findViewById(R.id.et_dialog_p_layout);
    textInputEditText=findViewById(R.id.et_dialog_p_text);
}

其次我们还需要对控件进行点击监听之类的操作,我通过编写一个按键监听接口来实现按键功能的设置,具体代码我贴在下面以供参考

//处理按钮事件
private void initEvent() {
    //确定
    positiveButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            if(onButtonClickListener!=null)
                onButtonClickListener.onPositiveButtonClick();
        }
    });
    //取消
    negativeButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            if(onButtonClickListener!=null)
                onButtonClickListener.onNegativeButtonClick();
        }
    });
}

public interface onButtonClickListener{

    void onPositiveButtonClick();

    void onNegativeButtonClick();
}

最后要注意的一点就是我们还需要设计一些方法来对Dialog进行定制化的操作,比如使用.show()时需要进行刷新操作,就可以这样写

public void show(){
    super.show();
    refreshView();
}

想设置Dialog是否无法关闭就可以这样写

//设置是否可以关闭
public DialogP setCanCancel(boolean canCancel){
    this.setCancelable(canCancel);
    return this;
}

其它的就真的可以自行发挥了,毕竟这只是一个最简单的自定义Dialog,没啥技术含量。

使用

完成自定义Dialog的编写,现在就可以在需要的地方调用刚刚写好的自定义Dialog了,我对Dialog进行了很多的方法拓展,基本做到了大部分UI都可以自己设置,但还是有一定的限制,不过在这个简单的项目里也很够用了,下面把使用自定义Dialog的代码贴上来:

//向用户申请弹窗
DialogP dialogP = new DialogP(this,DialogP.DIALOG_P_NORMAL);
dialogP.setMessage("使用此应用程序需要联网权限和存储权限")
        .setPosBtnText("同意")
        .setNegBtnText("拒绝")
        .setTitle("用户须知")
        .setCanCancel(false)
        .setOnButtonClickListener(new DialogP.onButtonClickListener() {
            @Override
            public void onPositiveButtonClick() {
                ```
            }

            @Override
            public void onNegativeButtonClick() {
                ```
            }
        }).show();

心得

其实这个自定义Dialog是很久之前就实现过的,我自己在做项目的时候也经常拿出来迭代一下,功能越来越完善,偶尔也会因为项目的难易程度而增加或者减少Dialog的显示类型以优化代码的数量,这次又把以往的经验拿出来进行定制化的修改,可以说是又巩固了一遍知识