进阶必读,安卓下 Builder 模式解析+自定义 Dialog

   2016-10-31 0
核心提示:**本文将从一下几个方面展开:1Bulider模式的原理和使用2系统Dailog的调用3自定义Dailog4自定义Dailog的一些小坑** 本文Github代码链接 https://github.com/AndroidMsky/AirDialog 自定义Dailog效果: 1.Bulider模式的原理和使用当你看到这样的一串代码是不是

**本文将从一下几个方面展开:

1Bulider模式的原理和使用

2系统Dailog的调用

3自定义Dailog

4自定义Dailog的一些小坑**

本文Github代码链接

https://github.com/AndroidMsky/AirDialog

自定义Dailog效果:

1.Bulider模式的原理和使用

当你看到这样的一串代码是不是觉得很炫酷?

airDialog = new AirDialog.Builder(this).
                    setLeftText("gogo").
                    setRightText("nono").
                    create();

通过几个点点,像一个链子一样配置组装一个对象。今天就教给大家自己也可以设计这样一条链子。相比构造方法,这种模式更加灵活,更加清晰。

先看看设计图:

 进阶必读,安卓下 Builder 模式解析+自定义 Dialog

别怕相信大多数人都看不懂。不过对设计模式了解比较多的人呢还是可以看懂的,今天就咱不谈这个类图(你看懂不如会用)。

为什么可以里连续…….的调用方法,其实就是每次调用方法后return一个对象就好喽。当前的表达式值就一直是这个对象所以可以无限的….下去。

public Builder setLeftText(String left) {
            this.left=left;
            return this;
        }

代码很清晰没个设置方法都是这样的,方法的返回类型就是当前的Builder。那么我们就可以继续的调用Builder类中的方法喽。

2.系统Dailog的调用

new AlertDialog.Builder(MainActivity.this).setTitle("系统提示")//设置对话框标题  

     .setMessage("!")//设置显示的内容  

     .setPositiveButton("确定",new DialogInterface.OnClickListener() {//添加确定按钮  
@Override  

         public void onClick(DialogInterface dialog, int which) {
         }  

     }).setNegativeButton("返回",new DialogInterface.OnClickListener() {//添加返回按钮  
@Override  
public void onClick(DialogInterface dialog, int which) { 
 }  
 }).show();//在按键响应事件中显示此对话框 

系统提供了很多的Dialog的子类本文不去详细介绍,接下来就说如何自己写一个类似Dialog的子类。

3.自定义Dailog

1继承Dialog并且实现构造方法:

public class AirDialog extends Dialog {

public AirDialog(Context context) {
        super(context, R.style.custom_dialog);
    }

super方法的第二个参数是为Dialog指定一个主题,那就在Styles。xml中加入如下代码:

<style name="custom_dialog" parent="@android:style/Theme.Dialog">
<item name="android:windowFrame">@null</item> <!-- 边框 -->
<item name="android:windowIsFloating">true</item> <!-- 是否浮现在activity之上 -->
<item name="android:windowIsTranslucent">true</item> <!-- 半透明 -->
<item name="android:windowNoTitle">true</item> <!-- 无标题 -->
<item name="android:windowBackground">@android:color/transparent</item>
</style>

常用的几个标签的意思已经注释。可以通过配置跟多的标签来扩展dialog的样式。

这样就可以去调用一个dialog了,但是不行,我们要加入Builder模式,于是参考安卓源码后新建内部静态类Builder

public static class Builder{

        private Context context;
        private Context context;
        private String left;
        private String right;
        private View.OnClickListener leftOCL;
        private View.OnClickListener rightOCL;
        private Button leftButton;
        private Button rightButton;

