Dialog伪装者——ActivityDialog

首先讲一下我实现ActivityDialog的原因:大家知道,只有Activity的Context可以启动Dialog,对于我们在其他无法便捷拿到Activity Context的场景,想使用Dialog是无法实现的.但是人人往往看到的是一个表象,只要可以实现一个Dialog相似的效果,他们都不会怀疑你的,所以我们就来实现一个ActivityDialog


提供一下只有Activity的Context可以启动Dialog的依据

这里写图片描述

参考:Android中Activity、Service和Application的Context分析

一.效果图展示

这里写图片描述

二.代码分析

1.Dialog布局文件baseres_activity_network_disconnection_dialog.xml

为了实现圆角和立体效果,最外层布局使用了CardView ,但是会有一些细节问题,CardView四个圆角会有边角阴影,已经优化解决

<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/white"
    app:cardBackgroundColor="@android:color/white"
    app:cardCornerRadius="8dp"
    app:cardElevation="4dp"
    app:cardPreventCornerOverlap="false">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@android:color/transparent"
        tools:context=".view.NetworkDisconnectionDialog">

        <TextView
            android:id="@+id/baseres_dialog_title"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/baseres_colorAccent"
            android:gravity="center"
            android:padding="5dp"
            android:text="@string/baseres_dialog_title"
            android:textColor="@android:color/white"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <TextView
            android:id="@+id/baseres_dialog_content"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@android:color/white"
            android:gravity="center_vertical"
            android:minLines="5"
            android:padding="5dp"
            android:text="@string/baseres_dialog_content"
            android:textColor="@android:color/black"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@id/baseres_dialog_title" />

        <View
            android:id="@+id/baseres_divide_line"
            android:layout_width="match_parent"
            android:layout_height="1px"
            android:background="@android:color/black"
            app:layout_constraintTop_toBottomOf="@id/baseres_dialog_content" />

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@android:color/white"
            android:orientation="horizontal"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@id/baseres_divide_line">

            <TextView
                android:id="@+id/baseres_dialog_cancle"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:gravity="center"
                android:padding="8dp"
                android:text="@string/baseres_dialog_cancle_text"
                android:textColor="@android:color/black" />

            <View
                android:id="@+id/baseres_divide_vertical_line"
                android:layout_width="1px"
                android:layout_height="match_parent"
                android:background="@android:color/black" />

            <TextView
                android:id="@+id/baseres_dialog_confirm"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:gravity="center"
                android:padding="8dp"
                android:text="@string/baseres_dialog_confirm_text"
                android:textColor="@android:color/black" />
        </LinearLayout>

    </androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>

2.Dialog背景baseres_dialog_bg.xml

设置Activity的背景弧度与layout中CardView的弧度一致,否则会出现边角

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
    <!-- 圆角半径   设置圆角半径和CardView中圆角半径相同-->
    <corners android:radius="8dp" />
</shape>

3.NetworkDisconnectionDialog.kt

设计逻辑:

1.在NetworkDisconnectionDialog 声明一个参数配置类DialogParams实例;
2.通过静态内部类Builder,创建DialogParams实例,配置Dialog相关的参数
3.通过show()完成Activity跳转,通过 applyDialog(p!!)使用配置的Dialog参数,实现Dialog功能



class NetworkDisconnectionDialog : AppCompatActivity() {

    companion object {
        private const val TAG = "NetworkDisconnectionDialog"
        /**
         * 声明静态变量DialogParams
         * Dialog的参数配置类
         */
        var p: DialogParams? = null
    }

    /**
     * 创建一个类似Dialog的静态内部类Builder
     */
    class Builder constructor(val mContext: Context) {

