當下發狀態和發評論已經漸漸成為不少軟件的必備功能,這兩者功能基本類似。但是有普通編輯和高級編輯之分,普通的評論只能發文本,一旦可以發送表情(非emoji表情)就需要用到圖文混排。並且系統只能提供emoji表情,要用到其他自定義表情需要自行添加表情鍵盤。
因為表情鍵盤和圖文混排寫在一起太長了分為兩期。本期以新浪微博的發微博頁面為例,整理添加表情鍵盤的步驟,下期會總結自己在編寫圖文混排中遇到的種種問題和解決方案。基本的頁面類似於這樣,有部分細節沒做不過也無關大雅了。編寫的語言用的是swift
如果你不是在董鉑然博客園看到本文,請點擊查看原文。
我表情鍵盤的做法是,在發布微博控制器頁面底部添加一個toolbar 然後底部的約束拖一根線到控制器裡,可以根據監聽鍵盤的彈出動態修改。
下面的表情鍵盤是新建一個xib或者storyboard 建一個普通控制器,上面放collectionView,下面放一個view或者toolbar顯示表情的種類。
collectionViewCell內部放一個imageView 和 一個Label。因為emoji表情是需要用label顯示的。
下圖是兩個設計界面
左邊的撰寫微博控制器和上面的效果截圖有些不同。因為設置了導航欄的顏色主題是黃色。裡面灰色的placeholder請發布微博是用代碼添加的設置為textView的子控件。上面的設置可以自行腦補在此不作過多贅述了,本文主要是總結表情鍵盤和圖文混排
右邊的表情鍵盤控制器也是可以清楚地看到cell裡有imgView和label
這裡記得要在撰寫微博控制器裡設置,點擊小圓臉就設置第一響應者,並且把彈出鍵盤的inputView設置成我們自定義的這個表情鍵盤控制器。
然後就是裡面cell的流水布局,把控制器裡的布局拖到控制器中修改
override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() setupLayout() } func setupLayout(){ let row:CGFloat = 3 let col:CGFloat = 7 let m:CGFloat = 10 let screenSize = self.collectionView.bounds.size let w = (screenSize.width - (col + 1) * m) / col layout.itemSize = CGSizeMake(w, w) layout.minimumInteritemSpacing = m layout.minimumLineSpacing = m /// 每一組之間的邊距 layout.sectionInset = UIEdgeInsetsMake(m, m, m, m) layout.scrollDirection = UICollectionViewScrollDirection.Horizontal collectionView.pagingEnabled = true }
之所以寫在ViewDidLayoutSubViews方法中,是為了等前面的布局完全加載好。
布局完畢後應該就是可以看到此效果。
然後就是加載表情圖片,把表情圖片依次填到這些方框中
表情圖片的加載方法:
1.下載個新浪微博的ipa解壓,在裡面能夠找到所有的表情包都是裝在一個emticons文件夾裡
2.文件夾中有個emoticons.plist文件,裡面是一個數組,裡面包含四個字典分別是四種表情的各項參數。和四個文件夾裡裝著四種表情
3.每一種表情的文件夾裡還有一個info.plist文件,這個文件裡是個字典包含幾個自己表情參數和一個數組,裡面裝的是本類別的所有表情
4.這裡面的參數目測應該就能看懂分別是干什麼的 如圖
5.這裡加載表情圖片時要注意不能直接使用第三方框架字典轉模型,因為字典轉模型之後的模型數組內值都是連續的,但是每頁的右下角還需要添加一個刪除按鈕,所以產生矛盾
6.所以加載表情圖片的基本思路是,手寫方法一層一層加載,先把emoticons.plist轉模型,再通過裡面的path可以取到每一個info.plist再轉模型。
7.然後info.plist中有一個數組裡裝著所有的表情,每一個表情又是一個字典再給他轉模型。並設置個模型數組
8.前面設置collectionView的布局是3*7,這裡就設置collectionView的Section每組21個,除去一個刪除按鈕正好是每頁20個表情。
9.把模型和模型數組整理好,該addObject的就addObject。
最後在數據源方法中加載:
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int { /// 返回有幾種表情 return emoticonSection?.count ?? 0 } func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { /// 返回每個種類中的表情數量 return emoticonSection![section].emoticons.count } func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCellWithReuseIdentifier("EmoticonsCell", forIndexPath: indexPath) as! EmoticonCell /// 屬性賦值 cell.emoticon = emoticonSection![indexPath.section].emoticons[indexPath.item] return cell }
至於cellForItem裡的屬性賦值,是在自定義的EmoticonCell裡設置didSet判斷模型的種類(是否是emoji表情)再完成數據分發
/// 自定義表情cell class EmoticonCell: UICollectionViewCell { @IBOutlet weak var iconView: UIImageView! @IBOutlet weak var emojiLabel: UILabel! var emoticon: Emoticon? { /// 賦值完成後調用 didSet { if let path = emoticon?.imagePath { iconView.image = UIImage(contentsOfFile: path) } else { iconView.image = nil } emojiLabel.text = emoticon?.emoji // 是否是刪除按鈕 if emoticon!.isDeleteButton { iconView.image = UIImage(named: "compose_emotion_delete_highlighted") } } } }
之後表情鍵盤就可以如圖的顯示了。
然後就是監聽每個按鈕表情的點擊事件。這裡需要用到代理。
定義一個協議協議裡有個方法點擊時把自己(表情控制器)和點中的表情模型傳過去
再在collectioView的代理方法中設置didSelected觸發
協議:
protocol EmoticonsViewControllerDelegate: NSObjectProtocol { /// 選中了某一個表情 func emoticonsViewControllerDidSelectEmoticon(vc:SXEmoticonsViewController, emoticon: Emoticon) }
代理方法:
/// 根據 indexPath 返回表情數據 func emoticon(indexPath: NSIndexPath) -> Emoticon { return emoticonSection![indexPath.section].emoticons[indexPath.item] } /// cell 被選中 func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) { // 使用 ? 不需要判斷代理是否實現方法 delegate?.emoticonsViewControllerDidSelectEmoticon(self, emoticon: emoticon(indexPath)) }
在撰寫微博控制器裡,接收到數據模型後能打印出來就證明前面的表情鍵盤都做好了。