        public Builder(Context context){
            this.context=context;

        }

指定各种组装配置方法:

public Builder setLeftText(String left) {
            this.left=left;
            return this;
        }
public Builder setRightText(String right) {
            this.right=right;
            return this;
        }
public Builder setLeftOnClick(View.OnClickListener left) {
            this.leftOCL=left;
            return this;
        }
public Builder setRightOnClick(View.OnClickListener right) {
            this.rightOCL=right;
            return this;
        }

可以看出没个方法都return 了一个Builder方便下次调用。

Builder类中的create方法最后调用根据前面的配置生成一个airDialog的对象:

public AirDialog create() {

            final AirDialog airDialog=new AirDialog(context);

            View view = LayoutInflater.from(context).inflate(R.layout.dialog, null);
            leftButton=(Button)view.findViewById(R.id.button2);
            rightButton=(Button)view.findViewById(R.id.quxiao_btn);

            if (!TextUtils.isEmpty(left))
            leftButton.setText(left);
            if (!TextUtils.isEmpty(right))
            rightButton.setText(right);
            if (leftOCL!=null)
            leftButton.setOnClickListener(leftOCL);
            if (rightOCL!=null)
            rightButton.setOnClickListener(rightOCL);



            Window win = airDialog.getWindow();
            win.getDecorView().setPadding(0, 0, 0, 0);
            WindowManager.LayoutParams lp = win.getAttributes();
            lp.width = WindowManager.LayoutParams.MATCH_PARENT;
            lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
            win.setAttributes(lp);
           // win.setGravity(Gravity.NO_GRAVITY);
            win.setGravity(Gravity.CENTER);
            airDialog.setContentView(view);
            airDialog.setCanceledOnTouchOutside(false);
           // airDialog.setCancelable(false);

            return airDialog;

        }

可以看出Dialog的现实原理,是在WindowManager的控制下现实出来的:

Window win = airDialog.getWindow();

win.getDecorView().setPadding(0, 0, 0, 0);

WindowManager.LayoutParams lp = win.getAttributes();

Activity像一个工匠(控制单元),

Window像窗户(承载模型),

View像窗花(显示视图)

LayoutInflater像剪刀,

Xml配置像窗花图纸。(大家都这么比喻,不是我发明的)

清晰的说出了几者关系。

最后调用我们的dialog出来吧:

if (airDialog == null)

            airDialog = new AirDialog.Builder(this).
                    setLeftText("gogo").
                    setRightText("nono").
                    setRightOnClick(new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            airDialog.dismiss();
                            Toast.makeText(MainActivity.this, "nono", Toast.LENGTH_SHORT).show();
                        }
                    }).
                    create();

        airDialog.show();

是不是很爽呢,自已可以做出这种链了。

4.自定义Dailog的一些小坑

第一次我xml是这样写的:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    android:id="@+id/activity_main"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
>


    <TextView
        android:id="@+id/text_content"
        android:layout_width="200dp"
        android:layout_height="150dp"
        android:background="#FFF222"
        android:gravity="center"
        android:text="(自定义Dialog弹窗)"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true"/>

    <Button
        android:id="@+id/button2"
        android:layout_width="100dp"
        android:layout_height="wrap_content"
        android:text="yes"
        android:background="#FFF000"
        android:layout_alignParentBottom="true"
        android:layout_toLeftOf="@+id/quxiao_btn"
        android:layout_toStartOf="@+id/quxiao_btn"/>

    <Button
        android:id="@+id/quxiao_btn"
        android:layout_width="100dp"
        android:background="#FFF999"
        android:layout_height="wrap_content"
        android:text="no"
        android:layout_alignParentBottom="true"
        android:layout_alignRight="@+id/text_content"
        android:layout_alignEnd="@+id/text_content"/>

    <TextView
        android:id="@+id/textView"
        android:layout_width="200dp"
        android:layout_height="50dp"
        android:background="#cecb9e"
        android:gravity="center"
        android:text="标题"
        android:layout_above="@+id/text_content"
        android:layout_alignLeft="@+id/text_content"
        android:layout_alignStart="@+id/text_content"/>

