在 Swift 中以编程方式将 UIImageView 左右对齐

Posted

技术标签:

【中文标题】在 Swift 中以编程方式将 UIImageView 左右对齐【英文标题】:Aligning UIImageView to the left and right programmatically in Swift 【发布时间】:2018-04-13 02:29:15 【问题描述】:

我正在开发一个带有消息气泡的聊天应用程序。我已经弄清楚了如何根据发送消息的人有条件地格式化消息(颜色、大小等);但是我很难让聊天气泡与视图控制器的左侧或右侧对齐。现在所有项目都向左对齐。我已经搜索过 SO 并且无法找到答案,所以我决定问。

更新:显示 setCell 函数的剩余代码,该函数根据“传入”的值确定消息的格式。还包括 tableView 功能以显示单元格配置。最后一个函数是设置函数。

func setCell(cell: ConversationCell, incoming: [Int], indexPath: IndexPath) 

    var layoutAttribute: NSLayoutAttribute
    var layoutConstant: CGFloat
    var smavalayoutConstant: CGFloat
    for i in 0 ..< self.incoming.count 

        if (self.incoming[indexPath.row] == 1) 
            cell.bubbleImageView.image=#imageLiteral(resourceName: "chat_bubble_received")
            cell.messageLbl.textColor = UIColor.black
            cell.messageLbl.textAlignment = .left
            cell.messageLbl?.numberOfLines = 0
            cell.messageLbl?.lineBreakMode = .byWordWrapping
            layoutAttribute = .left
            layoutConstant = 0
            cell.contentView.addConstraint(NSLayoutConstraint(item: cell.bubbleImageView, attribute: .left, relatedBy: .equal, toItem: cell.contentView, attribute: layoutAttribute, multiplier: 1, constant: layoutConstant))
            cell.contentView.addConstraint(NSLayoutConstraint(item: cell.smavaImg, attribute: .left, relatedBy: .equal, toItem: cell.contentView, attribute: layoutAttribute, multiplier: 1, constant: layoutConstant))
            cell.contentView.addConstraint(NSLayoutConstraint(item: cell.postpictureImg, attribute: .left, relatedBy: .equal, toItem: cell.contentView, attribute: layoutAttribute, multiplier: 1, constant: layoutConstant))
        
        if (self.incoming[indexPath.row] == 0) 
            cell.bubbleImageView.image = #imageLiteral(resourceName: "chat_bubble_sent")
            cell.messageLbl.textColor = UIColor.white
            cell.messageLbl.textAlignment = .right
            layoutAttribute = .right
            layoutConstant = -100
            smavalayoutConstant = 300
            cell.contentView.addConstraint(NSLayoutConstraint(item: cell.bubbleImageView, attribute: .leftMargin, relatedBy: .lessThanOrEqual, toItem: cell.contentView, attribute: layoutAttribute, multiplier: 1, constant: layoutConstant))
            cell.contentView.addConstraint(NSLayoutConstraint(item: cell.bubbleImageView, attribute: .right, relatedBy: .equal, toItem: cell.contentView, attribute: layoutAttribute, multiplier: 1, constant: layoutConstant))
            cell.contentView.addConstraint(NSLayoutConstraint(item: cell.smavaImg, attribute: .right, relatedBy: .equal, toItem: cell.smavaImg, attribute: layoutAttribute, multiplier: 1, constant: smavalayoutConstant))
            cell.contentView.addConstraint(NSLayoutConstraint(item: cell.smavaImg, attribute: .left, relatedBy: .equal, toItem: cell.smavaImg, attribute: .left, multiplier: 1, constant: 300))


        
    

//单元配置

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 

let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! ConversationCell

// shortcuts
let hhpost = hhmessages[indexPath.row]
let image = avas[indexPath.row]
let smimages = images[indexPath.row]


let messagetext = hhpost["messagetext"] as? String
let date = hhpost["date"] as? String
cell.messageLbl.text = messagetext
cell.dateLbl.text = date
cell.smavaImg.image = image
cell.postpictureImg.image = smimages
DispatchQueue.main.async 

    tableView.transform = CGAffineTransform(rotationAngle: -CGFloat.pi)
    cell.transform = CGAffineTransform(rotationAngle: CGFloat.pi)
    self.setCell(cell: cell, incoming: self.incoming, indexPath: indexPath)


