Изучение разработки под iOS

Сделайте приложение для рисования на iOS в SwiftUI

Создайте полностью настраиваемое представление для использования в SwiftUI

Если вам нужно полностью настраиваемое представление, которое не имеет ни один из существующих компонентов UIView, вы должны создать свое собственное. Лучшим примером является создание вида чертежа, то есть вида, который, основываясь на вашем прикосновении, вы рисуете на нем.

С появлением Jetpack Compose и SwiftUI я изучил, как можно создать приложение для рисования в Jetpack Compose, как указано в статье ниже.



Я также подумал о том, чтобы изучить SwiftUI, чтобы узнать, как с его помощью можно создавать приложения для рисования. К сожалению, SwiftUI не имеет прямого доступа к CGContext в соответствии с этим StackOverflow. (Сообщите мне, если это неправда).

Но не волнуйтесь. Мы все еще можем обернуть традиционный UIView для использования в SwiftUI. Начнем с обычного UIView для нашего приложения для рисования.

Пользовательский UIView

Поскольку мы не можем превратить его в настраиваемый SwiftUI View, давайте воспользуемся обычным UIView, чтобы создать настраиваемый CanvasView для нашей цели рисования.

Сделайте индивидуальный вид для скаффолдера

Давайте создадим собственный UIView. Простой.

class CanvasView: UIView {}

Заменить функцию рисования

Теперь в CanvasView переопределите функцию draw и используйте UIGraphicsGenCurrentContext, который вернет CGContext, как очень полезный инструмент для рисования холста.

    override func draw(_ rect: CGRect){
        super.draw(rect)
        
        guard let context = UIGraphicsGetCurrentContext() else 
        { return }
        // Use CGContext to draw here.
        
        context.setLineWidth(10)
        context.setLineCap(.round)
        context.strokePath()
    }

Отменить сенсорную функцию

Теперь в CanvasView переопределите функцию захвата касания, чтобы мы могли соответственно получить координату. Давайте сделаем это для touchesBegin, а также для touchesMoved

    override func touchesBegan(
        _ touches: Set<UITouch>, with event: UIEvent?) {
        guard let point = touches.first?.location(in: self) 
        else { return }
        // Capture the coordinate to start new line
        setNeedsDisplay()
    }
    
    override func touchesMoved(
        _ touches: Set<UITouch>, with event: UIEvent?) {
        guard let point = touches.first?.location(in: self) 
        else { return }
        // Capture the coordinate to continue draw line
        setNeedsDisplay()
    }

Настроить класс пути

В отличие от Android, в iOS нет path структуры, о которой я знаю. Итак, мы должны создать один для хранения захвата координат из функций touches, чтобы функция draw могла его получить.

struct Path {
    let type: PathType
    let point: CGPoint
    
    init(type: PathType, point: CGPoint) {
        self.type = type
        self.point = point
    }
    
    enum PathType {
        case move
        case line
    }
}

Выше представлена ​​простая структура Path, которая хранит координату и указывает, является ли она move (т. Е. Началом новой строки) или line (т. Е. Непрерывным рисованием линии).

Имея это, теперь мы можем настроить координату из функций touch для перехода к функции draw.

class CanvasView: UIView {
    // An array of path to be drawn
    var paths = [Path]()
    
    override func draw(_ rect: CGRect){
        super.draw(rect)
        
        guard let context = UIGraphicsGetCurrentContext()
        else { return }
        // Setup the path to be drawn       
        paths.forEach { path in
            switch(path.type) {
            case .move:
                context.move(to: path.point)
                break
            case .line:
                context.addLine(to: path.point)
                break
            }
        }
        
        context.setLineWidth(10)
        context.setLineCap(.round)
        context.strokePath()
    }
    
    override func touchesBegan(
        _ touches: Set<UITouch>, with event: UIEvent?) {
        guard let point = touches.first?.location(in: self) 
        else { return }
        // Capture the beginning point of line
        paths.append(Path(type: .move, point: point))
        setNeedsDisplay()
    }
    
    override func touchesMoved(
        _ touches: Set<UITouch>, with event: UIEvent?) {
        guard let point = touches.first?.location(in: self)
        else { return }
        // Capture the line coordinates              
        paths.append(Path(type: .line, point: point))
        setNeedsDisplay()
    }
}

С помощью приведенного выше кода теперь у нас есть холст для рисования UIView.

Оберните в SwiftUI View

Как показано в приведенном выше коде, CanvasView на самом деле UIView. Вам просто нужно создать UIViewRepresentable (примечание: не обычный SwiftUI View) и переопределить две функции, чтобы вернуть CanvasView, а также установить backgroundColor.

struct CanvasViewWrapper : UIViewRepresentable {
    func makeUIView(context: Context) -> UIView {
        return CanvasView()
    }
    func updateUIView(_ uiView: UIView, context: Context) {
        uiView.backgroundColor = .white
    }
}

Если вы обнаружите, что рисунок может попасть в безопасную зону, вы можете обратиться к этому StackOverflow.

Если вы предпочитаете быть в ViewController

Но если вы еще не вошли в SwiftUI и все еще используете ViewController, вы можете использовать следующее.

class CanvasViewController: UIViewController {
    
    let canvas = CanvasView()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.addSubview(canvas)
        canvas.backgroundColor = .lightGray
        canvas.frame = view.frame
    }
}

Теперь у вас есть приложение для рисования в обычном приложении ViewController или в приложении на основе SwiftUI.

Если вам понравился код, вы можете получить его отсюда.