|
@@ -0,0 +1,685 @@
|
|
|
|
+package com.ys.bdtp.graph
|
|
|
|
+
|
|
|
|
+import android.graphics.Canvas
|
|
|
|
+import android.graphics.Matrix
|
|
|
|
+import android.graphics.PointF
|
|
|
|
+import android.graphics.RectF
|
|
|
|
+import android.util.Log
|
|
|
|
+import android.view.MotionEvent
|
|
|
|
+import com.ys.bdtp.graph.enums.SGraphyItemFlag
|
|
|
|
+import com.ys.bdtp.graph.listeners.SGraphyItemPosListener
|
|
|
|
+import com.ys.bdtp.graph.utils.MatrixUtil
|
|
|
|
+//import com.sybotan.base.extensions.toJson
|
|
|
|
+//import org.jetbrains.anko.doAsync
|
|
|
|
+import java.util.*
|
|
|
|
+import kotlin.concurrent.thread
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * SGraphy图形引擎Item类
|
|
|
|
+ *
|
|
|
|
+ * @author 庞利祥(sybotan@126.com)
|
|
|
|
+ */
|
|
|
|
+open class SGraphyItem(parent: SGraphyItem? = null) {
|
|
|
|
+ /**
|
|
|
|
+ * 类对象
|
|
|
|
+ */
|
|
|
|
+ companion object {
|
|
|
|
+ private val TAG = SGraphyItem::class.java.name
|
|
|
|
+
|
|
|
|
+ /** 当前移动Item */
|
|
|
|
+ private var currentMoveItem: SGraphyItem? = null
|
|
|
|
+
|
|
|
|
+ /** 当前焦点Item */
|
|
|
|
+ private var currentFocusItem: SGraphyItem? = null
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * MotionEvent转子对象MotionEvent
|
|
|
|
+ *
|
|
|
|
+ * @param child 子item对象
|
|
|
|
+ * @param e 事件参数
|
|
|
|
+ * @return 子对象MotionEvent
|
|
|
|
+ */
|
|
|
|
+ fun toChildMotionEvent(child: SGraphyItem, e: SMotionEvent): SMotionEvent {
|
|
|
|
+ val ce = SMotionEvent(e)
|
|
|
|
+// ce.matrix.postTranslate(child.pos.x, child.pos.y);
|
|
|
|
+// ce.matrix.postScale(child.scale.x, child.scale.y);
|
|
|
|
+// ce.matrix.postRotate(child.rotate,0f, 0f);
|
|
|
|
+ ce.matrix.preTranslate(child.pos.x, child.pos.y);
|
|
|
|
+ ce.matrix.preScale(child.scale.x, child.scale.y);
|
|
|
|
+ ce.matrix.preRotate(child.rotate, 0f, 0f);
|
|
|
|
+
|
|
|
|
+ // 不跟随缩放
|
|
|
|
+ if (!child.isTransform) {
|
|
|
|
+ val src = kotlin.floatArrayOf(0f, 1f, 2f, 3f, 4f, 5f, 6f, 7f, 8f)
|
|
|
|
+// ce.matrix.postScale(child._inverseScaleX, child._inverseScaleY);
|
|
|
|
+ ce.matrix.getValues(src)
|
|
|
|
+ val matrix = Matrix()
|
|
|
|
+ matrix.preTranslate(src[2], src[5])
|
|
|
|
+ matrix.preScale(child.scale.x, child.scale.y)
|
|
|
|
+ matrix.preRotate(child.rotate)
|
|
|
|
+ ce.matrix = matrix
|
|
|
|
+ }
|
|
|
|
+// se.setLocation((e.x - child.pos.x) / child.scale.x, (e.y - child.pos.y) / child.scale.y)
|
|
|
|
+ val matrixMat = Matrix()
|
|
|
|
+ ce.matrix.invert(matrixMat)
|
|
|
|
+ val matrixTransform = MatrixUtil.matrixTransform(matrixMat, e.viewX, e.viewY)
|
|
|
|
+ ce.x = matrixTransform.x
|
|
|
|
+ ce.y = matrixTransform.y
|
|
|
|
+ return ce
|
|
|
|
+ } // Function toSceneMotionEvent()
|
|
|
|
+ } // companion object
|
|
|
|
+
|
|
|
|
+ /** 父节点 */
|
|
|
|
+ var parent: SGraphyItem? = parent
|
|
|
|
+ set(value) {
|
|
|
|
+ if (field == value) { // 如果值没变化
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ if (null != field) { // 如果原parent不为空
|
|
|
|
+ // 将节点从原parent节点中摘除
|
|
|
|
+ field!!.children.remove(this)
|
|
|
|
+ }
|
|
|
|
+ field = value
|
|
|
|
+
|
|
|
|
+ if (null != field) { // 如果新parent不为空
|
|
|
|
+ // 将节点加入到新parent节点中
|
|
|
|
+ field!!.children.add(this)
|
|
|
|
+ field!!.children.sortByDescending { it.zOrder }
|
|
|
|
+ }
|
|
|
|
+ invalidate()
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /** 子节点列表 */
|
|
|
|
+ val children = ArrayList<SGraphyItem>()
|
|
|
|
+
|
|
|
|
+ /** item所属场景 */
|
|
|
|
+ var scene: SGraphyScene? = null
|
|
|
|
+ get() {
|
|
|
|
+ return if (null != parent) {
|
|
|
|
+ parent!!.scene
|
|
|
|
+ } else {
|
|
|
|
+ field
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /** item位置 */
|
|
|
|
+ var pos: PointF = PointF(0f, 0f)
|
|
|
|
+ set(value) {
|
|
|
|
+ if (field == value) { // 如果值没变化
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ field = value
|
|
|
|
+ invalidate()
|
|
|
|
+ posListener?.onMoveTo(field.x, field.y)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /** item位置变更监听器 */
|
|
|
|
+ var posListener: SGraphyItemPosListener? = null
|
|
|
|
+
|
|
|
|
+ /** z轴坐标,数值越大,越靠上 */
|
|
|
|
+ var zOrder = 0f
|
|
|
|
+ set(value) {
|
|
|
|
+ if (field == value) { // 如果值没变化
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ field = value
|
|
|
|
+ if (null != parent) { // 如果你节点不空
|
|
|
|
+ parent!!.children.sortByDescending { it.zOrder }
|
|
|
|
+ }
|
|
|
|
+ invalidate()
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /** 缩放比例 */
|
|
|
|
+ var scale = PointF(1f, 1f)
|
|
|
|
+
|
|
|
|
+ /** 旋转 */
|
|
|
|
+ var rotate = 0.0f
|
|
|
|
+
|
|
|
|
+ /** 是否进行变形 */
|
|
|
|
+ var isTransform = true;
|
|
|
|
+
|
|
|
|
+ /** 放缩反比例 */
|
|
|
|
+ var _inverseScaleX = 1f;
|
|
|
|
+ var _inverseScaleY = 1f;
|
|
|
|
+
|
|
|
|
+ /** item标志 */
|
|
|
|
+ var flags: EnumSet<SGraphyItemFlag> = EnumSet.noneOf(SGraphyItemFlag::class.java)
|
|
|
|
+
|
|
|
|
+ /** item是否可见 */
|
|
|
|
+ var isVisible = true
|
|
|
|
+ set(value) {
|
|
|
|
+ if (field == value) { // 如果值没变化
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ field = value
|
|
|
|
+ invalidate()
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /** item是否获得焦点 */
|
|
|
|
+ var focus = false
|
|
|
|
+ set(value) {
|
|
|
|
+ if (!flags.contains(SGraphyItemFlag.ItemIsFocusable)) { // 如果item不能获得焦点
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ if (field == value) { // 如果值没变化
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ field = value
|
|
|
|
+ if (value) { // 如果获得焦点
|
|
|
|
+ currentFocusItem?.focus = false
|
|
|
|
+ onGetFocus()
|
|
|
|
+ currentFocusItem = this
|
|
|
|
+ } else {
|
|
|
|
+ onLostFocus()
|
|
|
|
+ if (currentFocusItem === this) { // 如果当前焦点对象失去焦点
|
|
|
|
+ currentFocusItem = null
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 当前获得焦点的item对象
|
|
|
|
+ */
|
|
|
|
+ val focusItem: SGraphyItem?
|
|
|
|
+ get() = currentFocusItem
|
|
|
|
+
|
|
|
|
+ /** item是否被选中 */
|
|
|
|
+ var isSelected = false
|
|
|
|
+ set(value) {
|
|
|
|
+ if (field == value) { // 如果值没变化
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ field = value
|
|
|
|
+ invalidate()
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Item对象边界区域
|
|
|
|
+ *
|
|
|
|
+ * @return 边界区域
|
|
|
|
+ */
|
|
|
|
+ open fun boundingRect(): RectF {
|
|
|
|
+ return RectF()
|
|
|
|
+ } // Function boundingRect()
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 更新Item
|
|
|
|
+ *
|
|
|
|
+ * @param rect 更新区域
|
|
|
|
+ */
|
|
|
|
+ fun invalidate(rect: RectF = RectF()) {
|
|
|
|
+ scene?.update()
|
|
|
|
+ return
|
|
|
|
+ } // Function update()
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 延迟刷新
|
|
|
|
+ *
|
|
|
|
+ * @param delayed 延时的时间
|
|
|
|
+ */
|
|
|
|
+ fun postInvalidateDelayed(delayed: Long) {
|
|
|
|
+ /* doAsync {
|
|
|
|
+ Thread.sleep(delayed)
|
|
|
|
+ invalidate()
|
|
|
|
+ }*/
|
|
|
|
+
|
|
|
|
+ thread {
|
|
|
|
+ Thread.sleep(delayed)
|
|
|
|
+ invalidate()
|
|
|
|
+ }
|
|
|
|
+ return
|
|
|
|
+ } // Function postInvalidateDelayed()
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 隐藏item
|
|
|
|
+ */
|
|
|
|
+ fun hide() {
|
|
|
|
+ isVisible = false
|
|
|
|
+ return
|
|
|
|
+ } // Function hide()
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 显示item
|
|
|
|
+ */
|
|
|
|
+ fun show() {
|
|
|
|
+ isVisible = true
|
|
|
|
+ return
|
|
|
|
+ } // Function show()
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 移动item到指定位置
|
|
|
|
+ *
|
|
|
|
+ * @param pos 新的位置
|
|
|
|
+ */
|
|
|
|
+ fun moveTo(pos: PointF) {
|
|
|
|
+ this.pos = pos
|
|
|
|
+ return
|
|
|
|
+ } // Function move()
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 移动item到指定位置
|
|
|
|
+ *
|
|
|
|
+ * @param x 新位置的x坐标
|
|
|
|
+ * @param y 新位置的y坐标
|
|
|
|
+ */
|
|
|
|
+ fun moveTo(x: Float, y: Float) {
|
|
|
|
+ pos = PointF(x, y)
|
|
|
|
+ return
|
|
|
|
+ } // Function move()
|
|
|
|
+
|
|
|
|
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
+ // 坐标换算相关操作
|
|
|
|
+ /**
|
|
|
|
+ * 将场景中的xy坐标转换成item坐标。(该节点被加载到场景中,如果未被加载到场景中,计算会出错)
|
|
|
|
+ *
|
|
|
|
+ * @param x 场景中的横坐标
|
|
|
|
+ * @param y 场景中的纵坐标
|
|
|
|
+ *
|
|
|
|
+ * @return 在item中的坐标
|
|
|
|
+ */
|
|
|
|
+ fun mapFromScene(x: Float, y: Float): PointF {
|
|
|
|
+ val m = this.scene2itemMattrix()
|
|
|
|
+ val matrix = Matrix()
|
|
|
|
+ m.invert(matrix)
|
|
|
|
+ return MatrixUtil.matrixTransform(matrix, x, y)
|
|
|
|
+ } // Function mapFromScene()
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 将场景中的xy坐标转换成item坐标。(该节点被加载到场景中,如果未被加载到场景中,计算会出错)
|
|
|
|
+ *
|
|
|
|
+ * @param point 场景中的坐标
|
|
|
|
+ *
|
|
|
|
+ * @return 在item中的坐标
|
|
|
|
+ */
|
|
|
|
+ fun mapFromScene(point: PointF): PointF {
|
|
|
|
+ return mapFromScene(point.x, point.y)
|
|
|
|
+ } // Function mapFromScene()
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 将item中的xy坐标转换成场景坐标。(该节点被加载到场景中,如果未被加载到场景中,计算会出错)
|
|
|
|
+ *
|
|
|
|
+ * @param x item中的横坐标
|
|
|
|
+ * @param y item中的纵坐标
|
|
|
|
+ *
|
|
|
|
+ * @return 在场景中的坐标
|
|
|
|
+ */
|
|
|
|
+ fun mapToScene(x: Float, y: Float): PointF {
|
|
|
|
+ if (null == parent) {
|
|
|
|
+ return PointF(x, y)
|
|
|
|
+ }
|
|
|
|
+ val m = this.scene2itemMattrix()
|
|
|
|
+ return return MatrixUtil.matrixTransform(m, x, y)
|
|
|
|
+// return parent!!.mapToScene(x * scale.x + pos.x, y * scale.y + pos.y)
|
|
|
|
+ } // Function mapToScene()
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 将item中的xy坐标转换成场景坐标。(该节点被加载到场景中,如果未被加载到场景中,计算会出错)
|
|
|
|
+ *
|
|
|
|
+ * @param point item中的坐标
|
|
|
|
+ *
|
|
|
|
+ * @return 在场景中的坐标
|
|
|
|
+ */
|
|
|
|
+ fun mapToScene(point: PointF): PointF {
|
|
|
|
+ return mapToScene(point.x, point.y)
|
|
|
|
+ } // Function mapToScene()
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 获得item的路径节点列表。(该节点被加载到场景中,如果未被加载到场景中,计算会出错)
|
|
|
|
+ *
|
|
|
|
+ * @return 从根节点到当前节点的路径节点列表。
|
|
|
|
+ */
|
|
|
|
+ fun itemPath(): MutableList<SGraphyItem> {
|
|
|
|
+ if (null != parent) {
|
|
|
|
+ val list = parent!!.itemPath()
|
|
|
|
+ list.add(this)
|
|
|
|
+ return list
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return mutableListOf(this)
|
|
|
|
+ } // Function itemPath()
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 判断item是否包含点x,y
|
|
|
|
+ *
|
|
|
|
+ * @param x 横坐标(当前item)
|
|
|
|
+ * @param y 纵坐标(当前item)
|
|
|
|
+ *
|
|
|
|
+ * @return true包含;false不包含。
|
|
|
|
+ */
|
|
|
|
+ open fun contains(x: Float, y: Float): Boolean {
|
|
|
|
+// Log.e("boundingRect", boundingRect().contains(x, y).toString())
|
|
|
|
+ return boundingRect().contains(x, y)
|
|
|
|
+ } // Function ()
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 判断item是否包含点x,y
|
|
|
|
+ *
|
|
|
|
+ * @param point 点坐标(当前item)
|
|
|
|
+ *
|
|
|
|
+ * @return true包含;false不包含。
|
|
|
|
+ */
|
|
|
|
+ fun contains(point: PointF): Boolean {
|
|
|
|
+ return contains(point.x, point.y)
|
|
|
|
+ } // Function ()
|
|
|
|
+
|
|
|
|
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
+ // 事件回调
|
|
|
|
+ /**
|
|
|
|
+ * Item绘制操作
|
|
|
|
+ *
|
|
|
|
+ * @param canvas 画布对象
|
|
|
|
+ * @param rect 更新区域
|
|
|
|
+ */
|
|
|
|
+ open fun onPaint(canvas: Canvas, rect: RectF) {
|
|
|
|
+ canvas.save()
|
|
|
|
+// val mat1 = SJsonUtil.fromJson(canvas.matrix.toJson(), Matrix::class.java)
|
|
|
|
+ this.onDraw(canvas)
|
|
|
|
+// canvas.matrix = mat1
|
|
|
|
+ canvas.restore()
|
|
|
|
+ val src = kotlin.floatArrayOf(0f, 1f, 2f, 3f, 4f, 5f, 6f, 7f, 8f)
|
|
|
|
+ for (i in 1..children.size) { // 倒序依次取item列中的所有item。将所有item的边界做并交处理。
|
|
|
|
+ val item = children[children.size - i]
|
|
|
|
+ if (!item.isVisible) { // 如果对象不可见
|
|
|
|
+ continue
|
|
|
|
+ }
|
|
|
|
+ try {
|
|
|
|
+ // 保存画布状态
|
|
|
|
+ canvas.save()
|
|
|
|
+// val mat = SJsonUtil.fromJson(canvas.matrix.toJson(), Matrix::class.java)
|
|
|
|
+ // item位移到指定位置绘制
|
|
|
|
+ canvas.translate(item.pos.x, item.pos.y)
|
|
|
|
+ canvas.scale(item.scale.x, item.scale.y)
|
|
|
|
+ canvas.rotate(item.rotate)
|
|
|
|
+
|
|
|
|
+ if (!item.isTransform) {
|
|
|
|
+ canvas.matrix.getValues(src)
|
|
|
|
+ val matrix = Matrix()
|
|
|
|
+ matrix.preTranslate(src[2], src[5])
|
|
|
|
+ matrix.preScale(item.scale.x, item.scale.y)
|
|
|
|
+ matrix.preRotate(item.rotate)
|
|
|
|
+ canvas.matrix = matrix
|
|
|
|
+// matrix.getValues(src)
|
|
|
|
+// item._inverseScaleX = 1.0f/src[0]
|
|
|
|
+// item._inverseScaleY = 1.0f/src[4]
|
|
|
|
+// canvas.scale(item._inverseScaleX,item._inverseScaleY)
|
|
|
|
+
|
|
|
|
+// matrix.preTranslate(src[2], src[5])
|
|
|
|
+// matrix.preTranslate(item.scale.x,item.scale.y)
|
|
|
|
+// matrix.preRotate(item.rotate)
|
|
|
|
+// canvas.matrix = matrix
|
|
|
|
+ }
|
|
|
|
+ // 设置绘制区域
|
|
|
|
+ // canvas.clipRect(item.boundingRect())
|
|
|
|
+ // 绘制item
|
|
|
|
+ item.onPaint(canvas, rect)
|
|
|
|
+ // 恢复画布状态
|
|
|
|
+ canvas.restore()
|
|
|
|
+// canvas.matrix = mat;
|
|
|
|
+ } catch (e: Exception) {
|
|
|
|
+ e.printStackTrace()
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return
|
|
|
|
+ } // Function paint()
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Item 绘制操作
|
|
|
|
+ *
|
|
|
|
+ * @param painter 绘制对象
|
|
|
|
+ */
|
|
|
|
+ open fun onDraw(canvas: Canvas) {
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 获得焦点变更回调
|
|
|
|
+ */
|
|
|
|
+ open fun onGetFocus() {
|
|
|
|
+ // DO NOTHING
|
|
|
|
+ return
|
|
|
|
+ } // Function onGetFocus()
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 失去焦点变更回调
|
|
|
|
+ */
|
|
|
|
+ open fun onLostFocus() {
|
|
|
|
+ // DO NOTHING
|
|
|
|
+ return
|
|
|
|
+ } // Function onLostFocus()
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 用户按下触发.
|
|
|
|
+ *
|
|
|
|
+ * @param e 按下手势事件。
|
|
|
|
+ * @return 如果事件被处理返回 true , 否则返回 false 。
|
|
|
|
+ */
|
|
|
|
+ open fun onDown(e: SMotionEvent): Boolean {
|
|
|
|
+ for (item in children) {
|
|
|
|
+ if (!item.isVisible) { // 如果对象不可见
|
|
|
|
+ continue
|
|
|
|
+ }
|
|
|
|
+ val ce = toChildMotionEvent(item, e)
|
|
|
|
+ if (item.contains(ce.x, ce.y) // 如果点在子项目上
|
|
|
|
+ && item.onDown(ce)) { // 且子项目处理了事件
|
|
|
|
+ return true
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (flags.contains(SGraphyItemFlag.ItemIsFocusable)) { // 如果是可获得焦点Item
|
|
|
|
+ focus = true
|
|
|
|
+ return true
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return false
|
|
|
|
+ } // Function onDown()
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 用户释放触发.
|
|
|
|
+ *
|
|
|
|
+ * @param e 释放手势事件。
|
|
|
|
+ * @return 如果事件被处理返回 true , 否则返回 false 。
|
|
|
|
+ */
|
|
|
|
+ open fun onSingleTapUp(e: SMotionEvent): Boolean {
|
|
|
|
+ Log.d(TAG, "onSingleTapUp: releaseItem")
|
|
|
|
+ releaseItem()
|
|
|
|
+ for (item in children) {
|
|
|
|
+ if (!item.isVisible) { // 如果对象不可见
|
|
|
|
+ Log.e("手势3scene", "$e")
|
|
|
|
+ continue
|
|
|
|
+ }
|
|
|
|
+ val ce = toChildMotionEvent(item, e)
|
|
|
|
+// Log.e("手势view", "${scene?.view?.scale}")
|
|
|
|
+// Log.e("手势e", "${e.x}, ${e.y}")
|
|
|
|
+// Log.e("手势ce", "${ce.x}, ${ce.y}")
|
|
|
|
+// Log.e("手势1scene", (item.contains(ce.x, ce.y)).toString())
|
|
|
|
+ if (item.contains(ce.x, ce.y) // 如果点在子项目上
|
|
|
|
+ && item.onSingleTapUp(ce)) { // 且子项目处理了事件
|
|
|
|
+// Log.e("手势4scene", e.toJson())
|
|
|
|
+ return true
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+// Log.e("手势2scene", e.toJson())
|
|
|
|
+ return false
|
|
|
|
+ } // Function onSingleTapUp()
|
|
|
|
+
|
|
|
|
+ open fun onActionUp() {
|
|
|
|
+ releaseItem()
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ open fun onActionMove(event: MotionEvent) {
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 用户点击触发
|
|
|
|
+ *
|
|
|
|
+ * @param e 手势事件。
|
|
|
|
+ * @return 如果事件被处理返回 true , 否则返回 false 。
|
|
|
|
+ */
|
|
|
|
+ open fun onShowPress(e: SMotionEvent): Boolean {
|
|
|
|
+ Log.d(TAG, "onShowPress: releaseItem")
|
|
|
|
+ for (item in children) {
|
|
|
|
+ if (!item.isVisible) { // 如果对象不可见
|
|
|
|
+ continue
|
|
|
|
+ }
|
|
|
|
+ val ce = toChildMotionEvent(item, e)
|
|
|
|
+ if (item.contains(ce.x, ce.y) // 如果点在子项目上
|
|
|
|
+ && item.onShowPress(ce)) { // 且子项目处理了事件
|
|
|
|
+ return true
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return false
|
|
|
|
+ } // Function onShowPress()
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 长按触摸屏超过一定时间。
|
|
|
|
+ *
|
|
|
|
+ * @param e 长按手势事件。
|
|
|
|
+ * @return 如果事件被处理返回 true , 否则返回 false 。
|
|
|
|
+ */
|
|
|
|
+ open fun onLongPress(e: SMotionEvent): Boolean {
|
|
|
|
+ Log.d(TAG, "onLongPress: releaseItem")
|
|
|
|
+ releaseItem()
|
|
|
|
+
|
|
|
|
+ for (item in children) {
|
|
|
|
+ if (!item.isVisible) { // 如果对象不可见
|
|
|
|
+ continue
|
|
|
|
+ }
|
|
|
|
+ val ce = toChildMotionEvent(item, e)
|
|
|
|
+ if (item.contains(ce.x, ce.y) // 如果点在子项目上
|
|
|
|
+ && item.onLongPress(ce)) { // 且子项目处理了事件
|
|
|
|
+ return true
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return false
|
|
|
|
+ } // Function onLoagPress()
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 用户按下触摸屏,并拖动。
|
|
|
|
+ *
|
|
|
|
+ * @param e1 第1个 ACTION_DOWN 手势事件
|
|
|
|
+ * @param e2 最后一个 ACTION_MOVE 手势事件
|
|
|
|
+ * @param distanceX X轴上的移动距离,单位:像素
|
|
|
|
+ * @param distanceY Y轴上的移动距离,单位:像素
|
|
|
|
+ * @return 如果事件被处理返回 true , 否则返回 false 。
|
|
|
|
+ */
|
|
|
|
+ open fun onScroll(e1: SMotionEvent, e2: SMotionEvent, distanceX: Float, distanceY: Float): Boolean {
|
|
|
|
+ if (flags.contains(SGraphyItemFlag.ItemIsMovable) && currentMoveItem === this) {
|
|
|
|
+ moveTo(pos.x - distanceX * scale.x, pos.y - distanceY * scale.y)
|
|
|
|
+ return true
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ for (item in children) {
|
|
|
|
+ if (!item.isVisible) { // 如果对象不可见
|
|
|
|
+ continue
|
|
|
|
+ }
|
|
|
|
+ val ce1 = toChildMotionEvent(item, e1)
|
|
|
|
+ val ce2 = toChildMotionEvent(item, e2)
|
|
|
|
+ // 如果点在子项目上且子项目目处理了事件
|
|
|
|
+ if (item.contains(ce2.x, ce2.y) // 如果点在子项目上
|
|
|
|
+ && item.onScroll(ce1, ce2, distanceX / item.scale.x, distanceY / item.scale.y)) { // 且子项目处理了事件
|
|
|
|
+ return true
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (flags.contains(SGraphyItemFlag.ItemIsMovable) && null == currentMoveItem) { // 如果是可移动Item
|
|
|
|
+ grabItem(this)
|
|
|
|
+ currentMoveItem = this
|
|
|
|
+ return true
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return false
|
|
|
|
+ } // Function onScroll()
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 用户按下触摸屏、快速移动后松开。即滑动操作。
|
|
|
|
+ *
|
|
|
|
+ * @param e1 第1个 ACTION_DOWN 手势事件
|
|
|
|
+ * @param e2 最后一个 ACTION_MOVE 手势事件
|
|
|
|
+ * @param velocityX X轴上的移动速度,像素/秒
|
|
|
|
+ * @param velocityY Y轴上的移动速度,像素/秒
|
|
|
|
+ * @return 如果事件被处理返回 true , 否则返回 false 。
|
|
|
|
+ */
|
|
|
|
+ open fun onFling(e1: SMotionEvent, e2: SMotionEvent, velocityX: Float, velocityY: Float): Boolean {
|
|
|
|
+ Log.d(TAG, "onFling: releaseItem")
|
|
|
|
+ releaseItem()
|
|
|
|
+
|
|
|
|
+ for (item in children) {
|
|
|
|
+ if (!item.isVisible) { // 如果对象不可见
|
|
|
|
+ continue
|
|
|
|
+ }
|
|
|
|
+ val ce1 = toChildMotionEvent(item, e1)
|
|
|
|
+ val ce2 = toChildMotionEvent(item, e2)
|
|
|
|
+ // 如果点在子项目上且子项目目处理了事件
|
|
|
|
+ if (item.contains(ce2.x, ce2.y) // 如果点在子项目上
|
|
|
|
+ && item.onFling(ce1, ce2, velocityX / item.scale.x, velocityY / item.scale.y)) { // 且子项目处理了事件
|
|
|
|
+ return true
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return false
|
|
|
|
+ } // Function onFling()
|
|
|
|
+
|
|
|
|
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
+ // 私有方法
|
|
|
|
+ /**
|
|
|
|
+ * 锁定item
|
|
|
|
+ *
|
|
|
|
+ * @param item 被锁定的item
|
|
|
|
+ */
|
|
|
|
+ private fun grabItem(item: SGraphyItem) {
|
|
|
|
+ Log.d(TAG, "grabItem")
|
|
|
|
+ isSelected = true
|
|
|
|
+ scene!!.grabItem = item
|
|
|
|
+ return
|
|
|
|
+ } // Function grabItem
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 释放被锁定的item
|
|
|
|
+ */
|
|
|
|
+ private fun releaseItem() {
|
|
|
|
+ isSelected = false
|
|
|
|
+ currentMoveItem = null
|
|
|
|
+ scene!!.grabItem = null
|
|
|
|
+ return
|
|
|
|
+ } // Function grabItem
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 场景对象到 item 对象的转换矩阵
|
|
|
|
+ *
|
|
|
|
+ * @return 转换矩阵
|
|
|
|
+ */
|
|
|
|
+ fun scene2itemMattrix(): Matrix {
|
|
|
|
+ var m = Matrix()
|
|
|
|
+ val list = this.itemPath()
|
|
|
|
+ for (item in list) {
|
|
|
|
+// m.postTranslate(item.pos.x, item.pos.y);
|
|
|
|
+// m.postScale(item.scale.x, item.scale.y);
|
|
|
|
+// m.postRotate(item.rotate)
|
|
|
|
+ m.preTranslate(item.pos.x, item.pos.y);
|
|
|
|
+ m.preScale(item.scale.x, item.scale.y);
|
|
|
|
+ m.preRotate(item.rotate)
|
|
|
|
+
|
|
|
|
+ // 如果不进行变形处理,则取消 painter 的变型操作
|
|
|
|
+ if (!item.isTransform) {
|
|
|
|
+// m.postScale(item._inverseScaleX, item._inverseScaleY);
|
|
|
|
+ /****************************************** 待确认 ************************************************/
|
|
|
|
+ val src = kotlin.floatArrayOf(0f, 1f, 2f, 3f, 4f, 5f, 6f, 7f, 8f)
|
|
|
|
+ m.getValues(src)
|
|
|
|
+ val matrix = Matrix()
|
|
|
|
+ matrix.preTranslate(src[2], src[5])
|
|
|
|
+ matrix.preScale(item.scale.x, item.scale.y)
|
|
|
|
+ matrix.preRotate(item.rotate)
|
|
|
|
+ m = matrix
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return m
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+} // Class SGraphyItem
|