return cell


    public func setup() 
    bubbleImageView = UIImageView(image: #imageLiteral(resourceName: "chat_bubble_sent"), highlightedImage: #imageLiteral(resourceName: "chat_bubble_sent"))
    bubbleImageView.isUserInteractionEnabled = true

    messageLbl = UILabel(frame: CGRect.zero)
    messageLbl.font = UIFont.systemFont(ofSize: 15)
    messageLbl.numberOfLines = 0
    messageLbl.isUserInteractionEnabled = true
    selectionStyle = .none
    contentView.addSubview(bubbleImageView)
    contentView.addSubview(smavaImg)
    bubbleImageView.addSubview(messageLbl)
    messageLbl.translatesAutoresizingMaskIntoConstraints = false
    bubbleImageView.translatesAutoresizingMaskIntoConstraints = false
    contentView.addConstraint(NSLayoutConstraint(item: bubbleImageView, attribute: .left, relatedBy: .equal, toItem: contentView, attribute: .left, multiplier: 1, constant: 10))
    contentView.addConstraint(NSLayoutConstraint(item: bubbleImageView, attribute: .top, relatedBy: .equal, toItem: contentView, attribute: .top, multiplier: 1, constant: 4.5))
    bubbleImageView.addConstraint(NSLayoutConstraint(item: bubbleImageView, attribute: .width, relatedBy: .equal, toItem: messageLbl, attribute: .width, multiplier: 1, constant: 30))
    contentView.addConstraint(NSLayoutConstraint(item: bubbleImageView, attribute: .bottom, relatedBy: .equal, toItem: contentView, attribute: .bottom, multiplier: 1, constant: -4.5))

    bubbleImageView.addConstraint(NSLayoutConstraint(item: messageLbl, attribute: .centerX, relatedBy: .equal, toItem: bubbleImageView, attribute: .centerX, multiplier: 1, constant: -2))

    bubbleImageView.addConstraint(NSLayoutConstraint(item: messageLbl, attribute: .centerY, relatedBy: .equal, toItem: bubbleImageView, attribute: .centerY, multiplier: 1, constant: -0.5))
    messageLbl.preferredMaxLayoutWidth = 218
    bubbleImageView.addConstraint(NSLayoutConstraint(item: messageLbl, attribute: .height, relatedBy: .equal, toItem: bubbleImageView, attribute: .height, multiplier: 1, constant: -15))

    contentView.addConstraint(NSLayoutConstraint(item: smavaImg, attribute: .centerX, relatedBy: .equal, toItem: smavaImg, attribute: .centerX, multiplier: 1, constant: -2))

    contentView.addConstraint(NSLayoutConstraint(item: smavaImg, attribute: .centerY, relatedBy: .equal, toItem: smavaImg, attribute: .centerY, multiplier: 1, constant: -0.5))


【问题讨论】:

你可以阅读如何做,或者使用这个框架github.com/MessageKit/MessageKit或者这个github.com/jessesquires/JSQMessagesViewController 您是否以编程方式创建了单元格视图? @maximo 我实际上是在情节提要中创建了它,但其余的自定义是通过编程完成的 @techgirl 你用的是collectionView、tableView还是scrollView?在将单元格返回到 CollectionView 或 TableView 之前在单元格内创建约束不是一个好方法。相反,最好在单元格内创建约束并在返回单元格以显示在 CollectionView 或 TableView 控制器中之前更改参数。给我更多关于你的项目的信息,我会尽力帮助你解决这个问题。 @maximo 非常感谢。我正在使用表格视图。我列出的代码位于使用单元格参数作为输入的函数中 【参考方案1】:

在您的 Playground 中查看我的 git hub 项目 // 马克西莫卢科西:https://github.com/lucosi/ChatTableView 您可以使用所有约束创建 tableViewCell 并更改单元格内的约束。 在 Playgournd > View > Assistant Editor > Show Assistant Editor 中打开项目

类 MyViewController: UIViewController

// Messages for test
var messages: [Message] = []

// Table View here + basic configuration
lazy var tableView: UITableView = 
    let view = UITableView()
    view.translatesAutoresizingMaskIntoConstraints = false
    view.delegate = self
    view.dataSource = self
    view.backgroundColor = .white
    view.separatorStyle = .none
    return view
()

override func viewDidLoad() 
    super.viewDidLoad()

    // Set the screen size befor implement layour. NOTICE: Only for playground test
    self.view.frame = frame

    // Messages for test //
    self.messages.append(Message.init(message: "I'm working on a chat app with message bubbles.",
                                      image: UIImage.init(),
                                      incoming: 0))

    self.messages.append(Message.init(message: "What is your dificulte.",
                                      image: UIImage(),
                                      incoming: 1))

    self.messages.append(Message.init(message: "I'm having difficulty getting the chat bubbles to align to the left or right side of the view controller.",
                                      image: UIImage.init(),
                                      incoming: 0))

    self.messages.append(Message.init(message: "One more for me",
                                      image: UIImage(),
                                      incoming: 1))

    self.messages.append(Message.init(message: "I have already implemented a function that redraws UILabels with a passed ratio. So all I need to find is the text in UILabel from my view that would require the maximum ratio to redraw UILabels. So finally I need to do something like this:",
                                      image: UIImage(), incoming: 1))
    // End //


    // Add the tableView
    self.view.addSubview(tableView)

    // Register teh cell in the tableView
    self.tableView.register(ConversationCell.self, forCellReuseIdentifier: cellId)

    // Criate a contraint for the table view
    NSLayoutConstraint.activate(
        [
            tableView.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 44),
            tableView.leftAnchor.constraint(equalTo: self.view.leftAnchor),
            tableView.rightAnchor.constraint(equalTo: self.view.rightAnchor),
            tableView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor)
        ]
    )

