de Neo Ighodaro

Cum să construiți un editor de text colaborativ folosind Swift

Cum sa construiti un editor de text colaborativ folosind Swift
Fotografie de rawpixel pe Unsplash

Editorii de text sunt din ce în ce mai populari în zilele noastre, indiferent dacă sunt încorporați într-un formular de comentarii ale site-ului web sau folosiți ca notepad. Există mulți editori diferiți din care să alegeți. În această postare, vom învăța nu numai cum să construim o aplicație mobilă de editare textă frumoasă în iOS, ci și cum să facem posibilă colaborarea la o notă în timp real folosind Pusher

Vă rugăm să rețineți, totuși, că pentru a simplifica aplicația, articolul nu va acoperi modificările simultane. Prin urmare, doar o singură persoană poate edita în același timp, în timp ce alții se uită.

Aplicația va funcționa prin declanșarea unui eveniment la introducerea unui anumit text. Acest eveniment va fi trimis către Pusher și apoi preluat de dispozitivul colaboratorului și actualizat automat.

Pentru a continua acest tutorial, veți avea nevoie de următoarele:

ad-banner
  1. Cocoapode: a instala, rula gem install cocoapods pe mașina dvs.
  2. Xcode
  3. A Aplicație Pusher: puteți crea un cont și o aplicație gratuită aici
  4. Câteva cunoștințe despre Rapid limba
  5. Node.js

În cele din urmă, este necesară o înțelegere de bază despre Swift și Node.js pentru a urma acest tutorial.

Noțiuni introductive despre aplicația noastră iOS în Xcode

Lansați Xcode și creați un proiect nou. O voi suna pe a mea Collabo. După ce ați urmat expertul de configurare și cu spațiul de lucru deschis, închideți Xcode și apoi cd la rădăcina proiectului dvs. și rulați comanda pod init. Acest lucru ar trebui să genereze un Podfile Pentru dumneavoastră. Schimbați conținutul fișierului Podfile:

# Uncomment the next line to define a global platform for your project    platform :ios, '9.0'
    target 'textcollabo' do      # Comment the next line if you're not using Swift and don't want to use dynamic frameworks      use_frameworks!
      # Pods for anonchat      pod 'Alamofire'      pod 'PusherSwift'    end

Acum executați comanda pod install deci managerul de pachete Cocoapods poate extrage dependențele necesare. Când aceasta este finalizată, închideți Xcode (dacă este deschis) și apoi deschideți fișierul .xcworkspace fișier care se află în rădăcina folderului de proiect.

Proiectarea vizualizărilor pentru aplicația noastră iOS

Vom crea câteva vizualizări pentru aplicația noastră iOS. Acestea vor fi coloana vertebrală în care vom conecta toată logica. Folosind tabloul de bord Xcode, faceți ca vizualizările dvs. să semene puțin cu capturile de ecran de mai jos.

Acesta este LaunchScreen.storyboard fişier. Tocmai am proiectat ceva simplu, fără nicio funcționalitate.

Cum sa construiti un editor de text colaborativ folosind Swift

Următorul scenariu pe care îl vom proiecta este Main.storyboard. După cum sugerează și numele, va fi principalul. Aici avem toate punctele de vedere importante care sunt atașate unei anumite logici.

1611285727 858 Cum sa construiti un editor de text colaborativ folosind Swift

Aici avem trei puncte de vedere.

Prima vizualizare este concepută pentru a arăta exact ca ecranul de lansare, cu excepția unui buton pe care l-am legat pentru a deschide a doua vizualizare.

A doua vedere este controlerul de navigare. Este atașat la o a treia vedere care este o ViewController. Am setat a treia vizualizare ca controler rădăcină la controlerul nostru de navigație.

În a treia vedere, avem un UITextView care este editabil, care este plasat în vizualizare. Există, de asemenea, o etichetă care ar trebui să fie un contor de caractere. Acesta este locul în care vom incrementa caracterele pe măsură ce utilizatorul introduce text în vizualizarea text.

Codificarea aplicației iOS editor de text colaborativ

Acum că am creat cu succes vizualizările necesare pentru încărcarea aplicației, următorul lucru pe care îl vom face este să începem să codificăm logica aplicației.

