内置小表情面板 | 自定义表情面板 |
| ![]() |



CustomFaceResource.bundle 拖到您的 xcode 工程中。然后在 App 启动时加载即可。
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {// ...self.setupCustomSticker()return YES}func setupCustomSticker() {guard let service = TIMCommonMediator.shared.getObject(for: TUIEmojiMeditorProtocol.self) else {assertionFailure("There's not any object implement TUIEmojiMeditorProtocol")return}let bundlePath = TUISwift.tuiBundlePath("CustomFaceResource", key: "TIMAppKit.TUIKit")// 4350 groupvar faces4350 = [TUIFaceCellData]()for i in 0...17 {let data = TUIFaceCellData()let name = String(format: "yz%02d", i)let path = "4350/\\(name)"data.name = namedata.path = bundlePath + "/" + pathfaces4350.append(data)}if faces4350.count > 0 {let group4350 = TUIFaceGroup()group4350.groupIndex = 1group4350.groupPath = bundlePath + "/4350/"group4350.faces = faces4350group4350.rowCount = 2group4350.itemCountPerRow = 5group4350.menuPath = bundlePath + "/4350/menu"service.appendFaceGroup(group4350)}// 4351 groupvar faces4351 = [TUIFaceCellData]()for i in 0...15 {let data = TUIFaceCellData()let name = String(format: "ys%02d", i)let path = "4351/\\(name)"data.name = namedata.path = bundlePath + "/" + pathfaces4351.append(data)}if faces4351.count > 0 {let group4351 = TUIFaceGroup()group4351.groupIndex = 2group4351.groupPath = bundlePath + "/4351/"group4351.faces = faces4351group4351.rowCount = 2group4351.itemCountPerRow = 5group4351.menuPath = bundlePath + "/4351/menu"service.appendFaceGroup(group4351)}// 4352 groupvar faces4352 = [TUIFaceCellData]()for i in 0...16 {let data = TUIFaceCellData()let name = String(format: "gcs%02d", i)let path = "4352/\\(name)"data.name = namedata.path = bundlePath + "/" + pathfaces4352.append(data)}if faces4352.count > 0 {let group4352 = TUIFaceGroup()group4352.groupIndex = 3group4352.groupPath = bundlePath + "/4352/"group4352.faces = faces4352group4352.rowCount = 2group4352.itemCountPerRow = 5group4352.menuPath = bundlePath + "/4352/menu"service.appendFaceGroup(group4352)}}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {app = self;// Load the emoji resources when starting the app[self setupCustomSticker];return YES;}- (void)setupCustomSticker {// 1. Get the path of the bundle file of the custom sticker.NSString *customFaceBundlePath = [[NSBundle mainBundle] pathForResource:@"CustomFaceResource" ofType:@"bundle"];// 2. Load the custom emoji group// 2.1 Load the `programer` emoji resource images and parse them into `TUIFaceCellData`NSMutableArray<TUIFaceCellData *> *faceItems = [NSMutableArray array];for (int i = 0; i <= 17; i++) {TUIFaceCellData *data = [[TUIFaceCellData alloc] init];// The filename of the emoji resource images (the extension can be saved) for multi-terminal connection (which requires that filenames are consistent)data.name = [NSString stringWithFormat:@"yz%02d", i];// The path of the emoji resource images for local displaydata.path = [customFaceBundlePath stringByAppendingPathComponent:[NSString stringWithFormat:@"programer/%@", data.name]];[faceItems addObject:data];}// 2.2 Create the `programer` emoji group and parse it into `TUIFaceGroup`TUIFaceGroup *programGroup = [[TUIFaceGroup alloc] init];// Indicate the serial number of the current emoji group on the emoji panel for multi-terminal connection (which can be used together with the emoji name to find an image on the receiver's device)// Note that `groupIndex` starts from `0` and indicates the actual position of the current sticker on the emoji panel (`0` is the default value for the built-in `emoji` emoji group)programGroup.groupIndex = 1;// The root path of the current sticker in the bundle file of the custom emojisprogramGroup.groupPath = [customFaceBundlePath stringByAppendingPathComponent:@"programer/"];// The emoji resources in the current stickerprogramGroup.faces = faceItems;// The layout of the current stickerprogramGroup.rowCount = 2;programGroup.itemCountPerRow = 5;// The path of the thumbnail of the current sticker (without the extension)programGroup.menuPath = [customFaceBundlePath stringByAppendingPathComponent:@"programer/menu"];// 3. Add the `programer` emoji group to the emoji panelid<TUIEmojiMeditorProtocol> service = [[TIMCommonMediator share] getObject:@protocol(TUIEmojiMeditorProtocol)];[service appendFaceGroup:programGroup];}
TUIFaceCellData 的 name 字段值需要多端一致;TUIFaceGroup 的 groupIndex 字段值需要多端一致。
TUIConfig 的 - appendFaceGroup: 方法即可。TUIConfig.defaultConfig.faceGroups;func setupCustomSticker() {guard let service = TIMCommonMediator.shared.getObject(for: TUIEmojiMeditorProtocol.self) else {assertionFailure("There's not any object implement TUIEmojiMeditorProtocol")return}let bundlePath = TUISwift.tuiBundlePath("CustomFaceResource", key: "TIMAppKit.TUIKit")// 4350 groupvar faces4350 = [TUIFaceCellData]()for i in 0...17 {let data = TUIFaceCellData()let name = String(format: "yz%02d", i)let path = "4350/\\(name)"data.name = namedata.path = bundlePath + "/" + pathfaces4350.append(data)}if faces4350.count > 0 {let group4350 = TUIFaceGroup()group4350.groupIndex = 1group4350.groupPath = bundlePath + "/4350/"group4350.faces = faces4350group4350.rowCount = 2group4350.itemCountPerRow = 5group4350.menuPath = bundlePath + "/4350/menu"service.appendFaceGroup(group4350)}// 4351 groupvar faces4351 = [TUIFaceCellData]()for i in 0...15 {let data = TUIFaceCellData()let name = String(format: "ys%02d", i)let path = "4351/\\(name)"data.name = namedata.path = bundlePath + "/" + pathfaces4351.append(data)}if faces4351.count > 0 {let group4351 = TUIFaceGroup()group4351.groupIndex = 2group4351.groupPath = bundlePath + "/4351/"group4351.faces = faces4351group4351.rowCount = 2group4351.itemCountPerRow = 5group4351.menuPath = bundlePath + "/4351/menu"service.appendFaceGroup(group4351)}// 4352 groupvar faces4352 = [TUIFaceCellData]()for i in 0...16 {let data = TUIFaceCellData()let name = String(format: "gcs%02d", i)let path = "4352/\\(name)"data.name = namedata.path = bundlePath + "/" + pathfaces4352.append(data)}if faces4352.count > 0 {let group4352 = TUIFaceGroup()group4352.groupIndex = 3group4352.groupPath = bundlePath + "/4352/"group4352.faces = faces4352group4352.rowCount = 2group4352.itemCountPerRow = 5group4352.menuPath = bundlePath + "/4352/menu"service.appendFaceGroup(group4352)}}
- (void)setupCustomSticker {// 1. Get the path of the bundle file of the custom sticker.NSString *customFaceBundlePath = [[NSBundle mainBundle] pathForResource:@"CustomFaceResource" ofType:@"bundle"];// 2. Load the custom emoji group// 2.1 Load the `programer` emoji resource images and parse them into `TUIFaceCellData`NSMutableArray<TUIFaceCellData *> *faceItems = [NSMutableArray array];for (int i = 0; i <= 17; i++) {TUIFaceCellData *data = [[TUIFaceCellData alloc] init];// The filename of the emoji resource images (the extension can be saved) for multi-terminal connection (which requires that filenames are consistent)data.name = [NSString stringWithFormat:@"yz%02d", i];// The path of the emoji resource images for local displaydata.path = [customFaceBundlePath stringByAppendingPathComponent:[NSString stringWithFormat:@"programer/%@", data.name]];[faceItems addObject:data];}// 2.2 Create the `programer` emoji group and parse it into `TUIFaceGroup`TUIFaceGroup *programGroup = [[TUIFaceGroup alloc] init];// Indicate the serial number of the current emoji group on the emoji panel for multi-terminal connection (which can be used together with the emoji name to find an image on the receiver's device)// Note that `groupIndex` starts from `0` and indicates the actual position of the current sticker on the emoji panel (`0` is the default value for the built-in `emoji` emoji group)programGroup.groupIndex = 0;// The root path of the current sticker in the bundle file of the custom emojisprogramGroup.groupPath = [customFaceBundlePath stringByAppendingPathComponent:@"programer/"];// The emoji resources in the current stickerprogramGroup.faces = faceItems;// The layout of the current stickerprogramGroup.rowCount = 2;programGroup.itemCountPerRow = 5;// The path of the thumbnail of the current sticker (without the extension)programGroup.menuPath = [customFaceBundlePath stringByAppendingPathComponent:@"programer/menu"];// 3. Add the `programer` emoji group to the front of the emoji panelid<TUIEmojiMeditorProtocol> service = [[TIMCommonMediator share] getObject:@protocol(TUIEmojiMeditorProtocol)];[service appendFaceGroup:programGroup];}
TUIFaceGroup 的 menuPath 属性设置封面图的路径(无需 @2x.png 的扩展名)来自定义表情组封面。menu@2x.png 图片作为封面图片。func setupCustomSticker() {// ...// 4350 groupvar faces4350 = [TUIFaceCellData]()for i in 0...17 {let data = TUIFaceCellData()let name = String(format: "yz%02d", i)let path = "4350/\\(name)"data.name = namedata.path = bundlePath + "/" + pathfaces4350.append(data)}if faces4350.count > 0 {let group4350 = TUIFaceGroup()group4350.groupIndex = 1group4350.groupPath = bundlePath + "/4350/"group4350.faces = faces4350group4350.rowCount = 2group4350.itemCountPerRow = 5group4350.menuPath = bundlePath + "/4350/menu"service.appendFaceGroup(group4350)}// ...}
- (void)setupCustomSticker {....// 2.2 Create the `programer` emoji group and parse it into `TUIFaceGroup`TUIFaceGroup *programGroup = [[TUIFaceGroup alloc] init];....// The path of the thumbnail of the current sticker (without the extension)programGroup.menuPath = [customFaceBundlePath stringByAppendingPathComponent:@"programer/menu"];........}
func setupCustomSticker() {// ...// 4350 groupvar faces4350 = [TUIFaceCellData]()for i in 0...17 {let data = TUIFaceCellData()let name = String(format: "yz%02d", i)let path = "4350/\\(name)"data.name = namedata.path = bundlePath + "/" + pathfaces4350.append(data)}if faces4350.count > 0 {let group4350 = TUIFaceGroup()group4350.groupIndex = 1group4350.groupPath = bundlePath + "/4350/"group4350.faces = faces4350group4350.rowCount = 2group4350.itemCountPerRow = 5group4350.menuPath = bundlePath + "/4350/menu"service.appendFaceGroup(group4350)}// ...}
- (void)setupCustomSticker {...// 2.2 Create the `programer` emoji group and parse it into `TUIFaceGroup`TUIFaceGroup *programGroup = [[TUIFaceGroup alloc] init];// The layout of the current stickerprogramGroup.rowCount = 2;programGroup.itemCountPerRow = 5;...}
TUIInputController 的 - faceView:didSelectItemAtIndexPath: 方法,并将您点选的表情名称和对应表情组在面板中的索引信息回调给您。public func faceVerticalView(_ faceView: TUIFaceVerticalView, didSelectItemAtIndexPath indexPath: IndexPath) {let group = faceView.faceGroups[indexPath.section]if let face = group.faces?[indexPath.row] as? TUIFaceCellData {if group.isNeedAddInInputBar {inputBar?.addEmoji(face)updateRecentMenuQueue(face.name ?? "")} else {let message = V2TIMManager.sharedInstance().createFaceMessage(index: Int32(group.groupIndex), data: face.name?.data(using: .utf8) ?? Data())!delegate?.inputController(self, didSendMessage: message)}}}
- (void)faceView:(TUIFaceView *)faceView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{TUIFaceGroup *group = [TUIConfig defaultConfig].faceGroups[indexPath.section];TUIFaceCellData *face = group.faces[indexPath.row];if(indexPath.section == 0){// Built-in emojis need to be displayed in the input box.[_inputBar addEmoji:face];}else{// Custom emojis are directly sent to the receiver.if (face.name) {// Create an emoji messageV2TIMMessage *message = [[V2TIMManager sharedInstance] createFaceMessage:group.groupIndex data:[face.name dataUsingEncoding:NSUTF8StringEncoding]];// Send the message to receiverif(_delegate && [_delegate respondsToSelector:@selector(inputController:didSendMessage:)]){[_delegate inputController:self didSendMessage:message];}}}}
TUIFaceMessageCellData 的 - getCellData: 方法,并在其中将表情消息解析成用于展示表情的 TUIFaceMessageCellData 。TUIMessageCellData 赋值给 TUIFaceMessageCell 用于渲染。override class func getCellData(message: V2TIMMessage) -> TUIMessageCellData {guard let elem = message.faceElem else { return TUIFaceMessageCellData(direction: .incoming) }let faceData = TUIFaceMessageCellData(direction: message.isSelf ? .outgoing : .incoming)faceData.groupIndex = elem.indexif let data = elem.data {faceData.faceName = String(data: data, encoding: .utf8)}if let groups = TIMConfig.shared.faceGroups {for group in groups {if group.groupIndex == faceData.groupIndex {if let url = URL(string: group.groupPath ?? "") {let path = url.appendingPathComponent(faceData.faceName ?? "").pathfaceData.path = path}break}}}faceData.reuseId = "TFaceMessageCell"return faceData}
+ (TUIMessageCellData *)getCellData:(V2TIMMessage *)message{// Parse the emoji information after receiving the messageV2TIMFaceElem *elem = message.faceElem;// Create the `TUIFaceMessageCellData` for emoji displayTUIFaceMessageCellData *faceData = [[TUIFaceMessageCellData alloc] initWithDirection:(message.isSelf ? MsgDirectionOutgoing : MsgDirectionIncoming)];// Get the order information of the current emoji group on the emoji panelfaceData.groupIndex = elem.index;// Get the filename of the emoji imagefaceData.faceName = [[NSString alloc] initWithData:elem.data encoding:NSUTF8StringEncoding];// Get the specific path of the local sticker of the emoji image based on the name of the emoji image and the emoji groupfor (TUIFaceGroup *group in [TUIConfig defaultConfig].faceGroups) {if(group.groupIndex == faceData.groupIndex){NSString *path = [group.groupPath stringByAppendingPathComponent:faceData.faceName];faceData.path = path;break;}}faceData.reuseId = TFaceMessageCell_ReuseId;return faceData;}
文档反馈