扩展字符串

//* Calculeta the hight string Function
func calculateTextFrameRect(
    objectsInPlaceHeight: CGFloat,
    objectsInPlaceWidth: CGFloat,
    fontSize: CGFloat,
    fontWeight: CGFloat) -> CGSize

    let bounding = CGSize(width: UIScreen.main.bounds.width - objectsInPlaceWidth, height: .infinity)
    let rect = NSString(string: self).boundingRect(
        with: bounding,
        options: NSStringDrawingOptions.usesFontLeading.union(NSStringDrawingOptions.usesLineFragmentOrigin),
        attributes: [NSAttributedStringKey.font: UIFont.systemFont(ofSize: fontSize, weight: UIFont.Weight(rawValue: fontWeight))],
        context: nil)
    return CGSize(width: UIScreen.main.bounds.width, height: rect.height + objectsInPlaceHeight )

// 使表视图与委托和数据源一致 扩展 MyViewController: UITableViewDelegate, UITableViewDataSource

// Change the hight of the cell
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat 

    // Calculate the hight of the cell
    let text = self.messages[indexPath.item].message
    let frameSize = text.calculateTextFrameRect(
        objectsInPlaceHeight: 44 + 10,
        objectsInPlaceWidth: 20 + 44 + 20 + self.view.frame.width * 0.4,
        fontSize: UIFont.preferredFont(forTextStyle: UIFontTextStyle.body).pointSize,
        fontWeight: UIFont.Weight.medium.rawValue)
    return frameSize.height


// Number os cells
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
    return self.messages.count


// Return cell to display on the tableView
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 

    let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as! ConversationCell
    cell.messageData = self.messages[indexPath.item]
    return cell


//****** 自定义单元格类 ******/// 类 ConversationCell: UITableViewCell

var messageData: Message? 
    didSet 
        // Umrap the value incide the cell
        if let message = messageData 

            // Confiture the constraints for cell
            if message.incoming == 0 
                // Text
                self.messageTextView.textAlignment = .left
                self.bubleImage.backgroundColor = .orange

                // Constraints
                self.lefBubleConstraint.isActive = true
                self.rightBubleConstraint.isActive = false

             else 
                // Text
                self.messageTextView.textAlignment = .right
                self.bubleImage.backgroundColor = .blue

                // Constraints
                self.lefBubleConstraint.isActive = false
                self.rightBubleConstraint.isActive = true

            

            if lefBubleConstraint.isActive == true 

                self.leftMessageLable.isActive = true
                self.rightMessageLable.isActive = false

             else 

                self.leftMessageLable.isActive = false
                self.rightMessageLable.isActive = true

            

            // Set the data
            self.messageTextView.text = message.message
            self.bubleImage.image = message.image

        
    