Creați un nou fișier de clasă cacao și denumiți-l TextEditorViewController și conectați-l la a treia vizualizare în Main.storyboard fişier. TextViewController ar trebui să adopte, de asemenea UITextViewDelegate. Acum poti ctrl+drag UITextView Si deasemenea ctrl+drag UILabel în Main.storyboard fișier la TextEditorViewController clasă.

De asemenea, ar trebui să importați fișierul PusherSwift și AlamoFire biblioteci la TextViewController. Ar trebui să aveți ceva apropiat de acest lucru după ce ați terminat:

import UIKit    import PusherSwift    import Alamofire
    class TextEditorViewController: UIViewController, UITextViewDelegate {        @IBOutlet weak var textView: UITextView!        @IBOutlet weak var charactersLabel: UILabel!    }

Acum trebuie să adăugăm câteva proprietăți de care vom avea nevoie mai târziu în controler.

import UIKit    import PusherSwift    import Alamofire
    class TextEditorViewController: UIViewController, UITextViewDelegate {        static let API_ENDPOINT = "http://localhost:4000";
        @IBOutlet weak var textView: UITextView!
        @IBOutlet weak var charactersLabel: UILabel!
        var pusher : Pusher!
        var chillPill = true
        var placeHolderText = "Start typing..."
        var randomUuid : String = ""    }

Acum vom împărți logica în trei părți:

  1. Vizualizați și evenimente de la tastatură
  2. Metode UITextViewDelegate
  3. Gestionarea evenimentelor Pusher.

Vizualizați și evenimente de la tastatură

Deschide TextEditorViewController și actualizați-l cu metodele de mai jos:

