2015年1月19日月曜日

ファイル閲覧機能のライブラリ化(本編2+使用例編)

Documentsフォルダのファイル閲覧機能をライブラリ化する話の続きです。前回はTableViewだけを生成したので、残りのUI部品の生成を順番に取り上げます。

 

続きの最初は、ファイル内容を表示するTextViewの生成処理です。見出しテキストと文字数を表示する2つのラベルが付きます。ラベルが付きます。

これらの3つのUI部品は、自分で何か処理するわけではなく、TableViewを操作したときに値を設定されるだけの存在です。そのため、単に生成してUIViewに貼付けるだけです。具体的なSwiftコードは、次のようになりました。

// ================================================== ファイル内容を表示
var txvFileText: UITextView! // ファイル内容を表示
var lblFileSize: UILabel!  // 文字数を表示
 
private func setupTxtViewF() {
    // Label
    let iX : CGFloat = W_MARGIN_LEFT + W_TABLE_VIEW + W_MARGIN_CENTER + 5
    let iY : CGFloat = H_MARGIN_TOP
    let iWidth : CGFloat = 300
    let iHeight : CGFloat = H_LABEL_W_MARGIN
    let lblFileText : UILabel = createLblF("選択ファイルの内容", 18, ALIGN_LEFT, iX, iY, iWidth, iHeight)
    self.addSubview(lblFileText)
    // TextView
    let iX2 : CGFloat = W_MARGIN_LEFT + W_TABLE_VIEW + W_MARGIN_CENTER
    let iY2 : CGFloat = H_MARGIN_TOP + H_LABEL_W_MARGIN
    let iWidth2 : CGFloat = viewWidth - (W_MARGIN_LEFT + W_TABLE_VIEW + W_MARGIN_CENTER + W_MARGIN_RIGHT)
    let iHeight2 : CGFloat = viewHeight - (H_MARGIN_TOP + H_LABEL_W_MARGIN + H_BUTTON_MARGIN + H_BUTTON + H_MARGIN_BOTTOM)
    txvFileText = createTxtViewF("", 12, ALIGN_LEFT, iX2, iY2, iWidth2, iHeight2)
    self.addSubview(txvFileText)
    // Label(文字数の表示)
    let iX3 : CGFloat = viewWidth - (W_LABEL_CHAR_COUNT + W_MARGIN_RIGHT + 10)
    let iY3 : CGFloat = H_MARGIN_TOP + 5
    let iWidth3 : CGFloat = W_LABEL_CHAR_COUNT
    let iHeight3 : CGFloat = 20
    lblFileSize = createLblF("", 14, ALIGN_RIGHT, iX3, iY3, iWidth3, iHeight3)
    self.addSubview(lblFileSize)
}

他のUI部品と同じように、表示位置や大きさを4行で計算しています。それぞれのUI部品の生成は、独自ライブラリとして用意しているグローバル関数を使い、どれも1行で書いています。

 

続いて、処理終了やエラーを伝える、メッセージ欄のLabelです。これも同じで、次のようなSwiftコードとなります。

// ================================================== メッセージ欄
var lblMsg : UILabel!

private func setupMsgF() {
    let iX : CGFloat = W_MARGIN_LEFT
    let iY : CGFloat = viewHeight - (H_MARGIN_BOTTOM + 25)
    let iWidth : CGFloat = viewWidth - (W_MARGIN_LEFT + W_BUTTON_COPY + W_MARGIN_RIGHT + 10)
    let iHeight : CGFloat = 25
    lblMsg = createLblF("", 16, ALIGN_RIGHT, iX, iY, iWidth, iHeight)
    self.addSubview(lblMsg)
}

こちらも、他のUI部品と同じような形で生成しています。この次に紹介するコピーボタンの処理結果を、このメッセージ欄に表示します。

 

最後は、TextViewに表示したファイル内容を、クリップボードへとコピーするためのボタンです。ボタンを生成するための関数と、ボタンをタップしたときに呼ばれる関数の2つを用意します。次のようなSwiftコードで。

// ================================================== ファイル内容をコピー
var btnCopy: UIButton!
let psbFileCont : UIPasteboard = UIPasteboard.generalPasteboard()

private func setupBtnCopyF() {
    // ファイル内容をコピーするボタン
    let iX : CGFloat = viewWidth - (W_BUTTON_COPY + W_MARGIN_RIGHT)
    let iY : CGFloat = viewHeight - (H_BUTTON + H_MARGIN_BOTTOM)
    let iWidth : CGFloat = W_BUTTON_COPY
    let iHeight : CGFloat = H_BUTTON
    btnCopy = createBtnF("選択ファイルの内容をコピー", FONT_SIZE_BTN_S, iX, iY, iWidth, iHeight)
    btnCopy.addTarget(self, action:"copyFileTextF:", forControlEvents: .TouchUpInside)
    self.addSubview(btnCopy)
}
// 選択したファイルの内容をコピーする
func copyFileTextF(rSender:UIButton) {
    if enableCopy {
        psbFileCont.setValue(txvFileText.text, forPasteboardType:"public.text") // クリップボードへコピー
        // 完了メッセージを表示
        zBase.setMsgWTimerF(lblMsg, "クリップボードにコピーしました。", .OK, TIME_I_MSG_OK_S)
    } else {
        // 警告メッセージを表示
        zBase.setMsgWTimerF(lblMsg, "コピー可能なファイルを選んでください。", .Caution, TIME_I_MSG_CAU_S)
    }
}

