模拟Toast 自定义提示框
前言
为满足产品需求,发现现在的ToastUtils不是太重就是不太满足需求,这边写个简单易用的工具,几十行代码解决的问题,还要啥轮子。
 
功能如下:
- 自动消失
- 相对锚点位置 可配置,正中间,左中,右中,下中,等
- 高宽自适应
TipPop
class TipPopup : PopupWindow {
    private val ctx: Context
    constructor(ctx: Context, content: String) : super(ctx) {
        this.ctx = ctx
        contentView = LayoutInflater.from(ctx).inflate(R.layout.toast_tip, null)
        width = ViewGroup.LayoutParams.WRAP_CONTENT
        height = ViewGroup.LayoutParams.WRAP_CONTENT
        isFocusable = true
        isOutsideTouchable = true
        animationStyle = R.style.dialog_animation_style
        setBackgroundDrawable(ColorDrawable())
        contentView.findViewById<TextView>(R.id.toast_tv_tip_content).setText(content)
    }
    fun show(parent: View, gravity: Int) {
        val it = IntArray(2)
        parent.getLocationOnScreen(it)
        val centerX = parent.measuredWidth / 2 + it[0]
        val centerY = parent.measuredHeight / 2 + it[1]
        /*使用前先测量*/
        contentView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED)
        var x: Int
        var y: Int
        when (gravity) {
            Gravity.LEFT or Gravity.CENTER_VERTICAL -> {
                x = centerX - contentView.measuredWidth
                y = centerY - contentView.measuredHeight / 2
            }
            Gravity.RIGHT or Gravity.CENTER_VERTICAL -> {
                x = centerX
                y = centerY - contentView.measuredHeight / 2
            }
            Gravity.TOP or Gravity.CENTER_HORIZONTAL -> {
                x = centerX - contentView.measuredWidth / 2
                y = centerY - contentView.measuredHeight
            }
            Gravity.BOTTOM or Gravity.CENTER_HORIZONTAL -> {
                x = centerX - contentView.measuredWidth / 2
                y = centerY
            }
            /*默认正中间*/
            else -> {
                x = centerX - contentView.measuredWidth / 2
                y = centerY - contentView.measuredHeight / 2
            }
        }
        showAtLocation(parent, Gravity.NO_GRAVITY, x, y)
    }
}
XML
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="vertical">
    <!--场景模式文字提示-->
    <TextView
        android:layout_gravity="center"
        android:id="@+id/toast_tv_tip_content"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@color/black_50"
        android:gravity="center"
        android:text="@string/calibrating"
        android:minWidth="@dimen/dimen_66dp"
        android:paddingLeft="@dimen/dimen_12dp"
        android:paddingTop="@dimen/dimen_3dp"
        android:paddingRight="@dimen/dimen_12dp"
        android:paddingBottom="@dimen/dimen_3dp"
        android:textColor="@color/white"
        android:textSize="@dimen/sp_14"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</FrameLayout>
Style
    <style name="dialog_animation_style">
        <item name="android:windowEnterAnimation">@anim/anim_show_in</item>
        <item name="android:windowExitAnimation">@anim/anim_show_out</item>
    </style>
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    >
	<alpha
	   android:interpolator="@android:anim/accelerate_decelerate_interpolator"
	   android:fromAlpha="0"
	   android:toAlpha="1.0"
	   android:duration="300"
	   />
</set>    
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
	<alpha
	   android:interpolator="@android:anim/accelerate_decelerate_interpolator"
       android:fromAlpha="1.0"
       android:toAlpha="0"
       android:duration="300"
       />
</set>    
使用
private var tipPopup: TipPopup? = null
/**
 * 提示框,自动消失
 */
private fun shoTip(id: Int, start: () -> Unit, end: () -> Unit) {
    start()
    if (tipPopup == null) {
        tipPopup = TipPopup(requireContext(), getStr(id))
    }
    if (false == tipPopup?.isShowing) {
        tipPopup?.show(line, Gravity.TOP or Gravity.CENTER_HORIZONTAL)
    }
    Handler().postDelayed({
        tipPopup?.dismiss()
        end()
    }, 1500)
}
shoTip(R.string.calibrating, fun() {
   //开始弹出
}, fun() {
   	//关闭弹窗
})
showAtLocation的理解
showAtLocation,这里查阅资料,主要是对第二个参数的理解比较重要,因为其代表的是相对屏幕的坐标点,所以笔者直接配置为Gravity.NO_GRAVITY
第二个参数:请记住屏幕原点是屏幕的左上角。Gravity.TOP |
Gravity.RIGHT指的就是屏幕的右上角,那么pw的中心点坐标是(屏幕宽,0)。pw默认是在屏幕的中间,也就是Gravity.LEFT表示pw的中心点坐标是(0,1/2屏幕高);
使用前先测量
如下代码,动态获取控件高宽,即可做到大小自适应
   contentView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED)



















