一.領域特定語言 DSL的概念
1.什么是DSL
DSL(domain specific language),即領域專用語言:專門解決某一特定問題的計算機語言,由于它是以簡潔的形式進行表達,整體上直觀易懂,使得呼叫代碼和讀代碼的成本都得以降低,即使是不懂編程語言的一般人都可以進行使用,比如大家比較熟悉的SQL陳述句和正則運算式, 所謂領域也就是限定語言是適用于一定范圍的,可以看做是封裝了一套東西, 用于特定的功能, 優勢是復用性和可讀性的增強,
(1.)DSL的特點
- 用于專門領域,不能用于其他領域,
- 有更高級的抽象,不涉及類似資料結構的細節,
- 表現力有限,其只能描述該領域的模型,
(2.)通用編程語言和DSL的區別:
通用編程語言(如 Java、Kotlin、Python等),往往提供了全面的庫來幫助開發者開發完整的應用程式,而 DSL 只專注于某個領域,比如 SQL 僅支持資料庫的相關處理,而正則運算式只用來檢索和替換文本,無法用 SQL 或者正則運算式來開發一個完整的應用,
2.外部 DSL 和內部 DSL
DSL分為外部DSL和內部 DSL
(1.)外部DSL
在主程式設計語言之外,用一種單獨的語言表示領域專有語言,可以是定制語法,或者遵循另外一種語法,如 XML、JSON,(從零開始構建的語言,需要實作語法決議器等),
(2.)內部 DSL
通常是基于通用編程語言實作,具有特定的風格,如Android 的主流編譯工具 Gradle,(從一種宿主語言構建而來),
二.Koltin封裝DSL風格彈窗
許多現代語言為創建內部 DSL 提供了一些先進的方法, Kotlin 也不例外,下面就通過kotlin的高階函式和擴展方法, 封裝一個簡單的DSL風格的彈窗:
1.撰寫彈窗布局檔案
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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="wrap_content"
android:layout_gravity="center"
android:minHeight="200dp">
<TextView
android:id="@+id/title_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:textColor="@android:color/black"
android:textSize="20sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="title text" />
<TextView
android:id="@+id/message_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:padding="16dp"
android:textColor="@android:color/black"
android:textSize="16sp"
app:layout_constraintBottom_toTopOf="@+id/right_button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/title_tv"
tools:ignore="RtlCompat"
tools:text="message" />
<TextView
android:id="@+id/left_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:textAllCaps="true"
android:textColor="@color/colorAccent"
android:textSize="18sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="@+id/right_button"
app:layout_constraintEnd_toStartOf="@+id/right_button"
app:layout_constraintTop_toTopOf="@+id/right_button"
tools:ignore="RtlCompat"
tools:text="cancle" />
<TextView
android:id="@+id/right_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp"
android:textAllCaps="true"
android:textColor="@color/colorAccent"
android:textSize="18sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
tools:ignore="RtlCompat"
tools:text="sure" />
</androidx.constraintlayout.widget.ConstraintLayout>
2.封裝確認彈窗
class ConfirmDialogFragment : DialogFragment() {
private var titleTv: TextView? = null
private var messageTv: TextView? = null
private var leftButton: TextView? = null
private var rightButton: TextView? = null
//左邊按鈕點擊回呼
private var leftClicks: (() -> Unit)? = null
//右邊邊按鈕點擊回呼
private var rightClicks: (() -> Unit)? = null
//是否可以消失
var cancelOutside: Boolean = true
//彈窗標題
var title: String? = null
//彈窗內容
var message: String? = null
//左邊按鈕文字
var leftValue: String? = null
//左邊按鈕點擊是否關閉彈窗
var leftButtonDismissAfterClick = true
//右邊按鈕文字
var rightValue: String? = null
//右邊按鈕點擊是否關閉彈窗
var rightButtonDismissAfterClick = true
companion object {
fun newInstance(): ConfirmDialogFragment {
return ConfirmDialogFragment()
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setStyle(DialogFragment.STYLE_NO_TITLE, android.R.style.Theme_Material_Light_Dialog)
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.dialog_custom, container).apply {
titleTv = findViewById(R.id.title_tv)
messageTv = findViewById(R.id.message_tv)
leftButton = findViewById(R.id.left_button)
rightButton = findViewById(R.id.right_button)
}
init()
return view
}
private fun init() {
dialog?.setCancelable(cancelOutside)
title?.let { text ->
titleTv?.visibility = View.VISIBLE
titleTv?.text = text
}
message?.let { text ->
messageTv?.visibility = View.VISIBLE
messageTv?.text = text
}
leftClicks?.let { onClick ->
leftButton?.text = leftValue
leftButton?.visibility = View.VISIBLE
leftButton?.setOnClickListener {
onClick()
if (leftButtonDismissAfterClick) {
dismissAllowingStateLoss()
}
}
}
rightClicks?.let { onClick ->
rightButton?.text = rightValue
rightButton?.setOnClickListener {
onClick()
if (rightButtonDismissAfterClick) {
dismissAllowingStateLoss()
}
}
}
}
fun leftClicks(key: String = "取消", dismissAfterClick: Boolean = true, callback: () -> Unit) {
leftValue = key
leftButtonDismissAfterClick = dismissAfterClick
leftClicks = callback
}
fun rightClicks(key: String = "確定", dismissAfterClick: Boolean = true, callback: () -> Unit) {
rightValue = key
rightButtonDismissAfterClick = dismissAfterClick
rightClicks = callback
}
}
3.給AppCompatActivity添加擴展方法
inline fun AppCompatActivity.showDialog(settings: ConfirmDialogFragment.() -> Unit) : ConfirmDialogFragment {
val dialog = ConfirmDialogFragment.newInstance()
dialog.apply(settings)
val ft = this.supportFragmentManager.beginTransaction()
val prev = this.supportFragmentManager.findFragmentByTag("confirm_dialog")
if (prev != null) {
ft.remove(prev)
}
ft.addToBackStack(null)
dialog.show(ft, "dialog")
return dialog
}
4.在Activity中通過擴展方法使用DSL風格的彈窗
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
findViewById<View>(R.id.button_dialog).setOnClickListener {
showDialog {
cancelOutside = true //可以取消
title = "我是彈窗的標題"
message =
"我是彈窗里面的內容,我是彈窗里面的內容,我是彈窗里面的內容,我是彈窗里面的內容"
leftClicks("取消", true) {
toast("左邊按鈕被點擊!")
}
rightClicks("確定", true) {
toast("右邊按鈕被點擊!")
}
}
}
}
}
5.效果展示

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/398033.html
標籤:AI
