現在越來越多涉及到圖片展示的應用都會加入標簽功能,標簽功能也越來越流行。想起以前做過的一個項目用到過這個功能,所以趁有時間,整理一下,僅供參考,不足之處還請多多指教。
1、標記界面

這個界面放一個UIImageView,寬高比例1:1。進入這個界面之前,圖片建議是裁剪成1:1,這個比例有利於標簽的展示。這個界面代碼就不用展示了。
還有給這個UIImageView加入一個點擊事件,記得設置userInteractionEnabled = YES。
2、加標簽按鈕

我們項目中是將標簽分為兩類,文字標簽和地理位置標簽,基本上是相同的。按鈕的布局可以參考我的,也可以自定義。
- (void)setupButton { CGFloat btnWH = 70 CGFloat btnMargin = 50 UIButton *textBtn = [[UIButton alloc] initWithFrame:CGRectMake((screenW - btnWH * 2 - btnMargin) * 0.5, -btnWH, btnWH, btnWH)]; [textBtn setImage:[UIImage imageNamed:@"addtag"] forState:UIControlStateNormal]; [textBtn setImage:[UIImage imageNamed:@"addtag_selected"] forState:UIControlStateSelected]; [textBtn addTarget:self action:@selector(clickText) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:textBtn]; self.textBtn = textBtn; UILabel *textLabel = [[UILabel alloc] init]; textLabel.frame = (CGRect){{textBtn.frame.origin.x, CGRectGetMaxY(textBtn.frame)}, textBtn.frame.size}; textLabel.text = @"標簽"; textLabel.textAlignment = NSTextAlignmentCenter; textLabel.textColor = [UIColor whiteColor]; textLabel.font = [UIFont systemFontOfSize:12]; [self .view addSubview:textLabel]; self.textLabel = textLabel; UIButton *locationBtn = [[UIButton alloc] initWithFrame:CGRectMake(textBtn.frame.origin.x + btnWH + btnMargin, -btnWH, btnWH, btnWH)]; [locationBtn setImage:[UIImage imageNamed:@"addtaglocation"] forState:UIControlStateNormal]; [locationBtn setImage:[UIImage imageNamed:@"addtaglocation_selected"] forState:UIControlStateSelected]; [locationBtn addTarget:self action:@selector(clickLocation) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:locationBtn]; self.locationBtn = locationBtn; UILabel *locationLabel = [[UILabel alloc] init]; locationLabel.frame = (CGRect){{locationBtn.frame.origin.x, CGRectGetMaxY(locationBtn.frame)}, locationBtn.frame.size}; locationLabel.text = @"地點"; locationLabel.textAlignment = NSTextAlignmentCenter; locationLabel.textColor = [UIColor whiteColor]; locationLabel.font = [UIFont systemFontOfSize:12]; [self .view addSubview:locationLabel]; self.locationLabel = locationLabel; }
好了,定義好這兩個按鈕,其實是看不見的。因為我們做了一個效果,當點擊圖片,按鈕會蹦出來,當再點擊圖片,按鈕會蹦回去。在這個過程,我只是做了簡單的平移動畫,從上到下出現。有興趣的可以自己定義動畫(比如彈簧效果)。
點擊圖片的響應方法
- (void)clickimage:(UITapGestureRecognizer *)sender { //記得定義成員變量isClick用來判斷是否點擊圖片,初始化為NO if (self.isClick) { //如果有點擊圖片,讓按鈕消失 self.isClick = NO; //按鈕消失動畫 [UIView animateWithDuration:1.0 animations:^{ self.textBtn.frame = CGRectMake((screenW - btnWH * 2 - btnMargin) * 0.5, -btnWH, btnWH, btnWH); self.locationBtn.frame = CGRectMake(self.textBtn.frame.origin.x + btnWH + btnMargin, -btnWH, btnWH, btnWH); self.textLabel.frame = (CGRect){{self.textBtn.frame.origin.x, CGRectGetMaxY(self.textBtn.frame) + 5}, self.textBtn.frame.size}; self.locationLabel.frame = (CGRect){{self.locationBtn.frame.origin.x, CGRectGetMaxY(self.locationBtn.frame) + 5}, self.locationBtn.frame.size}; }]; } else { //如果沒有點擊圖片,讓按鈕出現。此時就是用戶開始進行添加標簽過程 self.isClick = YES; //記錄下用戶點擊的位置,點擊的位置就是所添加標簽的位置。 CGPoint point = [sender locationInView:self.imageview]; //用成員變量保存點擊的位置 self.clickpoint = point; //用小圓圈圖片做一個標記,讓用戶知道自己點了哪里。 UIImageView *pointView = [[UIImageView alloc] initWithFrame:CGRectMake(point.x, point.y, 15, 15)]; pointView.image = [UIImage imageNamed:@"tagpoint"]; pointView.tag = 1001; [self.imageview addSubview:pointView]; //按鈕出現動畫 [UIView animateWithDuration:1.0 animations:^{ self.textBtn.frame = CGRectMake((screenW - btnWH * 2 - btnMargin) * 0.5, (screenW - btnWH) * 0.5 + 64, btnWH, btnWH); self.locationBtn.frame = CGRectMake(self.textBtn.frame.origin.x + btnWH + btnMargin, (screenW - btnWH) * 0.5 + 64, btnWH, btnWH); self.textLabel.frame = (CGRect){{self.textBtn.frame.origin.x, CGRectGetMaxY(self.textBtn.frame)}, self.textBtn.frame.size}; self.locationLabel.frame = (CGRect){{self.locationBtn.frame.origin.x, CGRectGetMaxY(self.locationBtn.frame)}, self.locationBtn.frame.size}; }]; } }
3、響應按鈕點擊
- (void)clickText { //將狀態變成未點擊 self.isClick = NO; [UIView animateWithDuration:0.3 animations:^{ self.textBtn.frame = CGRectMake((screenW - btnWH * 2 - btnMargin) * 0.5, -btnWH, btnWH, btnWH); self.locationBtn.frame = CGRectMake(self.textBtn.frame.origin.x + btnWH + btnMargin, -btnWH, btnWH, btnWH); self.textLabel.frame = (CGRect){{self.textBtn.frame.origin.x, CGRectGetMaxY(self.textBtn.frame) + 5}, self.textBtn.frame.size}; self.locationLabel.frame = (CGRect){{self.locationBtn.frame.origin.x, CGRectGetMaxY(self.locationBtn.frame) + 5}, self.locationBtn.frame.size}; }]; //自定義一個添加文字的View,如下圖所示。 UIWindow *windows = [UIApplication sharedApplication].keyWindow; LMAddTextTagView *addtext = [[LMAddTextTagView alloc] init]; addtext.delegate = self; addtext.frame = [UIScreen mainScreen].bounds; addtext.tagListArray = self.taglistArray; [windows addSubview:addtext]; }

在這個界面,用戶可以自己創建標簽文字。這個界面並不難,添加好后,將文字傳到添加標簽界面,通過代理就可以實現,不貼代碼了。
4、封裝標簽信息並顯示標簽
這里我們定義了兩個實體類,LMTagInfo和LMTagFrameInfo。前一個封裝了標簽信息,后一個封裝了標簽子控件的frame信息。
// // LMTagInfo.h // 辣媽萌寶 #import <Foundation/Foundation.h> @interface LMTagInfo : NSObject @property(nonatomic, assign)CGFloat tagX; @property(nonatomic, assign)CGFloat tagY; /** 0表示文字標簽 1表示位置標簽 **/ @property(nonatomic, assign)int tagType; @property(nonatomic, copy)NSString *tagText; @end
// // LMTagFrameInfo.h // 辣媽萌寶 #import <Foundation/Foundation.h> @class LMTagInfo; @interface LMTagFrameInfo : NSObject @property(nonatomic, strong)LMTagInfo *tagInfo; /** 整個View **/ @property(nonatomic, assign)CGRect viewF; /** logoView **/ @property(nonatomic, assign)CGRect logoViewF; /** 文字按鈕 **/ @property(nonatomic, assign)CGRect textButtonF; /** 文字 **/ @property(nonatomic, assign)CGRect textLabelF; /** 左右判斷 **/ @property(nonatomic, assign)int isRight;
根據標簽信息算好標簽的Frame
// // LMTagFrameInfo.m // 辣媽萌寶 #import "LMTagFrameInfo.h" #import "LMTagInfo.h" #define pointWH 15 #define textBGW 22 #define textBGH 27 @implementation LMTagFrameInfo - (void)setTagInfo:(LMTagInfo *)tagInfo { _tagInfo = tagInfo; CGSize textSize = [tagInfo.tagText sizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:12]}]; CGFloat viewX; CGFloat viewY = tagInfo.tagY - textBGH * 0.5; CGFloat viewW = textBGW + textSize.width + pointWH; CGFloat viewH = textBGH; CGFloat logoViewX; CGFloat logoViewWH = pointWH; CGFloat logoViewY = (viewH - logoViewWH) * 0.5; CGFloat textButtonX; CGFloat textButtonY = 0; CGFloat textButtonW = textBGW + textSize.width; CGFloat textButtonH = textBGH; CGFloat textLabelX; CGFloat textLabelY = (textButtonH - textSize.height) * 0.5; CGFloat textLabelW = textSize.width; CGFloat textLabelH = textSize.height; if (textSize.width + textBGW + pointWH + tagInfo.tagX >= screenW) { //文字朝左 _isRight = 0; viewX = tagInfo.tagX - textSize.width - textBGW - pointWH * 0.5; logoViewX = textButtonW; textButtonX = 0; textLabelX = 0.3 * textBGW; } else { //文字朝右 _isRight = 1; viewX = tagInfo.tagX - pointWH * 0.5; logoViewX = 0; textButtonX = logoViewWH; textLabelX = textButtonX + 0.7 *textBGW; } _viewF = CGRectMake(viewX, viewY, viewW, viewH); _logoViewF = CGRectMake(logoViewX, logoViewY, logoViewWH, logoViewWH); _textButtonF = CGRectMake(textButtonX, textButtonY, textButtonW, textButtonH); _textLabelF = CGRectMake(textLabelX, textLabelY, textLabelW, textLabelH); } @end
然后就是自定義標簽View
// // LMTagView.h // 辣媽萌寶 #import <UIKit/UIKit.h> @class LMTagFrameInfo; @interface LMTagView : UIImageView @property(nonatomic, strong)LMTagFrameInfo *tagFrameInfo; //用來判斷這個標簽是否可以移動改變其位置 @property(nonatomic, assign)BOOL isTouch; @end
// // LMTagView.m // 辣媽萌寶 #import "LMTagView.h" #import "LMTagFrameInfo.h" #import "LMTagInfo.h" #import "UIImage+MJ.h" @interface LMTagView () @property(nonatomic, weak)UIImageView *logoView; @property(nonatomic, weak)UIImageView *textButton; @property(nonatomic, weak)UILabel *textLabel; @property(nonatomic, weak)UIImageView *animationView; @property(nonatomic, assign)CGPoint beginPoint; @property(nonatomic, assign)CGPoint beginCenter; @end @implementation LMTagView - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { self.userInteractionEnabled = YES; self.backgroundColor = [UIColor clearColor]; UIImageView *logoView = [[UIImageView alloc] init]; [self addSubview:logoView]; self.logoView = logoView; UIImageView *textButton = [[UIImageView alloc] init]; textButton.userInteractionEnabled = YES; [self addSubview:textButton]; self.textButton = textButton; UILabel *textLabel = [[UILabel alloc] init]; textLabel.textColor = [UIColor whiteColor]; textLabel.textAlignment = NSTextAlignmentCenter; textLabel.font = [UIFont systemFontOfSize:12]; [self addSubview:textLabel]; self.textLabel = textLabel; } return self; } - (void)setTagFrameInfo:(LMTagFrameInfo *)tagFrameInfo { _tagFrameInfo = tagFrameInfo; LMTagInfo *tagInfo = tagFrameInfo.tagInfo; self.logoView.frame = tagFrameInfo.logoViewF; if (tagInfo.tagType == 0) { self.logoView.image = [UIImage imageNamed:@"tagpoint"]; } else { self.logoView.image = [UIImage imageNamed:@"taglocation"]; } self.textButton.frame = tagFrameInfo.textButtonF; if (tagFrameInfo.isRight == 1) { self.textButton.image = [UIImage resizedImageWithName:@"tag_text_bg_left" left:0.7 top:0.5]; } else { self.textButton.image = [UIImage resizedImageWithName:@"tag_text_bg_right" left:0.3 top:0.5]; } self.textLabel.frame = tagFrameInfo.textLabelF; self.textLabel.text = tagInfo.tagText; } - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { if (!self.isTouch) { return; } UITouch *touch = [touches anyObject]; self.beginPoint = [touch locationInView:self]; self.beginCenter = self.center; } - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { if (!self.isTouch) { return; } UITouch *touch = [touches anyObject]; CGPoint nowPoint = [touch locationInView:self]; float offsetX = nowPoint.x - self.beginPoint.x; float offsetY = nowPoint.y - self.beginPoint.y; CGPoint newcenter = CGPointMake(self.center.x + offsetX, self.center.y + offsetY); float halfx = CGRectGetMidX(self.bounds); newcenter.x = MAX(halfx, newcenter.x); newcenter.x = MIN(self.superview.bounds.size.width - halfx, newcenter.x); float halfy = CGRectGetMidY(self.bounds); newcenter.y = MAX(halfy, newcenter.y); newcenter.y = MIN(self.superview.bounds.size.height - halfy, newcenter.y); self.center = newcenter; } - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { if (!self.isTouch) { return; } self.tagFrameInfo.tagInfo.tagX += self.center.x - self.beginCenter.x; self.tagFrameInfo.tagInfo.tagY += self.center.y - self.beginCenter.y; } @end
好了,我們需要的信息和view都定義好了,其中這個標簽添加好后,是可以拖拽它,更改它的位置。然后用到的圖片素材我會放到最后。
接着在控制器中響應添加標簽方法
- (void)addTextTagWith:(NSString *)tagtext { LMTagInfo *tagInfo = [[LMTagInfo alloc] init]; tagInfo.tagX = self.clickpoint.x; tagInfo.tagY = self.clickpoint.y; tagInfo.tagText = tagtext;
tagInfo.tagType = 0; //addtagArray用於存放標簽信息,因為標簽可能不止一個。 [self.addtagArray addObject:tagInfo]; LMTagFrameInfo *tagFrameInfo = [[LMTagFrameInfo alloc] init]; tagFrameInfo.tagInfo = tagInfo; LMTagView *tagView = [[LMTagView alloc] init]; tagView.userInteractionEnabled = YES; //同時點擊標簽可以提示是否刪除此標簽,刪除方法中將tagInfo從addtagArray數組中刪除然后再將tagView從superview刪除即可。 UITapGestureRecognizer *tagtap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(clickDelete:)]; [tagView addGestureRecognizer:tagtap]; tagView.isTouch = YES; tagView.frame = tagFrameInfo.viewF; tagView.tagFrameInfo = tagFrameInfo; [self.imageview addSubview:tagView]; }
效果如圖所示

可以拖拽標簽改變其位置哦,嘿嘿。另外地理標簽同位置標簽一樣,將tagType設置為1就行了。
文字信息建議使用高德地圖,可以獲取到用戶附近建築物地址,用戶選擇好,傳回地址文字信息就行了。

5、提交信息到服務器。
需要服務器端配合,我們做的標簽圖片,標簽信息和圖片信息是分開的,但需要一一對應。
6、用到的資源




![]()
![]()
![]()
![]()
#import "UIImage+MJ.h" @implementation UIImage (MJ) //用於拉伸圖片的分類 + (UIImage *)resizedImageWithName:(NSString *)name { return [self resizedImageWithName:name left:0.5 top:0.5]; } + (UIImage *)resizedImageWithName:(NSString *)name left:(CGFloat)left top:(CGFloat)top { UIImage *image = [self imageNamed:name]; return [image stretchableImageWithLeftCapWidth:image.size.width * left topCapHeight:image.size.height * top]; } @end
