Android实战场景 - 用Kotlin写个能让我进步的Dialog

去年接到过一个小需求,一个简简单单的弹框,不论是用dialog、popupWindow都能很轻松的实现;之所以记录是因为每一次都感觉好像进步了一点点…

弹框相关Blog

一个小小需求,我使用了俩种实现方式,其一为我的惯性常规实现,其二为项目中所学的进阶实现,用到的新技术也多一点

      • 效果分析
      • 常规实现
        • 弹框样式
        • 按钮样式
        • 调用方式
      • 进阶实现
        • 弹框样式
        • 扩展函数
          • View、TextView (基本UI)
          • SpannableStringBuilder 自身(富文本)
          • SpannableStringBuilder 引用
        • 调用方式

效果分析

效果图

在这里插入图片描述

记录原因

  • kotlin 写弹框
  • 命令式UI、声明式UI 自定义弹框视图
  • 富文本样式
  • SpannableStringBuilder 扩展函数
  • 典型的弹框场景

功能分析

常规实现

按照我的开发习惯,我一般是先画 dialog 的 UI...

弹框样式

提示TypefaceTextViewsplitties 库提供的控件,其继承自 AppCompatTextView 的视图类,如不使用可自行用TextView,加粗用自带的即可

dialog_layout_discount

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:orientation="vertical">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <LinearLayout
            android:layout_marginRight="@dimen/mp_25"
            android:layout_marginLeft="@dimen/mp_25"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_marginTop="@dimen/mp_25"
            android:background="@drawable/icon_dialog_discount_bg"
            android:orientation="vertical"
            android:paddingTop="@dimen/mp_35">

            <splitties.widgets.TypefaceTextView
                android:id="@+id/title"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginLeft="@dimen/mp_20"
                android:layout_marginRight="@dimen/mp_20"
                android:layout_marginBottom="@dimen/mp_15"
                android:ellipsize="end"
                android:gravity="center"
                android:text="温馨提示"
                android:textColor="@color/font_33"
                android:textSize="@dimen/textSize_17" />

            <TextView
                android:id="@+id/content"
                android:layout_width="match_parent"
                android:layout_height="0dp"
                android:layout_weight="1"
                android:layout_marginRight="@dimen/mp_20"
                android:layout_marginLeft="@dimen/mp_20"
                android:gravity="center"
                android:text="您还未领取0折购基打折卡,无法享受 \n 0折购基的优惠,是否现在去领取?"
                android:textColor="#97755F"
                tools:textSize="@dimen/textSize_15" />

            <LinearLayout
                android:id="@+id/dialog_layout"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="@dimen/mp_30"
                android:layout_marginBottom="20dp">

                <TextView
                    android:id="@+id/cancel"
                    android:layout_width="0dp"
                    android:layout_height="38dp"
                    android:layout_centerInParent="true"
                    android:layout_gravity="center_horizontal"
                    android:layout_marginLeft="@dimen/mp_20"
                    android:layout_weight="1"
                    android:background="@drawable/shape_dialog_discount_cancel_bg"
                    android:gravity="center"
                    android:text="暂不领取"
                    android:textColor="@color/font_33"
                    android:textSize="@dimen/textSize_middle"
                    android:visibility="visible" />

                <TextView
                    android:id="@+id/confirm"
                    android:layout_width="0dp"
                    android:layout_height="38dp"
                    android:layout_centerInParent="true"
                    android:layout_gravity="center_horizontal"
                    android:layout_marginLeft="@dimen/mp_15"
                    android:layout_marginRight="@dimen/mp_20"
                    android:layout_weight="1"
                    android:background="@drawable/shape_dialog_discount_confirm_bg"
                    android:gravity="center"
                    android:text="免费领取"
                    android:textColor="#F9E6D4"
                    android:textSize="@dimen/textSize_middle" />
            </LinearLayout>
        </LinearLayout>

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:src="@drawable/icon_discount_alert" />
    </RelativeLayout>
</LinearLayout>

该处重写主要在其内部添加了设置字体粗度的功能

package xxx