ボタンを生成するsetupBtnCopyF関数では、他のUI部品と同じように、位置と大きさを計算してから生成関数を呼び出しているだけです。ボタンをタップしたときに呼び出される関数を設定している点だけが異なります。

呼び出される関数では、コピーできるファイルかどうかを調べて、可能ならコピーします。コピーの有無に関わらず、結果のメッセージを表示して知らせます。

メッセージの表示には、数秒後に自動で消えるメソッドを使っています。このメソッドは、共通ライブラリとして作ったもので、以前の投稿「数秒後に自動で消えるメッセージ表示」で紹介しました。消えるまでの時間も、メッセージの役割別に複数用意してあり、その中から選んで使っています。メッセージの表示には、このメソッドを使うので、メッセージ欄のLabelにアクセスする関数を別に用意してはいません。

 

ここまで紹介した全てのUI部品は、生成する関数の形で用意して、最初に取り上げた初期処理から呼ばれます。繰り返しになりますが、このような形式で作ることにより、ソースコードがUI部品ごとに区切られ、読みやすさが向上します。

今回作ったクラスのSwiftコードは、以上で終わりです。必要最低限の機能しか作らなかったので、短いソースコードとなりました。これだけでも実用的には十分ですし、iOSの将来の更新にも対応しやすく配慮してもあります。

UIViewの大きさも、ある程度までですが変更可能で、そこそこですが使いやすくできました。このクラスのインスタンスを生成して貼付ければ、Documentsフォルダの中身が見れるようになります。

 

続いて、このクラスの使い方を紹介します。使うのは非常に簡単ですから、手短に。インスタンスを生成してから、位置と大きさを設定して、使う画面に貼り付けるだけです。操作されたときの処理は、TableViewやボタンに付けられるので、生成後に設定する処理はありません。具体的には、次のようなSwiftコードになります。

// 今回のクラスを、アプリで使う例
...
// アプリの初期処理で、共通ライブラリのインスタンス生成
zBase = BaseFunc()      // 基本機能(メッセージなど)
zFiles = BaseFiles()    // ファイル管理機能を開始
...
// この機能を使うUIViewControllerクラス内で、インスタンスを生成して貼り付ける
...
let viewFileBrows = DocsFileView()       // インスタンス生成
viewFileBrows.setupF(50, 100, 900, 600)  // 初期化(表示位置とサイズを指定)
self.view.addSubview(viewFileBrows)      // 親Viewへ貼り付け
...

今回のクラスは、メッセージ表示やファイル処理で、他の共通ライブラリを使っています。それらのインスタンスを先に生成する必要があります。その生成処理は、アプリの初期処理で行ないます。

このクラスを使うのは、対象となる画面表示のUIViewControllerクラス内です。このクラスのインスタンスを生成して、自分のビューに貼り付けるだけです。

貼り付けた画面を使い終わったとき、UIViewControllerのインスタンスが開放されるともに、このクラスのインスタンスも開放されます。

 

大きさが可変のUIViewなので、作成後のテストでは、いろいろな大きさで表示させてみます。最小サイズで正しく動くかはもちろん、サイズを変えてもバランスが悪くならないかなど、主に使い勝手を試します。

もし使い勝手が悪いと感じたら、レイアウトの変更を考えなければなりません。どこを可変にするのか、計算式が複雑になりすぎないか、などを検討します。

ただし、このような機能は、アプリの本来の処理ではありません。何か問題があったときに調べる処理ですから、使い勝手が少しぐらい悪くても、できるだけ単純なアルゴリズムで作れることを重視すべきでしょう。トラブル時に使う処理がトラブったのでは、シャレになりませんので。

 

以上が、独自ライブラリとして作ったファイル閲覧機能クラスの紹介です。今後は最低限の記述だけで、どのアプリにもファイル閲覧機能が付けられます。

サイズの可変にする場合の注意点、レイアウトを想像しやすい定義値の書き方、親クラス自体の機能を拡張しないサブクラスでの配慮点など、作る際に考えていることをいくつか書きました。共感できた点があれば、自分のプログラムでも使ってみてください。

ここまで書き終えてから、改めて気付いた点があります。UIViewを継承しながら、UIView自体を何も拡張していないので、初期化処理としてinit()を付けませんでした。そのような考えは、何か残さないと気付きませんから、ソースコードにコメントとして残すべきですね。これを書き終わった後で、追加しておきます。

 

(使用開発ツール:Xcode 6.1.1, SDK iOS 8.1)

0 件のコメント:

コメントを投稿