セルの高さが可変のUITableView:IBでは機能しますが、プログラムでは機能しません

スラグ:

TL; DR

プログラムで作成したテーブルビューセルはUITableViewAutomaticDimension、上部と下部の両方の制約を使用および設定しているにもかかわらず、カスタムビューの固有のコンテンツの高さに従ってサイズ変更されません

問題はおそらく私のUITableViewCellサブクラスの実装にあります。以下のコードをプログラム機能しない>コード> MyCustomCell.swiftで参照してください

ゴール

カスタムモンゴル語キーボードの提案バーを作成しようとしています。モンゴル語は縦書きです。Androidでは次のようになります。

ここに画像の説明を入力してください

進捗

UITableViewiOS 8以降で利用可能な可変セル高さのを使用する必要があることを学びました。これには、自動レイアウトを使用し、セルの高さの自動寸法を使用するようにテーブルビューに指示する必要があります。

途中で学ばなければならなかったいくつかのことが、最近のSOの質問と回答に示されています。

それで、固有のコンテンツサイズをサポートする垂直ラベルがあるようになりました。これらのラベルは、カスタムテーブルビューのセルに挿入されます。また、次のセクションで説明するように、ストーリーボードで実行すると機能しますが、プログラムですべてを作成すると機能しません。

IBで働く

問題を特定するために、2つの基本的なプロジェクトを作成しました。1つはストーリーボードを使用するプロジェクトで、もう1つはプログラムですべてを行うプロジェクトです。ストーリーボードプロジェクトが機能します。次の画像からわかるように、各テーブルビューのセルは、カスタム垂直ラベルの高さに合わせてサイズ変更されます。

ここに画像の説明を入力してください

IBで

ラベルを中央に配置するだけでなく、上部と下部を固定するように制約を設定しました。

ここに画像の説明を入力してください

コード

ViewController.swift

import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

    let myStrings: [String] = ["a", "bbbbbbb", "cccc", "dddddddddd", "ee"]
    let cellReuseIdentifier = "cell"

    @IBOutlet var tableView: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()

        tableView.delegate = self
        tableView.dataSource = self

        tableView.estimatedRowHeight = 44.0
        tableView.rowHeight = UITableViewAutomaticDimension
    }

    // number of rows in table view
    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.myStrings.count
    }

    // create a cell for each table view row
    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

        let cell:MyCustomCell = self.tableView.dequeueReusableCellWithIdentifier(cellReuseIdentifier) as! MyCustomCell
        cell.myCellLabel.text = self.myStrings[indexPath.row]
        return cell
    }

    // method to run when table view cell is tapped
    func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        print("You tapped cell number \(indexPath.row).")
    }
}

MyCustomCell.swift

import UIKit
class MyCustomCell: UITableViewCell {
    @IBOutlet weak var myCellLabel: UIMongolSingleLineLabel!
}

プログラムで機能しない

提案バーを最終的なキーボードの一部にしたいので、プログラムで作成できるようにする必要があります。ただし、上記のサンプルプロジェクトをプログラムで再作成しようとすると、機能しません。次の結果が得られます。

ここに画像の説明を入力してください

セルの高さはサイズ変更されず、カスタムの垂直ラベルは互いに重なり合っています。

次のエラーも発生します。

Warning once only: Detected a case where constraints ambiguously suggest a height of zero for a tableview cell's content view. We're considering the collapse unintentional and using standard height instead.

This error has been brought up before multiple times on Stack Overflow:

However, the problem for most of those people is that they were not setting both a top and bottom pin constraint. I am, or at least I think I am, as is shown in my code below.

Code

ViewController.swift

import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

    let myStrings: [String] = ["a", "bbbbbbb", "cccc", "dddddddddd", "ee"]
    let cellReuseIdentifier = "cell"
    var tableView = UITableView()

    override func viewDidLoad() {
        super.viewDidLoad()

        // Suggestion bar
        tableView.frame = CGRect(x: 0, y: 20, width: view.bounds.width, height: view.bounds.height)
        tableView.registerClass(MyCustomCell.self, forCellReuseIdentifier: cellReuseIdentifier)
        tableView.delegate = self
        tableView.dataSource = self
        tableView.estimatedRowHeight = 44.0
        tableView.rowHeight = UITableViewAutomaticDimension
        view.addSubview(tableView)
    }

    // number of rows in table view
    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.myStrings.count
    }

    // create a cell for each table view row
    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

        let cell:MyCustomCell = self.tableView.dequeueReusableCellWithIdentifier(cellReuseIdentifier) as! MyCustomCell
        cell.myCellLabel.text = self.myStrings[indexPath.row]
        return cell
    }

    // method to run when table view cell is tapped
    func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        print("You tapped cell number \(indexPath.row).")
    }
}

