質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.92%

SwiftにてTableViewCellなどの細かい位置調整がしたい

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 193

Atsushi_Kygo

score 5

GoogleKeepのような見た目をSwiftで作成したい

現在SwiftでGoogleKeepのようなアプリ(Todoリストアプリ)を作成しようとしています。
TableViewCell・TableViewHeaderの位置調整を細かくしたいのですが、どこを変更すれば良いかがわかりません。
(チェックボックスなどは一旦置いときます)
初心者のため初歩的な質問かもしれませんがよろしくお願いします。

【現在のシミュレーター↓】
![現在のシミュレーター
【完成形のデザイン↓】
完成形のデザイン

発生している問題・エラーメッセージ

//  viewForHeaderInSectionメソッド内にて
// この記述が適用されない&この記述が適切か分からない(セクションタイトルの位置を変更しようとしている)
sectionTitle.frame = CGRect(x:50, y:10, width: 100, height: 50)

該当のソースコード

import UIKit

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UITextFieldDelegate {

    @IBOutlet weak var tableView: UITableView!
    @IBOutlet weak var textField: UITextField!

    var notSelectedList = ["リストアイテム1", "リストアイテム2"] 
    var selectedList = [String]()
    var thisSectionTitle = "タイトル"

    override func viewDidLoad() {
        super.viewDidLoad()

        tableView.delegate = self
        tableView.dataSource = self
        textField.delegate = self
    }


    // セクションの数
    func numberOfSections(in tableView: UITableView) -> Int {
        return 2
    }


    // セクションタイトルの微調整
    func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {

        let sectionTitle: UILabel = UILabel()
        sectionTitle.backgroundColor = .white
        sectionTitle.textColor = .black
        // 以下のコードが適用されない
        // sectionTitle.frame = CGRect(x:50, y:10, width: 100, height: 50)

        if section == 0 {
            sectionTitle.text = thisSectionTitle
            tableView.sectionHeaderHeight = 40
            sectionTitle.font = UIFont.systemFont(ofSize: 28.0)
        } else {
            sectionTitle.text = "選択中のアイテム ▼"
        }

        return sectionTitle
    }


    // セルの個数
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if section == 0 {
            return notSelectedList.count
        } else {
            return selectedList.count
        }
    }


    // セルの設定
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        // identifierに紐づいたセルを取得し、変数cellに代入
        let cell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)

        if indexPath.section == 0 {
            cell.textLabel!.text = notSelectedList[indexPath.row]
        } else {
            cell.textLabel!.text = selectedList[indexPath.row]
        }

        return cell

    }
}

試したこと・調べたこと

・layoutMarginsについて調べた
(マージンを0にする記事が多く、よく分からなかった)

・UIEdgeInsetsについて調べた
(記述方法等がよく分からなかった)

・カスタムセルについて調べた
(調べた限りではカスタムセルにするほどでもないと予想)

補足情報(FW/ツールのバージョンなど)

Swift version 5.2.4

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • TsukubaDepot

    2020/07/15 21:52

    実現されたいことが具体的に想像できないので(細かくしたいのであれば尚更)、できれば図を用いて(現時点でのスクリーンキャプチャに手書きなどでこのへんをこうしたい、など)説明していただければ助かりますのでご検討ください。

    キャンセル

  • Atsushi_Kygo

    2020/07/15 22:37

    修正依頼ありがとうございます。

    キャンセル

回答 1

checkベストアンサー

+1

実際に GoogleKeep をインストールしてみました。
GoogleKeep がどのような技術を使って実現されているのかはわかりませんが

・カスタムセルについて調べた
(調べた限りではカスタムセルにするほどでもないと予想)

これが一番楽だと思います。

マージンなどを調整する方法もあると思いますが、AutoLayout という技術があるのですから、それを活用した方が楽かと思います。

基本的には

  • タイトルを表示するカスタムセル 
  • 個別の ToDo を表示するカスタムセル

を作ります。
それぞれのカスタムセル内に必要なラベルやボタンなどを配置し、カスタムセルを基準して制約をつけていけば、セルの生成時に細かい作業を行わなくても思ったような表示ができるのではないでしょうか。

いま簡単に作ってみましたが、

イメージ説明

こんな感じになります。

制約などは次のような感じです。

イメージ説明

作ってしまったので、ソースコードも貼っておきます。

ただ注意していただきたいのは、下記のコードにおけるデータの管理方法は褒められた例ではない、ということです。

データ(オブジェクト)の管理方法はいろいろあるかと思いますが、私は全然勉強が追いついていないのでこんな感じの管理方法となっていますが、それについては是非ご自身で理解を深めていただければと思います。

import UIKit

class Item {
    var isDone = false
    var itemTitle = ""

    init(itemTitle title: String, done: Bool) {
        self.itemTitle = title
        self.isDone = done
    }
}

class ToDo {
    var title = ""
    var items = [Item]()
}

class ViewController: UIViewController, UITableViewDataSource {

    @IBOutlet weak var todoListTable: UITableView!
    var todo = ToDo()

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.

        todoListTable.dataSource = self

        // 区切り線を消す
        // 一部だけ消すのであれば
        // https://qiita.com/takashings/items/693ba4b31d07dbe90778
        todoListTable.separatorStyle = .none

        // 仮の ToDo を作る
        todo.title = "きょうやること"
        todo.items.append(Item(itemTitle: "朝起きる", done: true))
        todo.items.append(Item(itemTitle: "歯を磨く", done: false))
        todo.items.append(Item(itemTitle: "マスクをする", done: true))
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // 表示したいセルはToDo の 「要素数 + タイトル」
        let itemCount = todo.items.count + 1

        return itemCount
    }

    // MARK: セルの表示行数によって使うセルを切り替える
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        if indexPath.row == 0 {
            // タイトル
            let headerCell = tableView.dequeueReusableCell(withIdentifier: "Header", for: indexPath) as! HeaderTableViewCell
            headerCell.titleLabel.text = todo.title

            return headerCell
        } else {
            // 個別の ToDo
            let itemCell = tableView.dequeueReusableCell(withIdentifier: "Item", for: indexPath) as! ItemTableViewCell
            let item = todo.items[indexPath.row - 1]
            itemCell.item = item

            itemCell.updateCell()

            //print("cell: ", indexPath.row)
            //dump(item)

            return itemCell
        }
    }
}

class HeaderTableViewCell: UITableViewCell {
    @IBOutlet weak var titleLabel: UILabel!

    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
    }

}

class ItemTableViewCell: UITableViewCell {
    @IBOutlet weak var itemLabel: UILabel!
    @IBOutlet weak var checkButton: UIButton!

    // MARK: セルにでも個別の ToDo を保持する
    var item: Item!

    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
    }

    // MARK: セルの状態変更
    func updateCell () {
        itemLabel.text = item.itemTitle

        if item.isDone {
            checkButton.setImage(UIImage(systemName: "checkmark.rectangle"), for: .normal)
        } else {
            checkButton.setImage(UIImage(systemName: "rectangle"), for: .normal)
        }
    }

    // MARK: チェックマークが呼び出された時
    @IBAction func buttonSelected(_ sender: Any) {
        //dump(item)
        item.isDone.toggle()

        // self (つまり、このクラス)の superView は UITableView
        // UITableView.reloadData() を呼び出している
        (self.superview as! UITableView).reloadData()
    }
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/07/17 22:10

    GoogleKeepのインストールやアプリの作成など何から何まで本当にありがとうございます。
    解説等もわかりやすく、非常に参考になりました。
    カスタムセルでの開発に取り組んでみます!

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.92%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る