override func viewDidLoad() {        super.viewDidLoad()        // Notification trigger        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)        // Gesture recognizer        view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(tappedAwayFunction(_:))))        // Set the controller as the textView delegate        textView.delegate = self        // Set the device ID        randomUuid = UIDevice.current.identifierForVendor!.uuidString        // Listen for changes from Pusher        listenForChanges()    }    override func viewWillAppear(_ animated: Bool) {        super.viewWillAppear(animated)        if self.textView.text == "" {            self.textView.text = placeHolderText            self.textView.textColor = UIColor.lightGray        }    }    func keyboardWillShow(notification: NSNotification) {        if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {            if self.charactersLabel.frame.origin.y == 1.0 {                self.charactersLabel.frame.origin.y -= keyboardSize.height            }        }    }    func keyboardWillHide(notification: NSNotification) {        if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {            if self.view.frame.origin.y != 1.0 {                self.charactersLabel.frame.origin.y += keyboardSize.height            }        }    }

În viewDidLoad metoda, am înregistrat funcțiile tastaturii, astfel încât acestea să răspundă la evenimentele tastaturii. Am adăugat, de asemenea, recunoașteri de gesturi care vor închide tastatura atunci când atingeți în afara UITextView. Și am setat textView delega controlorului însuși. În cele din urmă, am apelat la o funcție pentru a asculta noi actualizări (vom crea acest lucru mai târziu).

În viewWillAppear , pur și simplu am piratat UITextView pentru a avea un text substituent, deoarece, în mod implicit, UITextView nu are această caracteristică. Mă întreb de ce, Apple …

În keyboardWillShow și keyboardWillHide funcții, am făcut ca eticheta de numărare a caracterelor să crească cu tastatura și, respectiv, să coboare cu ea. Acest lucru va împiedica Tastatura să acopere eticheta atunci când este activă.

Metode UITextViewDelegate

Actualizați fișierul TextEditorViewController cu următoarele:

func textViewDidChange(_ textView: UITextView) {        charactersLabel.text = String(format: "%i Characters", textView.text.characters.count)
        if textView.text.characters.count >= 2 {            sendToPusher(text: textView.text)        }    }
    func textViewShouldBeginEditing(_ textView: UITextView) -> Bool {        self.textView.textColor = UIColor.black
        if self.textView.text == placeHolderText {            self.textView.text = ""        }
        return true    }
    func textViewDidEndEditing(_ textView: UITextView) {        if textView.text == "" {            self.textView.text = placeHolderText            self.textView.textColor = UIColor.lightGray        }    }
    func tappedAwayFunction(_ sender: UITapGestureRecognizer) {        textView.resignFirstResponder()    }

textViewDidChange metoda pur și simplu actualizează eticheta de numărare a caracterelor și, de asemenea, trimite modificările către Pusher folosind API-ul nostru backend (pe care îl vom crea într-un minut).

textViewShouldBeginEditing se obține de la UITextViewDelegate și se declanșează când vizualizarea textului este pe cale să fie editată. Aici, ne jucăm practic cu substituentul, la fel ca textViewDidEndEditing metodă.

În cele din urmă, în tappedAwayFunction definim callback-ul evenimentului pentru gestul pe care l-am înregistrat în secțiunea anterioară. În metodă, practic renunțăm la tastatură.

Gestionarea evenimentelor Pusher

Actualizați controlerul cu următoarele metode:

func sendToPusher(text: String) {        let params: Parameters = ["text": text, "from": randomUuid]
        Alamofire.request(TextEditorViewController.API_ENDPOINT + "/update_text", method: .post, parameters: params).validate().responseJSON { response in            switch response.result {
            case .success:                print("Succeeded")            case .failure(let error):                print(error)            }        }    }
    func listenForChanges() {        pusher = Pusher(key: "PUSHER_KEY", options: PusherClientOptions(            host: .cluster("PUSHER_CLUSTER")        ))
        let channel = pusher.subscribe("collabo")        let _ = channel.bind(eventName: "text_update", callback: { (data: Any?) -> Void in
            if let data = data as? [String: AnyObject] {                let fromDeviceId = data["deviceId"] as! String
                if fromDeviceId != self.randomUuid {                    let text = data["text"] as! String                    self.textView.text = text                    self.charactersLabel.text = String(format: "%i Characters", text.characters.count)                }            }        })
        pusher.connect()    }

În sendToPusher , trimitem sarcina utilă aplicației noastre backend folosind AlamoFire, care, la rândul său, îl va trimite lui Pusher.

În listenForChanges apoi ascultăm modificările textului și, dacă există, aplicăm modificările la vizualizarea textului.

? Remember pentru a înlocui cheia și clusterul cu valoarea reală pe care ați obținut-o de la tabloul de bord Pusher.

Dacă ați urmat îndeaproape tutorialul, atunci TextEditorViewController ar trebui să arate cam așa:

import UIKit    import PusherSwift    import Alamofire
    class TextEditorViewController: UIViewController, UITextViewDelegate {        static let API_ENDPOINT = "http://localhost:4000";
        @IBOutlet weak var textView: UITextView!
        @IBOutlet weak var charactersLabel: UILabel!
        var pusher : Pusher!
        var chillPill = true
        var placeHolderText = "Start typing..."
        var randomUuid : String = ""
        override func viewDidLoad() {            super.viewDidLoad()
            // Notification trigger            NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)            NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
            // Gesture recognizer            view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(tappedAwayFunction(_:))))
            // Set the controller as the textView delegate            textView.delegate = self
            // Set the device ID            randomUuid = UIDevice.current.identifierForVendor!.uuidString
            // Listen for changes from Pusher            listenForChanges()        }
        override func viewWillAppear(_ animated: Bool) {            super.viewWillAppear(animated)
            if self.textView.text == "" {                self.textView.text = placeHolderText                self.textView.textColor = UIColor.lightGray            }        }
        func keyboardWillShow(notification: NSNotification) {            if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {                if self.charactersLabel.frame.origin.y == 1.0 {                    self.charactersLabel.frame.origin.y -= keyboardSize.height                }            }        }
        func keyboardWillHide(notification: NSNotification) {            if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {                if self.view.frame.origin.y != 1.0 {                    self.charactersLabel.frame.origin.y += keyboardSize.height                }            }        }
        func textViewDidChange(_ textView: UITextView) {            charactersLabel.text = String(format: "%i Characters", textView.text.characters.count)
            if textView.text.characters.count >= 2 {                sendToPusher(text: textView.text)            }        }
        func textViewShouldBeginEditing(_ textView: UITextView) -> Bool {            self.textView.textColor = UIColor.black
            if self.textView.text == placeHolderText {                self.textView.text = ""            }
            return true        }
        func textViewDidEndEditing(_ textView: UITextView) {            if textView.text == "" {                self.textView.text = placeHolderText                self.textView.textColor = UIColor.lightGray            }        }
        func tappedAwayFunction(_ sender: UITapGestureRecognizer) {            textView.resignFirstResponder()        }
        func sendToPusher(text: String) {            let params: Parameters = ["text": text, "from": randomUuid]
            Alamofire.request(TextEditorViewController.API_ENDPOINT + "/update_text", method: .post, parameters: params).validate().responseJSON { response in                switch response.result {
                case .success:                    print("Succeeded")                case .failure(let error):                    print(error)                }            }        }
        func listenForChanges() {            pusher = Pusher(key: "PUSHER_KEY", options: PusherClientOptions(                host: .cluster("PUSHER_CLUSTER")            ))
            let channel = pusher.subscribe("collabo")            let _ = channel.bind(eventName: "text_update", callback: { (data: Any?) -> Void in
                if let data = data as? [String: AnyObject] {                    let fromDeviceId = data["deviceId"] as! String
                    if fromDeviceId != self.randomUuid {                        let text = data["text"] as! String                        self.textView.text = text                        self.charactersLabel.text = String(format: "%i Characters", text.characters.count)                    }                }            })
            pusher.connect()        }    }

Grozav! Acum trebuie să realizăm backend-ul aplicației.

Construirea aplicației Nod backend

Acum că am terminat cu partea Swift, ne putem concentra pe crearea backend-ului Node.js pentru aplicație. Vom folosi Express, astfel încât să putem repara rapid ceva.

Creați un director pentru aplicația web și apoi creați câteva fișiere noi.

index.js fişier:

let path = require('path');    let Pusher = require('pusher');    let express = require('express');    let bodyParser = require('body-parser');    let app = express();    let pusher = new Pusher(require('./config.js'));
    app.use(bodyParser.json());    app.use(bodyParser.urlencoded({ extended: false }));
    app.post('/update_text', function(req, res){      var payload = {text: req.body.text, deviceId: req.body.from}      pusher.trigger('collabo', 'text_update', payload)      res.json({success: 200})    });
    app.use(function(req, res, next) {        var err = new Error('Not Found');        err.status = 404;        next(err);    });
    module.exports = app;
    app.listen(4000, function(){      console.log('App listening on port 4000!');    });

În fișierul JS de mai sus, folosim Express pentru a crea o aplicație simplă. În /update_text rută, primim pur și simplu sarcina utilă și o transmitem lui Pusher. Nimic complicat acolo.

Creeaza o pachet.json fișier, de asemenea:

{      "main": "index.js",      "dependencies": {        "body-parser": "^1.17.2",        "express": "^4.15.3",        "path": "^0.12.7",        "pusher": "^1.5.1"      }    }

pachet.json fișierul este locul în care definim toate dependențele NPM.

Ultimul fișier de creat este un config.js fişier. Aici vom defini valorile de configurare pentru aplicația noastră Pusher:

module.exports = {      appId: 'PUSHER_ID',      key: 'PUSHER_KEY',      secret: 'PUSHER_SECRET',      cluster: 'PUSHER_CLUSTER',      encrypted: true    };

? Remember pentru a înlocui cheia și clusterul cu valoarea reală pe care ați obținut-o de la tabloul de bord Pusher.

Acum fugi npm install pe director și apoi node index.js după finalizarea instalării npm. Ar trebui să vezi un Ascultarea aplicației pe portul 4000! mesaj.

1611285727 941 Cum sa construiti un editor de text colaborativ folosind Swift

Testarea aplicației

După ce ați rulat serverul web de nod local, va trebui să faceți câteva modificări, astfel încât aplicația dvs. să poată vorbi cu serverul web local. În info.plist fișier, efectuați următoarele modificări:

1611285728 391 Cum sa construiti un editor de text colaborativ folosind Swift

Cu această modificare, puteți crea și rula aplicația dvs. și aceasta va vorbi direct cu aplicația dvs. web locală.

Concluzie

În acest articol, am prezentat cum să construim un editor de text colaborativ în timp real pe iOS folosind Pusher. Sperăm că ați învățat un lucru sau două din urmarea tutorialului. Pentru practică, puteți extinde stările pentru a susține mai multe instanțe.

Această postare a fost publicată pentru prima dată pe Pusher.