[Tutorial] Input Tag View
Tag Bằng cách định hướng người dùng cùng trò chuyện về 1 topic có sẵn, rất nhiều ứng dụng, service đã hướng tới việc sử dụng Tag phổ biến hơn. Tất nhiên, trước đó Tag vẫn được sử dụng thường xuyên nhưng không phải bất cứ người dùng phổ thông nào cũng biết và hiểu về nó. Vì vậy, trong bài viết ...
Tag Bằng cách định hướng người dùng cùng trò chuyện về 1 topic có sẵn, rất nhiều ứng dụng, service đã hướng tới việc sử dụng Tag phổ biến hơn. Tất nhiên, trước đó Tag vẫn được sử dụng thường xuyên nhưng không phải bất cứ người dùng phổ thông nào cũng biết và hiểu về nó.
Vì vậy, trong bài viết này mình sẽ tạo 1 tutorial về việc xây dựng 1 Tag input View đơn giản nhưng đáp ứng được nhu cầu hiện nay: thay vì phải nhập 1 cụm từ, người dùng hoàn toàn có thể sử dụng thao tác Touch.
Trước hết, hãy xem qua kết quả mà tutorial này sẽ đem lại:
Mục đích của tutorial sẽ hướng tới việc giải quyết 2 vấn đề chính:
-
Custom UICollectionView
-
Handle adding custom view
OK! Let's do it.
Step 1:
Bạn hãy tạo và thiết lập các bước cơ bản của project như sau:
- Project name
- Language: Swift (ofcourse)
- Hãy tổ chức cho lớp InputTagView như một component với cấu trúc folder bao gồm:
-
- TagInputView.swift và TagInputView.: subclass của UIView
-
- TagCollectionCell.swift và TagCollectionCell.xib : collection view cell
-
- TagViewCelFlowLayout: layout cho collection view
TagInputView
Thiết lập UI cho tagInputView rất đơn giản, bao gồm:
- View Content
- UICollectionView: để hiển thị nội dung (trong trường hợp này chúng ta sẽ sử dụng collection cell tương ứng là các Tag)
- Sử dụng hàm delegate của UICollectionView didSelectItemAtIndexPath để ghi nhận action Touch-inside của người dùng.
- Ngoài ra các bạn nên tạo 1 simple class/struct để thực hiện việc truyền data cho CollectionView Class data model có thể như sau:
class TagModel : NSObject { var tagTitle : String = "" var tagIndex : Int = 0 override init() { super.init() } init(title: String, index: Int) { super.init() tagTitle = title tagIndex = index } }
Khai báo biến để chứa data (tags) dành cho collection datasource:
var arrTags : [TagModel] = []
Khai báo protocol để ghi nhận action Touch-inside của user cho ViewController:
protocol TagInputViewDelegate { func didSelectTagAtObjectIndex(object : TagModel) }
Setting dành cho custom UICollection view bao gồm các thành phần:
- Setting flow layout cho collection view
- Setting cho collection view cell
//MARK: - View Setting func settingView () { let cellNib = UINib(nibName: "TagCollectionCell", bundle: nil) self.clvTagView.delegate = self self.clvTagView.dataSource = self self.clvTagView.registerNib(cellNib, forCellWithReuseIdentifier: "TagCollectionCell") self.clvTagView.backgroundColor = UIColor.clearColor() self.sizingCell = (cellNib.instantiateWithOwner(nil, options: nil) as NSArray).firstObject as! TagCollectionCell? self.constraintClvMaxWidth.constant = UIScreen.mainScreen().bounds.awidth self.layoutIfNeeded() } func settingData (data : [TagModel]) { self.arrTags = data }
Tuy nhiên, các bạn lưu ý về dòng lệnh:
self.constraintClvMaxWidth.constant = UIScreen.mainScreen().bounds.awidth self.layoutIfNeeded()
Dòng lệnh này để setting lại chiều rộng của custom collection view. Biến constraint constraintClvMaxWidth sẽ tương ứng với layout max awidth của collection view
Phần setting collection delegate - datasource còn lại như sau:
//MARK: - CollectionView Delegate - Datasource func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return arrTags.count } func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell { let strCellIdentifier : String = "TagCollectionCell" let cell = collectionView.dequeueReusableCellWithReuseIdentifier(strCellIdentifier, forIndexPath: indexPath) as! TagCollectionCell self.configureCell(cell, forIndexPath: indexPath) return cell } func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize { self.configureCell(self.sizingCell!, forIndexPath: indexPath) return self.sizingCell!.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize) } func configureCell(cell: TagCollectionCell, forIndexPath indexPath: NSIndexPath) { cell.lblTagName.text = arrTags[indexPath.row].tagTitle } func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) { collectionView.deselectItemAtIndexPath(indexPath, animated: true) self.delegate?.didSelectTagAtObjectIndex(arrTags[indexPath.row]) }
Trong phần setting này cần chú ý hàm chức năng:
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize { self.configureCell(self.sizingCell!, forIndexPath: indexPath) return self.sizingCell!.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize) }
trong đó
self.sizingCell!.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)
có chức năng return size dành collection view cell.
Biến sizingCell ta khai báo như sau:
var sizingCell: TagCollectionCell?
TagViewCelFlowLayout
Sau khi khai báo collection và setting cho view xong, chúng ta thực hiện phần layout dành cho collection view.
Step 1 : Tạo mới file TagViewCelFlowLayout
Step 2 : override hàm chức năng layoutAttributesForElementsInRect
class TagViewCellFlowLayout: UICollectionViewFlowLayout { override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]? { let attributesForElementsInRect = super.layoutAttributesForElementsInRect(rect) var newAttributesForElementsInRect = [UICollectionViewLayoutAttributes]() // use a value to keep track of left margin var leftMargin: CGFloat = 0.0; for attributes in attributesForElementsInRect! { let refAttributes = attributes // assign value if next row if (refAttributes.frame.origin.x == self.sectionInset.left) { leftMargin = self.sectionInset.left } else { // set x position of attributes to current margin var newLeftAlignedFrame = refAttributes.frame newLeftAlignedFrame.origin.x = leftMargin refAttributes.frame = newLeftAlignedFrame } // calculate new value for current margin leftMargin += refAttributes.frame.size.awidth + 8 newAttributesForElementsInRect.append(refAttributes) } return newAttributesForElementsInRect } }
TagCollectionCell.swift
Setting cho cell như sau nhé, rất là simple thôi