2023-09-27 14:37:28 +08:00

215 lines
7.1 KiB
Kotlin

package com.angcyo.tablayout
import android.graphics.Rect
import android.graphics.RectF
import android.view.Gravity
/**
* [android.view.Gravity] 辅助计算类
* Email:angcyo@126.com
* @author angcyo
* @date 2019/12/13
* Copyright (c) 2019 ShenZhen O&M Cloud Co., Ltd. All rights reserved.
*/
class DslGravity {
/**束缚范围*/
val gravityBounds: RectF = RectF()
/**束缚重力*/
var gravity: Int = Gravity.LEFT or Gravity.TOP
/**使用中心坐标作为定位参考, 否则就是四条边*/
var gravityRelativeCenter: Boolean = true
/**额外偏移距离, 会根据[Gravity]自动取负值*/
var gravityOffsetX: Int = 0
var gravityOffsetY: Int = 0
fun setGravityBounds(rectF: RectF) {
gravityBounds.set(rectF)
}
fun setGravityBounds(rect: Rect) {
gravityBounds.set(rect)
}
fun setGravityBounds(
left: Int,
top: Int,
right: Int,
bottom: Int
) {
gravityBounds.set(left.toFloat(), top.toFloat(), right.toFloat(), bottom.toFloat())
}
fun setGravityBounds(
left: Float,
top: Float,
right: Float,
bottom: Float
) {
gravityBounds.set(left, top, right, bottom)
}
//计算后的属性
var _horizontalGravity: Int = Gravity.LEFT
var _verticalGravity: Int = Gravity.TOP
var _isCenterGravity: Boolean = false
var _targetWidth = 0f
var _targetHeight = 0f
var _gravityLeft = 0
var _gravityTop = 0
var _gravityRight = 0
var _gravityBottom = 0
//根据gravity调整后的offset
var _gravityOffsetX = 0
var _gravityOffsetY = 0
/**根据[gravity]返回在[gravityBounds]中的[left] [top]位置*/
fun applyGravity(
width: Float = _targetWidth,
height: Float = _targetHeight,
callback: (centerX: Int, centerY: Int) -> Unit
) {
_targetWidth = width
_targetHeight = height
val layoutDirection = 0
val absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection)
val verticalGravity = gravity and Gravity.VERTICAL_GRAVITY_MASK
val horizontalGravity = absoluteGravity and Gravity.HORIZONTAL_GRAVITY_MASK
//调整offset
_gravityOffsetX = when (horizontalGravity) {
Gravity.RIGHT -> -gravityOffsetX
Gravity.END -> -gravityOffsetX
else -> gravityOffsetX
}
_gravityOffsetY = when (verticalGravity) {
Gravity.BOTTOM -> -gravityOffsetY
else -> gravityOffsetY
}
//计算居中的坐标
val centerX = when (horizontalGravity) {
Gravity.CENTER_HORIZONTAL -> (gravityBounds.left + gravityBounds.width() / 2 + _gravityOffsetX).toInt()
Gravity.RIGHT -> (gravityBounds.right + _gravityOffsetX - if (gravityRelativeCenter) 0f else _targetWidth / 2).toInt()
Gravity.END -> (gravityBounds.right + _gravityOffsetX - if (gravityRelativeCenter) 0f else _targetWidth / 2).toInt()
else -> (gravityBounds.left + _gravityOffsetX + if (gravityRelativeCenter) 0f else _targetWidth / 2).toInt()
}
val centerY = when (verticalGravity) {
Gravity.CENTER_VERTICAL -> (gravityBounds.top + gravityBounds.height() / 2 + _gravityOffsetY).toInt()
Gravity.BOTTOM -> (gravityBounds.bottom + _gravityOffsetY - if (gravityRelativeCenter) 0f else _targetHeight / 2).toInt()
else -> (gravityBounds.top + _gravityOffsetY + if (gravityRelativeCenter) 0f else _targetHeight / 2).toInt()
}
//缓存
_horizontalGravity = horizontalGravity
_verticalGravity = verticalGravity
_isCenterGravity = horizontalGravity == Gravity.CENTER_HORIZONTAL &&
verticalGravity == Gravity.CENTER_VERTICAL
_gravityLeft = (centerX - _targetWidth / 2).toInt()
_gravityRight = (centerX + _targetWidth / 2).toInt()
_gravityTop = (centerY - _targetHeight / 2).toInt()
_gravityBottom = (centerY + _targetHeight / 2).toInt()
//回调
callback(centerX, centerY)
}
}
/**
* 默认计算出的是目标中心点坐标参考距离
* [com.angcyo.drawable.DslGravity.getGravityRelativeCenter]
* */
fun dslGravity(
rect: RectF, //计算的矩形
gravity: Int, //重力
width: Float, //放置目标的宽度
height: Float, //放置目标的高度
offsetX: Int = 0, //额外的偏移,会根据[gravity]进行左右|上下取反
offsetY: Int = 0,
callback: (dslGravity: DslGravity, centerX: Int, centerY: Int) -> Unit
): DslGravity {
val _dslGravity = DslGravity()
_dslGravity.setGravityBounds(rect)
_config(_dslGravity, gravity, width, height, offsetX, offsetY, callback)
return _dslGravity
}
/**
* 默认计算出的是目标中心点坐标参考距离
* [com.angcyo.drawable.DslGravity.getGravityRelativeCenter]
* */
fun dslGravity(
rect: Rect, //计算的矩形
gravity: Int, //重力
width: Float, //放置目标的宽度
height: Float, //放置目标的高度
offsetX: Int = 0, //额外的偏移,会根据[gravity]进行左右|上下取反
offsetY: Int = 0,
callback: (dslGravity: DslGravity, centerX: Int, centerY: Int) -> Unit
): DslGravity {
val _dslGravity = DslGravity()
_dslGravity.setGravityBounds(rect)
_config(_dslGravity, gravity, width, height, offsetX, offsetY, callback)
return _dslGravity
}
private fun _config(
_dslGravity: DslGravity,
gravity: Int, //重力
width: Float, //放置目标的宽度
height: Float, //放置目标的高度
offsetX: Int = 0, //额外的偏移,会根据[gravity]进行左右|上下取反
offsetY: Int = 0,
callback: (dslGravity: DslGravity, centerX: Int, centerY: Int) -> Unit
) {
_dslGravity.gravity = gravity
_dslGravity.gravityOffsetX = offsetX
_dslGravity.gravityOffsetY = offsetY
_dslGravity.applyGravity(width, height) { centerX, centerY ->
callback(_dslGravity, centerX, centerY)
}
}
/**居中*/
fun Int.isCenter(): Boolean {
val layoutDirection = 0
val absoluteGravity = Gravity.getAbsoluteGravity(this, layoutDirection)
val verticalGravity = this and Gravity.VERTICAL_GRAVITY_MASK
val horizontalGravity = absoluteGravity and Gravity.HORIZONTAL_GRAVITY_MASK
return verticalGravity == Gravity.CENTER_VERTICAL && horizontalGravity == Gravity.CENTER_HORIZONTAL
}
fun Int.isLeft(): Boolean {
val layoutDirection = 0
val absoluteGravity = Gravity.getAbsoluteGravity(this, layoutDirection)
val horizontalGravity = absoluteGravity and Gravity.HORIZONTAL_GRAVITY_MASK
return horizontalGravity == Gravity.LEFT
}
fun Int.isRight(): Boolean {
val layoutDirection = 0
val absoluteGravity = Gravity.getAbsoluteGravity(this, layoutDirection)
val horizontalGravity = absoluteGravity and Gravity.HORIZONTAL_GRAVITY_MASK
return horizontalGravity == Gravity.RIGHT
}
fun Int.isTop(): Boolean {
val verticalGravity = this and Gravity.VERTICAL_GRAVITY_MASK
return verticalGravity == Gravity.TOP
}
fun Int.isBottom(): Boolean {
val verticalGravity = this and Gravity.VERTICAL_GRAVITY_MASK
return verticalGravity == Gravity.BOTTOM
}