###前書き
これは絵文字のことを考慮していない アプローチです。絵文字を考慮したものは回答の最下部に書いてみました。
###実装の流れ
今回実装したい機能の流れとしては
テキストがない場合抜ける
カーソルの位置が一番右にある場合抜ける
ターゲットとする文字の左側のインデックスおよび右側のインデックスの取得を行う。
文字列の頭からターゲットの左側までの文字列およびターゲットの右側から文字列の最後尾の二つを取得する
4で取得した文字列の結合
となります。
やることは前回した回答と同じような流れではあるのですが2の場合の抜け方とtargetOfLeftIndexおよびtargetOfRightIndexの取得方法が若干異なります。
###型の違い
前回の質問の段階でもっと丁寧にしておけばと思っていたのですが今回その機会がやってきたので少し説明をしておきます。今回出てくる定数のうちstartIndex, endIndex, targetOfLefindex, targetOfRightIndexはString.indexという少々特殊な型です。が一方でoffsetは基本的なIntになります。後述してあるfullText.countも同様にIntです。型が違うのでそのままたし算、ひき算は出来ません。
###インデックスについて
インデックスの認識というのは慣れるまで分かりにくいので図を用意してみました。
この図では文字「お」をターゲットとして定めた場合の各定数、プロパティの名称等をふんわりと図にしたものです(汚いのはご容赦ください)。この時のカーソルの位置は「お」の左側 にあります。また左右混乱しやすいのでゆっくり確認してください。
offsetに関してですが、
カーソルが「あ」の左側 にある場合
になります。
またカーソルが「く」の左側 にある場合
となります。
カーソルが「こ」の右側 にある場合は
です。
###コーディングの前準備
前回した回答との違いは実のところ2と3だけになります。
前回の質問では2の部分は「カーソルの位置が一番左にある場合抜ける」でした。
そしてカーソルの位置が一番左の時を表すコードは
でした。では「カーソルが一番右にある場合」を表すコードはどうなるでしょうか。使えそうなのはすでに入力されている文字列の量です。
今度考える点は3です。これはつまりtargetOfLeftIndexとtargetOfRightIndexの関係性を考えることになります。これら二つはstartIndexを起点とするとtargetOfLeftIndexはstartIndexからoffset分移動したところにあると言えます。ではtargetOfRightIndexはというとstartIndexからoffset分移動したところにあるtargetOfLeftIndexの一つ隣になります。
以上を考えた上でコーディングを行なっていきます。
###サンプルコード
swift
1
2
3 //(1)
4 guard let fullText = textView . text else {
5 return
6 }
7
8 //(2)
9 let count = fullText . count
10 let offset = textView . selectedRange . location
11 if offset >= count {
12 return
13 }
14
15 //(3)
16 let startIndex = fullText . startIndex
17 let endIndex = fullText . endIndex
18 let targetOfLeftIndex = fullText . index ( startIndex , offsetBy : offset )
19 let targetOfRightIndex = fullText . index ( startIndex , offsetBy : offset + 1 ) //targetOfLeftIndexの一つ隣
20
21 //(4)
22 let leftText = fullText [ startIndex . . < targetOfLeftIndex ]
23 let rightText = fullText [ targetOfRightIndex . . < endIndex ]
24
25 //(5)
26 let modifiedText = leftText + rightText
27 textView . text = String ( modifiedText )
###絵文字が混ざった場合
swift
1
2 /*
3 事前情報
4
5 今回絵文字が含まれているのでUTF16に関する知識が多少必要になり、さらにアプローチが上記のものとは部分的に変わっています。
6 */
7
8 /*
9 アプローチについて
10
11 絵文字を考慮しつつカーソルの右側を削除する場合、考えることは
12 1.入力された全ての文字列
13 2.startIndexからカーソルまでの文字列
14 3.削除する文字数
15 4.カーソルの右側に残った文字列の数
16 5.UTF16の文字列は「あ」という文字は1文字として認識されるが「????」という文字は2文字として認識される。さらに色付きの文字だったりすると倍になったりする(詳細はUTF16, unicode等検索して下さい)
17 6.5番を踏まえるとカーソルの右が普通の文字であろうと絵文字であろうと対応できるコードを書かなければならない
18
19 1.はfullText
20 2.はfullText[startIndex..<cursorIndex]
21 3.はカーソルの右側1文字だけなのでamountOfCharacter = 1
22 4.は実機等画面に表示されている全ての文字列の数 - leftTextの数 - ammountOfCharacter
23 で表します。
24 5.これのおかげでUITextView.index(_,offsetBy:)で隣の文字を取得するという方法が使えません。
25 6.なので4番で取得した文字列分fullTextから切り取る、という方法を取ります。
26 */
27
28 //(1)
29 guard let fullText = textView . text else {
30 return
31 }
32
33 //UITextView.selectedRange.locationで取れる位置はUTF16で換算されているようです(要検証)
34 let offset = textView . selectedRange . location
35 let count = fullText . utf16 . count
36
37 if offset >= count {
38 return
39 }
40
41 //(2)
42 //文字列の最初のインデックス情報
43 let startIndex = fullText . utf16 . startIndex
44 //カーソルのインデックス情報
45 let cursorIndex = fullText . utf16 . index ( startIndex , offsetBy : offset )
46 //文字列の最初からカーソルまでの文字列
47 let leftText = fullText [ startIndex . . < cursorIndex ]
48
49 //(3),(4)
50 //文字数の把握及び計算
51 let amountOfFullTextCharacter = fullText . underestimatedCount
52 let amountOfLeftTextCharacter = String ( leftText ) . underestimatedCount
53 let amountOfDeleteCharacter = 1
54 let remain = amountOfFullTextCharacter - amountOfLeftTextCharacter - amountOfDeleteCharacter
55
56 //(5),(6)
57 //文字列の末尾からremain分切り取り
58 let rightText = fullText . suffix ( remain )
59
60 //文字列の結合。カーソルの左側を削除した文字列になる
61 let modifiedText = leftText + rightText
62
63 //modifiedTextはsubstringでStringではないのでStringにしてUITextView.textに代入
64 textView . text = String ( modifiedText )
65
66 //カーソルの位置を元に戻す
67 textView . selectedRange . location = offset
68
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/11/06 05:46
2017/11/06 06:39
2017/11/06 12:17
2017/11/07 01:53
2017/11/07 07:49 編集
2017/11/08 02:52
2017/11/08 02:54
2017/11/08 03:03
2017/11/09 00:25
2017/11/13 05:40
2017/11/13 07:16
2017/11/13 11:02
2017/11/13 11:03
2017/11/13 11:07 編集
2017/11/13 11:28 編集
2017/11/13 11:25 編集
2017/11/13 11:29
2017/11/14 06:04
2017/11/14 08:29
2017/11/14 13:25
2017/11/14 13:55
2017/11/15 06:12
2017/11/15 08:57
2017/11/15 09:36
2017/11/15 09:39
2017/11/16 06:12
2017/12/22 06:23