Android implementa el diálogo de efecto de ventana emergente

El código principal de SmartDialog puede realizar el cuadro de diálogo de posicionamiento del punto de anclaje, ubicar el cuadro de diálogo de contenido calculando las coordenadas de la Vista del punto de anclaje en la pantalla, modificar la posición de visualización del cuadro de diálogo configurando la dirección y el margen, y admitir la configuración dinámica de la anchura y la altura máximas.

/**
 * 作者 我的安卓之路
 * CreateTime 2022/12/2814:38
 * 任意位置弹出的dialog
 */
class SmartDialog private constructor(val build: DialogBuild) : DialogFragment() {
    private val rootView by lazy {
        val linearLayout = RelativeLayout(context!!)
        val layoutParams = ViewGroup.LayoutParams(
            ViewGroup.LayoutParams.MATCH_PARENT,
            ViewGroup.LayoutParams.MATCH_PARENT
        )
        linearLayout.layoutParams = layoutParams
        linearLayout
    }
    private var anchorPointView: View? = null//锚点View
    private val anchorPoint by lazy {
        val anchorLocation = intArrayOf(0, 0)
        anchorPointView?.getLocationInWindow(anchorLocation)
        anchorLocation
    }
    private val background by lazy { //背景
        val v = View(context)
        val layoutParams = FrameLayout.LayoutParams(
            ViewGroup.LayoutParams.MATCH_PARENT,
            ViewGroup.LayoutParams.MATCH_PARENT,
        )
        v.setBackgroundResource(build.backgroundRes)
        v.alpha = build.dimAmount
        v.layoutParams = layoutParams
        v.visibility = View.INVISIBLE
        v
    }
    private val windowHeight by lazy { rootView.height+titleBarHeight }
    private val windowWith by lazy { Utils.getScreenWidth(context) }
    private var gravity: Int = RelativeLayout.ALIGN_PARENT_TOP
    var dismissListener:(()->Unit)?=null
    private val titleBarHeight by lazy {
        Utils.getStatusBarHeight(context)
    }

