矩形围栏修改为每个角都可以拖动,且对角固定不动
This commit is contained in:
@@ -30,8 +30,8 @@ android {
|
||||
targetSdkVersion 35
|
||||
versionCode 2601
|
||||
// versionName "2.6.1"
|
||||
versionName "2.6.1-Beta2"
|
||||
4
|
||||
versionName "2.6.1-Beta3"
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
ndk {
|
||||
|
||||
@@ -618,7 +618,7 @@ open class AddAndEditFencesZoneBaseActivity :
|
||||
R.color.red_color3,
|
||||
R.drawable.icon_fences_zone_gps_red_svg,
|
||||
R.drawable.icon_fence_rect_zoom_red_svg,
|
||||
R.drawable.icon_fence_dot_red_svg,
|
||||
R.drawable.icon_fence_rect_zoom_red,
|
||||
R.drawable.icon_fence_rect_red_rotate_svg
|
||||
)
|
||||
fencesZonePolygonView.setColorAndImage(
|
||||
|
||||
@@ -14,7 +14,7 @@ import com.abbidot.tracker.util.LonAndLatUtil
|
||||
import com.abbidot.tracker.vm.GeoCoderViewModel
|
||||
import com.abbidot.tracker.widget.FencesCircleView
|
||||
import com.abbidot.tracker.widget.FencesPolygonView
|
||||
import com.abbidot.tracker.widget.FencesRectView
|
||||
import com.abbidot.tracker.widget.FencesRectView2
|
||||
import com.google.android.gms.maps.model.LatLng
|
||||
|
||||
/**
|
||||
@@ -30,7 +30,7 @@ class FencesAddEditMapCommon : BaseMapCommon() {
|
||||
context: Context,
|
||||
fencesBean: FencesBean,
|
||||
fencesCircleView: FencesCircleView,
|
||||
fencesRectView: FencesRectView,
|
||||
fencesRectView: FencesRectView2,
|
||||
fencesPolygonView: FencesPolygonView,
|
||||
isEdit: Boolean,
|
||||
onActivityCallBack: OnActivityCallBack?,
|
||||
|
||||
@@ -823,7 +823,15 @@ class MapV3Fragment : BaseFragment<FragmentMapV3Binding>(FragmentMapV3Binding::i
|
||||
isMoveCamera = false
|
||||
}
|
||||
mHomeMapCommon.startRefreshUserLocation()
|
||||
mHomeMapCommon.updateOtherPetLatLng(otherPets)
|
||||
getHomeV2Activity()?.let { m ->
|
||||
m.getPet(false)?.let { p ->
|
||||
//删除当前选中宠物
|
||||
otherPets?.let { o ->
|
||||
mHomeMapCommon.updateOtherPetLatLng(o.filter { it.petId != p.petId }
|
||||
.toMutableList())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isShowFence) {
|
||||
fences?.let { fences ->
|
||||
|
||||
@@ -13,7 +13,7 @@ import com.abbidot.tracker.util.LonAndLatUtil
|
||||
import com.abbidot.tracker.util.Util
|
||||
import com.abbidot.tracker.widget.FencesCircleView
|
||||
import com.abbidot.tracker.widget.FencesPolygonView
|
||||
import com.abbidot.tracker.widget.FencesRectView
|
||||
import com.abbidot.tracker.widget.FencesRectView2
|
||||
import com.baidu.location.BDLocation
|
||||
import com.baidu.mapapi.map.BaiduMap
|
||||
import com.baidu.mapapi.map.MapStatus
|
||||
@@ -31,7 +31,7 @@ class FencesAddEditBaiduMapFragment : BaseBaiduMapFragment() {
|
||||
private lateinit var mFencesBean: FencesBean
|
||||
private var isEditFences = false
|
||||
private lateinit var mFencesCircleView: FencesCircleView
|
||||
private lateinit var mFencesRectView: FencesRectView
|
||||
private lateinit var mFencesRectView: FencesRectView2
|
||||
private lateinit var mFencesPolygonView: FencesPolygonView
|
||||
private var mOnActivityCallBack: FencesAddEditMapCommon.OnActivityCallBack? = null
|
||||
|
||||
@@ -45,7 +45,7 @@ class FencesAddEditBaiduMapFragment : BaseBaiduMapFragment() {
|
||||
context: Context,
|
||||
fencesBean: FencesBean,
|
||||
fencesCircleView: FencesCircleView,
|
||||
fencesRectView: FencesRectView,
|
||||
fencesRectView: FencesRectView2,
|
||||
fencesPolygonView: FencesPolygonView,
|
||||
isEdit: Boolean,
|
||||
onActivityCallBack: FencesAddEditMapCommon.OnActivityCallBack?,
|
||||
|
||||
@@ -12,7 +12,7 @@ import com.abbidot.tracker.ui.common.map.FencesAddEditMapCommon
|
||||
import com.abbidot.tracker.util.Util
|
||||
import com.abbidot.tracker.widget.FencesCircleView
|
||||
import com.abbidot.tracker.widget.FencesPolygonView
|
||||
import com.abbidot.tracker.widget.FencesRectView
|
||||
import com.abbidot.tracker.widget.FencesRectView2
|
||||
import com.google.android.gms.maps.GoogleMap
|
||||
import com.google.android.gms.maps.model.LatLng
|
||||
import kotlin.math.abs
|
||||
@@ -28,7 +28,7 @@ class FencesAddEditGoogleMapFragment : BaseGoogleMapFragment() {
|
||||
private lateinit var mFencesBean: FencesBean
|
||||
private var isEditFences = false
|
||||
private lateinit var mFencesCircleView: FencesCircleView
|
||||
private lateinit var mFencesRectView: FencesRectView
|
||||
private lateinit var mFencesRectView: FencesRectView2
|
||||
private lateinit var mFencesPolygonView: FencesPolygonView
|
||||
private var mOnActivityCallBack: FencesAddEditMapCommon.OnActivityCallBack? = null
|
||||
|
||||
@@ -46,7 +46,7 @@ class FencesAddEditGoogleMapFragment : BaseGoogleMapFragment() {
|
||||
context: Context,
|
||||
fencesBean: FencesBean,
|
||||
fencesCircleView: FencesCircleView,
|
||||
fencesRectView: FencesRectView,
|
||||
fencesRectView: FencesRectView2,
|
||||
fencesPolygonView: FencesPolygonView,
|
||||
isEdit: Boolean,
|
||||
onActivityCallBack: FencesAddEditMapCommon.OnActivityCallBack?,
|
||||
|
||||
@@ -32,7 +32,7 @@ import kotlin.math.sqrt
|
||||
/**
|
||||
*Created by .yzq on 2022/1/22/022.
|
||||
* @link
|
||||
* @description:添加围栏矩形,只针对围栏
|
||||
* @description:添加围栏矩形,只针对围栏,固定一个角拖动,其他角会跟随拖动
|
||||
*
|
||||
* 按以下点组成的矩形
|
||||
* A B
|
||||
|
||||
@@ -25,6 +25,7 @@ import com.qmuiteam.qmui.util.QMUIDisplayHelper
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.atan2
|
||||
import kotlin.math.cos
|
||||
import kotlin.math.max
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.sin
|
||||
import kotlin.math.sqrt
|
||||
@@ -32,7 +33,7 @@ import kotlin.math.sqrt
|
||||
/**
|
||||
*Created by .yzq on 2022/1/22/022.
|
||||
* @link
|
||||
* @description:添加围栏矩形,只针对围栏
|
||||
* @description:添加围栏矩形,只针对围栏,拖动哪个角就哪个角就变化,其他角会保持不动
|
||||
*
|
||||
* 按以下点组成的矩形
|
||||
* A B
|
||||
@@ -63,8 +64,8 @@ class FencesRectView2 : View {
|
||||
|
||||
//定位图标
|
||||
private var mLocationBitmap: Bitmap? = null
|
||||
private var mDotBitmap: Bitmap? = null
|
||||
private var mZoomBitmap: Bitmap? = null
|
||||
private var mZoomBitmap1: Bitmap? = null
|
||||
private var mZoomBitmap2: Bitmap? = null
|
||||
private var mRotateBitmap: Bitmap? = null
|
||||
|
||||
private var mDashedColor = 0
|
||||
@@ -76,6 +77,23 @@ class FencesRectView2 : View {
|
||||
private var mOldX = 0f
|
||||
private var mOldY = 0f
|
||||
|
||||
//是否正在拖动4个角中的一个
|
||||
private var isCornerDrag = false
|
||||
|
||||
//当前拖动的是哪个角(POINT_A/B/C/D)
|
||||
private var mCornerDragPoint = 0
|
||||
|
||||
//拖动时保持不动的对角屏幕坐标
|
||||
private var mFixedCornerX = 0f
|
||||
private var mFixedCornerY = 0f
|
||||
|
||||
//本手势是否已触碰过最小尺寸,保证每次手势只弹一次提示
|
||||
private var mHitMinThisGesture = false
|
||||
|
||||
//按下时localX/localY的正负号(1或-1),拖动中变号说明越过了对角,钉住不动
|
||||
private var mInitialLocalXSign = 0
|
||||
private var mInitialLocalYSign = 0
|
||||
|
||||
//是否显示距离
|
||||
private var isShowDistance = true
|
||||
private var mRectWidthDistanceText = ""
|
||||
@@ -137,11 +155,12 @@ class FencesRectView2 : View {
|
||||
mTextPaint.textSize = QMUIDisplayHelper.sp2px(context, 14).toFloat()
|
||||
mTextPaint.color = ContextCompat.getColor(mContext, R.color.black)
|
||||
|
||||
mDotBitmap = ImageUtil.getBitmapFromDrawableAndSvg(context, R.drawable.icon_fence_dot_svg)
|
||||
mLocationBitmap =
|
||||
ImageUtil.getBitmapFromDrawableAndSvg(context, R.drawable.icon_fences_zone_gps_svg)
|
||||
mZoomBitmap =
|
||||
mZoomBitmap1 =
|
||||
ImageUtil.getBitmapFromDrawableAndSvg(context, R.drawable.icon_fence_rect_zoom_svg)
|
||||
mZoomBitmap2 =
|
||||
ImageUtil.getBitmapFromDrawableAndSvg(context, R.drawable.icon_fence_rect_zoom)
|
||||
mRotateBitmap =
|
||||
ImageUtil.getBitmapFromDrawableAndSvg(context, R.drawable.icon_fence_rect_rotate_svg)
|
||||
|
||||
@@ -175,14 +194,6 @@ class FencesRectView2 : View {
|
||||
rotate(mRotateAngle.toFloat())
|
||||
startDraw(this)
|
||||
restore()
|
||||
// val a = getRectABCDXYPoint(FencesRectView.POINT_A)
|
||||
// drawCircle(a[0], a[1], 50f, mTextPaint)
|
||||
// val b = getRectABCDXYPoint(FencesRectView.POINT_B)
|
||||
// drawCircle(b[0], b[1], 50f, mTextPaint)
|
||||
// val c = getRectABCDXYPoint(FencesRectView.POINT_C)
|
||||
// drawCircle(c[0], c[1], 50f, mTextPaint)
|
||||
// val d = getRectABCDXYPoint(FencesRectView.POINT_D)
|
||||
// drawCircle(d[0], d[1], 50f, mTextPaint)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -213,25 +224,6 @@ class FencesRectView2 : View {
|
||||
canvas.drawRect(mRectF, mFillPaint)
|
||||
canvas.drawRect(mRectF, mStrokePaint)
|
||||
|
||||
mDotBitmap?.apply {
|
||||
val dotImageHalfWidth = width / 2f
|
||||
val dotImageHalfHeight = height / 2f
|
||||
canvas.drawBitmap(
|
||||
this, mRectLeft - dotImageHalfWidth, mRectTop - dotImageHalfHeight, null
|
||||
)
|
||||
canvas.drawBitmap(
|
||||
this, mRectRight - dotImageHalfWidth, mRectTop - dotImageHalfHeight, null
|
||||
)
|
||||
canvas.drawBitmap(
|
||||
this, mRectLeft - dotImageHalfWidth, mRectBottom - dotImageHalfHeight, null
|
||||
)
|
||||
if (!isShowDistance) {
|
||||
canvas.drawBitmap(
|
||||
this, mRectRight - dotImageHalfWidth, mRectBottom - dotImageHalfHeight, null
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (isShowDistance) {
|
||||
|
||||
@@ -250,12 +242,22 @@ class FencesRectView2 : View {
|
||||
mRectTop - height - QMUIDisplayHelper.dpToPx(2).toFloat(),
|
||||
null
|
||||
)
|
||||
mStartRotateAngle = atan2(mRectTop - height, startX - width / 2) / Math.PI * 180
|
||||
}
|
||||
mZoomBitmap?.apply {
|
||||
mZoomBitmap1?.apply {
|
||||
canvas.drawBitmap(
|
||||
this, mRectRight - width / 2, mRectBottom - height / 2, null
|
||||
)
|
||||
canvas.drawBitmap(
|
||||
this, mRectLeft - width / 2, mRectTop - height / 2, null
|
||||
)
|
||||
}
|
||||
mZoomBitmap2?.apply {
|
||||
canvas.drawBitmap(
|
||||
this, mRectRight - width / 2, mRectTop - height / 2, null
|
||||
)
|
||||
canvas.drawBitmap(
|
||||
this, mRectLeft - width / 2, mRectBottom - height / 2, null
|
||||
)
|
||||
}
|
||||
|
||||
canvasDistanceText(canvas)
|
||||
@@ -339,9 +341,10 @@ class FencesRectView2 : View {
|
||||
dashedColorRes: Int = 0,
|
||||
fillBgColorRes: Int = 0,
|
||||
locationDrawableRes: Int = 0,
|
||||
zoomDrawableRes: Int = 0,
|
||||
dotDrawableRes: Int = 0,
|
||||
rotateDrawableRes: Int = 0,disTextColorRes: Int = 0
|
||||
zoom1DrawableRes: Int = 0,
|
||||
zoom2DrawableRes: Int = 0,
|
||||
rotateDrawableRes: Int = 0,
|
||||
disTextColorRes: Int = 0
|
||||
) {
|
||||
var isRefresh = false
|
||||
if (dashedColorRes > 0) {
|
||||
@@ -359,18 +362,18 @@ class FencesRectView2 : View {
|
||||
mLocationBitmap = ImageUtil.getBitmapFromDrawableAndSvg(context, locationDrawableRes)
|
||||
isRefresh = true
|
||||
}
|
||||
if (zoomDrawableRes > 0) {
|
||||
mZoomBitmap = ImageUtil.getBitmapFromDrawableAndSvg(context, zoomDrawableRes)
|
||||
if (zoom1DrawableRes > 0) {
|
||||
mZoomBitmap1 = ImageUtil.getBitmapFromDrawableAndSvg(context, zoom1DrawableRes)
|
||||
isRefresh = true
|
||||
}
|
||||
if (zoom2DrawableRes > 0) {
|
||||
mZoomBitmap2 = ImageUtil.getBitmapFromDrawableAndSvg(context, zoom2DrawableRes)
|
||||
isRefresh = true
|
||||
}
|
||||
if (rotateDrawableRes > 0) {
|
||||
mRotateBitmap = ImageUtil.getBitmapFromDrawableAndSvg(context, rotateDrawableRes)
|
||||
isRefresh = true
|
||||
}
|
||||
if (dotDrawableRes > 0) {
|
||||
mDotBitmap = ImageUtil.getBitmapFromDrawableAndSvg(context, dotDrawableRes)
|
||||
isRefresh = true
|
||||
}
|
||||
if (disTextColorRes > 0) {
|
||||
mTextPaint.color = ContextCompat.getColor(context, disTextColorRes)
|
||||
isRefresh = true
|
||||
@@ -442,28 +445,38 @@ class FencesRectView2 : View {
|
||||
val x = event.x
|
||||
val y = event.y
|
||||
LogUtil.e("action_down,x=$x,y=$y")
|
||||
//1. 旋转按钮(优先,旋转状态下禁止其他手势)
|
||||
mRotateBitmap?.apply {
|
||||
LogUtil.e("x2=${width / 2f + mCentreX},x1=${-width / 2f + mCentreX}")
|
||||
LogUtil.e("y2=${-(mRectHeight / 2 + height) + mCentreY},aaa=${-mRectHeight / 2 + mCentreY}")
|
||||
|
||||
if (isClickRotate(x, y, mRotateAngle)) {
|
||||
LogUtil.e("点击了旋转")
|
||||
//按下瞬间记录起始角度 = 当前旋转的等效起始角度,这样MOVE里 transformAngle - mStartRotateAngle 保留已有旋转并叠加增量
|
||||
mStartRotateAngle =
|
||||
atan2(y - mCentreY, x - mCentreX) / Math.PI * 180 - mRotateAngle
|
||||
isRotate = true
|
||||
return true
|
||||
}
|
||||
}
|
||||
//是否按下了放大缩小按钮
|
||||
mZoomBitmap?.apply {
|
||||
if (!isRotate && isClickScale(x, y, mRotateAngle)) {
|
||||
isScale = true
|
||||
LogUtil.e("点击了放大缩小")
|
||||
mOldX = x
|
||||
mOldY = y
|
||||
//2. 矩形的4个角点,按下后拖角、对角不动(优先于角点上的放大按钮,因为放大按钮功能已被角点拖覆盖)
|
||||
if (isClickCorner(x, y)) {
|
||||
LogUtil.e("点击了角点:$mCornerDragPoint")
|
||||
isCornerDrag = true
|
||||
return true
|
||||
}
|
||||
}
|
||||
//3. 放大缩小按钮(作为后备,在非角点区域)
|
||||
// mZoomBitmap1?.apply {
|
||||
// if (isClickScale(x, y, mRotateAngle)) {
|
||||
// isScale = true
|
||||
// LogUtil.e("点击了放大缩小")
|
||||
// mOldX = x
|
||||
// mOldY = y
|
||||
// return true
|
||||
// }
|
||||
// }
|
||||
|
||||
//因为有旋转角度,需要减去中心
|
||||
//4. 整体拖动(需要在矩形区域内,且旋转时判断不准,可接受)
|
||||
if (mRectF.contains(x - mCentreX, y - mCentreY)) {
|
||||
isDrag = true
|
||||
mOldX = x
|
||||
@@ -487,26 +500,34 @@ class FencesRectView2 : View {
|
||||
LogUtil.e("mRotateAngle=$mRotateAngle")
|
||||
invalidate()
|
||||
return true
|
||||
} else if (isScale) {
|
||||
LogUtil.e("mRectWidth=$mRectWidth,mRectHeight=$mRectHeight,x - oldX=${x - mOldX},y - oldY=${y - mOldY}")
|
||||
val transformX = x - mOldX
|
||||
val transformY = y - mOldY
|
||||
val newRectWidth = mRectWidth + transformX
|
||||
val newRectHeight = mRectHeight + transformY
|
||||
//限制缩放不能太小
|
||||
if (mLimitSide == 0f) {
|
||||
if (newRectWidth < mLocationBitmap!!.height || newRectHeight < mLocationBitmap!!.height) {
|
||||
return true
|
||||
}
|
||||
} else if (newRectWidth < mLimitSide || newRectHeight < mLimitSide) {
|
||||
return true
|
||||
}
|
||||
mRotateScaleClickListener?.rectScalingClick()
|
||||
mRectWidth = newRectWidth
|
||||
mRectHeight = newRectHeight
|
||||
mOldX = x
|
||||
mOldY = y
|
||||
invalidate()
|
||||
// else if (isScale) {
|
||||
// LogUtil.e("mRectWidth=$mRectWidth,mRectHeight=$mRectHeight,x - oldX=${x - mOldX},y - oldY=${y - mOldY}")
|
||||
// val transformX = x - mOldX
|
||||
// val transformY = y - mOldY
|
||||
// val newRectWidth = mRectWidth + transformX
|
||||
// val newRectHeight = mRectHeight + transformY
|
||||
// //限制缩放不能太小
|
||||
// if (mLimitSide == 0f) {
|
||||
// if (newRectWidth < mLocationBitmap!!.height || newRectHeight < mLocationBitmap!!.height) {
|
||||
// isHasLimitSide = true
|
||||
// return true
|
||||
// }
|
||||
// } else if (newRectWidth < mLimitSide || newRectHeight < mLimitSide) {
|
||||
// isHasLimitSide = true
|
||||
// mRotateScaleClickListener?.rectMinSizeClick()
|
||||
// return true
|
||||
// }
|
||||
// mRotateScaleClickListener?.rectScalingClick()
|
||||
// mRectWidth = newRectWidth
|
||||
// mRectHeight = newRectHeight
|
||||
// mOldX = x
|
||||
// mOldY = y
|
||||
// invalidate()
|
||||
// return true
|
||||
// }
|
||||
else if (isCornerDrag) {
|
||||
moveCorner(x, y)
|
||||
return true
|
||||
} else if (isDrag) {
|
||||
val transformX = x - mOldX
|
||||
@@ -521,6 +542,22 @@ class FencesRectView2 : View {
|
||||
}
|
||||
|
||||
MotionEvent.ACTION_UP -> {
|
||||
handleActionUpOrCancel()
|
||||
}
|
||||
|
||||
MotionEvent.ACTION_CANCEL -> {
|
||||
handleActionUpOrCancel()
|
||||
}
|
||||
}
|
||||
return super.onTouchEvent(event)
|
||||
}
|
||||
|
||||
/**
|
||||
* ACTION_UP 和 ACTION_CANCEL 共用的收尾:重置所有手势状态
|
||||
* ACTION_CANCEL 在父 View(如百度地图)拦截触摸时触发,必须正确清理
|
||||
*/
|
||||
private fun handleActionUpOrCancel() {
|
||||
mHitMinThisGesture = false
|
||||
if (isRotate) {
|
||||
mRotateScaleClickListener?.rectRotateClick()
|
||||
isRotate = false
|
||||
@@ -529,6 +566,10 @@ class FencesRectView2 : View {
|
||||
mRotateScaleClickListener?.rectScaleEndClick()
|
||||
isScale = false
|
||||
}
|
||||
if (isCornerDrag) {
|
||||
mRotateScaleClickListener?.rectScaleEndClick()
|
||||
isCornerDrag = false
|
||||
}
|
||||
if (isDrag) {
|
||||
mRotateScaleClickListener?.rectEndDragClick()
|
||||
isDrag = false
|
||||
@@ -536,9 +577,6 @@ class FencesRectView2 : View {
|
||||
invalidate()
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.onTouchEvent(event)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param x 是坐标轴移动以(mCentreX,mCentreY)原点的坐标
|
||||
@@ -563,14 +601,19 @@ class FencesRectView2 : View {
|
||||
return floatArrayOf((b).toFloat(), (a).toFloat())
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否点击按下了旋转,按照移动了坐标轴原点(mCentreX,mCentreY)计算初始坐标
|
||||
*/
|
||||
private fun isClickRotate(clickX: Float, clickY: Float, rotate: Double): Boolean {
|
||||
var x1 = -(mRectWidth / 2 - mRotateBitmap!!.width / 2)
|
||||
var x2 = (mRectWidth / 2 - mRotateBitmap!!.width / 2)
|
||||
var y1 = -(mRectHeight / 2 + mRotateBitmap!!.height + mRotateBitmap!!.width)
|
||||
var y2 = -(mRectHeight / 2 - mRotateBitmap!!.height)
|
||||
private fun isClick(
|
||||
clickX: Float,
|
||||
clickY: Float,
|
||||
xX1: Float,
|
||||
xX2: Float,
|
||||
yY1: Float,
|
||||
yY2: Float,
|
||||
rotate: Double
|
||||
): Boolean {
|
||||
var x1 = xX1
|
||||
var x2 = xX2
|
||||
var y1 = yY1
|
||||
var y2 = yY2
|
||||
val minX = getRotateXY(x1, y1, rotate)
|
||||
val maxX = getRotateXY(x2, y2, rotate)
|
||||
x1 = minX[0]
|
||||
@@ -586,63 +629,161 @@ class FencesRectView2 : View {
|
||||
y2 = minX[1]
|
||||
}
|
||||
|
||||
//处理旋转到某个角度时,旋转图片按钮会超出坐标范围内,不在可点击坐标范围内,把可点击的坐标范围扩大
|
||||
if (abs(x2 - x1) < mRotateBitmap!!.height) {
|
||||
if (x2 > 0) {
|
||||
x2 += mRotateBitmap!!.height
|
||||
} else {
|
||||
x1 -= mRotateBitmap!!.height
|
||||
}
|
||||
}
|
||||
if (abs(y2 - y1) < mRotateBitmap!!.height) {
|
||||
if (y2 > 0) {
|
||||
y2 += mRotateBitmap!!.height
|
||||
} else {
|
||||
y1 -= mRotateBitmap!!.height
|
||||
}
|
||||
}
|
||||
//旋转到某些角度时按钮投影会变小,加一个小触摸容差保证可点
|
||||
val padding = QMUIDisplayHelper.dpToPx(8).toFloat()
|
||||
x1 -= padding
|
||||
x2 += padding
|
||||
y1 -= padding
|
||||
y2 += padding
|
||||
|
||||
val transformX = clickX - mCentreX
|
||||
val transformY = clickY - mCentreY
|
||||
|
||||
if (transformX in x1..x2 && transformY in y1..y2) {
|
||||
return true
|
||||
return transformX in x1..x2 && transformY in y1..y2
|
||||
}
|
||||
return false
|
||||
|
||||
/**
|
||||
* 是否点击按下了旋转,按照移动了坐标轴原点(mCentreX,mCentreY)计算初始坐标
|
||||
* 按钮绘制在矩形上边中点正上方,点击范围紧贴按钮自身大小
|
||||
*/
|
||||
private fun isClickRotate(clickX: Float, clickY: Float, rotate: Double): Boolean {
|
||||
val halfW = mRotateBitmap!!.width / 2f
|
||||
val halfH = mRotateBitmap!!.height / 2f
|
||||
//按钮中心在本地坐标的位置(以矩形中心为原点,未旋转)
|
||||
val btnCx = 0f
|
||||
val btnCy = -(mRectHeight / 2f + halfH + QMUIDisplayHelper.dpToPx(2).toFloat())
|
||||
val x1 = btnCx - halfW
|
||||
val x2 = btnCx + halfW
|
||||
val y1 = btnCy - halfH
|
||||
val y2 = btnCy + halfH
|
||||
return isClick(clickX, clickY, x1, x2, y1, y2, rotate)
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否点击按下了放大缩小,按照移动了坐标轴原点(mCentreX,mCentreY)计算初始坐标
|
||||
*/
|
||||
private fun isClickScale(clickX: Float, clickY: Float, rotate: Double): Boolean {
|
||||
var x1 = (mRectWidth / 2 - mZoomBitmap!!.width)
|
||||
var x2 = (mRectWidth / 2 + mZoomBitmap!!.width)
|
||||
var y1 = (mRectHeight / 2 - mRotateBitmap!!.height)
|
||||
var y2 = (mRectHeight / 2 + mRotateBitmap!!.height)
|
||||
val minX = getRotateXY(x1, y1, rotate)
|
||||
val maxX = getRotateXY(x2, y2, rotate)
|
||||
x1 = minX[0]
|
||||
x2 = maxX[0]
|
||||
if (minX[0] > maxX[0]) {
|
||||
x1 = maxX[0]
|
||||
x2 = minX[0]
|
||||
}
|
||||
y1 = minX[1]
|
||||
y2 = maxX[1]
|
||||
if (minX[1] > maxX[1]) {
|
||||
y1 = maxX[1]
|
||||
y2 = minX[1]
|
||||
val x1 = (mRectWidth / 2 - mZoomBitmap1!!.width / 2)
|
||||
val x2 = (mRectWidth / 2 + mZoomBitmap1!!.width / 2)
|
||||
val y1 = (mRectHeight / 2 - mZoomBitmap1!!.height)
|
||||
val y2 = (mRectHeight / 2 + mZoomBitmap1!!.height)
|
||||
return isClick(clickX, clickY, x1, x2, y1, y2, rotate)
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否按下了矩形的4个角中的一个,按下时记录当前拖动的角和需要保持不动的对角坐标
|
||||
*/
|
||||
private fun isClickCorner(clickX: Float, clickY: Float): Boolean {
|
||||
if (mRectWidth == 0f && mRectHeight == 0f) return false
|
||||
//因为有旋转角度,先把点击的坐标逆旋转回矩形本地坐标系(以矩形中心为原点)
|
||||
val angle = Math.toRadians(mRotateAngle)
|
||||
val cosAngle = cos(angle).toFloat()
|
||||
val sinAngle = sin(angle).toFloat()
|
||||
val transformX = clickX - mCentreX
|
||||
val transformY = clickY - mCentreY
|
||||
|
||||
if (transformX in x1..x2 && transformY in y1..y2) {
|
||||
val localX = transformX * cosAngle + transformY * sinAngle
|
||||
val localY = -transformX * sinAngle + transformY * cosAngle
|
||||
for (corner in intArrayOf(POINT_A, POINT_B, POINT_C, POINT_D)) {
|
||||
val cornerXY = getRectLocalCornerXY(corner)
|
||||
val offsetX = localX - cornerXY[0]
|
||||
val offsetY = localY - cornerXY[1]
|
||||
if (sqrt(offsetX.pow(2) + offsetY.pow(2)) <= getCornerTouchRadius()) {
|
||||
mCornerDragPoint = corner
|
||||
//记录需要保持不动的对角(屏幕坐标)
|
||||
val fixedXY = getRectABCDXYPoint(getOppositePoint(corner))
|
||||
mFixedCornerX = fixedXY[0]
|
||||
mFixedCornerY = fixedXY[1]
|
||||
//记录角点在本地坐标系中的正负号,拖动中变号说明越过了对角
|
||||
mInitialLocalXSign = if (cornerXY[0] >= 0f) 1 else -1
|
||||
mInitialLocalYSign = if (cornerXY[1] >= 0f) 1 else -1
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* 角点的触摸范围(圆形半径),基于实际绘制在角点的按钮尺寸,外加手指容差
|
||||
*/
|
||||
private fun getCornerTouchRadius(): Float {
|
||||
val cornerIconHalf = listOfNotNull(mZoomBitmap1, mZoomBitmap2)
|
||||
.maxOfOrNull { max(it.width, it.height) / 2f } ?: 0f
|
||||
return cornerIconHalf + QMUIDisplayHelper.dpToPx(10)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取矩形某个角在本地坐标系(以矩形中心为原点,未旋转)的坐标
|
||||
*/
|
||||
private fun getRectLocalCornerXY(wherePoint: Int): FloatArray {
|
||||
val halfWidth = mRectWidth / 2f
|
||||
val halfHeight = mRectHeight / 2f
|
||||
return when (wherePoint) {
|
||||
POINT_A -> floatArrayOf(-halfWidth, -halfHeight)
|
||||
POINT_B -> floatArrayOf(halfWidth, -halfHeight)
|
||||
POINT_D -> floatArrayOf(-halfWidth, halfHeight)
|
||||
else -> floatArrayOf(halfWidth, halfHeight)//POINT_C
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取对角的点,A对C,B对D
|
||||
*/
|
||||
private fun getOppositePoint(wherePoint: Int): Int {
|
||||
return when (wherePoint) {
|
||||
POINT_A -> POINT_C
|
||||
POINT_B -> POINT_D
|
||||
POINT_C -> POINT_A
|
||||
POINT_D -> POINT_B
|
||||
else -> wherePoint
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 拖动角点,对角保持不动,只改变当前拖动角的位置
|
||||
* 对角指向手指的向量投影到矩形的宽高方向得到新的宽高,中心点取对角与拖动角连线的中点
|
||||
*/
|
||||
private fun moveCorner(moveX: Float, moveY: Float) {
|
||||
//保持不动的对角指向手指位置的向量
|
||||
val vectorX = moveX - mFixedCornerX
|
||||
val vectorY = moveY - mFixedCornerY
|
||||
val angle = Math.toRadians(mRotateAngle)
|
||||
val cosAngle = cos(angle).toFloat()
|
||||
val sinAngle = sin(angle).toFloat()
|
||||
//把向量逆旋转回矩形本地坐标系,得到在宽、高方向上的投影
|
||||
val localX = vectorX * cosAngle + vectorY * sinAngle
|
||||
val localY = -vectorX * sinAngle + vectorY * cosAngle
|
||||
//拖动中localX/localY变号说明手指已越过对角,钉住不动防止闪跳
|
||||
val xSignFlipped = mInitialLocalXSign != 0 && (localX > 0f) != (mInitialLocalXSign > 0)
|
||||
val ySignFlipped = mInitialLocalYSign != 0 && (localY > 0f) != (mInitialLocalYSign > 0)
|
||||
//限制边长不能小于最小值,达到最小值后钉住不动,不允许翻过对角
|
||||
val minSide =
|
||||
if (mLimitSide == 0f) (mLocationBitmap?.height ?: 0).toFloat() else mLimitSide
|
||||
if (xSignFlipped || ySignFlipped ||
|
||||
(minSide > 0f && (abs(localX) < minSide || abs(localY) < minSide))
|
||||
) {
|
||||
if (!mHitMinThisGesture) {
|
||||
mHitMinThisGesture = true
|
||||
mRotateScaleClickListener?.rectMinSizeClick()
|
||||
}
|
||||
//已是最小值或越过对角,直接返回保持当前状态,不更新矩形
|
||||
return
|
||||
}
|
||||
//脱离最小值,清标志
|
||||
if (mHitMinThisGesture) {
|
||||
mHitMinThisGesture = false
|
||||
}
|
||||
//限制后的本地坐标再转回屏幕坐标系
|
||||
val newVectorX = localX * cosAngle - localY * sinAngle
|
||||
val newVectorY = localX * sinAngle + localY * cosAngle
|
||||
mRectWidth = abs(localX)
|
||||
mRectHeight = abs(localY)
|
||||
//中心点=对角与拖动角连线的中点,保证对角的位置不会动
|
||||
mCentreX = mFixedCornerX + newVectorX / 2f
|
||||
mCentreY = mFixedCornerY + newVectorY / 2f
|
||||
mRotateScaleClickListener?.rectScalingClick()
|
||||
invalidate()
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置显示编辑的矩形(利用假设方式)
|
||||
* 错误方式
|
||||
@@ -736,22 +877,13 @@ class FencesRectView2 : View {
|
||||
override fun onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow()
|
||||
LogUtil.e("onDetachedFromWindow,${javaClass.canonicalName}视图销毁")
|
||||
if (null != mDotBitmap) {
|
||||
mDotBitmap?.recycle()
|
||||
mDotBitmap = null
|
||||
listOf(mLocationBitmap, mRotateBitmap, mZoomBitmap1, mZoomBitmap2).forEach { bm ->
|
||||
if (bm != null && !bm.isRecycled) bm.recycle()
|
||||
}
|
||||
if (null != mLocationBitmap) {
|
||||
mLocationBitmap?.recycle()
|
||||
mLocationBitmap = null
|
||||
}
|
||||
if (null != mRotateBitmap) {
|
||||
mRotateBitmap?.recycle()
|
||||
mRotateBitmap = null
|
||||
}
|
||||
if (null != mZoomBitmap) {
|
||||
mZoomBitmap?.recycle()
|
||||
mZoomBitmap = null
|
||||
}
|
||||
mZoomBitmap1 = null
|
||||
mZoomBitmap2 = null
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
app:fences_circle_dashed_color="@color/select_color"
|
||||
app:fences_circle_fill_bg_color="@color/select_color4" />
|
||||
|
||||
<com.abbidot.tracker.widget.FencesRectView
|
||||
<com.abbidot.tracker.widget.FencesRectView2
|
||||
android:id="@+id/fences_zone_rect_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
|
||||
Reference in New Issue
Block a user