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

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

ただいまの
回答率

88.77%

お世話になります。 Swift初心者です。 お忙しい中大変申し訳ございませんが、 CollectionViewの実装で悩んでおります 長文となりまして、ご面倒をお掛け致しますが、どうぞよろしくお願

解決済

回答 1

投稿

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

sw07

score 6

お世話になります。
Swift初心者です。

お忙しい中大変申し訳ございませんが、
CollectionViewの実装で悩んでおります

長文となりまして、ご面倒をお掛け致しますが、どうぞよろしくお願い致します

現在、1列目と1行目にヘッダ情報が含まれる表形式のビュー(CollectionView利用)を表示させ
左右にスクロールする場合は、表の1列目が固定され
上下にスクロールする場合は、表の1行目が固定されるような画面を構築中です
こちらの回答を参考

1つのセルは、4つのアイテムで構築しておりまして、上から
1段目に「タイトル」文言(UILabel)
2段目にイメージ画像(UIImageView)
3段目に「詳細」文言(UILabel)
そして、中央にチェックボックスのイメージ画像(UIImageView)を配置しセル位置により表示切り替えをします
最左上のセルは何も表示せず
そこを除いた1列目と1行目のセルには、1〜3段目のアイテム、その他のセルにはチェックボックス画像のみを表示する構成となります

構築にあたり、UICollectionViewLayoutを使用しておりまして
スクロールは行えており、各セルに想定したアイテムは配置はされておりますが
可変となるセルのサイズ指定(受け渡し)方法がわからず
また、制約がうまく動作せずで、行き詰まっております

 前提・実現したいこと

1.下記のUIViewController内の★1の計算結果をUICollectionViewLayoutへ渡す方法を知りたいです

2.制約について、タイトルと詳細(UILabel)は折り返しで表示、イメージ画像がある場合はタイトルと詳細の間に差し込みたく、ない場合は上に詰めて表示。チェックボックスは、画面の中央に画像を配置する表示動作を想定しております

 該当のソースコード

▼▼UIViewController

class SelectItemViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {

  @IBOutlet weak var selectView: UICollectionView!

  override func viewDidLoad() {
    super.viewDidLoad()
    selectView.delegate = self
    selectView.dataSource = self
  }

  override func viewWillAppear(_ animated: Bool) {
    // タイトル情報
    getTitles()
    // イメージ画像
    getImages()
  }

  override func viewWillLayoutSubviews() {
    super.viewWillLayoutSubviews()
    // CoreDataから取得したタイトル長とイメージ画像を元に幅と高さ計算(★1)
    cellWidth = getWidth()
    cellHeight = getWidth()
  }

  // セルのサイズ
  func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    return CGSize(width: cellWidth, height: cellHeight)
  }
  // セルの数を返す
  func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
  {
    return columnTitles.count
  }
  func numberOfSections(in collectionView: UICollectionView) -> Int {
    return rowTitles.count
  }
  // セルの設定
  func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
  {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! SelectItemCollectionViewCell

    // 1行目
    if indexPath.section == 0 {
      // 1列目
      if indexPath.row == 0 {
        cell.title.text = ""
        cell.image.image = UIImage(named: "")
        cell.detail.text = ""
        cell.chk.image = UIImage(named: "")
      // 2列目以降
      } else {
        cell.title.text = rowTitles[indexPath.row]
        cell.image.image = UIImage(named: rowImages[indexPath.row])
        cell.detail.text = rowDetails[indexPath.row]
        cell.chk.image = UIImage(named: "")
        cell.isRowImage = isRowImage
        // 制約
        cell.configure(indexPath: indexPath)
      }
    // 2行目以降
    } else {
      // 1列目
      if indexPath.row == 0 {
        cell.title.text = columnTitles[indexPath.section]
        cell.image.image = UIImage(named: columnImages[indexPath.section])
        cell.detail.text = columnDetails[indexPath.section]
        cell.chk.image = UIImage(named: "")
        cell.isColumnImage = isColumnImage
        // 制約
        cell.configure(indexPath: indexPath)
      // 2列目以降
      } else {
        cell.title.text = ""
        cell.image.image = UIImage(named: "")
        cell.detail.text = ""
        cell.chk.image = UIImage(named: "Check_off")
        // 制約
        cell.configure(indexPath: indexPath)
      }
    }
    return cell
  }
}


▼▼UICollectionViewCell

class SelectItemCollectionViewCell: UICollectionViewCell {

  @IBOutlet weak var title: UILabel!
  @IBOutlet weak var image: UIImageView!
  @IBOutlet weak var detail: UILabel!
  @IBOutlet weak var chk: UIImageView!
  var isRowImage: Bool = false
  var isColumnImage: Bool = false

