首先讲一下我实现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技术专栏,希望可以和大家一起学习,探讨和分享自己的实战经验