        init {
            /**
             * 使用静态内部类第一件事,就是初始化Dialog的参数配置类
             */
            p = DialogParams()
        }
        /**
         * 设置标题
         */
        fun setTitle(title: String): Builder {
            p!!.title = title
            return this
        }
        /**
         * 设置提示内容
         */
        fun setContent(content: String): Builder {
            p!!.content = content
            return this
        }
        /**
         * 设置左边取消按钮的文字
         */
        fun setCancleText(cancleText: String): Builder {
            p!!.cancleText = cancleText
            return this
        }
        /**
         * 设置右边确认按钮的文字
         */
        fun setConfirmText(confirmText: String): Builder {
            p!!.confirmText = confirmText
            return this
        }

        /**
         * 设置左边取消按钮的点击操作接口
         */
        fun setNegativeveListener(mNegativeveListener: DialogParams.NegativeveListener): Builder {
            p!!.mNegativeveListener = mNegativeveListener
            return this
        }
        /**
         * 设置右边确认按钮的点击操作接口
         */
        fun setPositiveListener(mPositiveListener: DialogParams.PositiveListener): Builder {
            p!!.mPositiveListener = mPositiveListener
            return this
        }
        /**
         * 显示Dialog
         * 执行Activity跳转操作
         */
        fun show() {
            val mIntent = Intent(mContext, NetworkDisconnectionDialog::class.java)
            mIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
            mContext.startActivity(mIntent)
        }

    }

    @SuppressLint("ResourceType")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.baseres_activity_network_disconnection_dialog)
        //设置点击Dialog其他区域,Dialog会消失,如果不想点击其他区域Dialog消失,把true改为false
        setFinishOnTouchOutside(true)
        //设置Dialog居中显示
        window.setGravity(Gravity.CENTER)
        //获取屏幕尺寸
        val mDisplayMetrics = Resources.getSystem().displayMetrics
        //创建LayoutParams布局相关的参数
        val dialogLayoutParams: WindowManager.LayoutParams = WindowManager.LayoutParams()
        //设置Dialog的宽度为屏幕的3/4
        dialogLayoutParams.width = (mDisplayMetrics.widthPixels * 3 * 1.0 / 4).toInt()
        /**
         * 设置Dialog的高度为自适应,即Dialog的高度即为layout布局文件的高度
         * 如果dialogLayoutParams.height大于layout布局文件的高度,全显layout布局文件的高度,
         * 但是Dialog上下会有一定高度的区域点击之后Dialog不消失,因为他属于Dialog只是没有显示
         */
        dialogLayoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT
        /**
         * 设置背景灰色区域的透明度
         * 与 window.addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND)配合使用
         */
        dialogLayoutParams.dimAmount = 0.5f
        //设置Dialog的布局参数
        window.attributes = dialogLayoutParams
        /**
         * 配合dimAmount控制背景透明度
         */
        window.addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND)
        /**
         * 获取Dialog窗口的顶层View
         */
        val view = window.decorView
        /**
         * 设置view背景为圆角背景,弧度与layout中CardView的弧度一致,否则会存在四个边角
         */
        view?.setBackgroundResource(R.drawable.baseres_dialog_bg)

        applyDialog(p!!)

    }

    /**
     * 根据静态内部类Builder中设置的DialogParams来控制Dialog的内容显示和相关操作
     */
    private fun applyDialog(p: DialogParams) {
        if (!StringUtils.isTrimEmpty(p.title)) {
            baseres_dialog_title.text = p.title
        }
        if (!StringUtils.isTrimEmpty(p.content)) {
            baseres_dialog_content.text = p.content
        }
        if (!StringUtils.isTrimEmpty(p.cancleText)) {
            baseres_dialog_cancle.text = p.cancleText
        }
        if (!StringUtils.isTrimEmpty(p.confirmText)) {
            baseres_dialog_confirm.text = p.confirmText
        }

        baseres_dialog_cancle.setOnClickListener {
            p.mNegativeveListener?.onClick()
            finish()
        }

        baseres_dialog_confirm.setOnClickListener {
            p.mPositiveListener?.onClick()
            finish()
        }
    }
}

4.DialogParams Dialog参数类

package com.hp.baseres.view