MyCustomCell.swift

I think the problem is probably in here since this is the main difference from the IB project.

import UIKit
class MyCustomCell: UITableViewCell {

    var myCellLabel = UIMongolSingleLineLabel()

    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        self.setup()
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    func setup() {
        self.myCellLabel.translatesAutoresizingMaskIntoConstraints = false
        self.myCellLabel.centerText = false
        self.myCellLabel.backgroundColor = UIColor.yellowColor()
        self.addSubview(myCellLabel)

        // Constraints
        // pin top
        NSLayoutConstraint(item: myCellLabel, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: self.contentView, attribute: NSLayoutAttribute.TopMargin, multiplier: 1.0, constant: 0).active = true
        // pin bottom
        NSLayoutConstraint(item: myCellLabel, attribute: NSLayoutAttribute.Bottom, relatedBy: NSLayoutRelation.Equal, toItem: self.contentView, attribute: NSLayoutAttribute.BottomMargin, multiplier: 1.0, constant: 0).active = true
        // center horizontal
        NSLayoutConstraint(item: myCellLabel, attribute: NSLayoutAttribute.CenterX, relatedBy: NSLayoutRelation.Equal, toItem: self.contentView, attribute: NSLayoutAttribute.CenterX, multiplier: 1, constant: 0).active = true

    }

    override internal class func requiresConstraintBasedLayout() -> Bool {
        return true
    }
}

Supplemental Code

I'll also include the code for the custom vertical label that I used in both projects above, but since the IB project works, I don't think the main problem is here.

import UIKit
@IBDesignable
class UIMongolSingleLineLabel: UIView {

    private let textLayer = LabelTextLayer()
    var useMirroredFont = false

    // MARK: Primary input value

    @IBInspectable var text: String = "A" {
        didSet {
            textLayer.displayString = text
            updateTextLayerFrame()
        }
    }

    @IBInspectable var fontSize: CGFloat = 17 {
        didSet {
            updateTextLayerFrame()
        }
    }

    @IBInspectable var centerText: Bool = true {
        didSet {
            updateTextLayerFrame()
        }
    }

    // MARK: - Initialization

    override init(frame: CGRect) {
        super.init(frame: frame)
        setup()
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)
        setup()
    }

    func setup() {


        // Text layer
        textLayer.backgroundColor = UIColor.yellowColor().CGColor
        textLayer.useMirroredFont = useMirroredFont
        textLayer.contentsScale = UIScreen.mainScreen().scale
        layer.addSublayer(textLayer)

    }

    override func intrinsicContentSize() -> CGSize {
        return textLayer.frame.size
    }

    func updateTextLayerFrame() {

        let myAttribute = [ NSFontAttributeName: UIFont.systemFontOfSize(fontSize) ]
        let attrString = NSMutableAttributedString(string: textLayer.displayString, attributes: myAttribute )
        let size = dimensionsForAttributedString(attrString)

        // This is the frame for the soon-to-be rotated layer
        var x: CGFloat = 0
        var y: CGFloat = 0
        if layer.bounds.width > size.height {
            x = (layer.bounds.width - size.height) / 2
        }
        if centerText {
            y = (layer.bounds.height - size.width) / 2
        }
        textLayer.frame = CGRect(x: x, y: y, width: size.height, height: size.width)
        textLayer.string = attrString
        invalidateIntrinsicContentSize()
    }

    func dimensionsForAttributedString(attrString: NSAttributedString) -> CGSize {

        var ascent: CGFloat = 0
        var descent: CGFloat = 0
        var width: CGFloat = 0
        let line: CTLineRef = CTLineCreateWithAttributedString(attrString)
        width = CGFloat(CTLineGetTypographicBounds(line, &ascent, &descent, nil))

        // make width an even integer for better graphics rendering
        width = ceil(width)
        if Int(width)%2 == 1 {
            width += 1.0
        }

        return CGSize(width: width, height: ceil(ascent+descent))
    }
}

