这是项目4个TabBar下的其中一个,用于电子名片的显示和更改。其中个人信息界面下,头像所在的cell设置tag为0,微信号设置tag为2,其他点击后会跳转到编辑页面更改信息的设置tag为1。
电子名片的文件格式标准是vCard,XMPP框架下的Extensions文件夹下面的XEP-0054提供了一种机制,可以通过XMPP发送电子名片。
使用电子名片的步骤分为以下4步:
1、在XMPPFramework.h中启用电子名片的扩展头文件
//电子名片模块
#import "XMPPvCardTempModule.h"
#import "XMPPvCardCoreDataStorage.h"
//电子名片头像模块
#import "XMPPvCardAvatarModule.h"
2、在XMPPTool中定义成员变量
3、为XMPPStream添加电子名片拓展
4、需要时使用
电子名片模块内部实现的功能有两个:
1. 发送请求从服务器获取“电子名片”数据
2. 把数据缓存到本地数据库
首先,在WCXMPPTool.h文件中定义成员变量
//电子名片模块
@property (nonatomic, strong, readonly) XMPPvCardTempModule *vCard;
//电子名片数据存储
@property (nonatomic, strong, readonly) XMPPvCardCoreDataStorage *vCardStorage;
//头像模块
@property (nonatomic, strong, readonly) XMPPvCardAvatarModule *avatar;
之后,为XMPPStream添加电子名片拓展,放在setupStream方法里面。
// 1.添加电子名片模块
_vCardStorage = [XMPPvCardCoreDataStorage sharedInstance];
_vCard = [[XMPPvCardTempModule alloc] initWithvCardStorage:_vCardStorage];
// 激活
[_vCard activate:_xmppStream];
// 2.添加头像模块
_avatar = [[XMPPvCardAvatarModule alloc] initWithvCardTempModule:_vCard];
[_avatar activate:_xmppStream];
在上一节中已经实现了注销的功能,这里不再重复贴代码,只贴上设置cell的数据的代码:
- (void)viewDidLoad
{
[super viewDidLoad];
//不能使用myvCard.jid.user获取,因为服务器返回的xml数据没有JABBERID节点
NSString *str = @"微信号: ";
self.wechatNumLabel.text = [str stringByAppendingString:[WCUser shareUser].loginAccount];
//登录用户的电子名片信息, 它会自动查找本地数据库,不需要自己写数据库操作语句
XMPPvCardTemp *myvCard = [WCXMPPTool sharedWCXMPPTool].vCard.myvCardTemp;
//获取头像
if (myvCard.photo) {
self.avatarImageView.image = [UIImage imageWithData:myvCard.photo];
}
}
@interface WCProfileViewController () <WCEditVCardViewControllerDelegate, UIImagePickerControllerDelegate, UIActionSheetDelegate, UINavigationControllerDelegate>
@property (weak, nonatomic) IBOutlet UIImageView *avatarImageView; //头像
@property (weak, nonatomic) IBOutlet UILabel *nicknameLabel; //昵称
@property (weak, nonatomic) IBOutlet UILabel *wechatNumLabel; //微信号
@property (weak, nonatomic) IBOutlet UILabel *orgNameLabel; //公司
@property (weak, nonatomic) IBOutlet UILabel *titleLabel; //职位
@property (weak, nonatomic) IBOutlet UILabel *telLabel; //电话
@property (weak, nonatomic) IBOutlet UILabel *emailLabel; //邮件
@end
@implementation WCProfileViewController
- (void)viewDidLoad
{
[super viewDidLoad];
//XMPP框架内电子名片xml数据解析的功能没有完善,有些节点没有解析,所以称为temp
XMPPvCardTemp *myvCard = [WCXMPPTool sharedWCXMPPTool].vCard.myvCardTemp;
//获取头像
if (myvCard.photo) {
self.avatarImageView.image = [UIImage imageWithData:myvCard.photo];
}
self.wechatNumLabel.text = [WCUser shareUser].loginAccount;
self.nicknameLabel.text = myvCard.nickname;
if (myvCard.orgUnits.count > 0) {
self.orgNameLabel.text = myvCard.orgUnits[0];
}
self.titleLabel.text = myvCard.title;
//XMPP框架内部没有解析电话节点,需要自己解析,这里使用 note 充当电话
self.telLabel.text = myvCard.note;
NSArray *emails = myvCard.emailAddresses;
if (emails.count > 0) {
self.emailLabel.text = emails[0];
}
}
上面的一些协议之后会用到,其中WCEditVCardViewControllerDelegate是之后编写编辑页面的功能时自己定义的协议,UIImagePickerControllerDelegate是编写更新头像功能时需要用到的协议。
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
switch (selectedCell.tag) {
case 0:
ZHLog(@"换头像");
[self chooseImage];
break;
case 1:
ZHLog(@"跳转到EditVCardViewController");
[self performSegueWithIdentifier:@"toEditVCard" sender:selectedCell];
break;
case 2:
ZHLog(@"不做任何操作");
break;
default:
break;
}
}
tag的设置在本文开头讲过了。
跳转到个人信息编辑页面:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
id destVc = segue.destinationViewController;
if ([destVc isKindOfClass:[WCEditVCardViewController class]]) {
WCEditVCardViewController *editVc = destVc;
editVc.cell = sender;
editVc.delegate = self;
}
}
#pragma mark 选择图片
- (void)chooseImage
{
UIActionSheet *sheet = [[UIActionSheet alloc] initWithTitle:@"请选择" delegate:self cancelButtonTitle:@"取消" destructiveButtonTitle:@"拍照" otherButtonTitles:@"图库", nil];
[sheet showInView:self.view];
}
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
ZHLog(@"%ld", (long)buttonIndex);
if (buttonIndex == 2) return;
//图片选择器
UIImagePickerController *imagePc = [[UIImagePickerController alloc] init];
imagePc.delegate = self;
//允许编辑图片
imagePc.allowsEditing = YES;
if (buttonIndex == 0) { //拍照
imagePc.sourceType = UIImagePickerControllerSourceTypeCamera;
}else{ //图库
imagePc.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
}
//显示
[self presentViewController:imagePc animated:YES completion:nil];
}
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
ZHLog(@"%@", info);
//获取编辑后的图片
UIImage *editImg = info[UIImagePickerControllerEditedImage];
//更新头像
self.avatarImageView.image = editImg;
//退出图片选择控制器
[self dismissViewControllerAnimated:YES completion:nil];
//更新数据到服务器
[self editVCardViewController:nil didClickSaveBtn:nil];
}
上面最后一句代码,编辑个人信息完成后、更新头像完成后都需要更新数据到服务器,因此不需要另外写一个方法,使用现成的即可。
#pragma mark 电子名片编辑器的代理方法
- (void)editVCardViewController:(WCEditVCardViewController *)editVc didClickSaveBtn:(id)sender
{
XMPPvCardTemp *myvCard = [WCXMPPTool sharedWCXMPPTool].vCard.myvCardTemp;
//myvCard.photo是NSData类型,因此需要使用UIImageJPEGRepresentation方法把图片转换为NSData类型
//第二个参数指图片压缩比例,比如10k*0.75=7.5k
myvCard.photo = UIImageJPEGRepresentation(self.avatarImageView.image, 0.75);
myvCard.nickname = self.nicknameLabel.text;
myvCard.orgName = self.orgNameLabel.text;
myvCard.title = self.titleLabel.text;
myvCard.note = self.telLabel.text;
if (self.emailLabel.text.length > 0) {
myvCard.emailAddresses = @[self.emailLabel.text];
}
//数据更新到服务器
[[WCXMPPTool sharedWCXMPPTool].vCard updateMyvCardTemp:myvCard];
}
这个代码有一个不好的地方就是每修改一个数据,就需要把个人信息全更新一遍,如果想优化这个代码,需要对openfire进行二次开发。
#import <UIKit/UIKit.h>
@class WCEditVCardViewController;
@protocol WCEditVCardViewControllerDelegate <NSObject>
@optional
- (void)editVCardViewController:(WCEditVCardViewController *)editVc didClickSaveBtn:(id)sender;
@end
@interface WCEditVCardViewController : UITableViewController
/** * 上一个控制器(Profile)传入的cell */
@property (nonatomic, strong) UITableViewCell *cell;
/** * 保存后通知Profile更新数据 */
@property (nonatomic, weak) id<WCEditVCardViewControllerDelegate> delegate;
@end
@implementation WCEditVCardViewController
- (void)viewDidLoad
{
[super viewDidLoad];
//设置控制器标题
self.title = self.cell.textLabel.text;
//设置输入框默认值
self.tectField.text = self.cell.detailTextLabel.text;
}
- (IBAction)saveBtnClick:(id)sender {
// 1.更新cell的detailTextLabel
self.cell.detailTextLabel.text = self.tectField.text;
[self.cell layoutSubviews];
// 2.退出当前控制器
[self.navigationController popViewControllerAnimated:YES];
// 3.通知代理
if ([self.delegate respondsToSelector:@selector(editVCardViewController:didClickSaveBtn:)]) {
[self.delegate editVCardViewController:self didClickSaveBtn:sender];
}
}
@end
以上。