1. Using UITextView
  2. estimatedSizeCell
  3. anchoredConstratints
    • from LBTATools
  4. Update a ownership of each chat bubble
    • Using struct

Using UITextView

Using LBTAListController currently!

Message : LBTAListCell : LBTAListController<MessageCell, Message>

struct Message {
    let text: String
}

UITextView is aligned top, UILabel is vertically centered. Also It has own background color. we need to specify textView’s background color is clear.

class MessageCell: LBTAListCell<Message> {
    
    let textView: UITextView = {
        let tv = UITextView()
        tv.backgroundColor = .clear
        tv.font = .systemFont(ofSize: 20)
        tv.isScrollEnabled = false
        tv.isEditable = false
        return tv
    }()
    
    override var item: Message! {
        didSet {
            textView.text = item.text
        }
    }
}

It’s a kind of chat log, below two properties should be false.

        textView.isScrollEnabled = false
        textView.isEditable = false

estimatedSizeCell

in sizeForItemAt function, each UITextView’s size should be set dynamically.

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        
        // estimated sizing
        let estimatedSizeCell = MessageCell(frame: .init(x: 0, y: 0, width: view.frame.width, height: 1000))
        
        estimatedSizeCell.item = self.items[indexPath.item]
        
        estimatedSizeCell.layoutIfNeeded()
        
        let estimatedSize = estimatedSizeCell.systemLayoutSizeFitting(.init(width: view.frame.width, height: 1000))
        
        return .init(width: view.frame.width, height: estimatedSize.height)
    }

First, initiate MessageCell with a pretty big size

        let estimatedSizeCell = MessageCell(frame: .init(x: 0, y: 0, width: view.frame.width, height: 1000))

Assign each item to estimatedSizeCell. And refreshing estimatedSizeCell using layoutIfNeeded()

        estimatedSizeCell.item = self.items[indexPath.item]
        
        estimatedSizeCell.layoutIfNeeded()

layoutIfNeeded()

Lays out the subviews immediately, if layout updates are pending.

Use this method to force the view to update its layout immediately. When using Auto Layout, the layout engine updates the position of views as needed to satisfy changes in constraints. Using the view that receives the message as the root view, this method lays out the view subtree starting at the root. If no layout updates are pending, this method exits without modifying the layout or calling any layout-related callbacks.

Last, get size of estimatedSizeCell using systemLayoutSizeFitting()

        let estimatedSize = estimatedSizeCell.systemLayoutSizeFitting(.init(width: view.frame.width, height: 1000))
        
        return .init(width: view.frame.width, height: estimatedSize.height)

systemLayoutSizeFitting(_:)

Returns the optimal size of the view based on its current constraints.

This method returns a size value for the view that optimally satisfies the view’s current constraints and is as close to the value in the targetSize parameter as possible. This method does not actually change the size of the view.

anchoredConstratints

Now, It’s time to give a bubble container to UITextView. Initiate bubbleContainer as a property of MessageCell.

    var anchoredContstraints: AnchoredConstraints!

    override func setupViews() {
        super.setupViews()
        
        addSubview(bubbleContainer)
        bubbleContainer.layer.cornerRadius = 16
        
        anchoredContstraints = bubbleContainer.anchor(top: topAnchor, leading: leadingAnchor, bottom: bottomAnchor, trailing: trailingAnchor)
        anchoredContstraints.leading?.constant = 20
        anchoredContstraints.trailing?.constant = -20
        
        bubbleContainer.widthAnchor.constraint(lessThanOrEqualToConstant: 285).isActive = true
        
        bubbleContainer.addSubview(textView)
        textView.fillSuperview(padding: .init(top: 4, left: 12, bottom: 4, right: 12))
    }

AnchoredConstraints

Using AnchoredConstraints, access all layoutConstraint

public struct AnchoredConstraints {
    public var top, leading, bottom, trailing, width, height: NSLayoutConstraint?
}

Update a ownership of each chat bubble

First, setting layout of chat bubbles by changing ownership

    override var item: Message! {
        didSet {
            textView.text = item.text
            
            if item.isFromCurrentLoggedUser {
                anchoredContstraints.trailing?.isActive = true
                anchoredContstraints.leading?.isActive = false
                bubbleContainer.backgroundColor = #colorLiteral(red: 1, green: 0.423529923, blue: 0.4469795823, alpha: 1)
                textView.textColor = .white
            } else {
                anchoredContstraints.trailing?.isActive = false
                anchoredContstraints.leading?.isActive = true
            }
        }
    }

Update Message struct.

struct Message {
    let text: String
    let isFromCurrentLoggedUser: Bool
}

Refactoring

Message : Model

MessageCell : View

Extract method in ChatLogController

    override func viewDidLoad() {
        super.viewDidLoad()
        
        items = [
            //...
        ]
        
        setupUI()
    }
    
    fileprivate func setupUI() {
        //...
    }

태그: ,

카테고리:

업데이트:

댓글남기기