mto を iOS に移植してみる
Mto for iOS
画面の構成は iPhone 4.7-inch のサイズでつくることにした。MainMenu.xib
ではなく、Main.storyboard
になっているのでこれを選択して部品を配置。しなければいけないのだが…… テキストボックスを配置する初っ端から詰まってしまった。Text View だけではテキストの量の応じてスクロールしないのだ。
調べてみると、どうやら Scroll View を配置して、その上にそれよりも少し小さい Text View を配置すれば良いらしい。View Controller Scene で見ると下のようになっている。
▼ View Controller Scene
▼ View Controller
▼ View
▼ Scroll View
Text View
[f:id:nakinor:20150826064246p:plain]
CocoaMto の方を確認してみると、やはり似たような形になっていた。
▼ Window
▼ View
▼ Scroll View - Text View
▼ Clip View
Text View
[f:id:nakinor:20150826064245p:plain]
Cocoa ではそういう部品として Text View が構成されているんだね。
iOS での Scroll View は「枠」というイメージで捉えるといいみたい。そしてその中にテキストを扱う Text View を置いていく。画像を表示したいなら、画像を扱う Image View を使う。
今回は設置するボタンが少なくていいね。HTML 版をつくった時の経験が生きてくるわ。でもこれ、ボタンらしい枠が無いんだね。iOS の UI 的にそうなってるのかな。
フォントなのだけど、デフォルトの System では日本語(の漢字)が簡体字になってしまうんだね。中国の影響は大きい。丸ゴチックが無いのでヒラギノ明朝にした。
[f:id:nakinor:20150826064244p:plain]
コードの実装に入る。といっても CocoaMto のコピペだが。iOS では NSTextView ではなく UITextView を使うみたい。そして UITextView は string
でなはく text
を使うようなので、_textArea.string
ではなく _textArea.text
のようにした。
辞書を作成するための [MTOAppDelegate alloc]
は [ViewController alloc]
のようにした。
Add Files to ... で kana-jisyo
と kanji-jisyo
をインポート。ここで「Destination: Copy items if needed にチェック」と「Added folders の Create folder references にチェック」を忘れないこと。
[f:id:nakinor:20150826064243p:plain]
あっさりと動いた!調べながらやって 1 時間くらいかな。Main.storyboard
で GUI 部品を組み立てて、ViewController.h
と ViewController.m
に CocoaMto の記述をコピペして、上記したように文字列をちょこちょこっと変えるだけでいけたわ。
Product の Archive が選択できないようになっているのは何でだろう?Apple Developer に登録していないからかしら?自分は実機を持っていないので、どのみち使う事は無いのだけれど気にはなる(Destination で iOS Device に変更すれば OK)。
[f:id:nakinor:20150826064242p:plain]
キーボードを出した時にテキストエリアが隠れてしまう事への対処方は、結構面倒なんだね。あと画面を回転した時の対応とか、大変だわ。
しかしよくよく考えてみると、このアプリは文章の変換が目的なので、これ自身で文章を入力する事は考慮する必要は無いのではないか?コピペして変換して確認するだけなんだから。あと回転してもレイアウトは変わらないようにしておけばいいのだし(Device Orientation の Landscape Left, Landscape Right のチェックをはずせばいい)。これで解決だ!
[f:id:nakinor:20150826064256p:plain]
ViewController.h
#import <UIKit/UIKit.h> @interface ViewController : UIViewController @property IBOutlet UITextView *textArea; @property NSMutableArray *innerDict; - (id)createDict:(NSString *)dict; - (NSString *)replaceStringCar:(NSString *)text; - (NSString *)replaceStringCdr:(NSString *)text; - (IBAction)ClearInput:(id)sender; - (IBAction)TradOldToModernNew:(id)sender; - (IBAction)ModernNewToTradOld:(id)sender; @end
ViewController.m
#import "ViewController.h" @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } // 内部辞書を作成する - (id)createDict:(NSString *)dict { NSString *filePath = dict; NSString *text = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil]; // 辞書ファイルのコメント行を削除するための正規表現 NSString *pat1 = @"^;.*|^$"; // 辞書ファイルのコメント部分を削除するための正規表現 NSString *pat2from = @"\\s+;.*"; // コメント部分を削除(空)にするためのもの NSString *pat2to = @""; // 改行文字で区切って配列に格納する NSArray *lines = [text componentsSeparatedByString:@"\n"]; NSMutableArray *tmpdict = [NSMutableArray array]; NSRegularExpression *regexp1 = [NSRegularExpression regularExpressionWithPattern:pat1 options:0 error:nil]; for (NSString *line in lines) { NSTextCheckingResult *match = [regexp1 firstMatchInString:line options:0 range:NSMakeRange(0, line.length)]; if(match.numberOfRanges){ } else { NSRegularExpression *regexp2 = [NSRegularExpression regularExpressionWithPattern:pat2from options:0 error:nil]; NSString *result = [regexp2 stringByReplacingMatchesInString:line options:0 range:NSMakeRange(0,line.length) withTemplate:pat2to]; [tmpdict addObject:[result componentsSeparatedByString:@" /"]]; } } _innerDict = tmpdict; return self; } // 文字列を置換する(carをcdrへ) - (NSString *)replaceStringCar:(NSString *)text { NSString *inputText = text; for(id cons in _innerDict){ inputText = [inputText stringByReplacingOccurrencesOfString:cons[0] withString:cons[1]]; } return inputText; } // 文字列を置換する(cdrをcarへ) - (NSString *)replaceStringCdr:(NSString *)text { NSString *inputText = text; for(id cons in _innerDict){ inputText = [inputText stringByReplacingOccurrencesOfString:cons[1] withString:cons[0]]; } return inputText; } // 入力エリアをクリアする - (IBAction)ClearInput:(id)sender { _textArea.text = @""; } // 旧字旧仮名を新字新仮名へ変換する - (IBAction)TradOldToModernNew:(id)sender { NSString *tmp = @""; NSString *kanadict = [[NSBundle mainBundle] pathForResource:@"kana-jisyo" ofType:nil]; NSString *kanjidict = [[NSBundle mainBundle] pathForResource:@"kanji-jisyo" ofType:nil]; id fuga = [[ViewController alloc] createDict:kanjidict]; tmp = [fuga replaceStringCdr:_textArea.text]; id hoge = [[ViewController alloc] createDict:kanadict]; _textArea.text = [hoge replaceStringCdr:tmp]; } // 新字新仮名を旧字旧仮名へ変換する - (IBAction)ModernNewToTradOld:(id)sender { NSString *tmp = @""; NSString *kanadict = [[NSBundle mainBundle] pathForResource:@"kana-jisyo" ofType:nil]; NSString *kanjidict = [[NSBundle mainBundle] pathForResource:@"kanji-jisyo" ofType:nil]; id hoge = [[ViewController alloc] createDict:kanadict]; tmp = [hoge replaceStringCar:_textArea.text]; id fuga = [[ViewController alloc] createDict:kanjidict]; _textArea.text = [fuga replaceStringCar:tmp]; } @end