/**
 * @Author tangdekun
 * @Date 2018/8/28-15:06
 * @Email tangdekun0924@gmail.com
 */
class DialogParams  {


    /***
     * Dialog标题
     */
    var title: String? = null

    /***
     * Dialog主题提示内容
     */
    var content: String? = null

    /***
     * Dialog取消对应的Text
     */
    var cancleText: String? = null
    /***
     * Dialog确定对应的Text
     */
    var confirmText: String? = null

    var mPositiveListener: PositiveListener? = null

    var mNegativeveListener: NegativeveListener? = null


    interface PositiveListener {

        fun onClick()
    }

    interface NegativeveListener {

        fun onClick()
    }

}

5.Style

  • parent=”Theme.AppCompat.Dialog”,继承的主题必须是Theme.AppCompat.*相关的Dialog主题,如果直接是Dialog会报Activity主题找不到的异常
  • 在Activity的主题中配置
 <style name="baseres_CustomDialogActivity" parent="Theme.AppCompat.Dialog">
        <item name="android:windowFullscreen">true</item>
        <!--设置dialog的背景-->
        <item name="android:windowBackground">@android:color/white</item>
        <!--设置Dialog的windowFrame框为无-->
        <item name="android:windowFrame">@android:color/transparent</item>
        <!--设置无标题-->
        <item name="windowNoTitle">true</item>
        <!--是否浮现在activity之上-->
        <item name="android:windowIsFloating">true</item>
        <!--是否半透明-->
        <item name="android:windowIsTranslucent">true</item>
        <!--设置窗口内容不覆盖-->
        <item name="android:windowContentOverlay">@android:color/transparent</item>
        <!--设置动画,在这里使用让它继承系统的Animation.Dialog-->
        <item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item>
        <!--背景是否模糊显示-->
        <item name="android:backgroundDimEnabled">true</item>
        <!--透明度 0.0f到1.0f之间。1.0完全不透明,-->
        <item name="android:backgroundDimAmount">0.4</item>
    </style>

6.Dialog的使用
使用场景不收限制,只要能拿到Context就可以,这里我使用的是Application中的Context

class NetworkDisConnectionState : NetworkState {

    private fun openNetworkDisconnectionDialog() {
        NetworkDisconnectionDialog.Builder(BaseApplication.mContext!!)
                .setContent(BaseApplication.mContext!!.getString(R.string.nlu_dialog_network_disconnection_content))
                .setConfirmText(BaseApplication.mContext!!.getString(R.string.nlu_dialog_network_disconnection_confirm))
                .setPositiveListener(object : DialogParams.PositiveListener {
                    override fun onClick() {
                        NetworkUtilsExtend.openWiFiSetting()
                    }
                })
                .show()

    }
}

三.注意事项

1.如果想实现圆角的Dialog,需要配置Activity的decorView背景,与Layout布局使用相同的弧度

 /**
         * 获取Dialog窗口的顶层View
         */
        val view = window.decorView
        /**
         * 设置view背景为圆角背景,弧度与layout中CardView的弧度一致,否则会存在四个边角
         */
        view?.setBackgroundResource(R.drawable.baseres_dialog_bg)

2.设置背景灰色区域的透明度与 window.addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND)配合使用,否则会没有效果

        dialogLayoutParams.dimAmount = 0.5f

        /**
         * 配合dimAmount控制背景透明度
         */
        window.addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND)

3.style必须继承Theme.AppCompat.*相关的Dialog主题,如果直接使用android:Theme.Dialog或者不继承其他主题会报Activity主题找不到的异常

4.Kotlin中内部类默认是静态内部类,外面可以直接使用。如果内部类使用inner关键字修饰则只能内部使用。Kotlin的静态变量直接申明在伴生对象object中,可以直接在内部类和外部类使用

Kotlin技术专栏

目前正在使用Kotlin开发Android项目,并建立了Kotlin技术专栏,希望可以和大家一起学习,探讨和分享自己的实战经验
这里写图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值