import android.content.Context
import android.graphics.Canvas
import android.graphics.Paint
import android.util.AttributeSet
import androidx.appcompat.widget.AppCompatTextView

open class TypefaceTextView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) :
    AppCompatTextView(context, attrs, defStyleAttr) {

    private var mTypefaceScale: Float = 0.0f

    enum class TypefaceScale {
        MEDIUM, MEDIUM_SMALL, DEFAULT,
    }

    override fun onDraw(canvas: Canvas?) {
        if (mTypefaceScale == 0f) {
            return super.onDraw(canvas)
        }
        val strokeWidth = paint.strokeWidth
        val style = paint.style
        paint.strokeWidth = mTypefaceScale
        paint.style = Paint.Style.FILL_AND_STROKE
        super.onDraw(canvas)
        paint.strokeWidth = strokeWidth
        paint.style = style
    }

    internal fun setTypefaceScale(scale: TypefaceScale = TypefaceScale.DEFAULT) {
        mTypefaceScale = when (scale) {
            TypefaceScale.DEFAULT -> 0.0f
            TypefaceScale.MEDIUM_SMALL -> 0.6f
            TypefaceScale.MEDIUM -> 1.1f
        }
        invalidate()
    }

}

按钮样式

我直接copy项目已有的shape,原始是支持按压和平时的俩种显示状态,因为我没有这项功能,所以我注释掉了…

shape_dialog_discount_confirm_bg

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

 <!--   <item android:state_pressed="true">
        <shape>
            <solid android: />
            <corners android:radius="5dp" />
        </shape>
    </item>-->
    <item android:state_pressed="false">
        <shape>
            <solid android:color="#3C3733" />
            <corners android:radius="5dp" />
        </shape>
    </item>
    <item>
        <shape>
            <solid android:color="#3C3733" />
            <corners android:radius="5dp" />
        </shape>
    </item>
</selector>

shape_dialog_discount_cancel_bg

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <!--   <item android:state_pressed="true">
           <shape>
               <solid android: />
               <corners android:radius="5dp" />
           </shape>
       </item>-->
    <item android:state_pressed="false">
        <shape>
            <solid android:color="#FFFFFF" />
            <corners android:radius="5dp" />
            <stroke android:width="0.5dp" android:color="#B4B4B4" />
        </shape>
    </item>
    <item>
        <shape>
            <solid android:color="#FFFFFF" />
            <corners android:radius="5dp" />
            <stroke android:width="0.5dp" android:color="#B4B4B4" />
        </shape>
    </item>
</selector>

调用方式

    var view = LayoutInflater.from(activity).inflate(R.layout.dialog_layout_discount, null)
    val alertDialog = AlertDialog.Builder(activity).setCancelable(false).setView(view).create()
    alertDialog.window?.setBackgroundDrawable(ColorDrawable(0))
    var title = view.findViewById<TypefaceTextView>(R.id.title)
    title.typefaceScale = TypefaceScale.MEDIUM_SMALL
    //富文本
    var content = view.findViewById<TextView>(R.id.content)
    val contentText = SpannableStringBuilder("您还未领取0折购基打折卡,无法享受\n0折购基的优惠,是否现在去领取?")
    contentText.setSpan(AbsoluteSizeSpan(13, true), 0, 4, Spannable.SPAN_INCLUSIVE_INCLUSIVE)
    contentText.setSpan(AbsoluteSizeSpan(17, true), 5, 9, Spannable.SPAN_INCLUSIVE_EXCLUSIVE)
    contentText.setSpan(AbsoluteSizeSpan(13, true), 9, contentText.length, Spannable.SPAN_INCLUSIVE_INCLUSIVE)
    content.text = contentText
    
    view.findViewById<TextView>(R.id.cancel).onClick { alertDialog.dismiss() }
    view.findViewById<TextView>(R.id.confirm).onClick { alertDialog.dismiss() }
    alertDialog.show()

进阶实现

项目中用到的新技术稍微多一些,这里稍微做下说明

  • 命令式UI用到了 splitties 视图框架
  • 部分控件用到了 扩展函数

弹框样式

package xx