    fun showDialog(anchorPoint: View?, manager: FragmentManager, tag: String) {
        this.anchorPointView = anchorPoint
        show(manager, tag)
    }


    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        setStyle(STYLE_NORMAL, build.themeStyle)
        rootView.removeAllViews()
        rootView.addView(background)
        rootView.addView(build.layoutView)
        initView()
        return rootView
    }

    private fun initView() {
        build.layoutView.visibility  = View.INVISIBLE
        build.layoutView.post {
            measure(build.layoutView.height)
        }
        build.layoutView.setOnClickListener {}
        rootView.setOnClickListener {
            if (build.cancelable) {
                dismiss()
            }
        }

        val layoutParams = build.layoutView.layoutParams
        layoutParams.height = build.height
        layoutParams.width = build.width
        build.layoutView.layoutParams = layoutParams
    }

    private fun measure(height: Int) {
        measureHeight(height)
        setVertical()
        setHorizontal()
        build.layoutView.visibility  = View.VISIBLE
    }

    //计算布局的高度
    private fun measureHeight(height: Int) {
        val layoutParams = build.layoutView.layoutParams
        if (build.maxHeight != ViewGroup.LayoutParams.MATCH_PARENT && build.maxHeight < height) {
            layoutParams.height = build.maxHeight
        }
        if (build.minHeight != ViewGroup.LayoutParams.WRAP_CONTENT && build.minHeight > height) {
            layoutParams.height = build.minHeight
        }
        build.layoutView.layoutParams = layoutParams
    }


    private fun setVertical() {
        val y =anchorPoint[1]
        val viewHeight: Int = anchorPointView?.height ?: 0
        val layoutHeight = build.layoutView.height
        val layoutParams = build.layoutView.layoutParams as RelativeLayout.LayoutParams
        rootView.gravity
        when (build.vertical) {
            VerticalPosition.ABOVE -> {//在上方
                layoutParams.bottomMargin = windowHeight - y - build.y
                gravity = RelativeLayout.ALIGN_PARENT_BOTTOM
            }
            VerticalPosition.BELOW -> {//在下方
                val mY =if (build.isHaveTitleBar) y  - titleBarHeight else y
                layoutParams.topMargin = mY + viewHeight + build.y
                gravity = RelativeLayout.ALIGN_PARENT_TOP
            }
            VerticalPosition.CENTER -> {//居中对齐
                val mY =if (build.isHaveTitleBar) y  - titleBarHeight else y
                layoutParams.topMargin = (viewHeight - layoutHeight) / 2 + mY + build.y
                gravity = RelativeLayout.ALIGN_PARENT_TOP
            }
            VerticalPosition.ALIGN_TOP -> {//顶部对齐
                val mY =if (build.isHaveTitleBar) y  - titleBarHeight else y
                layoutParams.topMargin = mY + build.y
                gravity = RelativeLayout.ALIGN_PARENT_TOP
            }
            VerticalPosition.ALIGN_BOTTOM -> {//底部对齐
                layoutParams.bottomMargin = windowHeight - viewHeight - y - build.y
                gravity = RelativeLayout.ALIGN_PARENT_BOTTOM
            }
        }


        if (layoutParams.bottomMargin < 0)
            layoutParams.bottomMargin = 0

        if (layoutParams.topMargin < 0)
            layoutParams.topMargin = 0
        layoutParams.addRule(gravity)
        build.layoutView.layoutParams = layoutParams
        setBackground(layoutParams.topMargin, layoutParams.bottomMargin)
    }

    private fun setHorizontal() {
        val x = anchorPoint[0]
        val viewWidth: Int = anchorPointView?.width ?: 0
        val layoutWith = build.layoutView.width
        val layoutParams = build.layoutView.layoutParams as RelativeLayout.LayoutParams

        when (build.horizontal) {
            HorizontalPosition.CENTER -> {
                layoutParams.leftMargin = (viewWidth - layoutWith) / 2 + x + build.x
                gravity = RelativeLayout.ALIGN_PARENT_LEFT
            }
            HorizontalPosition.LEFT -> {
                layoutParams.rightMargin = windowWith - x - build.x
                gravity = RelativeLayout.ALIGN_PARENT_RIGHT
            }
            HorizontalPosition.RIGHT -> {
                layoutParams.leftMargin = x + viewWidth + build.x
                gravity = RelativeLayout.ALIGN_PARENT_LEFT
            }
            HorizontalPosition.ALIGN_LEFT -> {
                layoutParams.leftMargin = x + build.x
                gravity = RelativeLayout.ALIGN_PARENT_LEFT

            }
            HorizontalPosition.ALIGN_RIGHT -> {
                layoutParams.rightMargin = windowWith - viewWidth - x - build.x
                gravity = RelativeLayout.ALIGN_PARENT_RIGHT
            }
        }
        if (layoutParams.leftMargin < 0)
            layoutParams.leftMargin = 0
        if (layoutParams.rightMargin < 0)
            layoutParams.rightMargin = 0
        layoutParams.addRule(gravity)
        build.layoutView.layoutParams = layoutParams
    }



    //设置背景所在参数
    private fun setBackground(topMargin: Int, botMargin: Int) {
        background.visibility = View.VISIBLE
        if (build.isBackgroundFullScreen)return
        val layoutParams = background.layoutParams as RelativeLayout.LayoutParams
        layoutParams.topMargin = topMargin
        layoutParams.bottomMargin = botMargin
        background.layoutParams = layoutParams
    }


    class DialogBuild(
        val layoutView: View,
        var horizontal: Int,
        var vertical: Int,
        var height: Int = ViewGroup.LayoutParams.WRAP_CONTENT,
        var width: Int = ViewGroup.LayoutParams.MATCH_PARENT,
        var minHeight: Int = ViewGroup.LayoutParams.WRAP_CONTENT,
        var maxHeight: Int = ViewGroup.LayoutParams.MATCH_PARENT,
        var themeStyle: Int = R.style.DialogThemeStyle,
        var animStyle: Int = 0,
        var x: Int = 0,
        var y: Int = 0,
        var dimAmount: Float = 0f,
        var cancelable: Boolean = false,
        var isHaveTitleBar:Boolean = true,
        var isBackgroundFullScreen:Boolean = false,
        var backgroundRes:Int = R.color.black
    ) {
        fun build(): SmartDialog {
            return SmartDialog(this)
        }
    }

    override fun onStart() {
        val dialog = dialog
        if (dialog != null) {
            val win = dialog.window
            // 一定要设置Background,如果不设置,window属性设置无效
            win!!.setBackgroundDrawable(ColorDrawable(0x00000000))
            val params = win.attributes
            params.gravity = Gravity.CENTER
            params.dimAmount = 0f
            // 使用ViewGroup.LayoutParams,以便Dialog 宽度充满整个屏幕
            params.width = ViewGroup.LayoutParams.MATCH_PARENT
            params.height =  Utils.getWindowContentHeight(activity)
//            params.height = Utils.getScreenHeight(context)+Utils.getStatusBarHeight(context)
            win.setWindowAnimations(build.animStyle)
            win.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND)
            win.attributes = params
        }
        super.onStart()
    }

    override fun dismiss() {
        super.dismiss()
        dismissListener?.invoke()
    }
}

  Modo paisaje 

    int CENTER = 0; alineación central
    int LEFT = 1; a la izquierda
    int RIGHT = 2; a la derecha
    int ALIGN_LEFT = 3; alineación a la izquierda
    int ALIGN_RIGHT = 4; alineación a la derecha



