iPad版9VAeきゅうべえ開発記録。
今日は、文字表示を頑張ってみよう。
CoreTextの描画関数がリンクエラーする
日本語を表示するには CoreTextを使う必要があるらしい
CoreTextの文字の範囲。
CoreTextで文字列の矩形領域を取得する - > blog
CoreTextを使うには、プロジェクトにCoreText.frameworkを追加し、CoreText.hをインクルードする必要があるのかふむ。ということで、とりあえず、
#include <CoreText/CoreText.h>
とする。
そうすると、CoreTextのレイアウトを作る関数はちゃんとリンクできたが、肝心の最終的に描画する関数、CTFrameDraw, CTLineDrawでリンクエラーが出る。これを使わないと文字が書けない。
色々調べて見たがわからないので方向転換。CoreTextのサンプルプロジェクトをダウンロードしてビルドしてみる。この中で、CTFrameDraw, CTLineDrawが使われているがリンクエラーは出ず、ちゃんと文字が書ける。
それで、2つのプロジェクトを比較する。まず、対応OSバージョンが違ってた。CoreTextPageViewerは6、今まで改造していた DrawPadは5.1 。6は iPad2以上。
それで対応OSバージョンの変更をしてみるが、今のXcodeでは、8以上にしか設定できない。それで、iPad miniにも対応する9.0 に設定したが、CTFrameDraw, CTLineDrawのリンクエラーは無くならなかった。うーむ。
こんな時は悩むのをやめて、エラーの出ないCoreTextViewerプロジェクトに乗り換えるに限る。9VAeを入れてみると、いくつか関数未定義のエラーが出たが、インクルードファイルに定義を入れていくと、ちゃんとリンクできた。なので、CTFrameDraw, CTLineDrawのリンクエラーの原因はわからないが、CoreTextViewerベースに乗り換えることにする。
ベースプロジェクトをCoreTextViewerに乗り換える
今まで改造してきたDrawPadはお絵かきアプリなので、これをベースにしたかったのだが、文字が描画できないのでは仕方がない。CoreTextViewerに乗り換えることにする。つまり、下のプロジェクトに 9VAeを搭載する。
DrawPadとCoreTextViewerのには次の違いがある。
- DrawPad 画面レイアウトに Storyboardを使っていてわかりやすい。
- CoreTextViewer Storyboardは単純で、Viewの中身をXMLテキストで書き換えている。
9VAeは、メイン画面として、QvaeViewというカスタムビューを作成したので、これを CoreTextViewerに埋め込めばよいはず。また、ファイル開くなどのメニューはCoreTextViewerにToolbarがあるので、これを利用しよう。
どのようにQvaeViewに置き換えていったか
7つ .xml (XMLテキスト)がプロジェクトに含まれている。.xmlをプロジェクトから探すと、RootViewController.m に見つかる。これが画面切り替えみたいなので、最初の画面を見つけて、QvaeViewに置き換える。
最初の画面が以下のようになっていた。
// Initialize our CoreTextScrollView and set the initial sample document shown
[coreTextScrollView reset:[[[AttributedStringDoc alloc] initWithFileNameFromBundle:@"Splash.xml"] autorelease] withDelegate:self];
そこで、coreTextScrollView を、QvaeViewに置き換えてみる。まず動く状態にしておいて、少しずつ差し替えていくというのが定番のやり方。
RootViewController.h を次のように修正する。
-
#import "QvaeView.h"
を入れる
-
// Our main CoreTextScrollView for drawing
//CoreTextScrollView* coreTextScrollView;
QvaeView* qvaeView;
-
//@property (nonatomic, retain) IBOutlet CoreTextScrollView *coreTextScrollView;
@property (nonatomic, retain) IBOutlet QvaeView *qvaeView;
として、coreTextScrollViewを、同じ書き方で、qvaeViewに置き換えてみる。
こうすると、RootViewController.m の coreTextScrollViewを使っている部分でエラーが起きるので、そこを、qvaeViewに置き換える。
//@synthesize coreTextScrollView;
@synthesize qvaeView;
//[coreTextScrollView reset:[[[AttributedStringDoc alloc] //initWithFileNameFromBundle:@"Splash.xml"] autorelease] withDelegate:self];
[qvaeView setQvaeFrame:self.qvaeView.frame];
などとする。実行すると、
int retVal = UIApplicationMain(argc, argv, nil, @"AppDelegate");
でエラーが起こった。これは、StoryBoaedの中の画面配置 Main の中に、ScrollViewが定義されており、これも、QvaeViewに置き換える必要がありそうだ。
さらに、ストーリーボードから、Outletのリンクを取り除くと起動するようになった。
QvaeView処理ルーチンを入れる
QvaeView は、9VAeきゅうべえエディタ画面そのもので、そのビューの中でアニメの作成、アニメ再生など、9VAeの全てが実行できる。タッチ処理やアニメーションの機能を持ったカスタムビューだ。これを動かすために、メインルーチンに次のようなタイマー処理を入れておく必要がある。
@property (nonatomic, retain) IBOutlet QvaeView *qvaeView;
@property (nonatomic, retain) NSTimer *qvaeTimer;
- (void)viewDidLoad {
[super viewDidLoad];
[qvaeView setQvaeFrame:self.qvaeView.frame]; //QvaeViewに画面サイズを与えて初期化
if(qvaeTimer==nil){
//タイマー処理
qvaeTimer = [NSTimer
scheduledTimerWithTimeInterval:0.2 //タイマー間隔(秒)
target:self //実行する処理の所属(self=自分)
selector:@selector(update:) //実行する処理名
userInfo:nil //ユーザーパラメータ
repeats:YES //繰り返すかどうか
];
}
}
-(void) update:(NSTimer *)timer
{
[QvaeView updateView:self qvaeView:qvaeView];
}
起動した時、qvaeView がnil になっていたが、StoryBoardで、9vaeView の ReferencingOutletd の設定を削除していたためだった。右側の丸が+になったときにドラッグして、StoryBoardの中の 9vaeViewとつなぐと設定されるようだ。これで起動したときに、StoryBoardの画面サイズに設定されるみたいだ。また、QvaeView内部のproperty変数の書き方が間違っていたようだ。QvaeViewの中の画像を保持するimageを
(copy, nonatomic)
にすると動くようになった。このあたりはメモリ確保の仕組みを定義しているようだがまだ理解不足。
Objective-C のプロパティ属性のガイドライン - Qiita
文字を書いてみる
QvaeViewが動くようになったので、肝心の文字表示にうつる。CoreTextの書き方を参考にして文字描画を移植。次のような文字が表示できるようになった。まだ、複数行の文字列が表示できない、濁点入りのかなが正しく表示できないといった問題がある。
CFString | Apple Developer Documentation