import android.content.Context
import android.graphics.Color
import android.text.SpannedString
import android.text.method.LinkMovementMethod
import android.widget.FrameLayout
import androidx.core.graphics.toColorInt
import splitties.dimensions.dp
import splitties.views.dsl.core.*
import splitties.views.*

internal class DiscountAlertDialogUi(context: Context) : FrameLayout(context) {

    private lateinit var messageView: TypefaceTextView
    private lateinit var negativeView: TypefaceTextView
    private lateinit var positiveView: TypefaceTextView

    init {
        horizontalPadding = 25.dp
        bottomPadding = 25.dp
        createView()
    }

    private fun createView() {
        add(lParams(width = matchParent) { topMargin = 27.dp }, verticalLayout {
            backgroundResource = R.drawable.icon_dialog_discount_bg
            horizontalPadding = 20.dp
            add(lParams(width = matchParent) { topMargin = 35.dp }, typefaceTextView {
                typefaceScale = TypefaceScale.MEDIUM_SMALL
                gravity = gravityCenterHorizontal
                textColor = "#363A37".toColorInt()
                textSize = 16f
                text = "温馨提示"
            })
            messageView = add(lParams(width = matchParent) { verticalMargin = 16.dp }, typefaceTextView {
                gravity = gravityCenterHorizontal
                textColor = "#97755F".toColorInt()
                textSize = 14f
                setLineSpacing(dp(4f), 1f)
            })
            add(lParams(width = matchParent, height = 44.dp) { topMargin = 20.dp }, horizontalLayout {
                negativeView = add(lParams(width = 0, weight = 1f, height = matchParent) { endMargin = 7.dp }, typefaceTextView {
                    typefaceScale = TypefaceScale.MEDIUM_SMALL
                    background = rectangleShape(radius = dp(4f), color = Color.WHITE) {
                        setStroke(1.dp, "#B4B4B4".toColorInt())
                    }
                    gravity = gravityCenter
                    setTextColor(enabledColorDrawable("#CC363A37".toColorInt(), "#363A37".toColorInt()))
                    textSize = 14f
                    text = "暂不领取"
                })
                positiveView = add(lParams(width = 0, weight = 1f, height = matchParent) { startMargin = 7.dp }, typefaceTextView {
                    background = enabledDrawable(radius = 4f.dp, disabledColor = "#CC3C3733", defaultColor = "#3C3733")
                    typefaceScale = TypefaceScale.MEDIUM_SMALL
                    gravity = gravityCenter
                    textColor = "#F9E6D4".toColorInt()
                    textSize = 14f
                    text = "免费领取"
                })
            })
        })
        add(lParams(width = wrapContent, gravity = gravityCenterHorizontal), imageView {
            imageResource = R.drawable.icon_discount_alert
        })
    }

    /**
     * 内容文字
     */
    fun setMessage(message: CharSequence) {
        messageView.text = message
        if (message is SpannedString) {
            messageView.movementMethod = LinkMovementMethod.getInstance()
        }
    }

    /**
     * 消极按钮
     */
    fun setNegativeButton(negativeText: CharSequence, listener: OnClickListener?) {
        negativeView.text = negativeText
        negativeView.setOnClick(listener)
    }

    /**
     * 积极按钮
     */
    fun setPositiveButton(positiveText: CharSequence, listener: OnClickListener?) {
        positiveView.text = positiveText
        positiveView.setOnClick(listener)
    }

}

扩展函数

View、TextView (基本UI)
@file:Suppress("NOTHING_TO_INLINE", "unused")

package xx.views

import android.graphics.Bitmap
import android.graphics.drawable.Drawable
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.annotation.ColorInt
import androidx.annotation.DrawableRes
import androidx.annotation.Px

val matchParent: Int = ViewGroup.LayoutParams.MATCH_PARENT

val wrapContent: Int = ViewGroup.LayoutParams.WRAP_CONTENT


val View.inflater: LayoutInflater
    get() = LayoutInflater.from(context)

var View.backgroundResource: Int
    @Deprecated(NO_GETTER, level = DeprecationLevel.HIDDEN) get() = noGetter
    set(value) {
        setBackgroundResource(value)
    }


