Domanda Crea UITextRange da NSRange


Ho bisogno di trovare il pixel-frame per diversi intervalli in una vista testo. Sto usando il - (CGRect)firstRectForRange:(UITextRange *)range; per farlo. Tuttavia non riesco a scoprire come effettivamente creare un UITextRange.

Fondamentalmente questo è quello che sto cercando:

- (CGRect)frameOfTextRange:(NSRange)range inTextView:(UITextView *)textView {

    UITextRange*range2 = [UITextRange rangeWithNSRange:range]; //DOES NOT EXIST 
    CGRect rect = [textView firstRectForRange:range2];
    return rect;
}

Apple dice che uno deve sottoclasse UITextRange e UITextPosition per adottare il UITextInput protocollo. Non lo faccio, ma ho comunque provato, seguendo il codice di esempio del doc e passando la sottoclasse a firstRectForRange che ha provocato l'arresto anomalo.

Se c'è un modo più semplice per aggiungere colori diversi UILables per una visualizzazione di testo, per favore dimmi. Ho provato a utilizzare UIWebView con content editable impostato su TRUE, ma non mi piace comunicare con JS e colorare è l'unica cosa di cui ho bisogno.

Grazie in anticipo.


44
2018-02-03 09:53


origine


risposte:


È possibile creare un intervallo di testo con il metodo textRangeFromPosition:toPosition. Questo metodo richiede due posizioni, quindi è necessario calcolare le posizioni per l'inizio e la fine dell'intervallo. Questo è fatto con il metodo positionFromPosition:offset, che restituisce una posizione da un'altra posizione e un carattere sfalsato.

- (CGRect)frameOfTextRange:(NSRange)range inTextView:(UITextView *)textView
{
    UITextPosition *beginning = textView.beginningOfDocument;
    UITextPosition *start = [textView positionFromPosition:beginning offset:range.location];
    UITextPosition *end = [textView positionFromPosition:start offset:range.length];
    UITextRange *textRange = [textView textRangeFromPosition:start toPosition:end];
    CGRect rect = [textView firstRectForRange:textRange];
    return [textView convertRect:rect fromView:textView.textInputView];
}

84
2018-03-07 17:36



È un po 'ridicolo che sembra essere così complicato. Una semplice "soluzione" sarebbe quella di selezionare l'intervallo (accetta NSRange) e quindi leggere il SelectedTextRange (restituisce UITextRange):

- (CGRect)frameOfTextRange:(NSRange)range inTextView:(UITextView *)textView {
    textView.selectedRange = range;
    UITextRange *textRange = [textView selectedTextRange]; 
    CGRect rect = [textView firstRectForRange:textRange];
    return rect;
}

Questo ha funzionato per me anche se textView non è il primo soccorritore.


Se non si desidera mantenere la selezione, è possibile ripristinare il valore selezionato:

textView.selectedRange = NSMakeRange(0, 0);

... o salvare la selezione corrente e ripristinarla in seguito

NSRange oldRange = textView.selectedRange;
// do something
// then check if the range is still valid and
textView.selectedRange = oldRange;

15
2017-10-05 20:13



Alla domanda del titolo, ecco a Estensione Swift 2 crea un UITextRange da un NSRange.

L'unico inizializzatore per UITextRange è un metodo di istanza sul protocollo UITextInput, quindi l'estensione richiede anche il passaggio in UITextInput come UITextField o UITextView.

extension NSRange {
    func toTextRange(textInput textInput:UITextInput) -> UITextRange? {
        if let rangeStart = textInput.positionFromPosition(textInput.beginningOfDocument, offset: location),
            rangeEnd = textInput.positionFromPosition(rangeStart, offset: length) {
            return textInput.textRangeFromPosition(rangeStart, toPosition: rangeEnd)
        }
        return nil
    }
}

5
2018-05-18 19:53



Swift 4 della risposta di Andrew Schreiber per una facile copia / incolla

extension NSRange {
    func toTextRange(textInput:UITextInput) -> UITextRange? {
        if let rangeStart = textInput.position(from: textInput.beginningOfDocument, offset: location),
            let rangeEnd = textInput.position(from: rangeStart, offset: length) {
            return textInput.textRange(from: rangeStart, to: rangeEnd)
        }
        return nil
    }
}

3
2017-09-17 21:08



Swift 4 della risposta di Nicolas Bachschmidt come UITextView estensione usando swifty Range<String.Index> invece di NSRange:

extension UITextView {
    func frame(ofTextRange range: Range<String.Index>?) -> CGRect? {
        guard let range = range else { return nil }
        let length = range.upperBound.encodedOffset-range.lowerBound.encodedOffset
        guard
            let start = position(from: beginningOfDocument, offset: range.lowerBound.encodedOffset),
            let end = position(from: start, offset: length),
            let txtRange = textRange(from: start, to: end)
            else { return nil }
        let rect = self.firstRect(for: txtRange)
        return self.convert(rect, to: textInputView)
    }
}

Possibile uso:

guard let rect = textView.frame(ofTextRange: text.range(of: "awesome")) else { return }
let awesomeView = UIView()
awesomeView.frame = rect.insetBy(dx: -3.0, dy: 0)
awesomeView.layer.borderColor = UIColor.black.cgColor
awesomeView.layer.borderWidth = 1.0
awesomeView.layer.cornerRadius = 3
self.view.insertSubview(awesomeView, belowSubview: textView)

0
2018-03-09 15:46



Qui è spiegato.

Un oggetto UITextRange rappresenta un intervallo di caratteri in un testo   contenitore; in altre parole, identifica un indice iniziale e un   terminare l'indice nella stringa che supporta un oggetto di immissione del testo.

Le classi che adottano il protocollo UITextInput devono creare personalizzato   Oggetti UITextRange per rappresentare gli intervalli all'interno del testo gestito da   la classe. Gli indici di partenza e di fine dell'intervallo sono   rappresentato da oggetti UITextPosition. Il sistema di testo usa entrambi   Oggetti UITextRange e UITextPosition per la comunicazione di layout di testo   informazione. Esistono due motivi per utilizzare gli oggetti per gli intervalli di testo   piuttosto che tipi primitivi come NSRange:

Alcuni documenti contengono elementi nidificati (ad esempio, tag HTML e   oggetti incorporati) e devi tracciare sia la posizione assoluta che   posizione nel testo visibile.

Il framework WebKit, su cui si basa il sistema di testo dell'iPhone,   richiede che gli indici e gli offset di testo siano rappresentati da oggetti.

Se si adotta il protocollo UITextInput, è necessario creare un'abitudine   Sottoclasse UITextRange e una sottoclasse UITextPosition personalizzata.

Ad esempio, come in quelle fonti


-1
2017-09-24 09:28