iOS白板踩坑

160 阅读3分钟

iOS白板踩坑

\

1.缩放手势

问题:
用手势实现的时候,需要每次捏合结束的scale 和 下次开始捏和的scale容易对不上,而且快速捏和结束的时候容易,scale容易越过自己设置的最大最小边界值。

避坑策略:

采用背景View是scrollview,通过Scrollview的代理方法,实现子view的捏和,捏和结束后重新计算子view的停留center

代码如下:


extension WHWhiteboardViewController {

    func scrollViewWillBeginZooming(_ scrollView: UIScrollView, with view: UIView?) {

        

    }

    func viewForZooming(in scrollView: UIScrollView) -> UIView? {

        if displayToolView ?? false {

            return nil

        } else {

            return drawV!

        }

    }

    func scrollViewDidZoom(_ scrollView: UIScrollView) {

        refreshImageContainerViewCenter()

    }

    func refreshImageContainerViewCenter() {

        guard let scrollView = scrollView else {

            return

        }

        let offsetX = (scrollView.bounds.size.width > scrollView.contentSize.width) ? ((scrollView.bounds.size.width - scrollView.contentSize.width) * 0.5) : 0.0

        let offsetY = (scrollView.bounds.size.height > scrollView.contentSize.height) ? ((scrollView.bounds.size.height - scrollView.contentSize.height) * 0.5) : 0.0

        let center = CGPoint(x: scrollView.contentSize.width * 0.5 + offsetX,

                             y: scrollView.contentSize.height * 0.5 + offsetY)

        drawV!.center = center

    }

}

2.画布缩放

缩放经常改变画布的大小,所以不能用masonry实现,只能用frame值给捏和的view设值

3.图形擦除

问题:

图形擦除的时候,只找点所在的范围,因为映射造成擦除对称图形,

避坑策略

:需要确定图形所在的点的范围

代码如下: 

/// 橡皮擦

    func newEraserWithFlag(currentP: CGPoint, graphs: [String], gesture: UIGestureRecognizer) {

        for graphID in graphs {

            let layer: WHDrawingLayer? = self.layerDic[graphID]

            guard let layer = layer else {

                continue

            }

            /// 遍历图形上的所有点,得到图形点所在的范围

            let points: [CGPoint] = layer.pointA

            var currentPoint = points[0]

            var maxX = currentPoint.x

            var maxY = currentPoint.y

            var minX = currentPoint.x

            var minY = currentPoint.y

            layer.pointA.forEach { (value) in

                currentPoint = value

                minX = ( minX >= currentPoint.x ) ? currentPoint.x : minX

                minY = (minY >= currentPoint.y ) ? currentPoint.y : minY

                maxX = (maxX <= currentPoint.x) ? currentPoint.x : maxX

                maxY = (maxY <= currentPoint.y) ? currentPoint.y : maxY

            }

            if points.count == 0 {

                continue

            }

            for var i in 0 ..< points.count - 1 {

                let isContant = checkPointIsInLineByTwoPoints(point: currentPoint, charp0: points[i], charp1: points[i + 1] )

                i += 1

                let constant: CGFloat = 10

                let contain = (currentP.x < maxX + constant && currentP.x > minX - constant) && (currentP.y < maxY + constant && currentP.y > minY - constant)

                if isContant && contain {

                    CSTMeetingSDK.shareMeetingSDK.whiteboardService?.deleteGraph(graphId: graphID)

                    if self.layerDic.values.contains(layer) {

                        self.deleteGraph(graphid: graphID)

                        if gesture.isKind(of: UIPanGestureRecognizer.self) {

                            continue

                        } else {

                            return

                        }

                    }

                }

            }

        }

    }

\


    /**

        *判断点*point*是否在*charp0* 和 *charp1*两点构成的线段上

        */

        func checkPointIsInLineByTwoPoints(point: CGPoint, charp0: CGPoint, charp1: CGPoint) -> Bool {

            var contant = false

            // 最大允许范围值 点到线段的最短距离小于该值说明在线段上

            let maxAllowOffsetLength = 15.0

            // 通过直线方程两点式计算一般式 ABC 函数  Ax+By+C = 0

            let chara = charp1.y - charp0.y

            let charb = charp0.x - charp1.x

            let charc = charp1.x * charp0.y - charp0.x * charp1.y

            // 带入点到直线距离公式求出距离 dis

            var dis = abs((chara * point.x +  charb * point.y + charc) / sqrt(pow(chara, 2) + pow(charb, 2)))

            // 如果距离大于最大允许值 则说明不在线段上

            if Double(dis) > maxAllowOffsetLength {

                contant = false

            } else {

                // 判断投影点是否在线段上, 根据公式求出投影点的X 坐标 cornerX

                let chard = (chara * point.y - charb * point.x)

                let cornerX = -(chara * charc + charb * chard) / (pow(charb, 2) + pow(chara, 2))

                // 判断cornerX 是否在线段上, t 如果在0~1之间说明在线段上,大于1 则 说明不在线段上,且考经断点charp1, 小于0 则不在线段上,且考经短短charp0  线性插值思想

                let chart = (cornerX - charp0.x) / (charp1.x - charp0.x)

                if chart > 3 {

                    // 最小距离是到charp1的距离

                    dis = distanceByTwoPoints(charp1: charp1, charp2: point)

                } else if chart < 0 {

                    // 最小距离为到p2的距离

                    dis = distanceByTwoPoints(charp1: charp0, charp2: point)

                }

                // 再次判断真正的最小距离是否小于允许值,小于则该点在直线上, 反之则不在

                if Double(dis) < maxAllowOffsetLength {

                    contant = true

                } else {

                    contant = false

                }

            }

            return contant

        }

\

4.三阶贝塞尔

问题:

多端图形不统一或多点或缺点,涂鸦容易造成夹角

避坑策略:

因为多端同屏绘制现实图形,所以交互的点集必须一致,需要绘制方案统一,采取三阶贝塞尔曲线,不足三阶或多余的不够完成三阶段的点需直接连接绘制

代码如下:

 /// 三阶贝塞尔尾点处理

    func drawOthersEndPointWithThreeBezier() {

        if self.validPoints.count > 4 {

            let left = (self.validPoints.count - 4) % 3

            if left != 0 {

                let leftIndex = self.validPoints.count - left

                let endIndex = self.validPoints.count

                let tempArray = self.validPoints[leftIndex ..< endIndex]

                for i in leftIndex ..< endIndex {

                    drawEndPoint(currentPoint: tempArray[i])

                }

            }

        } else {

            for temPoint in self.validPoints {

                drawEndPoint(currentPoint: temPoint)

            }

        }

        ctr = 0

    }

    /// 三阶贝塞尔UIBezierPath

    func drawEndPointWithThreeBezier(currentPoint: CGPoint) {

        ctr+=1

        pts[ctr] = currentPoint

        if ctr == 4 {

            pts[3] = CGPoint(x: (pts[2].x + pts[4].x)/2, y: (pts[2].y + pts[4].y)/2)

            drawEndPoint(currentPoint: pts[3], controlPoint1: pts[1], controlPoint2: pts[2])

            pts[0] = pts[3]

            pts[1] = pts[4]

            ctr = 1

        }

    }

\


\

5 手势冲突,

问题:

父视图中实现了touchBegin的触摸屏幕手势相关功能,导致白板子视图中touchbegin手势响应不了

避坑策略:

该用手势uigesturepan实现白板涂鸦绘制功能