// MARK: - Key Text Layer Class

class LabelTextLayer: CATextLayer {

    // set this to false if not using a mirrored font
    var useMirroredFont = true
    var displayString = ""

    override func drawInContext(ctx: CGContext) {
        // A frame is passed in, in which the frame size is already rotated at the center but the content is not.

        CGContextSaveGState(ctx)

        if useMirroredFont {
            CGContextRotateCTM(ctx, CGFloat(M_PI_2))
            CGContextScaleCTM(ctx, 1.0, -1.0)
        } else {
            CGContextRotateCTM(ctx, CGFloat(M_PI_2))
            CGContextTranslateCTM(ctx, 0, -self.bounds.width)
        }

        super.drawInContext(ctx)
        CGContextRestoreGState(ctx)
    }
}

Update

The entire code for the project is all here, so if anyone is interested enough to try it out, just make a new project and cut and paste the code above into the following three files:

  • ViewController.swift
  • MyCustomCell.swift
  • UIMongolSingleLineLabel.swift
Sulthan :

The error is pretty trivial:

Instead of

self.addSubview(myCellLabel)

use

self.contentView.addSubview(myCellLabel)

Also, I would replace

// pin top
NSLayoutConstraint(...).active = true
// pin bottom
NSLayoutConstraint(...).active = true
// center horizontal
NSLayoutConstraint(...).active = true

with

let topConstraint = NSLayoutConstraint(...)
let bottomConstraint = NSLayoutConstraint(...)
let centerConstraint = NSLayoutConstraint(...)

self.contentView.addConstraints([topConstraint, bottomConstraint, centerConstraint])

which is more explicit (you have to specify the constraint owner) and thus safer.

問題はactive = true、制約を呼び出すときに、レイアウトシステムが制約を追加するビューを決定する必要があることです。あなたの場合、との最初の共通の祖先はcontentViewmyCellLabelあるのでUITableViewCell、それらはに追加されたUITableViewCellため、実際にはを制約していませんでしたcontentView(制約は、スーパービューとサブビューの間ではなく、兄弟同士の間でした)。

あなたのコードは実際にコンソール警告を引き起こしました:

1回だけ警告:テーブルビューセルのコンテンツビューの高さがゼロであることを制約が曖昧に示唆しているケースを検出しました。意図しない折りたたみを考慮し、代わりに標準の高さを使用しています。

そのため、ラベルの制約が作成される方法をすぐに確認する必要がありました。

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

分類Dev

条件変数プログラムは2つのスレッドでは機能しますが、3つのスレッドでは機能しません

分類Dev

Scrotプログラムのエイリアスは.bashrcでは機能しませんが、ターミナルでは機能します

分類Dev

AdaプログラムはLinuxでは機能しますが、GPS Windows 10では機能しません

分類Dev

OpenGL-NDCでの位置の計算はシェーダーでは機能しますが、「通常の」プログラムでは機能しません

分類Dev

モデルがプログラムで変更された場合、ngChangeは機能しませんか?

分類Dev

JARは機能しませんが、プログラムはIDE内で機能します

分類Dev

CプログラムはGDBで機能しますが、通常は機能しません

分類Dev

私のプログラムではwhileループが正しく機能しません

分類Dev

プログラムでの印刷は機能しますが、gdbは「アドレスのメモリにアクセスできません...」と表示します。

分類Dev

プログラムでツールバーの高さを設定することは、Android4.4では機能しません

分類Dev

プログラムはC ++チューターで実行すると機能しますが、他の場所では機能しません

分類Dev

プログラムは文字列リテラルでは機能しますが、文字列配列では機能しません

分類Dev

同じプログラムはCで機能しますが、C ++では機能しません(Linuxシステムコールを使用)

分類Dev

Linuxサーバーでのサブプロセスの実行は機能しませんが、Windowsではローカルで機能します

分類Dev

リテラルの属性へのアクセスはすべてのタイプで機能しますが、 `int`では機能しません。どうして?

分類Dev

プラグインはレールの外では機能しますが、レールの内側では機能しません

分類Dev

スクリプトタグは本体の内部では機能しますが、外部では機能しません

