ぼくは、TextExpanderが好きで結構使っています。
といっても、それほどたくさんのスニペットを登録しているわけではないのですが、なくてはならないアプリです。
そんなTextExpanderですが、Macで出来ていることをiOSで実現するには比較的ややこしい内部処理をしているようで、バージョンアップのSDKの仕様が何回か変更されています。
現在、Version 2.3.1のSDKを利用しているのですが、デリゲートメソッドが結構あったのでBlocksへ置き換えたかったのと URLスキームのコールバックを受け取るためにUIApplicationDelegate
へ、コードを書かなければなりませんが大体は定型のコードだったので、他のアプリでも使いやすいようにラッパークラスを作って使っていくつかのアプリに使っていました。
結構、使いやすかったのでコードを整理して公開してみようと思います。
依存関係は、もちろんTextExpanderのframeworkが必要です。
使い方です。
シングルトンクラスですので、sharedManager
でアクセスしてください。
アプリ名とスニペットの更新用とfill-in用のURLスキームはあらかじめ変数として設定しておく必要があります。
URLSchemeを受け取れるように、忘れずにXcodeで予めスニペットの更新用とfill-in用のURLを設定しておきましょう。
sharedManagerWithAppName:getSnippetsScheme:fillCompletionScheme:
をUIApplicationDelegateクラスのインスタンスAppDelegate
で呼び、インスタンスを保持しておくという例が以下のコードです。
// 変数の設定
@interface AppDelegate ()
@property (nonatomic) JAGTextExpanderManager *textExpanderManager;
@end
// 初回起動時のタイミングのどこかで、このメソッドを呼ぶ。
- (void)_initialize{
_textExpanderManager = [JAGTextExpanderManager sharedManagerWithAppName:@"アプリ名"
getSnippetsScheme:@"スニペット更新用URLスキーム"
fillCompletionScheme: @"Fill-in用URLスキーム"];
}
上記の設定が終わると、まずTextExpanderからデータを受け取ってSnippetsのデータを最新のものへと更新しなければなりません。
アプリへのTextExpanderのデータの読み込み
よくあるのが、設定画面でスイッチをオンにしてTextExpanderを有効にするという機能です。
これは、以下のようなコードで実現します。
まず、UISwitch
のアクションを設定します。
- (void)changeTextExpanderOption:(id)sender {
UISwitch *swt = sender;
if (swt.on &&
JAGTextExpanderManager.isTextExpanderTouchInstalled) {
[[JAGTextExpanderManager sharedManager] getSnippets];
} else {
swt.on = NO;
}
}
次にAppDelegateでURLを受け取ります。
// Callback受け取り
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
if ([[JAGTextExpanderManager sharedManager] handleSchemeURL:url]) {
return YES;
}
return NO;
}
これで、データの読み込みはOKです。
スニペットを展開するための準備
通常であればUITextField
やUITextView
にスニペットを展開するために、UITextViewなどのインスタンス変数delegate
をSMTEDelegateController
のインスタンスにする必要があります。
そして、通常通りUIViewControllerでもデリゲートメソッドを受け取りたい場合は、SMTEDelegateController
のインスタンスのnextDelegate
にUIViewController
を設定する必要があります。
これを一発で解決するように、いくつかメソッドを用意しています。
// このメソッドをUIViewControllerのどこかで呼ぶ。(テキスト入力の前には設定しておく。)
- (void)_setupTextExpander{
_textExpanderManager = [JAGTextExpanderManager sharedManager];
BOOL enabledTextExpander = [_textExpanderManager snippetExpanded];
// 有効化確認
if (enabledTextExpander) {
// TextExpanderを有効にしたいビューを配列にする。
NSArray *textObjects = @[_textField,_textView];
// textObjects全てに、TextExpanderを有効にする。Fill-inは無効。
[_textExpanderManager enableTextExpanderToTextObjects:textObjects nextDelegate:self];
// textObjects全てに、Fill-inを有効にする。
[_textExpanderManager enableFillinsToTextObjects:textObjects];
}
}
これで、動くようになりました。
あとは、Fill-inの動作は基本的にデリゲートメソッドで受け取るのですがこれをBlocksで設定できるようにしています。
[[JAGTextExpanderManager sharedManager] fillinsAllActionsAtIdentifierForTextArea:^NSString *(id uiTextObject) {
if ([_textField isEqual:uiTextObject]) {
return @"_textField";
}
if ([_textView isEqual:uiTextObject]) {
return @"_textView";
}
return nil;
} prepareForFillinSwitch:^BOOL(NSString *textIdentifier) {
return YES;
} fillinCompletionHandler:^id(NSString *textIdentifier, BOOL userCanceledFill, NSInteger ioInsertionPointLocation) {
if ([textIdentifier isEqualToString:@"_textField"]) {
return _textField;
}
if ([textIdentifier isEqualToString:@"_textView"]) {
return _textView;
}
return nil;
}];
これらは、enableFillinsToTextObjects
などのメソッドを呼び出していれば先に設定しなくても動くようにしています。
Fill-inの動作を細かく設定したい場合に、お使いください。
他の機能は、ほとんど元々用意されているものをラップしているだけです。
ぜひ使ってみてください。
全てGitHubにあげていますので、自由にお使いください。
GitHub : JAGTextExpanderManager – TextExpander wrapper
CocoaPodsからの利用は、以下の文字列をpodsfileへ書き込んでください。
pod 'JAGTextExpanderManager'