inline var View.backgroundColor: Int
    @Deprecated(NO_GETTER, level = DeprecationLevel.HIDDEN) get() = noGetter
    set(@ColorInt colorInt) = setBackgroundColor(colorInt)

inline fun View.onLongClick(consume: Boolean = true, crossinline block: () -> Unit) = setOnLongClickListener { block(); consume }

inline var ImageView.imageResource: Int
    @Deprecated(NO_GETTER, level = DeprecationLevel.HIDDEN) get() = noGetter
    set(@DrawableRes value) = setImageResource(value)

inline var ImageView.imageDrawable: Drawable?
    get() = drawable
    set(value) = setImageDrawable(value)

inline var ImageView.imageBitmap: Bitmap
    @Deprecated(NO_GETTER, level = DeprecationLevel.HIDDEN) get() = noGetter
    set(value) = setImageBitmap(value)

// TextView
inline var TextView.lines: Int
    @Deprecated(NO_GETTER, level = DeprecationLevel.HIDDEN) get() = noGetter
    set(value) = setLines(value)

fun TextView.centerText() {
    textAlignment = View.TEXT_ALIGNMENT_CENTER
    gravity = Gravity.CENTER
}

fun TextView.alignTextToStart() {
    textAlignment = View.TEXT_ALIGNMENT_VIEW_START
    gravity = Gravity.START
}

fun TextView.alignTextToEnd() {
    textAlignment = View.TEXT_ALIGNMENT_VIEW_END
    gravity = Gravity.END
}

fun TextView.setCompoundDrawables(start: Drawable? = null, top: Drawable? = null, end: Drawable? = null, bottom: Drawable? = null, intrinsicBounds: Boolean = false) {
    if (intrinsicBounds) {
        setCompoundDrawablesWithIntrinsicBounds(start, top, end, bottom)
    } else {
        setCompoundDrawables(start, top, end, bottom)
    }
}

inline fun TextView.setCompoundDrawables(@DrawableRes start: Int = 0, @DrawableRes top: Int = 0, @DrawableRes end: Int = 0, @DrawableRes bottom: Int = 0) {
    setCompoundDrawablesWithIntrinsicBounds(start, top, end, bottom)
}

inline fun TextView.clearCompoundDrawables() = setCompoundDrawables(null, null, null, null)
SpannableStringBuilder 自身(富文本)

根据效果,我仅加入了字体大小的扩展函数

fun SpannableStringBuilder.appendRelativeSize(
    proportion: Float,
    text: CharSequence,
): SpannableStringBuilder = inSpans(RelativeSizeSpan(proportion)) { append(text) }

fun SpannableStringBuilder.appendAbsoluteSize(
    proportion: Int,
    text: CharSequence,
): SpannableStringBuilder = inSpans(AbsoluteSizeSpan(proportion,true)) { append(text) }

项目内较全的 SpannableStringBuilder 扩展函数

package xx
import android.text.SpannableStringBuilder
import android.text.style.AbsoluteSizeSpan
import android.text.style.ForegroundColorSpan
import android.text.style.RelativeSizeSpan
import android.text.style.StrikethroughSpan
import android.view.View
import androidx.annotation.ColorInt
import androidx.core.text.inSpans

inline fun SpannableStringBuilder.mediumSmall(
    builderAction: SpannableStringBuilder.() -> Unit
) = inSpans(MediumSmallSpan(), builderAction = builderAction)

inline fun SpannableStringBuilder.linearGradient(
    colors: IntArray,
    orientation: Int = LinearGradientFontSpan.HORIZONTAL,
    builderAction: SpannableStringBuilder.() -> Unit
): SpannableStringBuilder {
    return inSpans(LinearGradientFontSpan(colors, orientation), builderAction = builderAction)
}

inline fun SpannableStringBuilder.clickable(
    listener: View.OnClickListener,
    builderAction: SpannableStringBuilder.() -> Unit
): SpannableStringBuilder {
    return inSpans(ClickableSpan(listener), builderAction = builderAction)
}

