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

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

ただいまの
回答率

89.64%

【iOS,Swift】UICollectionViewControllerのsizeForItemAtIndexPathでレイアウトが崩れる

受付中

回答 0

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,558

Kesth

score 81

UICollectionViewControllerを使用した
レイアウトに関して質問させてください。

現在下記の様なレイアウトの画面を作成していまして、indexPath.section == 0の方は
高さがカスタムセルの高さによって動的に変化するセル、indexPath.section == 1の方は
高さ固定のセルになります。

イメージ説明
その上で、今回問題が発生しているのが高さ可変の方の
indexPath.section == 0のセルになります。

セルの高さを動的に可変にしたいと思い、下記のような形で
実装しているのですがビルドしてみると上の画像の右側のように
実際のカスタムセルの高さの数倍ほどの高さになっており
ガッツリと余白が空いてしまいます。

カスタムセルを作成

UICollectionViewController上でカスタムセルのインスタンスを生成し
カスタムセル内の要素をすべて内包している要素である
UIView(後述)の高さの値を持つ変数を生成

その変数をsizeForItemAtIndexPathの中で
returnし、高さを返す


なお、カスタムセルは下記のような構成となっています。

UIView(以下の要素を内包し、高さが変動する)
  UIImage(高さ固定)
  UILabel(高さ可変)
  UIButton(高さ固定)


カスタムセル自体の表示では、カスタムセル内の
UIViewの高さは正常に調整されており、レイアウトも
キレイになっているので、UICollectionViewController上で
高さを取得した際に何らかの原因でおかしくなってしまっているのかと
思います。

考えられる原因について、ご教授頂ければ幸いです。


※カスタムセルおよびUICollectionViewControllerの
ソースコードはそれぞれ下記になります。
(文字数の関係上、必要な部分のみ記載します)


import UIKit

class CollectionViewController: UIViewController,UICollectionViewDelegate,UICollectionViewDelegateFlowLayout,UICollectionViewDataSource{

    var collectionView : UICollectionView!
    let sectionInsetsTop = UIEdgeInsets(top:0, left: 0, bottom: 60.0, right: 0)
    let sectionInsets = UIEdgeInsets(top: 10.0, left: 10.0, bottom: 10.0, right: 10.0)
   
    
    override func viewDidLoad(){
        super.viewDidLoad()
               
        let layout = UICollectionViewFlowLayout()
        layout.scrollDirection = .Vertical
        
        collectionView = UICollectionView(frame: CGRect(x: 0, y: 0, width: self.view.bounds.width, height: self.view.bounds.height), collectionViewLayout: layout)
        
        //問題のカスタムセル
        collectionView.registerClass(customCell.self, forCellWithReuseIdentifier: "customCell")
        
        collectionView.delegate = self
        collectionView.dataSource = self
        self.view.addSubview(collectionView)

    }
    
    func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
        return 2
    }
    
    func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        
        switch section{
        case 0:
            return 1 
        case 1:
            return 10   
        default:
            return 0
        }
    }
    
    func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
        
        let customCell = collectionView.dequeueReusableCellWithReuseIdentifier("customCell",forIndexPath: indexPath) as! CustomCell
        
        switch indexPath.section {          
        case 0:     
           return customCell
        case 1:
          //以下、省略    
        }
    }
    
    
    func collectionView(collectionView: UICollectionView,
        layout collectionViewLayout: UICollectionViewLayout,
        insetForSectionAtIndex section: Int) -> UIEdgeInsets {
            
            switch section{
            case 0:
                return sectionInsetsTop
            case 1:
                return sectionInsets
            default:
                return sectionInsets
            }
    }
    
    
    func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
        
        let customCell = CustomCell()
        
     //ここでカスタムセルのUIViewの高さを取得
        let height = customCell.container.frame.size.height
        
        switch indexPath.section{
            
            case 0:
       //カスタムセルのUIViewの高さをセット
                return CGSize(width: self.view.frame.size.width,height: height)
            
            case 1:
                return CGSize(width: (self.view.frame.size.width-10*2)/2, height: 200)
            
            default:
                return CGSizeMake(0,0)
        }
    }
        
}

import UIKit

class CustomCell:UICollectionViewCell{
    
    var container = UIView()
    var image = UIImageView()
    var label = UILabel()
    var button = UIButton()
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
    
    override init(frame: CGRect) {
        super.init(frame: frame)  
        setupView() 
    }
    
    private func setupView(){
        
        let screenWidth = self.bounds.width
      
      self.addSubview(container)
      
        let imageWidth:CGFloat = 69
        let imageHeight:CGFloat = 69
        image.frame = CGRectMake((screenWidth - imageWidth)/2, 10, imageWidth, imageHeight)
        self.container.addSubview(image)
        
        let labelWidth:CGFloat = screenWidth - 40
        label.frame = CGRectMake((screenWidth - labelWidth)/2 ,10 + imageHeight + 10, 10)
        label.text = "変動します"
        label.lineBreakMode = NSLineBreakMode.ByCharWrapping
        label.numberOfLines = 0
        label.font = UIFont(name: "Helvetica Neue", size: 13.5)
        label.sizeToFit()
        let labelHeight = self.label.frame.height
        self.container.addSubview(label)
        
        let buttonWidth:CGFloat = screenWidth - 90
        let buttonHeight:CGFloat = 26
        button.frame = CGRectMake((screenWidth - buttonWidth)/2,10 + imageHeight + 10 + labelHeight + 10, buttonWidth, buttonHeight)
        self.container.addSubview(button)

        //内包するviewの合計height
        let subviewsHeight:CGFloat = 10 + imageHeight + 10 + labelHeight + 10 + buttonHeight + 10
        //subviewsHeightをcontainerのHeightに設定
        container.frame = CGRectMake(0, 0, screenWidth,subviewsHeight)
        
    }
        
}
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

まだ回答がついていません

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

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