当你浏览公众号时来了一条新消息,通知在屏幕顶部会以自顶向下动画的形式入场,而且它是跨界面的全局浮窗(效果如下图)。虽然上一篇中抽象的浮窗工具类已经能实现这个需求。但本文在此基础上再封装一些更加友好的 API 来实现下沉式通知。
跨界面浮窗
这是 Android Window 应用的第二篇,系列文章目录如下:
预定义常用位置
上一篇抽象的show()接口通过指定x、y能精确地在屏幕任意位置显示浮窗。但有时候业务需求是模糊的,比如“在屏幕右侧中间显示浮窗”。如果能新增一个 API,再预定义一些常用位置,这样业务层就可以不用关心窗口坐标的计算。
屏幕的上下左右 4 个方向是常用位置,每个位置又可以有三种gravity:起点、中点、终点。组合一下就有 12 个常用位置。
当然可以定义 12 个常量,它们的值从 0-11 。但当每个位置新增一种 gravity,则要新增 4 个常量。将上下左右的方位和 gravity 分成两组可以解决这个问题:
object FloatWindow : View.OnTouchListener {
//'方位常量组'
const val POSIITION_TOP = 1
const val POSITION_LEFT = 2
const val POSITION_RIGHT = 3
const val POSITION_BOTTOM = 4
//'gravity常量组'
const val GRAVITY_START = 100
const val GRAVITY_MID = 101
const val GRAVITY_END = 102
}
重载一个带有常用位置参数的show()函数:
object FloatWindow : View.OnTouchListener {
fun show(
context: Context,
tag: String,
windowInfo: WindowInfo? = windowInfoMap[tag],
//'新增参数:位置'
position: Int,
//'新增参数:gravity'
gravity: Int
) {
//'根据常用位置计算窗口左上角坐标,省略了计算过程'
when (position){
POSITION_TOP -> {
when (gravity) -> {
GRAVITY_START -> {...}
GRAVITY_MID -> {...}
GRAVITY_END -> {...}
else -> {...}
}
}
POSITION_LEFT -> {
when (gravity) -> {
GRAVITY_START -> {...}
GRAVITY_MID -> {...}
GRAVITY_END -> {...}
else -> {...}
}
}
POSITION_RIGHT -> {
when (gravity) -> {
GRAVITY_START -> {...}
GRAVITY_MID -> {...}
GRAVITY_END -> {...}
else -> {...}
}
}
POSITION_BOTTOM -> {
when (gravity) -> {
GRAVITY_START -> {...}
GRAVITY_MID -> {...}
GRAVITY_END -> {...}
else -> {...}
}
}
else -> {...}
}
//'将计算出的坐标传入上一篇抽象的show函数'
show( context, tag, windowInfo, x, y, false)
}
}
没毛病,但show()函数新增了两个参数,而且这两个参数得合起来才表达一个完整的语义:窗口的位置。
二进制位管理多个状态
有没有什么办法将两个参数合并成一个参数?有!更好的解决方案就藏在View的源码里:
public class View {
/*
* '状态常量'
* |-------|-------|-------|-------|
* 1 PFLAG_WANTS_FOCUS
* 1 PFLAG_FOCUSED
* 1 PFLAG_SELECTED
* 1 PFLAG_IS_ROOT_NAMESPACE
* 1 PFLAG_HAS_BOUNDS
* 1 PFLAG_DRAWN
* 1 PFLAG_DRAW_ANIMATION
* 1 PFLAG_SKIP_DRAW
* 1 PFLAG_REQUEST_TRANSPARENT_REGIONS
* 1 PFLAG_DRAWABLE_STATE_DIRTY
* 1 PFLAG_MEASURED_DIMENSION_SET
* 1 PFLAG_FORCE_LAYOUT
* 1 PFLAG_LAYOUT_REQUIRED
* 1 PFLAG_PRESSED
* 1 PFLAG_DRAWING_CACHE_VALID
* 1 PFLAG_ANIMATION_STARTED
* 1 PFLAG_SAVE_STATE_CALLED
* 1 PFLAG_ALPHA_SET
* 1 PFLAG_SCROLL_CONTAINER
* 1 PFLAG_SCROLL_CONTAINER_ADDED
* 1 PFLAG_DIRTY
* 1 PFLAG_DIRTY_MASK
* 1 PFLAG_OPAQUE_BACKGROUND
* 1 PFLAG_OPAQUE_SCROLLBARS
* 11 PFLAG_OPAQUE_MASK
* 1 PFLAG_PREPRESSED
* 1 PFLAG_CANCEL_NEXT_UP_