</RelativeLayout>

textView设置再了剧中的content之上,在xml中正常显示但是到程序中就无法显示了。问题在于这行代码,高度设置成了WRAP_CONTENT。结果没有吧titleView计算到view中来。

lp.height = WindowManager.LayoutParams.WRAP_CONTENT;

后来我就在想安卓为什么这么设计,为什么不MATCH_PARENT,其实原因很简单:

// win.setGravity(Gravity.NO_GRAVITY);
            win.setGravity(Gravity.CENTER);

弹窗之所以叫弹窗,因为它只是窗口不是全屏幕的东西,所谓安卓希望我们的窗口可以动态指定位置如Gravity.CENTER,Gravity.BOTTOM等。这样窗口更加灵活不用多个xml支持。所以建议大家写dialog的布局的时候从“头“开始,不要以一个center的view为基准,本文的正确的xml如下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    android:id="@+id/activity_main"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    >


    <TextView
        android:id="@+id/text_content"
        android:layout_width="200dp"
        android:layout_height="150dp"
        android:layout_below="@+id/text_title"
        android:layout_centerHorizontal="true"
        android:background="#FFF222"
        android:gravity="center"
        android:text="(自定义Dialog弹窗)"/>

    <Button
        android:id="@+id/quxiao_btn"
        android:layout_width="100dp"
        android:layout_height="wrap_content"
        android:layout_alignEnd="@+id/text_content"
        android:layout_alignRight="@+id/text_content"
        android:layout_below="@+id/text_content"
        android:background="#FFF999"
        android:text="no"/>

    <TextView
        android:id="@+id/text_title"
        android:layout_width="150dp"
        android:layout_height="50dp"
        android:layout_alignEnd="@+id/text_content"
        android:layout_alignParentTop="true"
        android:layout_alignRight="@+id/text_content"
        android:background="#cecb9e"
        android:gravity="center"
        android:text="标题"/>

    <ImageView
        android:id="@+id/icon"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_alignLeft="@+id/text_content"
        android:layout_alignParentTop="true"
        android:background="#111FFF"
        android:layout_alignStart="@+id/text_content"
        />

    <Button
        android:id="@+id/button2"
        android:layout_width="100dp"
        android:layout_height="wrap_content"
        android:background="#bfba21"
        android:text="yes"
        android:layout_alignBaseline="@+id/quxiao_btn"
        android:layout_alignBottom="@+id/quxiao_btn"
        android:layout_alignLeft="@+id/text_content"
        android:layout_alignStart="@+id/text_content"/>

</RelativeLayout>

相信阅读本文后自定义花哨的dialog肯定不成问题了。

如果觉得这篇文章对你有帮助 欢迎star我的github。也算对笔者的一种支持。

本文Github代码链接

https://github.com/AndroidMsky/AirDialog

欢迎加安卓开发交流群:308372687

博主原创未经允许不许转载。

 进阶必读,安卓下 Builder 模式解析+自定义 Dialog

 
标签: 安卓开发
反对 0举报 0 评论 0
 

