前言

PopWindow工具类
import android.app.Activityimport android.content.Contextimport android.graphics.drawable.BitmapDrawableimport android.os.Buildimport android.view.Displayimport android.view.Gravityimport android.view.Viewimport android.view.WindowManagerimport android.widget.PopupWindow/*** * PopWindowUtil * Created by zxjie on 2021/5/17. * address:bailingkeji * describe:使用时请先调用init进行初始化,之后调用showPopWindow进行显示,该工具类采用单例设计模式 * link:https://blog.csdn.net/weixin_46603990/article/details/116987681 * https://juejin.cn/post/6963513638783205406/ * example: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - *          |   -实例化对象- *          |   private val popWindowUtil = PopWindowUtil *          | *          |   -初始化PopWindow- *          |   --设置固定大小 *          |   popWindowUtil.init(this,R.layout.pop_alert_two,295F,135F,null) *          |   --适应屏幕最大化 *          |   popWindowUtil.init(this,R.layout.pop_alert_two,PopWindowUtil.MATCH,PopWindowUtil.MATCH,null) *          |   --基于屏幕设置宽高,,Restraint中的参数只有在前者为CHANGE时才会生效,公式为 屏幕宽高-Restraint.width/height *          |   popWindowUtil.init(this,R.layout.pop_alert_two,PopWindowUtil.CHANGE,PopWindowUtil.CHANGE,Restraint(20,60)) *          |   --组合使用,宽置满,高基于屏幕设置 *          |   popWindowUtil.init(this,R.layout.pop_alert_two,PopWindowUtil.MATCH,PopWindowUtil.CHANGE,Restraint(0,60)) *          | *          |   -获取所用到的控件 *          |   val btn_ok = popWindowUtil.getViewById(R.id.btn_ok) as TextView *          | *          |   -设置点击窗口外边,窗口消失,默认为false *          |   popWindowUtil.outSideTouchable(true) *          | *          |   -获取焦点,默认为false *          |   popWindowUtil.itemClickable(true) *          | *          |   -使用默认的阴影效果,默认为false *          |   popWindowUtil.shadowShowAble(true) *          | *          |   -设置PopWindow消失监听 *          |   popWindowUtil.dismissListener = { *          |         -自定义背景 *          |      } *          | *          |   -弹出PopWindow 注意:弹出的PopWindow永远不会跃出屏幕 *          |   --基于整个屏幕居中弹出,向下偏移10dp *          |   popWindowUtil.showPopWindow(toolbar,true, Excursion(Gravity.CENTER,0,10),null) *          |   --基于整个屏幕在左上弹出,并向左偏移10dp 注意:这时候PopWindow已经显示在屏幕最左侧了,所以这个-10是无效的 *          |   popWindowUtil.showPopWindow(toolbar,true, Excursion(Gravity.LEFT or Gravity.TOP,-10,0),null) *          |   --基于整个屏幕从下方滑动弹出,并在tabLayout上方 *          |   popWindowUtil.showPopWindow(tab_layout, true, Excursion(Gravity.BOTTOM, 0, DensityUtil.px2dip(this, (tab_layout.layoutParams.height+nbHeight-4) * 1F)), *          |   --注意偏移的方向并不是正右下,负左上,它是根据位置约束来决定的,位置约束为BOTTOM,那么就是正上,负下,如果为TOP,就是正下,负上,x轴同理 *          |   --不建议使用 基于toolbar控件的左下弹出 注意:为false时位置约束(Gravity.CENTER)将会失效 *          |   popWindowUtil.showPopWindow(toolbar,false, Excursion(Gravity.CENTER,0,0),null) *          | *          |   -建议设置PopWindow弹出时按返回键关闭PopWindow,而不是关闭Activity,注意:onBackPressed()方法只有在Activity中才能重写 *          |   override fun onBackPressed() { *          |        if (!popWindowUtil.disMiss()) finish() *          |        } *          | *          |   -关闭PopWindow *          |   popWindowUtil.disMiss() *          | *          |   -销毁PopWindow所使用的的对象,在onDestroy调用 *          |   popWindowUtil.destroy() *          | *          |   -当工具类提供的方法不满足你的需求时可以调用以下方法获取PopWindow对象 *          |   popWindowUtil.getPopWindow() *          |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */object PopWindowUtil {         private var winHeight: Int = 0    private var winWidth: Int = 0    private var view: View? = null    private var popupWindow: PopupWindow? = null    private var context: Context? = null    private var canDown: Boolean = false    private var canClick: Boolean = false    private var canShow: Boolean = false    private var ERROR: Boolean = false    const val MATCH = -100F    const val CHANGE = -1000F    /***     * @param context 上下文     * @param layoutId 资源文件     * @param width PopWindow所需宽/dp 为MATCH时全屏 为CHANGE时可设置距屏幕的距离     * @param height PopWindow所需高/dp 为MATCH时全屏 为CHANGE时可设置距屏幕的距离     * @param restraint 该参数可为空,宽高非CHANGE情况下无效,当width为CHANGE时Restraint.width生效,即PopWindow距屏幕左右的距离/dp,     * 当height为CHANGE时Restraint.height生效,即PopWindow距屏幕上下的距离/dp     */    fun init(context: Context, layoutId: Int, width: Float, height: Float, restraint: Restraint?) {             this.context = context        if (isExist()) {                 popupWindow!!.dismiss()            popupWindow = null        }        val wm = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager        val display: Display = wm.defaultDisplay        winHeight = display.height        winWidth = display.width        view = View.inflate(context, layoutId, null)        val useWidth = when (width) {                 MATCH -> winWidth            CHANGE -> (winWidth - dip2px(restraint!!.width))            else -> dip2px(width)        }        ERROR = height == MATCH        val useHeight = when {                 height == MATCH -> winHeight            width == CHANGE -> (winHeight - dip2px(restraint!!.height))            else -> dip2px(height)        }        popupWindow = PopupWindow(view, useWidth, useHeight)    }    /**     * @param id 要获取的id     * @return 返回一个view对象,需要强转为所需控件类型     */    fun getViewById(id: Int): View? =        if (isExist()) view!!.findViewById(id)        else throw NullPointerException("查找控件失败,请初始化")    /**     * @param location 一个View对象,用来约束PopWindow的位置     * @param global 是否基于屏幕弹出 true基于屏幕弹出, false基于location控件的左下方弹出, 不建议使用false     * @param excursion 参数一是位置约束,global为false时位置约束将会失效,参数二传入x轴的偏移/dp,,参数三传入y轴的偏移/dp,注意偏移的方向并不是正右下,负左上,     * 它是根据位置约束来决定的,位置约束为BOTTOM,那么就是正上,负下,如果为TOP,就是正下,负上,x轴同理     * @param anim 动画效果,选择性传入,不需要时传入空     */    fun showPopWindow(location: View, global: Boolean, excursion: Excursion, anim: Int?) {             val disPose = disPose(location)        val x = dip2px(excursion.x.toFloat())        val y = dip2px(excursion.y.toFloat())        if (isExist()) {                 if (anim != null) popupWindow?.animationStyle = anim            popupWindow?.isFocusable = canClick            if (canDown) popupWindow?.setBackgroundDrawable(BitmapDrawable())            popupWindow?.isOutsideTouchable = canDown            if (canShow) setBackgroundAlpha(0.5F)            popupWindow!!.setOnDismissListener {                     if (canShow) setBackgroundAlpha(1F)                dismissListener?.invoke()            }            if (global) {                     if (ERROR) popupWindow?.height = winHeight - disPose                popupWindow?.showAtLocation(location, excursion.gravity, x, y)            } else {                     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && ERROR) {                         val height = location.layoutParams.height                    popupWindow?.height = winHeight - (disPose + height)                    popupWindow?.showAtLocation(location, Gravity.NO_GRAVITY, 0, disPose + height)                } else popupWindow?.showAsDropDown(location, x, y)            }        } else throw NullPointerException("显示PopWindow失败,请初始化")    }    /**     * 处理7.1之上Match覆盖控件的问题     */    fun disPose(location: View): Int {             val a = IntArray(2)        location.getLocationOnScreen(a)        return a[1]    }    /**     * 关闭PopWindow弹窗     * @return 成功关闭为true,否则为false     */    fun disMiss(): Boolean =        if (isExist() && isShowing()) {                 popupWindow!!.dismiss()            true        } else false        /**     * 获取当前PopWindow对象     * @return isExist()为true时返回一个PopWindow对象 为false时抛出异常     */    fun getPopWindow() =        if (isExist()) popupWindow        else throw NullPointerException("获取PopWindow对象失败,PopWindow示例对象为空")    /**     * 设置背景     */    fun setBackgroundAlpha(bgAlpha: Float) {             val activity: Activity = context as Activity        val lp = activity.window.attributes        lp.alpha = bgAlpha        if (bgAlpha == 1f) activity.window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND)        else activity.window.addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND)        activity.window.attributes = lp    }    /**     *设置是否使用自带的阴影效果     * @param canShow false 不使用, true 使用     */    fun shadowShowAble(canShow: Boolean) {             this.canShow = canShow    }    /**     * 设置是否能点击窗口外边窗口消失     * @param canDown false 不能点击消失, true 可以点击消失     */    fun outSideTouchable(canDown: Boolean) {             this.canDown = canDown    }    /**     * 设置是否获得焦点     * @param canClick false 不获取,无法点击, true 获取,可以点击     */    fun itemClickable(canClick: Boolean) {             this.canClick = canClick    }        /**     * PopWindow是否为显示状态     * @return true 显示, false 未显示     */    fun isShowing() = popupWindow!!.isShowing    /**     * PopWindow是否实例化     * @return true 已实例化, false 为空     */    fun isExist() = popupWindow != null    /**     * 将所用到的对象置空,建议调用     */    fun destroy() {             dismissListener = null        popupWindow?.dismiss()        popupWindow = null        context = null        view = null    }    /**     * 单位换算 dp转px     * @return 转为px后的数值     */    fun dip2px(dpValue: Float): Int =        (dpValue * this.context!!.resources.displayMetrics.density + 0.5f).toInt()    /**     * 通过方法变量实现接口回调     */    var dismissListener: (() -> Unit)? = null}/** * @param gravity 位置约束 参数为:Gravity.TOP,Gravity.BOTTOM,Gravity.LEFT,Gravity.RIGHT,Gravity.CENTER * @param x * @param y */data class Excursion(val gravity: Int, val x: Int, val y: Int)/** * @param width PopWindow距屏幕左右的距离 * @param height PopWindow距屏幕上下的距离 */data class Restraint(val width: Float, val height: Float)

更多相关文章

  1. 屏幕方向android:screenOrientation
  2. Android兼容性优化-Android(安卓)8.0设置Activity透明主题崩溃
  3. Android(安卓)Dimension
  4. Android(安卓)Dialog风格弹出框的Activity
  5. Android实用代码
  6. android nfc 开发
  7. 49.Android中各种Span的用法
  8. android在service中使用AsyncHttpClient加载网络资源
  9. Android(安卓)edittext刚进入页面取消焦点

随机推荐

  1. 关于android的mk文件的一些见解
  2. Android(安卓)sdk manager无法更新问题,使
  3. Android(安卓)图片压缩终极解决方案
  4. Unity与Android对比学习之生命周期方法
  5. Android(安卓)Room 数据库迁移,或者说升
  6. Android控件系列之相册Gallery&Adapter适
  7. Android(安卓)Market 账号注册和应用发布
  8. Android基本概念总结
  9. Android界面跳转时候onDestroy和onResume
  10. Android实战(三)------Myeclipse10搭建an