Yumico’s blog

iOS開発ブログ

swift: テキストの高さを取得する簡単な方法(UITextView,UILabel)

なんだかんだでよく使う、表示されるテキストの高さを取得する方法。
開発環境:Xcode8 + swift3

UILabel

    func labelHeight(label: UILabel) -> CGFloat{
        label.sizeToFit()
        return label.frame.height
    }

UITextView

    func textViewHeight(textView: UITextView) -> CGFloat {
        return textView.contentSize.height
    }

ただ、上記の方法だとUIから直接取得しているのでAutoLayoutのタイミングとか、Viewを読み込む処理スピードの低下とか色々都合が悪い時がある。 その場合は、NSStringクラスを使用して高さを取得しよう!

    func labelHeight(label: UILabel, s: String) -> CGFloat {
        let str: NSString = NSString(string: s)
        let size : CGSize = CGSize(width: label.frame.width, height: CGFloat.greatestFiniteMagnitude)
        let att: [String: Any] = [NSFontAttributeName: label.font]

        let rect: CGRect = str.boundingRect(with: size, options: NSStringDrawingOptions.usesLineFragmentOrigin, attributes: att, context: nil)
        return rect.height
    }

高さを取得しているのはNSStringクラスのstr.boundingRect(with: CGSize, options: NSStringDrawingOptions, attributes: [String : Any]?, context: NSStringDrawingContext?)メソッド。 設定する引数は下記の通り。

引数 説明
CGSize 表示するUIのサイズ。高さを取得したい場合は幅を表示サイズに、高さをCGFloat.greatestFiniteMagnitudeに設定。 幅を取得したい場合はその逆。
NSStringDrawingOptions テキストの表示方法。 2007-06-19 - at_yasuの日記もといメモ書きにわかりやすく記載してある。
[String : Any]? Attributesを設定。特にAttributedStringとかを使用していない場合は、[NSFontAttributeName: label.font]で良いです。

UITextViewの場合はUILabelをUITextViewに書き換えて使用してください。

UITableViewを実装してみよう!

f:id:Yumico:20161127144055p:plain:w230:right iOSエンジニアとして最初の登竜門的なUIがUITableViewだと思う。
これが理解できたらある程度どんなアプリも開発できる気がする。
まずは基本的な実装方法を。。。
Xcodeでプロジェクトを作成しておいてください。

開発環境:Xcode8 + swift3

1.UITableViewCellを準備しよう

UITalbeViewCellとはテーブルビュー内で表示されるリストの内容です。
基本的に同じデザインを繰り返し表示させる仕組みのため、スクリーンから消えたセルは次に表示されるセルに使い回されます。
エコですね!

UITalbeViewCellのファイルを追加します。

Xcode上で⌘+n>Cocoa Touch Classを選択してNextボタンをタップすると下記の様な感じになります。
f:id:Yumico:20161127151846p:plain

  • Class: 任意のクラス名を入力(今回はTableViewCellとします)
  • Subclass of: UITableViewCellと入力
  • Also create XIB file のチェックボックスをONにする

上記の様に入力したらNextボタンをタップしてCellのクラスを作成してください。
ファイルが2つ追加されているはずです。

  • TableViewCell.swift
  • TableViewCell.xib

cellのUIを完成させよう!

f:id:Yumico:20161127170346p:plain
今回はUILabelを二つ用意しました。
右上で四角に囲ってあるidentifierへの入力をお忘れなく。後ほどUITableViewを実装するときに使用します。
任意のidを入力しますが、今回はTableViewCellにしました。xibのファイル名と同名にすると分かりやすくて良いと思います。

TableViewCell.swiftにコードを書いて行こう!

いきなり完成コード全文。
全コピペ対応してますww

import UIKit

class TableViewCell: UITableViewCell {
    //TableViewCell.xibで追加したUILabelを繋げる。
    @IBOutlet weak var label: UILabel!
    @IBOutlet weak var nameLabel: UILabel!
    
    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
        //このメソッドは初回1回だけ呼ばれますので、1回だけで良い処理(初期化処理)はここに書きます。
    }
    
    //UITableViewで呼び出す用のメソッド。
    //ここでUILabelのテキストを変更しています。
    func setupCell(words: String?, name: String?) {
        label.text = words ?? "no text"
        nameLabel.text = name ?? "no name"
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)
        // Configure the view for the selected state
    }
}

これでUITableViewCellの処理は完成です✨

2.UITableViewを実装しよう!

いよいよメインテーマのテーブルビューです!
基本的な実装はとても簡単です。肩の力を抜いていきましょー。