分類Dev

明るさの変更はUnityで機能しますが、spectrwmでは機能しません

分類Dev

ビューポートのスケーリングは画像の幅では機能しますが、高さでは機能しません

分類Dev

Docker: localhost へのログの送信は機能しませんが、0.0.0.0 は機能します。なぜですか?

分類Dev

ドロワーはAppBarでのみ機能しますが、カスタムAppBarでは機能しません

分類Dev

pyowm呼び出しは独自のプログラムで機能しますが、他のプログラムから呼び出された場合は機能しません

分類Dev

FacebookのログインはChromeで機能しますが、Firefoxでは機能しません

分類Dev

セルの内容がVBAを介して変更された場合、Worksheet_changeは機能しませんが、手動で機能します

分類Dev

プログラムは別のデバイスでは機能しません

分類Dev

LinuxのC ++プロシージャから渡された配列を変更するx64アセンブリのプログラムは機能しませんが、類似のソリューションはx86で機能しました

分類Dev

URLはライブでは機能しませんが、cakephpプロジェクトのローカルでは正常に機能します

分類Dev

ggplotは個々のコードでは機能しますが、ループでは機能しません

分類Dev

ループは関数の外では機能しますが、関数では機能しません。

Related 関連記事

  1. 1

    条件変数プログラムは2つのスレッドでは機能しますが、3つのスレッドでは機能しません

  2. 2

    Scrotプログラムのエイリアスは.bashrcでは機能しませんが、ターミナルでは機能します

  3. 3

    AdaプログラムはLinuxでは機能しますが、GPS Windows 10では機能しません

  4. 4

    OpenGL-NDCでの位置の計算はシェーダーでは機能しますが、「通常の」プログラムでは機能しません

  5. 5

    モデルがプログラムで変更された場合、ngChangeは機能しませんか?

  6. 6

    JARは機能しませんが、プログラムはIDE内で機能します

  7. 7

    CプログラムはGDBで機能しますが、通常は機能しません

  8. 8

    私のプログラムではwhileループが正しく機能しません

  9. 9

    プログラムでの印刷は機能しますが、gdbは「アドレスのメモリにアクセスできません...」と表示します。

  10. 10

    プログラムでツールバーの高さを設定することは、Android4.4では機能しません

  11. 11

    プログラムはC ++チューターで実行すると機能しますが、他の場所では機能しません

  12. 12

    プログラムは文字列リテラルでは機能しますが、文字列配列では機能しません

  13. 13

    同じプログラムはCで機能しますが、C ++では機能しません(Linuxシステムコールを使用)

  14. 14

    Linuxサーバーでのサブプロセスの実行は機能しませんが、Windowsではローカルで機能します

  15. 15

    リテラルの属性へのアクセスはすべてのタイプで機能しますが、 `int`では機能しません。どうして?

  16. 16

    プラグインはレールの外では機能しますが、レールの内側では機能しません

  17. 17

    スクリプトタグは本体の内部では機能しますが、外部では機能しません

  18. 18

    明るさの変更はUnityで機能しますが、spectrwmでは機能しません

  19. 19

    ビューポートのスケーリングは画像の幅では機能しますが、高さでは機能しません

  20. 20

    Docker: localhost へのログの送信は機能しませんが、0.0.0.0 は機能します。なぜですか?

  21. 21

    ドロワーはAppBarでのみ機能しますが、カスタムAppBarでは機能しません

  22. 22

    pyowm呼び出しは独自のプログラムで機能しますが、他のプログラムから呼び出された場合は機能しません

  23. 23

    FacebookのログインはChromeで機能しますが、Firefoxでは機能しません

  24. 24

    セルの内容がVBAを介して変更された場合、Worksheet_changeは機能しませんが、手動で機能します

  25. 25

    プログラムは別のデバイスでは機能しません

  26. 26

    LinuxのC ++プロシージャから渡された配列を変更するx64アセンブリのプログラムは機能しませんが、類似のソリューションはx86で機能しました

  27. 27

    URLはライブでは機能しませんが、cakephpプロジェクトのローカルでは正常に機能します

  28. 28

    ggplotは個々のコードでは機能しますが、ループでは機能しません

  29. 29

    ループは関数の外では機能しますが、関数では機能しません。

ホットタグ

アーカイブ