//
fun SpannableStringBuilder.appendClickable(
    text: CharSequence,
    listener: View.OnClickListener
): SpannableStringBuilder = inSpans(ClickableSpan(listener)) { append(text) }

fun SpannableStringBuilder.appendColor(
    @ColorInt color: Int,
    text: CharSequence,
): SpannableStringBuilder = inSpans(ForegroundColorSpan(color)) { append(text) }

fun SpannableStringBuilder.appendStrikeThrough(
    text: CharSequence,
): SpannableStringBuilder = inSpans(StrikethroughSpan()) { append(text) }

fun SpannableStringBuilder.appendRelativeSize(
    proportion: Float,
    text: CharSequence,
): SpannableStringBuilder = inSpans(RelativeSizeSpan(proportion)) { append(text) }

fun SpannableStringBuilder.appendAbsoluteSize(
    proportion: Int,
    text: CharSequence,
): SpannableStringBuilder = inSpans(AbsoluteSizeSpan(proportion,true)) { append(text) }
//
fun SpannableStringBuilder.appendMore(
    @ColorInt color: Int? = null,
    text: CharSequence,
    listener: View.OnClickListener? = null,
): SpannableStringBuilder {
    val spans = mutableListOf<Any>()
    color?.also { spans.add(ForegroundColorSpan(color)) }
    listener?.also { spans.add(ClickableSpan(listener)) }
    inSpans(*spans.toTypedArray()) { append(text) }
    return this
}

fun SpannableStringBuilder.appendLabel(
    @ColorInt color: Int? = null,
    text: String,
    listener: View.OnClickListener? = null,
): SpannableStringBuilder {
    val splits = text.replace("</b>", "<b>").split("<b>")
    splits.forEachIndexed { index, s ->
        if (index % 2 == 1) {
            appendMore(color = color, s, listener)
        } else {
            append(s)
        }
    }
    return this
}
SpannableStringBuilder 引用

MediumSmallSpan

package xx.spannable

import android.graphics.Paint
import android.text.TextPaint
import android.text.style.MetricAffectingSpan

class MediumSmallSpan : MetricAffectingSpan() {

    override fun updateDrawState(paint: TextPaint?) = apply(paint)

    override fun updateMeasureState(paint: TextPaint) = apply(paint)

    private fun apply(paint: Paint?) {
        if (paint == null) return
        paint.strokeWidth = 0.6f
        paint.style = Paint.Style.FILL_AND_STROKE
    }

}

LinearGradientFontSpan

package xx.spannable

import android.graphics.Canvas
import android.graphics.LinearGradient
import android.graphics.Paint
import android.graphics.Shader
import android.text.style.ReplacementSpan
import android.widget.LinearLayout

class LinearGradientFontSpan(val colors: IntArray, val orientation: Int = HORIZONTAL) : ReplacementSpan() {
    companion object {
        const val HORIZONTAL = LinearLayout.HORIZONTAL   // 水平渐变方向
        const val VERTICAL = LinearLayout.VERTICAL       // 垂直渐变方向
    }

    private var mMeasureTextWidth = 0  // 测量的文本宽度

    override fun getSize(paint: Paint, text: CharSequence?, start: Int, end: Int, fontMetricsInt: Paint.FontMetricsInt?): Int {
        mMeasureTextWidth = paint.measureText(text ?: "", start, end).toInt()
        // 这段不可以去掉,字体高度没设置,会出现 draw 方法没有被调用的问题
        // 详情请见:https://stackoverflow.com/questions/20069537/replacementspans-draw-method-isnt-called
        val metrics = paint.fontMetrics
        fontMetricsInt?.top = metrics.top.toInt()
        fontMetricsInt?.ascent = metrics.ascent.toInt()
        fontMetricsInt?.descent = metrics.descent.toInt()
        fontMetricsInt?.bottom = metrics.bottom.toInt()
        return mMeasureTextWidth
    }