// Create and config the image
let bubleImage: UIImageView = 
    let view = UIImageView()
    view.translatesAutoresizingMaskIntoConstraints = false
    view.backgroundColor = .blue
    view.layer.cornerRadius = 22
    view.layer.masksToBounds = true
    return view
()

// Create and config the lable for the text
let messageTextView: UITextView = 
    let view = UITextView()
    view.translatesAutoresizingMaskIntoConstraints = false
    view.backgroundColor = UIColor.lightGray.withAlphaComponent(0.5)
    view.layer.cornerRadius = 10
    view.textContainerInset = UIEdgeInsetsMake(5, 5, 5, 5)
    view.isUserInteractionEnabled = false
    return view
()

// Constraints for configuration on didSet data
var lefBubleConstraint: NSLayoutConstraint!
var rightBubleConstraint: NSLayoutConstraint!
var leftMessageLable: NSLayoutConstraint!
var rightMessageLable: NSLayoutConstraint!

// Init the cell with local congiguration
override init(style: UITableViewCellStyle, reuseIdentifier: String?) 
    super.init(style: style, reuseIdentifier: nil)

    self.addSubview(bubleImage)
    self.addSubview(messageTextView)

    // Permanent constraints
    NSLayoutConstraint.activate(
        [
            self.bubleImage.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -10),
            self.bubleImage.heightAnchor.constraint(equalToConstant: 44),
            self.bubleImage.widthAnchor.constraint(equalToConstant: 44),

            self.messageTextView.topAnchor.constraint(equalTo: self.topAnchor, constant: 10),
            self.messageTextView.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -10),
            // NOTICE: Use the frame with as parameter for mesure the hight of cell on the main view
            self.messageTextView.widthAnchor.constraint(equalToConstant: self.frame.width * 0.7)
        ]
    )

    // Buble constraint for configuration
    self.lefBubleConstraint = self.bubleImage.leftAnchor.constraint(equalTo: self.leftAnchor, constant: 10)
    self.rightBubleConstraint = self.bubleImage.rightAnchor.constraint(equalTo: self.rightAnchor, constant: -10)

    // Message constrait for congiguration
    self.rightMessageLable = self.messageTextView.rightAnchor.constraint(equalTo: self.bubleImage.leftAnchor, constant: -10)
    self.leftMessageLable = self.messageTextView.leftAnchor.constraint(equalTo: self.bubleImage.rightAnchor, constant: 10)


// requerid init
required init?(coder aDecoder: NSCoder) 
    fatalError("init(coder:) has not been implemented")

【讨论】:

非常感谢。立即阅读并努力将其合并。敬请期待。 我在用我的数据库中的数组替换示例数据时遇到了一点问题。 现在当我查看对话并给出错误“无法将'__NSDictionaryM' (0x1128074f8) 类型的值转换为'Project.Message' (0x10f7f1478)”时它崩溃了。我有一个名为 loadMessages 的函数,它可以获取所有消息数据。 好的,我能够修复崩溃。但格式仍然全部向左对齐。 @teckgirl 我已尽力帮助您开发应用程序。现在您可以参考尝试解决代码中的问题。最好的;-)

以上是关于在 Swift 中以编程方式将 UIImageView 左右对齐的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Swift 4 中以编程方式将 IBAction 添加到按钮?

在 Swift 4 中以编程方式将 UIImageView、UILabel 添加到 UIStackView

在 Swift 中以编程方式将 UIImageView 左右对齐

在 Swift 中以编程方式将视图添加到 stackview

当 iAd 横幅出现时,如何将视图的内容上移? (在 Swift 中以编程方式)

我想通过在 Swift 中以编程方式将 UINavigationController 与 UITableViewController 嵌入 UITableViewController 这是 UITab