  // セルの制約
  func configure(indexPath: IndexPath)
  {
    // 1行目
    if indexPath.section == 0 {
      // 1列目
      if indexPath.row == 0 {
        // 制約なし
      // 2列目以降
      } else {
        // 行タイトル
        title.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
          title.topAnchor.constraint(equalTo: self.topAnchor, constant: 5.0),
          title.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 2.0),
          title.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: 2.0),
          title.bottomAnchor.constraint(greaterThanOrEqualTo: self.bottomAnchor, constant: -150.0)
        ])
        // 画像イメージ
        image.translatesAutoresizingMaskIntoConstraints = false
          if isRowImage == true {
            image.heightAnchor.constraint(equalToConstant: 72.0).isActive = true
            image.widthAnchor.constraint(equalToConstant: 128.0).isActive = true
          }
        image.topAnchor.constraint(equalTo: title.bottomAnchor, constant: 1.0).isActive = true
        image.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 5.0).isActive = true
        // 行詳細
        detail.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
          detail.topAnchor.constraint(equalTo: image.bottomAnchor, constant: 1.0),
          detail.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 5.0),
          detail.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: 5.0),
          detail.bottomAnchor.constraint(greaterThanOrEqualTo: self.bottomAnchor, constant: -150.0)
        ])
      }
    // 2行目以降
    } else {
      // 1列目
      if indexPath.row == 0 {
        // 列タイトル
        title.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
          title.topAnchor.constraint(equalTo: self.topAnchor, constant: 5.0),
          title.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 2.0),
          title.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: 2.0),
          title.bottomAnchor.constraint(greaterThanOrEqualTo: self.bottomAnchor, constant: -150.0)
        ])
        // 画像イメージ
        image.translatesAutoresizingMaskIntoConstraints = false
        if isColumnImage == true {
          image.heightAnchor.constraint(equalToConstant: 72.0).isActive = true
          image.widthAnchor.constraint(equalToConstant: 128.0).isActive = true
        }
        image.topAnchor.constraint(equalTo: title.bottomAnchor, constant: 1.0).isActive = true
        image.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 2.0).isActive = true
        // 列詳細
        detail.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
          detail.topAnchor.constraint(equalTo: image.bottomAnchor, constant: 1.0),
          detail.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 2.0),
          detail.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: 2.0),
          detail.bottomAnchor.constraint(greaterThanOrEqualTo: self.bottomAnchor, constant: -150.0)
        ])
      // 2列目以降
      } else {
        // 制約なし
      }
    }
  }
}


▼▼UICollectionViewLayout

class SelectItemUICollectionViewLayout: UICollectionViewLayout {

  var columns = 0
  var shouldPinFirstColumn = true
  var shouldPinFirstRow = true
  var itemAttributes = [[UICollectionViewLayoutAttributes]]()
  var itemsSize = [CGSize]()
  var contentSize: CGSize = .zero

  override func prepare() {
    (省略)
    if itemAttributes.count != collectionView.numberOfSections {
      generateItemAttributes(collectionView: collectionView)
      return
    }

    for section in 0..<collectionView.numberOfSections {
      for item in 0..<collectionView.numberOfItems(inSection: section) {
      (省略)
      }
    }
  }

  override var collectionViewContentSize: CGSize {
    return contentSize
  }

  override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
    return itemAttributes[indexPath.section][indexPath.row]
  }

  override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
    (省略)
    return attributes
  }

  override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
    return true
  }
}

// MARK: - Helpers
extension SelectItemUICollectionViewLayout {

  func generateItemAttributes(collectionView: UICollectionView) {
    if itemsSize.count != columns {
      calculateItemSizes()
    }

    var column = 0
    var xOffset: CGFloat = 0
    var yOffset: CGFloat = 0
    var contentWidth: CGFloat = 0
    itemAttributes = []

    for section in 0..<collectionView.numberOfSections {
      var sectionAttributes: [UICollectionViewLayoutAttributes] = []
      for index in 0..<columns {
        let itemSize = itemsSize[index]
        let indexPath = IndexPath(item: index, section: section)
        let attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath)
        attributes.frame = CGRect(x: xOffset, y: yOffset, width: itemSize.width, height: itemSize.height).integral
        (省略)
      }
      itemAttributes.append(sectionAttributes)
    }
    if let attributes = itemAttributes.last?.last {
      contentSize = CGSize(width: contentWidth, height: attributes.frame.maxY)
    }
  }

  func calculateItemSizes() {
    itemsSize = []
    for index in 0..<columns {
      itemsSize.append(sizeForItemWithColumnIndex(index))
    }
  }

  func sizeForItemWithColumnIndex(_ columnIndex: Int) -> CGSize {
    var text: NSString
    // ここでUIViewController内で計算したwidthとheightを利用したい
    return CGSize(width: 250, height: 200)
  }
}

 試したこと

1.について
UIViewControllerの「セルのサイズ」で計算した高さと幅を返すようにしておりますが、
この処理自体が呼び出されておらず、他にUICollectionViewLayout側へ計算値を渡す方法がないか模索中です。

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

swift4
xCode10.0

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 1

check解決した方法

-4

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/11/06 15:01

    質問は修正できますので、間違えた場合や修正依頼があった場合は随時修正して対応した方が良いです。

    キャンセル

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

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

関連した質問

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

  • トップ
  • Swiftに関する質問
  • お世話になります。 Swift初心者です。 お忙しい中大変申し訳ございませんが、 CollectionViewの実装で悩んでおります 長文となりまして、ご面倒をお掛け致しますが、どうぞよろしくお願