模拟Toast 自定义提示框

该文章介绍了一个简单的自定义TipPopup工具,用于替代标准的ToastUtils,提供了自动消失和多种位置配置功能,如正中、左中、右中、下中等。TipPopup基于PopupWindow实现,支持高度和宽度自适应,并包含动画效果。文章详细展示了类定义、XML布局、风格设置以及使用方法。
摘要由CSDN通过智能技术生成

模拟Toast 自定义提示框

前言

为满足产品需求,发现现在的ToastUtils不是太重就是不太满足需求,这边写个简单易用的工具,几十行代码解决的问题,还要啥轮子。
toast

功能如下:

  1. 自动消失
  2. 相对锚点位置 可配置,正中间,左中,右中,下中,等
  3. 高宽自适应

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)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值