【问题标题】:Problem with table cell autolayout not spacing the way I want表格单元格自动布局的问题没有按照我想要的方式间隔
【发布时间】:2020-10-04 07:34:50
【问题描述】:

我正在尝试将我设计的表格单元格放入我的表格视图中,该单元格应该显示艺术家的歌曲、专辑图片以及播放按钮,但我无法以正确的方式获得布局我想要它。

当前应用布局的屏幕截图:

我希望所有播放按钮都齐平到表格视图的右侧,但它似乎无视我在表格视图中放置的约束并且超出了范围。我还想要标签具有的额外空间(如下图链接所示),以便它在整个单元格中留出空间,以便播放按钮可以位于表格视图单元格的右侧。

当前表格视图单元格:

这是我的视图控制器布局和我对它们施加的约束的图片。如果有什么我可以做和改变的,请告诉我。谢谢。

查看控制器布局:

【问题讨论】:

    标签: ios swift uitableview autolayout


    【解决方案1】:

    尝试以编程方式执行此操作,在此示例中,我将 numberOfRowsInSection 设置为返回 20,在 UITableViewCell 类中设置对象:

    let containerViw: UIView = {
        let myView = UIView()
        myView.translatesAutoresizingMaskIntoConstraints = false
        myView.heightAnchor.constraint(equalToConstant: 100).isActive = true
        myView.widthAnchor.constraint(equalToConstant: 100).isActive = true
        return myView
    }()
    
    lazy var buttonPlay: UIButton = {
        let button = UIButton(type: .system)
        let image = UIImage(systemName: "play.circle")
        button.setBackgroundImage(image, for: .normal)
        button.addTarget(self, action: #selector(handlePlay), for: .touchUpInside)
        button.translatesAutoresizingMaskIntoConstraints = false
       
        return button
    }()
    
    let dummyLabel: UILabel = {
        let label = UILabel()
        label.text = "Dummy Label"
        label.font = .systemFont(ofSize: 16, weight: .regular)
        label.textColor = .black
        
        return label
    }()
    
    let finestraBackground: UIImageView = {
        
        let imageView = UIImageView()
        imageView.backgroundColor = .red
        imageView.image = UIImage(named: "yourImage")?.withRenderingMode(.alwaysOriginal)
        imageView.translatesAutoresizingMaskIntoConstraints  = false
        imageView.heightAnchor.constraint(equalToConstant: 100).isActive = true
        imageView.widthAnchor.constraint(equalToConstant: 100).isActive = true
        imageView.layer.cornerRadius = 50
        imageView.layer.masksToBounds = true
        
        return imageView
    }()
    

    现在在 UITableViewCell.CellStyle 中设置 stackView 并添加约束:

    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        
        backgroundColor = .white
        
        containerViw.addSubview(buttonPlay)
        buttonPlay.heightAnchor.constraint(equalToConstant: 50).isActive = true
        buttonPlay.widthAnchor.constraint(equalToConstant: 50).isActive = true
        buttonPlay.centerYAnchor.constraint(equalTo: containerViw.centerYAnchor).isActive = true
        buttonPlay.centerXAnchor.constraint(equalTo: containerViw.centerXAnchor).isActive = true
        
        let stackView = UIStackView(arrangedSubviews: [finestraBackground, dummyLabel, containerViw])
        stackView.distribution = .fillProportionally
        stackView.spacing = 10
        stackView.translatesAutoresizingMaskIntoConstraints = false
        
        contentView.addSubview(stackView)
        stackView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 10).isActive = true
        stackView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 10).isActive = true
        stackView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -10).isActive = true
        stackView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -10).isActive = true
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    

    最后一步设置播放功能:

    @objc fileprivate func handlePlay() {
        print("Play...")
    }
    

    结果如下:

    完整代码:

    class TableViewCellCustom: UITableViewCell {
    
    let containerViw: UIView = {
        let myView = UIView()
        myView.translatesAutoresizingMaskIntoConstraints = false
        myView.heightAnchor.constraint(equalToConstant: 100).isActive = true
        myView.widthAnchor.constraint(equalToConstant: 100).isActive = true
        return myView
    }()
    
    lazy var buttonPlay: UIButton = {
        let button = UIButton(type: .system)
        let image = UIImage(systemName: "play.circle")
        button.setBackgroundImage(image, for: .normal)
        button.addTarget(self, action: #selector(handlePlay), for: .touchUpInside)
        button.translatesAutoresizingMaskIntoConstraints = false
       
        return button
    }()
    
    let dummyLabel: UILabel = {
        let label = UILabel()
        label.text = "Dummy Label"
        label.font = .systemFont(ofSize: 16, weight: .regular)
        label.textColor = .black
        
        return label
    }()
    
    let finestraBackground: UIImageView = {
        
        let imageView = UIImageView()
        imageView.backgroundColor = .red
        imageView.image = UIImage(named: "yourImage")?.withRenderingMode(.alwaysOriginal)
        imageView.translatesAutoresizingMaskIntoConstraints  = false
        imageView.heightAnchor.constraint(equalToConstant: 100).isActive = true
        imageView.widthAnchor.constraint(equalToConstant: 100).isActive = true
        imageView.layer.cornerRadius = 50
        imageView.layer.masksToBounds = true
        
        return imageView
    }()
    
    @objc fileprivate func handlePlay() {
        print("Play...")
    }
    
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        
        backgroundColor = .white
        
        containerViw.addSubview(buttonPlay)
        buttonPlay.heightAnchor.constraint(equalToConstant: 50).isActive = true
        buttonPlay.widthAnchor.constraint(equalToConstant: 50).isActive = true
        buttonPlay.centerYAnchor.constraint(equalTo: containerViw.centerYAnchor).isActive = true
        buttonPlay.centerXAnchor.constraint(equalTo: containerViw.centerXAnchor).isActive = true
        
        let stackView = UIStackView(arrangedSubviews: [finestraBackground, dummyLabel, containerViw])
        stackView.distribution = .fillProportionally
        stackView.spacing = 10
        stackView.translatesAutoresizingMaskIntoConstraints = false
        
        contentView.addSubview(stackView)
        stackView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 10).isActive = true
        stackView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 10).isActive = true
        stackView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -10).isActive = true
        stackView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -10).isActive = true
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    }
    

    更新,以编程方式创建带有顶视图的 tableView 示例,没有情节提要

    import UIKit
    
    class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    
    let cellId = "cellId"
    let tableView = UITableView()
    
    let containerView = UIView()
    let dummyImageView = UIImageView()
    let artistLabel = UILabel()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        artistLabel.text = "Artist Name\nArtist Song Name"
        artistLabel.font = .systemFont(ofSize: 16, weight: .semibold)
        artistLabel.numberOfLines = 0
        artistLabel.textColor = .white
        
        dummyImageView.image = UIImage(named: "yourImage")
        dummyImageView.contentMode = .scaleAspectFill
        dummyImageView.clipsToBounds = true
        dummyImageView.translatesAutoresizingMaskIntoConstraints = false
        dummyImageView.widthAnchor.constraint(equalToConstant: 150).isActive = true
        dummyImageView.heightAnchor.constraint(equalToConstant: 150).isActive = true
        dummyImageView.layer.cornerRadius = 75
        
        containerView.backgroundColor = .darkGray
        containerView.translatesAutoresizingMaskIntoConstraints = false
        
        
        tableView.delegate = self
        tableView.dataSource = self
        tableView.translatesAutoresizingMaskIntoConstraints = false
        
        tableView.register(TableViewCellCustom.self, forCellReuseIdentifier: cellId)
        
        view.addSubview(containerView)
        containerView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
        containerView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor).isActive = true
        containerView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor).isActive = true
        containerView.heightAnchor.constraint(equalToConstant: 200).isActive = true
        
        let stackView = UIStackView(arrangedSubviews: [dummyImageView, artistLabel])
        stackView.axis = .horizontal
        stackView.spacing = 10
        stackView.distribution = .fillProportionally
        stackView.translatesAutoresizingMaskIntoConstraints = false
        
        containerView.addSubview(stackView)
        stackView.heightAnchor.constraint(equalToConstant: 150).isActive = true
        stackView.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: -20).isActive = true
        stackView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: 10).isActive = true
        stackView.centerYAnchor.constraint(equalTo: containerView.centerYAnchor).isActive = true
        
        view.addSubview(tableView)
        tableView.topAnchor.constraint(equalTo: containerView.bottomAnchor).isActive = true
        tableView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor).isActive = true
        tableView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor).isActive = true
        tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
    }
    
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 120
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 20
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as! TableViewCellCustom
        
        return cell
    }
    }
    

    在场景委托中像这样激活导航控制器:

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        guard let windowScene = (scene as? UIWindowScene) else { return }
        
        window = UIWindow(windowScene: windowScene)
        //        let controller = UINavigationController(rootViewController: ViewController())//if you want navigation controller uncomment that
        let controller = ViewController() // if you want navigation Controller COMMENT That
        window?.makeKeyAndVisible()
        window?.rootViewController = controller
    }
    

    或者你可以使用 didSelecrRowAt 方法: 只需在 TableViewController 中添加这两行:

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        print("Play...", indexPath.row)
    }
    

    【讨论】:

    • 我是否要删除我设计的表格单元格并将其保留为空白?我将其删除,然后尝试以编程方式执行此操作,但是当加载表格视图时,未创建单元格。
    • 我用一个示例更新了我的答案,说明如何在没有情节提要的情况下以编程方式创建带有自定义 tableViewCell 的表格视图...创建一个新项目并尝试它,复制并粘贴视图控制器类,创建一个新文件并复制并粘贴自定义单元格,如果我的答案详尽无遗,请将其作为正确答案进行检查:)
    • 可能是我自己解释的不好,把表格的代码复制粘贴一遍,我修改了一下……至于模态展示,把MY ViewController类改个名字就好了(es: ArtistController) 并将您的 ViewController 与呼叫操作按钮一起使用...
    • @raymanan11Hi,添加这个方法,里面有一个标签:func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { let label = UILabel() label.text = "流行歌曲" label.font = .systemFont(ofSize: 16, weight: .bold) label.backgroundColor = .red label.textColor = .white label.textAlignment = .center label .frame = CGRect(x: 0, y: 0, width: view.frame.size.width, height: 100) 返回标签 }
    • @raymanan11after that call height for heather in section like this: func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { return 100 } 就是这样
    【解决方案2】:

    正如我所见,您给出的约束不正确,您可以更改播放按钮的约束,将其拖到超级视图并将其垂直赋予超级视图。如果有的话,请从按钮中删除前导,这将使其位于单元格视图的右侧。

    并将图像 View 作为顶部和底部以及前导约束给 superView,并使 superView 或 cellView 的高度保持不变。

    然后将标签引导约束到 ImageView 并与图像视图/超级视图垂直居中。并给按钮尾随的标签一个固定的联系人,比如只有 10。你很高兴。

    【讨论】:

      【解决方案3】:

      无需代码即可实现。

      只需将“播放按钮”的 Content Compression Resistance Priority 设置为 1000,将 Content Hugging Priority 设置为高于“歌曲名称”标签,例如按钮设置为 251,标签设置为 250。

      【讨论】:

        【解决方案4】:

        我认为这是因为您将 PlayButton 放在 StackView 中。 StackView 自动将您的组件并排放置。 尝试将您的播放按钮放在 StackView 之外,并为 stackView 和 PlayButton 添加约束。

        【讨论】:

          猜你喜欢
          • 2015-03-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-01-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多