import androidx.annotation.IntDef;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@IntDef({
        HorizontalPosition.CENTER,
        HorizontalPosition.LEFT,
        HorizontalPosition.RIGHT,
        HorizontalPosition.ALIGN_LEFT,
        HorizontalPosition.ALIGN_RIGHT,
})
@Retention(RetentionPolicy.SOURCE)
public @interface HorizontalPosition {
    int CENTER = 0;
    int LEFT = 1;
    int RIGHT = 2;
    int ALIGN_LEFT = 3;
    int ALIGN_RIGHT = 4;
}

   modo retrato 

    int CENTRO = 0; alinear al centro
    int ARRIBA = 1; alinear arriba
    int ABAJO = 2; alinear abajo
    int ALIGN_TOP = 3; alinear arriba
    int ALIGN_BOTTOM = 4; alinear abajo

import androidx.annotation.IntDef;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@IntDef({
        VerticalPosition.CENTER,
        VerticalPosition.ABOVE,
        VerticalPosition.BELOW,
        VerticalPosition.ALIGN_TOP,
        VerticalPosition.ALIGN_BOTTOM,
})
@Retention(RetentionPolicy.SOURCE)
public @interface VerticalPosition {
    int CENTER = 0;
    int ABOVE = 1;
    int BELOW = 2;
    int ALIGN_TOP = 3;
    int ALIGN_BOTTOM = 4;
}

estilo de estilo

   <style name="DialogThemeStyle" parent="Theme.AppCompat.Light.Dialog">
        <item name="android:windowNoTitle">true</item>
        <item name="android:windowBackground">@android:color/transparent</item>
        <item name="android:colorBackgroundCacheHint">@null</item>
        <item name="android:windowSoftInputMode">adjustPan</item>
        <item name="android:windowIsFloating">true</item>
        <item name="android:windowContentOverlay">@null</item>
    </style>

Supongo que te gusta

Origin blog.csdn.net/qq_35644925/article/details/128496834
Recomendado
Clasificación