如何在UIView中绘制可调整大小的矩形,我在google和github上进行了很多搜索,我发现这一个Click Here使用swift 2.3并且我将它转换为swift 3 ..但我无法在绘制后调整矩形大小它就是代码
//
// ResizableRectangleView.swift
// DrawShapes
//
// Created by Jordan Focht on 3/9/15.
// Copyright (c) 2015 Jordan Focht. All rights reserved.
//
import Foundation
import UIKit
private let DefaultTint = UIColor(red: 0, green: 164 / 255.0, blue: 1.0, alpha: 1.0).cgColor
private let DefaultStrokeTint = UIColor(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0).cgColor
private let ClearColor = UIColor.clear.cgColor
private let DefaultCircleRadius: CGFloat = 8
private let CornerTouchSize: CGFloat = 44
protocol ResizableRectangleViewDelegate : class {
func didSelectResizableRectangleView(_ view: ResizableRectangleView)
func didDeselectResizableRectangleView(_ view: ResizableRectangleView)
}
class ResizableRectangleView: UIControl {
fileprivate var borderLayer: CALayer = CALayer()
fileprivate var topLeftCircle = CALayer()
fileprivate var topRightCircle = CALayer()
fileprivate var bottomLeftCircle = CALayer()
fileprivate var bottomRightCircle = CALayer()
weak var delegate: ResizableRectangleViewDelegate?
var strokeTintColor: CGColor = DefaultStrokeTint
var circleRadius: CGFloat = DefaultCircleRadius
var nLocation : CGPoint!
override var frame: CGRect {
get {
return super.frame
}
set {
super.frame = newValue
self.updateLayers()
}
}
override var isSelected: Bool {
get {
return super.isSelected
}
set {
let changed = self.isSelected != newValue
super.isSelected = newValue
if changed {
if isSelected {
self.delegate?.didSelectResizableRectangleView(self)
} else {
self.delegate?.didDeselectResizableRectangleView(self)
}
}
}
}
func updateLayers() {
if self.layer.sublayers == nil {
self.layer.addSublayer(self.borderLayer)
self.layer.addSublayer(self.topLeftCircle)
self.layer.addSublayer(self.topRightCircle)
self.layer.addSublayer(self.bottomLeftCircle)
self.layer.addSublayer(self.bottomRightCircle)
let layers = (self.layer.sublayers ?? []) as [CALayer]
for layer in layers {
layer.contentsScale = UIScreen.main.scale
}
}
self.updateBorderLayer()
let circleFrame = self.borderLayer.frame
updateCircleLayer(topLeftCircle, center: CGPoint(x: circleFrame.origin.x, y: circleFrame.origin.y))
updateCircleLayer(topRightCircle, center: CGPoint(x: circleFrame.origin.x, y: circleFrame.maxY))
updateCircleLayer(bottomLeftCircle, center: CGPoint(x: circleFrame.maxX, y: circleFrame.origin.y))
updateCircleLayer(bottomRightCircle, center: CGPoint(x: circleFrame.maxX, y: circleFrame.maxY))
}
func borderedFrame() -> CGRect {
return self.borderLayer.frame
}
// var trackingFrameTransform: ((CGPoint) -> ())?
func moveFrame(_ originalFrame: CGRect, initialTouchLocation: CGPoint, _ location: CGPoint) {
let targetX = originalFrame.origin.x + location.x - initialTouchLocation.x
let targetY = originalFrame.origin.y + location.y - initialTouchLocation.y
let insetBounds = self.insetBounds()
self.frame.origin.x = max(insetBounds.origin.x, min(insetBounds.maxX - self.frame.width, targetX))
self.frame.origin.y = max(insetBounds.origin.y, min(insetBounds.maxY - self.frame.height, targetY))
nLocation = location
}
fileprivate func insetBounds() -> CGRect {
let inset = self.inset()
let contentBounds = (self.superview as? DrawableView)?.contentBounds ?? self.bounds
return contentBounds.insetBy(dx: -inset, dy: -inset)
}
func updateRect(_ anchor: CGPoint, initialTouchLocation: CGPoint, originalCorner: CGPoint , _ location: CGPoint) {
let insetBounds = self.insetBounds()
let locationX = max(insetBounds.origin.x, min(insetBounds.maxX, location.x))
let locationY = max(insetBounds.origin.y, min(insetBounds.maxY, location.y))
let targetX = originalCorner.x + locationX - initialTouchLocation.x
let targetY = originalCorner.y + locationY - initialTouchLocation.y
let minSize = self.inset() + circleRadius
if insetBounds.origin.x < targetX && targetX < insetBounds.maxX {
self.frame.origin.x = min(targetX, anchor.x)
self.frame.size.width = max(minSize * 2, abs(anchor.x - targetX))
}
if insetBounds.origin.y < targetY && targetY < insetBounds.maxY {
self.frame.origin.y = min(targetY, anchor.y)
self.frame.size.height = max(minSize * 2, abs(anchor.y - targetY))
}
nLocation = location
}
override func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
CATransaction.begin()
CATransaction.setDisableActions(true)
if let superview = self.superview as? DrawableView {
for view in superview.subviews {
if let view = view as? ResizableRectangleView {
if view != self {
view.isSelected = false
view.updateLayers()
}
}
}
superview.bringSubview(toFront: self)
}
let location = touch.location(in: self.superview)
nLocation = location
var anchor: CGPoint?
var corner: CGPoint?
switch (location.x, location.y) {
case (let x, let y) where x < self.frame.origin.x + CornerTouchSize && y < self.frame.origin.y + CornerTouchSize:
anchor = CGPoint(x: self.frame.maxX, y: self.frame.maxY)
corner = CGPoint(x: self.frame.minX, y: self.frame.minY)
case (let x, let y) where x < self.frame.origin.x + CornerTouchSize && y > self.frame.maxY - CornerTouchSize:
anchor = CGPoint(x: self.frame.maxX, y: self.frame.minY)
corner = CGPoint(x: self.frame.minX, y: self.frame.maxY)
case (let x, let y) where x > self.frame.maxX - CornerTouchSize && y < self.frame.origin.y + CornerTouchSize:
anchor = CGPoint(x: self.frame.minX, y: self.frame.maxY)
corner = CGPoint(x: self.frame.maxX, y: self.frame.minY)
case (let x, let y) where x > self.frame.maxX - CornerTouchSize && y > self.frame.maxY - CornerTouchSize:
anchor = CGPoint(x: self.frame.minX, y: self.frame.minY)
corner = CGPoint(x: self.frame.maxX, y: self.frame.maxY)
default:
self.moveFrame(self.frame, initialTouchLocation: location , nLocation)
}
if let anchor = anchor {
if let corner = corner {
self.didMove = true
self.isSelected = true
self.updateRect(anchor, initialTouchLocation: location, originalCorner: corner, nLocation)
self.updateLayers()
}
}
CATransaction.commit()
return true
}
var didMove = false
override func continueTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
CATransaction.begin()
CATransaction.setDisableActions(true)
didMove = true
let location = touch.location(in: self.superview)
nLocation = location
//self.trackingFrameTransform?(location)
self.updateLayers()
CATransaction.commit()
return true
}
override func endTracking(_ touch: UITouch?, with event: UIEvent?) {
CATransaction.begin()
CATransaction.setDisableActions(true)
if !didMove {
self.isSelected = !self.isSelected
}
didMove = false
self.updateLayers()
// self.trackingFrameTransform = nil
nLocation = nil
CATransaction.commit()
}
func updateCircleLayer(_ layer: CALayer, center: CGPoint) {
layer.isHidden = !self.isSelected
layer.frame = CGRect(x: center.x - circleRadius, y: center.y - circleRadius, width: 2 * circleRadius, height: 2 * circleRadius)
layer.backgroundColor = self.tintColor.cgColor
layer.borderColor = strokeTintColor
layer.cornerRadius = self.circleRadius
layer.borderWidth = 1
layer.setNeedsDisplay()
}
func inset() -> CGFloat {
let circleInset = (CornerTouchSize - (self.circleRadius * 2)) / 2
return self.circleRadius + circleInset
}
func updateBorderLayer() {
self.borderLayer.masksToBounds = false
self.borderLayer.borderWidth = 1
self.borderLayer.borderColor = self.tintColor.cgColor
let inset = self.inset()
self.borderLayer.frame = self.bounds.insetBy(dx: inset, dy: inset)
self.borderLayer.setNeedsDisplay()
}
}
DrawableView.swift
import Foundation
import UIKit
struct ColoredRect {
let color: UIColor
let origin: CGPoint
let size: CGSize
var width: CGFloat {
get {
return self.size.width
}
}
var height: CGFloat {
get {
return self.size.height
}
}
}
class DrawableView: UIControl {
fileprivate let colorPicker = ColorPicker()
fileprivate var currentRect: ResizableRectangleView?
fileprivate var originalLocation: CGPoint?
fileprivate var rectIsPending = false
var contentSize: CGSize?
var contentBounds: CGRect? {
get {
if let contentSize = self.contentSize {
let scale = min(self.bounds.width / contentSize.width, self.bounds.height / contentSize.height)
let scaledWidth = contentSize.width * scale
let scaledHeight = contentSize.height * scale
let x = round(0.5 * (self.bounds.width - scaledWidth))
let y = round(0.5 * (self.bounds.height - scaledHeight))
return CGRect(x: x, y: y, width: scaledWidth, height: scaledHeight)
} else {
return nil
}
}
}
var shapes: [ColoredRect] {
get {
var shapes = [ColoredRect]()
for view in self.subviews {
if let view = view as? ResizableRectangleView {
let f = view.convert(view.borderedFrame(), to: self)
let relX = min(1.0, max(0.0, f.origin.x / self.bounds.width))
let relY = min(1.0, max(0.0, f.origin.y / self.bounds.height))
let relWidth = min(1.0, max(0.0, f.width / self.bounds.width))
let relHeight = min(1.0, max(0.0, f.height / self.bounds.height))
let relOrigin = CGPoint(x: relX, y: relY)
let relSize = CGSize(width: relWidth, height: relHeight)
let rect = ColoredRect(color: view.tintColor, origin: relOrigin, size: relSize)
shapes.append(rect)
}
}
return shapes
}
set {
let shapes = newValue
for view in self.subviews {
if let view = view as? ResizableRectangleView {
view.removeFromSuperview()
}
}
self.colorPicker.alpha = 0
for shape in shapes {
let x = shape.origin.x * self.bounds.width
let y = shape.origin.y * self.bounds.height
let width = shape.width * self.bounds.width
let height = shape.height * self.bounds.height
let rectFrame = CGRect(x: x, y: y, width: width, height: height)
let view = ResizableRectangleView()
let inset = view.inset()
view.tintColor = shape.color
view.frame = rectFrame.insetBy(dx: -inset, dy: -inset)
view.delegate = self
self.addSubview(view)
}
self.bringSubview(toFront: self.colorPicker)
}
}
// override init() {
// super.init()
// self.addColorPicker()
// }
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.addColorPicker()
}
override init(frame: CGRect) {
super.init(frame: frame)
self.addColorPicker()
}
override func awakeFromNib() {
super.awakeFromNib()
self.addColorPicker()
}
fileprivate func addColorPicker() {
colorPicker.delegate = self
colorPicker.alpha = 0
self.addSubview(colorPicker)
self.bringSubview(toFront: self.colorPicker)
colorPicker.frame = CGRect(x: self.bounds.width - 44, y: 0, width: 44, height: self.bounds.height)
}
override func layoutSubviews() {
super.layoutSubviews()
colorPicker.frame = CGRect(x: self.bounds.width - 44, y: 0, width: 44, height: self.bounds.height)
}
override var canBecomeFirstResponder : Bool {
return true
}
override func motionEnded(_ motion: UIEventSubtype, with event: UIEvent?) {
if (motion == UIEventSubtype.motionShake) {
self.shapes = []
}
}
override func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
let location = touch.location(in: self)
if let contentBounds = self.contentBounds {
if (!contentBounds.contains(location)) {
return false
}
}
rectIsPending = true
let newRect = ResizableRectangleView()
newRect.frame = CGRect(x: location.x, y: location.y, width: 1, height: 1)
newRect.tintColor = UIColor(cgColor: self.colorPicker.color)
self.currentRect = newRect
self.originalLocation = location
CATransaction.begin()
CATransaction.setDisableActions(true)
for view in self.subviews {
if let view = view as? ResizableRectangleView {
view.isSelected = false
view.updateLayers()
}
}
CATransaction.commit()
return true
}
override func continueTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
if let currentRect = self.currentRect {
if rectIsPending {
currentRect.delegate = self
self.addSubview(currentRect)
self.bringSubview(toFront: self.colorPicker)
}
CATransaction.begin()
CATransaction.setDisableActions(true)
if let originalLocation = self.originalLocation {
let location = touch.location(in: self)
currentRect.updateRect(originalLocation, initialTouchLocation: originalLocation, originalCorner: originalLocation, location)
// currentRect.updateRect(originalLocation, initialTouchLocation: originalLocation, originalCorner: originalLocation ,location: location)
}
CATransaction.commit()
}
return super.continueTracking(touch, with: event)
}
override func endTracking(_ touch: UITouch?, with event: UIEvent?) {
self.currentRect = nil
self.rectIsPending = false
}
}
extension DrawableView: ColorPickerDelegate {
func colorPicker(_ picker: ColorPicker, didChangeColor color: CGColor) {
CATransaction.begin()
CATransaction.setDisableActions(true)
for view in self.subviews {
if let view = view as? ResizableRectangleView {
if view.isSelected {
view.tintColor = UIColor(cgColor: color)
view.updateLayers()
}
}
}
CATransaction.commit()
}
}
extension DrawableView: ResizableRectangleViewDelegate {
func didSelectResizableRectangleView(_ view: ResizableRectangleView) {
self.bringSubview(toFront: self.colorPicker)
if self.colorPicker.alpha == 0 {
UIView.animate(withDuration: 0.15, animations: {
self.colorPicker.alpha = 1
})
}
}
func didDeselectResizableRectangleView(_ view: ResizableRectangleView) {
self.bringSubview(toFront: self.colorPicker)
if colorPicker.alpha == 1 {
let selectionCount = self.subviews.reduce(0) {
acc, view in
if let view = view as? ResizableRectangleView {
return acc + (view.isSelected ? 1 : 0)
}
return acc
}
if selectionCount == 0 {
UIView.animate(withDuration: 0.15, animations: {
self.colorPicker.alpha = 0
})
}
}
}
}