效果

声明:原作者为 TSWeChat,这里只是记录笔者移植到自己项目中使用的过程。

安装

pod添加依赖:

pod 'Dollar', '9.0.0'      # 操作数组的神器,比如将数组划分成若干个子集
pod 'RxSwift', '~> 5'      # 一个组合异步和事件驱动编程的库
pod 'RxCocoa', '~> 5'      # iOS响应式编程中的两个主流框架(RxSwift+RxCocoa)
pod 'SnapKit', '~> 5.0.0'  # 自动布局第三方库

代码实例

工具类

  1. UIImage+Chat.swift,图片资源
import Foundation
import UIKittypealias IMAssets = UIImage.Asset// 资源文件的快速访问
extension UIImage {enum Asset: String {case Chat_add_friend = "chat_add_friend"case Chat_add_newmessage = "chat_add_newmessage"case Chat_add_scan = "chat_add_scan"case Chat_MessageRightTopBg = "chat_MessageRightTopBg"case Chat_add = "chat_add"// 还可以这样写?var image: UIImage {return UIImage(asset: self)}}// 便利构造函数通常都是写在extension里面convenience init!(asset: Asset) {self.init(named: asset.rawValue)}
}
  1. UINavigationItem+Extension.swift
import Foundation
import UIKit//
// 来自于[TSWeChat](https://github.com/hilen/TSWeChat)
//public typealias ActionHandler = () -> Voidpublic extension UINavigationItem {// left barfunc leftButtonAction(_ image: UIImage, action: @escaping ActionHandler) {let button: UIButton = UIButton(type: UIButton.ButtonType.custom)button.setImage(image, for: UIControl.State())button.frame = CGRect(x: 0, y: 0, width: 40, height: 30)button.imageView!.contentMode = .scaleAspectFitbutton.contentHorizontalAlignment = .leftbutton.ngl_addAction(forControlEvents: .touchUpInside, withCallback: {action()})let barButton = UIBarButtonItem(customView: button)let gapItem = UIBarButtonItem(barButtonSystemItem: .fixedSpace, target: nil, action: nil)gapItem.width = -7 // fix the spaceself.leftBarButtonItems = [gapItem, barButton]}// right barfunc rightButtonAction(_ image: UIImage, action: @escaping ActionHandler) {let button: UIButton = UIButton(type: UIButton.ButtonType.custom)button.setImage(image, for: UIControl.State())button.frame = CGRect(x: 0, y: 0, width: 40, height: 30)button.imageView!.contentMode = .scaleAspectFitbutton.contentHorizontalAlignment = .rightbutton.ngl_addAction(forControlEvents: .touchUpInside, withCallback: {action()})let barButton = UIBarButtonItem(customView: button)let gapItem = UIBarButtonItem(barButtonSystemItem: .fixedSpace, target: nil, action: nil)gapItem.width = -7 // fix the spaceself.rightBarButtonItems = [gapItem, barButton]}
}/*Block of UIControl
*/
open class ClosureWrapper : NSObject {let _callback : () -> Voidinit(callback : @escaping () -> Void) {_callback = callback}@objc open func invoke() {_callback()}
}var AssociatedClosure: UInt8 = 0extension UIControl {fileprivate func ngl_addAction(forControlEvents events: UIControl.Event, withCallback callback: @escaping () -> Void) {let wrapper = ClosureWrapper(callback: callback)addTarget(wrapper, action:#selector(ClosureWrapper.invoke), for: events)objc_setAssociatedObject(self, &AssociatedClosure, wrapper, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)}
}
  1. IMActionFloatView.swift
import Foundationimport UIKit
import SnapKit
import Dollar
import RxSwift
import RxCocoaprivate let kActionViewWidth: CGFloat = 140   //container view width
private let kActionViewHeight: CGFloat = 155    //container view height
private let kActionButtonHeight: CGFloat = 44   //button height
private let kFirstButtonY: CGFloat = 12 //the first button Y valueclass IMActionFloatView: UIView {weak var delegate: ActionFloatViewDelegate?let disposeBag = DisposeBag()override init (frame: CGRect) {super.init(frame : frame)self.initContent()}convenience init () {self.init(frame:CGRect.zero)self.initContent()}required init?(coder aDecoder: NSCoder) {super.init(coder: aDecoder)}fileprivate func initContent() {self.backgroundColor = UIColor.clearlet actionImages = [IMAssets.Chat_add_friend.image,IMAssets.Chat_add_newmessage.image,IMAssets.Chat_add_scan.image,]let actionTitles = ["发起群聊","添加朋友","扫一扫",]//Init containerViewlet containerView : UIView = UIView()containerView.backgroundColor = UIColor.clearself.addSubview(containerView)containerView.snp.makeConstraints { (make) -> Void inmake.top.equalTo(self.snp.top).offset(3)make.right.equalTo(self.snp.right).offset(-5)make.width.equalTo(kActionViewWidth)make.height.equalTo(kActionViewHeight)}//Init bgImageViewlet stretchInsets = UIEdgeInsets.init(top: 14, left: 6, bottom: 6, right: 34)let bubbleMaskImage = IMAssets.Chat_MessageRightTopBg.image.resizableImage(withCapInsets: stretchInsets, resizingMode: .stretch)let bgImageView: UIImageView = UIImageView(image: bubbleMaskImage)containerView.addSubview(bgImageView)bgImageView.snp.makeConstraints { (make) -> Void inmake.edges.equalTo(containerView)}//init custom buttonsvar yValue = kFirstButtonYfor index in 0 ..< actionImages.count {let itemButton: UIButton = UIButton(type: .custom)itemButton.backgroundColor = UIColor.clearitemButton.titleLabel!.font = UIFont.systemFont(ofSize: 17)itemButton.setTitleColor(UIColor.white, for: UIControl.State())itemButton.setTitleColor(UIColor.white, for: .highlighted)// titlelet title = Dollar.fetch(actionTitles, index, orElse: "")itemButton.setTitle(title, for: .normal)itemButton.setTitle(title, for: .highlighted)// header imagelet image = Dollar.fetch(actionImages, index, orElse: nil)itemButton.setImage(image, for: .normal)itemButton.setImage(image, for: .highlighted)itemButton.addTarget(self, action: #selector(IMActionFloatView.buttonTaped(_:)), for: UIControl.Event.touchUpInside)itemButton.contentHorizontalAlignment = .leftitemButton.contentEdgeInsets = UIEdgeInsets.init(top: 0, left: 12, bottom: 0, right: 0)itemButton.titleEdgeInsets = UIEdgeInsets.init(top: 0, left: 10, bottom: 0, right: 0)itemButton.tag = index// parent viewcontainerView.addSubview(itemButton)itemButton.snp.makeConstraints { (make) -> Void inmake.top.equalTo(containerView.snp.top).offset(yValue)make.right.equalTo(containerView.snp.right)make.width.equalTo(containerView.snp.width)make.height.equalTo(kActionButtonHeight)}yValue += kActionButtonHeight}//add tap to viewlet tap = UITapGestureRecognizer()self.addGestureRecognizer(tap)tap.rx.event.subscribe { _ inself.hide(true)}.disposed(by:self.disposeBag)self.isHidden = true}@objc func buttonTaped(_ sender: UIButton!) {guard let delegate = self.delegate else {self.hide(true)return}let type = ActionFloatViewItemType(rawValue:sender.tag)!delegate.floatViewTapItemIndex(type)self.hide(true)}/**Hide the float view- parameter hide: is hide*/func hide(_ hide: Bool) {if hide {self.alpha = 1.0UIView.animate(withDuration: 0.2 ,animations: {self.alpha = 0.0},completion: { finish inself.isHidden = trueself.alpha = 1.0})} else {self.alpha = 1.0self.isHidden = false}}
}/***  TSMessageViewController Float view delegate methods*/
protocol ActionFloatViewDelegate: class {/**Tap the item with index*/func floatViewTapItemIndex(_ type: ActionFloatViewItemType)
}enum ActionFloatViewItemType: Int {case groupChat = 0, addFriend, scan, payment
}

使用

  1. 在任意ViewController.swift中,声明一个变量
class IMChatViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, IMConversationManagerDelegate {@IBOutlet var sessionTabView: UITableView!var list: [SessionModel] = []// 声明var actionFloat: IMActionFloatView!
}

2.在viewDidLoad初始化悬浮框

   override func viewDidLoad() {super.viewDidLoad()// 在顶部右侧添加按钮(加群、扫一扫、加朋友等)self.navigationItem.rightButtonAction(IMAssets.Chat_add.image) { () -> Void inself.actionFloat.hide(!self.actionFloat.isHidden)}//Init ActionFloatViewself.actionFloat = IMActionFloatView()self.actionFloat.delegate = selfself.view.addSubview(self.actionFloat)self.actionFloat.snp.makeConstraints { (make) -> Void inmake.edges.equalTo(UIEdgeInsets.init(top: 85, left: 0, bottom: 0, right: 0))}// ……
}

3.监听点击回调

// MARK: - @protocol ActionFloatViewDelegate
extension IMChatViewController: ActionFloatViewDelegate {func floatViewTapItemIndex(_ type: ActionFloatViewItemType) {IMLog.info(item: "floatViewTapItemIndex:\(type)")switch type {case .groupChat:breakcase .addFriend:breakcase .scan:breakcase .payment:break}}
}

关于作者

推荐下自己的开源IM,纯Golang编写:

CoffeeChat:
https://github.com/xmcy0011/CoffeeChat
opensource im with server(go) and client(flutter+swift)

参考了TeamTalk、瓜子IM等知名项目,包含服务端(go)和客户端(flutter+swift),单聊和机器人(小微、图灵、思知)聊天功能已完成,目前正在研发群聊功能,欢迎对golang和跨平台开发flutter技术感兴趣的小伙伴Star加关注。

————————————————
版权声明:本文为CSDN博主「许非」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/xmcy001122/article/details/109381059

Swift——仿微信发起群聊悬浮框实现相关推荐

  1. Android仿微信发起群聊的列表样式

    场景:今天一个朋友微信找我说碰到个问题让我看下,就是仿微信发起群聊的那个列表样式,其实这个功能实现起来没什么困难的地方,但是他遇到的问题是,最后的那个"搜索",随着前边列表的增加或 ...

  2. 高仿微信发起群聊添加联系人界面

    微信中发起群聊页面,每点击一个item(联系人),左上角就会添加上相应的联系人,再次点击就会取消选中,点击上面已选中的联系人也会取消选中,而且上面的联系人展示中会慢慢挤压右边的搜索框,直到右边有一定的 ...

  3. 仿微信 发起群聊 类似样式

    前段时间项目中有用到类似像微信发起群聊的功能,现在整理了出来 分享给大家 效果图如下: 选中后 添加到下面的选择栏中 ,点击选择栏中已选择的 就取消选择 简单说下思路: 自定义HorizontalSc ...

  4. Android 仿微信添加群聊界面——addView

    仿微信添加群聊界面--addView 转载于:https://www.cnblogs.com/zhujiabin/p/5916746.html

  5. Android仿微信视频群聊,Android 仿钉钉、微信 群聊组合头像

    功能生成类似钉钉.微信 群聊组合头像Bitmap 可使用图片资源id.bitmap或者使用url从网络加载,传入对应数组即可 网络加载时支持线程池 支持磁盘缓存.内存缓存.(记得申请磁盘缓存需要的文件 ...

  6. native聊天界面 react_ReactNative 聊天 App 实战|RN 仿微信界面群聊|朋友圈

    前言 这次要给大家分享的是基于ReactNative开发的聊天APP实战项目RN_ChatRomm,运用react-native+react-navigation+react-redux+react- ...

  7. 仿微信九宫格群聊view

    效果如下: 自定义view的源码 public class NineGridImageView<T> extends ViewGroup {private int mRowCount;// ...

  8. 移动端和pc端微信加入群聊

    移动端微信加入群聊 点击+ 发起群聊 选择两个或多个联系人 创建成功 是否免费 免费 是否有人数限制 有(500人) 不是群主是否能踢人出群 不能 不是群主或管理人能否邀请他人 能 群满员之后还能否加 ...

  9. 微信加入群聊的设计点

    微信加入群聊的设计点 pc端: 1.点击加号+是否可用 2.点击加号+能否弹出选择好友列表 3.点击好友以后是否有对应的对勾提示 4.选中后的好友点击对勾以后能否正常取消已选中 5.选中联系人之后,能 ...

最新文章

  1. Actor-critic强化学习方法应用于CartPole-v1
  2. 看不到日志_Kubernetes中常用的日志收集方案
  3. 阿里云服务器买了,如何建站呀?
  4. Java基础入门笔记-数组链表
  5. 从零开始学前端:上节课案例+break,continue以及while和do while --- 今天你学习了吗?(JS:Day5)
  6. c++ 终止 超时_c++超时问题
  7. 记录表类型 oracle,[转]关于oracle的记录类型
  8. 英文教材《FPGA-Prototyping-By-Verilog-Examples》下载
  9. python统计字符串中某个字符出现的次数_【面试题总结】1、统计字符串中某个字符出现的次数(2-Python实现)...
  10. Python备份文件实现以及备份大文件出错解决方案
  11. ACE Admin 模板实现sidebar菜单联动tabs页签
  12. Android控件 - TextView、Button、EditText、CompoundButton、CheckBox简介
  13. TestStand顺序过程模型中的模型回调序列列表
  14. lamp一键安装包+linux,linux下的lanmp/lamp/lnmp一键安装包
  15. java pdf添加图片_java pdf指定位置插入图片?
  16. 创业指南:如何快速拿到天使投资?
  17. 走进Visual C++
  18. 关于香港高防IP需要关注的几个问题
  19. laravel跨域问题
  20. Julia文件和文件夹相关基础函数01

热门文章

  1. 2023上海大学计算机考研信息汇总
  2. TP5 操作excel 导出
  3. 美团数据指标体系搭建实战
  4. [ github ] 使用GitHub
  5. 招联金融研发总监姜良雷做客选型宝 亲身讲述大数据平台选型历程
  6. idea支付宝扫一扫支付 史上最详细支付宝支付入门
  7. iot 开源平台thingsboard使用总结
  8. jenkins中maven的安装及配置,如何在jenkins中创建maven任务。
  9. 制作视频数据集(一):截取视频帧
  10. python批量修改文件名(将中文改为英文首字母)和xml文件