免责声明:本文仅代表作者个人观点,与乐学笔记(本网)无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
    本网站有部分内容均转载自其它媒体,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责,若因作品内容、知识产权、版权和其他问题,请及时提供相关证明等材料并与我们留言联系,本网站将在规定时间内给予删除等相关处理.

  • 安卓中通知功能的具体实现
    安卓中通知功能的具体实现
    通知[Notification]是Android中比较有特色的功能,当某个应用程序希望给用户发出一些提示信息,而该应用程序又不在前台运行时,就可以借助通知实现。使用通知的步骤1、需要一个NotificationManager来获得NotificationManager manager = (NotificationManager
    02-05 安卓开发
  • Android view系统分析-setContentView
    Android view系统分析-setContentView
    第一天上班,列了一下今年要学习的东西。主要就是深入学习Android相关的系统源代码,夯实基础。对于学习Android系统源代码,也没什么大概,就从我们平常使用最基础的东西学起,也就是从view这个切入点开始学习Android的源码,在没分析源码之前,我们有的时候
    02-05 安卓开发
  • 如何进行网络视频截图/获取视频的缩略图
    如何进行网络视频截图/获取视频的缩略图
    小编导读:获取视频的缩略图,截图正在播放的视频某一帧,是在音视频开发中,常遇到的问题。本文是主要用于点播中截图视频,同时还可以获取点播视频的缩略图进行显示,留下一个问题,如下图所示, 如果要获取直播中节目视频缩略图,该怎么做呢?(ps:直播是直
  • Android NDK 层发起 HTTP 请求的问题及解决
    Android NDK 层发起 HTTP 请求的问题及解决
    前言新的一年,大家新年快乐~~鸡年大吉!本次给大家带来何老师的最新文章~虽然何老师还在过节,但依然放心不下广大开发者,在此佳节还未结束之际,给大家带来最新的技术分享~ 事件的起因不说了,总之是需要实现一个 NDK 层的网络请求。为了多端适用,还是选择
  • Android插件化(六): OpenAtlasの改写aapt以防止资源ID冲突
    Android插件化(六): OpenAtlasの改写aapt以防
    引言Android应用程序的编译中,负责资源打包的是aapt,如果不对打包后的资源ID进行控制,就会导致插件中的资源ID冲突。所以,我们需要改写aapt的源码,以达到通过某种方式传递资源ID的Package ID,通过aapt打包时获取到这个Package ID并且应用才插件资源的命名
    02-05 安卓开发
  • Android架构(一)MVP架构在Android中的实践
    Android架构(一)MVP架构在Android中的实践
    为什么要重视程序的架构设计 对程序进行架构设计的原因,归根结底是为了 提高生产力 。通过设计是程序模块化,做到模块内部的 高聚合 和模块之间的 低耦合 (如依赖注入就是低耦合的集中体现)。 这样做的好处是使得程序开发过程中,开发人员主需要专注于一点,
    02-05 安卓开发
  • 安卓逆向系列教程 4.2 分析锁机软件
    安卓逆向系列教程 4.2 分析锁机软件
    安卓逆向系列教程 4.2 分析锁机软件 作者: 飞龙 这个教程中我们要分析一个锁机软件。像这种软件都比较简单,完全可以顺着入口看下去,但我这里还是用关键点来定位。首先这个软件的截图是这样,进入这个界面之后,除非退出模拟器,否则没办法回到桌面。上面那
    02-05 安卓开发
  • Android插件化(二):OpenAtlas插件安装过程分析
    Android插件化(二):OpenAtlas插件安装过程分析
    在前一篇博客 Android插件化(一):OpenAtlas架构以及实现原理概要 中,我们对应Android插件化存在的问题,实现原理,以及目前的实现方案进行了简单的叙述。从这篇开始,我们要深入到OpenAtlas的源码中进行插件安装过程的分析。 插件的安装分为3种:宿主启动时立
    02-05 安卓开发
  • [译] Android API 指南
    [译] Android API 指南
    众所周知,Android开发者有中文网站了,API 指南一眼看去最左侧的菜单都是中文,然而点进去内容还是很多是英文,并没有全部翻译,我这里整理了API 指南的目录,便于查看,如果之前还没有通读,现在可以好好看一遍。注意,如果标题带有英文,说明官方还没有翻
  • 使用FileProvider解决file:// URI引起的FileUriExposedException
    使用FileProvider解决file:// URI引起的FileUri
    问题以下是一段简单的代码,它调用系统的相机app来拍摄照片:void takePhoto(String cameraPhotoPath) {File cameraPhoto = new File(cameraPhotoPath);Intent takePhotoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);takePhotoIntent.putExtra(Medi
    02-05 安卓开发
点击排行