    override fun draw(canvas: Canvas, text: CharSequence?, start: Int, end: Int, x: Float, top: Int, y: Int, bottom: Int, paint: Paint) {
        if (text.isNullOrEmpty()) return
        val linearGradient = if (orientation == VERTICAL) {
            LinearGradient(0f, 0f, 0f, paint.descent() - paint.ascent(), colors, null, Shader.TileMode.REPEAT)
        } else {
            LinearGradient(x, 0f, x + mMeasureTextWidth, 0f, colors, null, Shader.TileMode.REPEAT)
        }
        val shader = paint.shader
        val alpha = paint.alpha
        //
        paint.shader = linearGradient
        paint.alpha = 255                    //  如果是则设置不透明
        //
        canvas.drawText(text, start, end, x, y.toFloat(), paint)
        //绘制完成之后将画笔的透明度还原回去
        paint.shader = shader
        paint.alpha = alpha
    }

}

ClickableSpan

package xx.spannable

import android.text.TextPaint
import android.view.View
import xx.OnClickWrapListener

class ClickableSpan(val listener: View.OnClickListener) : android.text.style.ClickableSpan() {

    override fun onClick(widget: View) {
        OnClickWrapListener(listener).onClick(widget)
    }

    override fun updateDrawState(ds: TextPaint) {
        ds.isUnderlineText = false
    }
}

OnClickWrapListener

//private var clickTime = 0L

class OnClickWrapListener(val listener: View.OnClickListener) : View.OnClickListener {
    companion object {
        private val clickTime = AtomicLong(0)
    }

    override fun onClick(v: View?) {
        val currentTime = System.currentTimeMillis()
        if (currentTime - clickTime.get() > 500) {
            clickTime.set(currentTime)
            listener.onClick(v)
        }
    }
}

调用方式

纯净版

    override suspend fun checkDiscountIntercept(activity: BaseActivity): Boolean = suspendCancellableCoroutine { coroutine ->
            val discountAlertDialogUi = DiscountAlertDialogUi(activity)
            val alertDialog = AlertDialog.Builder(activity).setView(discountAlertDialogUi).create()
            alertDialog.window?.setBackgroundDrawableResource(R.color.transparent)
            alertDialog.setCanceledOnTouchOutside(false)
            discountAlertDialogUi.setMessage(
                buildSpannedString {
                    append("您还未领取")
                    appendAbsoluteSize(17, "0折购基")
                    append("打折卡,无法享受0折购基的优惠,是否现在去领取?")
                }
            }
            discountAlertDialogUi.setNegativeButton("暂不领取") {
                alertDialog.dismiss()
                coroutine.resume(false)
            }
            discountAlertDialogUi.setPositiveButton("免费领取") {
                alertDialog.dismiss()
                toDiscount(activity)
                coroutine.resume(true)
            }
    }

项目版(因项目版有业务场景,仅做记录,方便日后回顾

    override suspend fun checkDiscountIntercept(activity: BaseActivity, state: Int): Boolean = suspendCancellableCoroutine { coroutine ->
        if (state == 0 || state == 3) {
            val discountAlertDialogUi = DiscountAlertDialogUi(activity)
            val alertDialog = AlertDialog.Builder(activity).setView(discountAlertDialogUi).create()
            alertDialog.window?.setBackgroundDrawableResource(R.color.transparent)
            alertDialog.setCanceledOnTouchOutside(false)
            discountAlertDialogUi.setMessage(if (state == 0) {
                buildSpannedString {
                    append("您还未领取")
                    appendAbsoluteSize(17, "0折购基")
                    append("打折卡,无法享受0折购基的优惠,是否现在去领取?")
                }
            } else {
                "您的0折购基打折卡已过期,无法享受0折购基的优惠,是否现在去续期?"
            })
            discountAlertDialogUi.setNegativeButton(if (state == 0) "暂不领取" else "暂不续期") {
                alertDialog.dismiss()
                coroutine.resume(false)
            }
            discountAlertDialogUi.setPositiveButton(if (state == 0) "免费领取" else "免费续期") {
                alertDialog.dismiss()
                toDiscount(activity)
                coroutine.resume(true)
            }
            alertDialog.show()
        } else {
            coroutine.resume(false)
        }
    }
posted @ 2023-04-26 16:14  cps666  阅读(287)  评论(0编辑  收藏  举报