StoryboardにUITableViewを追加する

f:id:Yumico:20161127144440p:plain
こんな感じでUITableViewをUIViewController全体にベタッと貼り付けます。 今回はUINavigationControllerもつけていますが、つけなくても大丈夫です。

f:id:Yumico:20161127144928p:plain:w100:right
ちなみにUINavigationControllerと合わせて使うケース、非常に多いと思います。 今回のようにUITableViewをUIViewController全体に貼り付ける場合、Adjust Scroll View Insetsにチェックを入れてください。でなければ、NavigationBarとTableViewが被ってしまいます。
右の画像はUIViewControllerの設定です。参考にしてください。

ViewController.swiftにUITableViewを実装する

先ほどのStoryboardでテーブルビューを貼り付けたViewControllerのファイルにコードを追加していきます。
完成コードはこちら。

import UIKit

class ViewController: UIViewController {

    //StoryboardからTableViewを繋げておきます。
    @IBOutlet weak var tableView: UITableView!
    
    //テーブルビューで表示させるデータ。表示内容が多い場合などはstractとかクラスを使うケースが多いかもしれませんが
    //今回はArrayの中にDictionaryを入れ子にした設計で簡単に済ませています。
    var data: [[String:String]] {
        get {
            //それぞれ"words"と"name"をkeyにしたdictionaryを生成
            let w1: [String: String] = ["words" : "歳をとればとるほど、動機こそが大切だという核心が深まる。",           "name" : "スティーブ・ジョブズ"]
            let w2: [String: String] = ["words" : "キャリアではない。私の人生なんだ。",                             "name" : "スティーブ・ジョブズ"]
            let w3: [String: String] = ["words" : "何を捨てるかで誇りが問われ、何を守るかで愛情が問われる。",          "name" : "スティーブ・ジョブズ"]
            let w4: [String: String] = ["words" : "昔を振り返るのはここでやめにしよう。大切なのは明日何が起きるかだ。",  "name" : "スティーブ・ジョブズ"]
            let w5: [String: String] = ["words" : "大事なのは自分の心に素直になることだ。",                         "name" : "スティーブ・ジョブズ"]
            //arrayを生成して上記のdictionaryを追加していきます。
            var d: [[String:String]] = []
            d.append(w1)
            d.append(w2)
            d.append(w3)
            d.append(w4)
            d.append(w5)
            return d
        }
    }
        
    override func viewDidLoad() {
        super.viewDidLoad()
        //dataSourceにselfを設定(これを忘れると、まっさらのTableViewが表示されることとなります)
        self.tableView.dataSource = self
        self.tableView.delegate = self
        //このtableviewで使用するcellを登録します。幾つでも登録できます!
        let nib : UINib = UINib(nibName: "TableViewCell", bundle: nil)
        //forCellReuseIdentifierにはxibファイル内で登録したidentifierと同じ文字列を入れましょう!
        self.tableView.register(nib, forCellReuseIdentifier: "TableViewCell")
        //テーブルビューの余分なセパレーターが気になったから消しちゃいます。
        self.tableView.tableFooterView = UIView()
    }
}

extension ViewController: UITableViewDataSource {
//UITableViewをコントロールするDataSourceを実装します。(最低限必要なメソッドは下記2つのみ!)

    //テーブルビューはまずこのメソッドが呼ばれます。セクションの中でデータがいくつ必要かの数を返します。
    //今回はセクションが1つしかないので、dataの数をそのまま返します。
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return data.count
    }
    
    //セルに値をセットするにはこのメソッドを使います。
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        //indexPathを元にデータを抽出。
        let d : [String : String] = data[indexPath.row]
        //cellを呼び出して値をセットしていきます。(identifierはxibファイルで登録したものと同じ文字列を!)
        let cell: TableViewCell = tableView.dequeueReusableCell(withIdentifier: "TableViewCell", for: indexPath) as! TableViewCell
        cell.setup(words: d["words"], name: d["name"])
        return cell
    }
}

extension ViewController: UITableViewDelegate {
    //テーブルビューのセルが選択されたときに呼ばれます。
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        //選択されたセルの色を解除します。
        tableView.deselectRow(at: indexPath, animated: true)
        
        let d : [String : String] = data[indexPath.row]
        print("「\(d["words"] ?? "no data")」が選択されました!")
    }
}

こちらも全文コピペ対応済みww
貼り付けて実行して色々と触ってみてください。思ったより簡単に実装できるはずです。
不明点だったり、うまくできなかった方はコメントください。
わかる範囲でお答えいたします。