iOS微信朋友圈的點贊、評論功能,即點擊昵稱跳轉到個人主頁

pskz8116 8年前發布 | 25K 次閱讀 iOS開發 移動開發

很多社交軟件,都會有這么一個功能,就是點擊部分文字,觸發一個事件,像微信朋友圈、QQ空間那樣點擊評論者的昵稱跳轉到個人主頁,或者點擊點贊人的昵稱跳轉到個人主頁。

本菜鳥在做社交項目的時候也遇到這個問題,一開始不知道怎么處理好。找了網上的方法,都是說:1:昵稱上面覆蓋一個UIButton 。 2:設置文字部分區域,觸發事件。

本菜鳥覺得第二種方法可靠,于是找了第三方,比如:TTTAttributedLabel、YYText 、RTLabel都是很不錯的第三方富文本。但是本菜鳥又突發奇想,我只是要實現這個簡單的功能,強大的蘋果應該不至于這么傻吧,于是就想著這么折騰一個不用第三方的辦法出來,然后就.... 你懂的 ... 下面直接貼效果圖 ... 不喜勿噴,大神多多指教。</code></pre>

評論的效果圖:

點贊的效果圖:

直接貼代碼:(調用UILable的擴展類)

在使用的地方調用方法:

-(void)richTextLable
{
    //評論
    NSString nameOne = @"張三";
    NSString nameTwo = @"我是李四";
    NSString *replyString = @"您好,您現在在干什么,么么噠。這個功能應該滿足需求了。";

NSString *totalString = [NSString stringWithFormat:@"%@回復%@:%@",nameOne,nameTwo,replyString];
NSMutableAttributedString *newString = [[NSMutableAttributedString alloc] initWithString:totalString];
[newString addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:16] range:NSMakeRange(0, totalString.length)];
[newString addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:NSMakeRange(0, nameOne.length)];
[newString addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:NSMakeRange(nameOne.length+2, nameTwo.length)];
//設置行距 實際開發中間距為0太丑了,根據項目需求自己把握
NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init];
style.lineSpacing = 3;
[newString addAttribute:NSParagraphStyleAttributeName value:style range:NSMakeRange(0, totalString.length)];

UILabel *richTextLbl = [[UILabel alloc] initWithFrame:CGRectMake(20, 100, self.view.bounds.size.width - 40, 20)];
//richTextLbl.backgroundColor = [UIColor greenColor];
richTextLbl.numberOfLines = 0;//設置UILable自適應
richTextLbl.attributedText = newString;
[self.view addSubview:richTextLbl];
[richTextLbl sizeToFit];

[richTextLbl onTapRangeActionWithString:@[nameOne,nameTwo] tapClicked:^(NSString *string, NSRange range, NSInteger index) {
    NSLog(@"點擊了-->--%@ ---下標:%ld",string,index);
}];


//點贊
UILabel *goodLbl = [[UILabel alloc] init];
goodLbl.frame = CGRectMake(20, 170, 100, 20);
goodLbl.text = @"點贊的:";
[self.view addSubview:goodLbl];

NSArray *goodArray = @[@"張三",@"李四",@"王五",@"李兆",@"粟子",@"小李",@"李四",@"王五",@"李兆",@"粟子",@"小李"];
NSString *goodTotalString = [goodArray componentsJoinedByString:@", "];

NSMutableAttributedString *newGoodString = [[NSMutableAttributedString alloc] initWithString:goodTotalString];
[newGoodString addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:16] range:NSMakeRange(0, goodTotalString.length)];

//設置行距 實際開發中間距為0太丑了,根據項目需求自己把握
NSMutableParagraphStyle *paragraphstyle = [[NSMutableParagraphStyle alloc] init];
paragraphstyle.lineSpacing = 3;
[newGoodString addAttribute:NSParagraphStyleAttributeName value:paragraphstyle range:NSMakeRange(0, goodTotalString.length)];

UILabel *goodTextLbl = [[UILabel alloc] initWithFrame:CGRectMake(20, 200, self.view.bounds.size.width - 40, 20)];
goodTextLbl.backgroundColor = [UIColor orangeColor];
goodTextLbl.numberOfLines = 0;//設置UILable自適應
goodTextLbl.attributedText = newGoodString;
[self.view addSubview:goodTextLbl];
[goodTextLbl sizeToFit];

[goodTextLbl onTapRangeActionWithString:goodArray tapClicked:^(NSString *string, NSRange range, NSInteger index) {
    NSLog(@"這是第--%ld--個點贊的,他是--%@",index,string);
}];

}</code></pre>

下面是UILable擴展類

#import <UIKit/UIKit.h>

@interface XLRichTextModel : NSObject

@property (nonatomic, copy) NSString *string; @property (nonatomic, assign) NSRange range;

@end

@interface UILabel (Category)

///是否顯示點擊效果,默認是打開 @property (nonatomic, assign) BOOL isShowTagEffect;

///TagArray 點擊的字符串數組

  • (void)onTapRangeActionWithString:(NSArray <NSString > )TagArray tapClicked:(void (^) (NSString *string , NSRange range , NSInteger index))tapClick;

@end</code></pre>

#import "UILabel+Category.h"

import <objc/runtime.h>

import <CoreText/CoreText.h>

import <Foundation/Foundation.h>

@implementation XLRichTextModel

@end

@implementation UILabel (Category)

pragma mark - AssociatedObjects

  • (NSMutableArray *)attributeStrings { return objc_getAssociatedObject(self, _cmd); }

  • (void)setAttributeStrings:(NSMutableArray *)attributeStrings { objc_setAssociatedObject(self, @selector(attributeStrings), attributeStrings, OBJC_ASSOCIATION_RETAIN_NONATOMIC); }

  • (NSMutableDictionary *)effectDic { return objc_getAssociatedObject(self, _cmd); }

  • (void)setEffectDic:(NSMutableDictionary *)effectDic { objc_setAssociatedObject(self, @selector(effectDic), effectDic, OBJC_ASSOCIATION_RETAIN_NONATOMIC); }

  • (BOOL)isTapAction { return [objc_getAssociatedObject(self, _cmd) boolValue]; }

  • (void)setIsTapAction:(BOOL)isTapAction { objc_setAssociatedObject(self, @selector(isTapAction), @(isTapAction), OBJC_ASSOCIATION_ASSIGN); }

  • (void (^)(NSString *, NSRange, NSInteger))tapBlock { return objc_getAssociatedObject(self, _cmd); }

  • (void)setTapBlock:(void (^)(NSString *, NSRange, NSInteger))tapBlock { objc_setAssociatedObject(self, @selector(tapBlock), tapBlock, OBJC_ASSOCIATION_COPY_NONATOMIC); }

  • (BOOL)isShowTagEffect { return [objc_getAssociatedObject(self, _cmd) boolValue]; }

-(void)setIsShowTagEffect:(BOOL)isShowTagEffect { objc_setAssociatedObject(self, @selector(isShowTagEffect), @(isShowTagEffect), OBJC_ASSOCIATION_ASSIGN); self.isTapEffect = isShowTagEffect; }

  • (BOOL)isTapEffect { return [objc_getAssociatedObject(self, _cmd) boolValue]; }

  • (void)setIsTapEffect:(BOOL)isTapEffect { objc_setAssociatedObject(self, @selector(isTapEffect), @(isTapEffect), OBJC_ASSOCIATION_ASSIGN); }

pragma mark - 事件方法

  • (void)onTapRangeActionWithString:(NSArray <NSString > )TagArray tapClicked:(void (^) (NSString *string , NSRange range , NSInteger index))tapClick { //獲取部分點擊的區域 [self tagRangeActionWithString:TagArray];

    if (self.tapBlock != tapClick) {

      self.tapBlock = tapClick;
    

    } }

pragma mark - touchAction

  • (void)touchesBegan:(NSSet<UITouch > )touches withEvent:(UIEvent *)event { if (!self.isTapAction) {

      return;
    

    }

    if (objc_getAssociatedObject(self, @selector(isShowTagEffect))) {

      self.isTapEffect = self.isShowTagEffect;
    

    }

    UITouch *touch = [touches anyObject];

    CGPoint point = [touch locationInView:self];

    __weak typeof(self) weakSelf = self;

    [self tapFrameWithTouchPoint:point result:^(NSString *string, NSRange range, NSInteger index) {

      if (weakSelf.tapBlock) {
          weakSelf.tapBlock (string , range , index);
      }
    
      if (self.isTapEffect) {
    
          [self saveEffectDicWithRange:range];
    
          [self tapEffectWithStatus:YES];
      }
    
    

    }]; }

  • (UIView )hitTest:(CGPoint)point withEvent:(UIEvent )event {

    if (self.isTapAction) {

      if ([self tapFrameWithTouchPoint:point result:nil]) {
          return self;
      }
    

    } return [super hitTest:point withEvent:event]; }

pragma mark - 獲取點擊的范圍

  • (BOOL)tapFrameWithTouchPoint:(CGPoint)point result:(void (^) (NSString *string , NSRange range , NSInteger index))resultBlock { CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)self.attributedText);

    CGMutablePathRef Path = CGPathCreateMutable();

    CGPathAddRect(Path, NULL, CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height));

    CTFrameRef frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), Path, NULL);

    CFRange range = CTFrameGetVisibleStringRange(frame);

    if (self.attributedText.length > range.length) {

      UIFont *font ;
    
      if ([self.attributedText attribute:NSFontAttributeName atIndex:0 effectiveRange:nil]) {
    
          font = [self.attributedText attribute:NSFontAttributeName atIndex:0 effectiveRange:nil];
    
      }else if (self.font){
          font = self.font;
    
      }else {
          font = [UIFont systemFontOfSize:17];
      }
    
      Path = CGPathCreateMutable();
    
      CGPathAddRect(Path, NULL, CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height + font.lineHeight));
    
      frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), Path, NULL);
    

    }

    CFArrayRef lines = CTFrameGetLines(frame);

    if (!lines) {

      return NO;
    

    }

    CFIndex count = CFArrayGetCount(lines);

    CGPoint origins[count];

    CTFrameGetLineOrigins(frame, CFRangeMake(0, 0), origins);

    CGAffineTransform transform = [self transformForCoreText];

    CGFloat verticalOffset = 0;

    for (CFIndex i = 0; i < count; i++) {

      CGPoint linePoint = origins[i];
    
      CTLineRef line = CFArrayGetValueAtIndex(lines, i);
    
      CGRect flippedRect = [self lineBounds:line point:linePoint];
    
      CGRect rect = CGRectApplyAffineTransform(flippedRect, transform);
    
      rect = CGRectInset(rect, 0, 0);
    
      rect = CGRectOffset(rect, 0, verticalOffset);
    
      NSParagraphStyle *style = [self.attributedText attribute:NSParagraphStyleAttributeName atIndex:0 effectiveRange:nil];
    
      CGFloat lineSpace;
    
      if (style) {
          lineSpace = style.lineSpacing;
      }else {
          lineSpace = 0;
      }
    
      CGFloat lineOutSpace = (self.bounds.size.height - lineSpace * (count - 1) -rect.size.height * count) / 2;
    
      rect.origin.y = lineOutSpace + rect.size.height * i + lineSpace * i;
    
      if (CGRectContainsPoint(rect, point)) {
    
          CGPoint relativePoint = CGPointMake(point.x - CGRectGetMinX(rect), point.y - CGRectGetMinY(rect));
    
          CFIndex index = CTLineGetStringIndexForPosition(line, relativePoint);
    
          CGFloat offset;
    
          CTLineGetOffsetForStringIndex(line, index, &offset);
    
          if (offset > relativePoint.x) {
              index = index - 1;
          }
    
          NSInteger link_count = self.attributeStrings.count;
    
          for (int j = 0; j < link_count; j++) {
    
              XLRichTextModel *model = self.attributeStrings[j];
    
              NSRange link_range = model.range;
              if (NSLocationInRange(index, link_range)) {
                  if (resultBlock) {
                      resultBlock (model.string , model.range , (NSInteger)j);
                  }
                  return YES;
              }
          }
      }
    

    } return NO; }

  • (void)touchesEnded:(NSSet<UITouch > )touches withEvent:(UIEvent *)event { if (self.isTapEffect) {

      [self performSelectorOnMainThread:@selector(tapEffectWithStatus:) withObject:nil waitUntilDone:NO];
    
    

    } }

  • (void)touchesCancelled:(NSSet<UITouch > )touches withEvent:(UIEvent *)event { if (self.isTapEffect) {

      [self performSelectorOnMainThread:@selector(tapEffectWithStatus:) withObject:nil waitUntilDone:NO];
    
    

    } }

  • (CGAffineTransform)transformForCoreText { return CGAffineTransformScale(CGAffineTransformMakeTranslation(0, self.bounds.size.height), 1.f, -1.f); }

  • (CGRect)lineBounds:(CTLineRef)line point:(CGPoint)point { CGFloat ascent = 0.0f; CGFloat descent = 0.0f; CGFloat leading = 0.0f; CGFloat width = (CGFloat)CTLineGetTypographicBounds(line, &ascent, &descent, &leading); CGFloat height = ascent + fabs(descent) + leading;

    return CGRectMake(point.x, point.y , width, height); }

pragma mark - 是否顯示點擊效果 默認是 項目中一般是現實點擊效果

  • (void)tapEffectWithStatus:(BOOL)status { if (self.isTapEffect) {

      NSMutableAttributedString *attStr = [[NSMutableAttributedString alloc] initWithAttributedString:self.attributedText];
    
      NSMutableAttributedString *subAtt = [[NSMutableAttributedString alloc] initWithAttributedString:[[self.effectDic allValues] firstObject]];
    
      NSRange range = NSRangeFromString([[self.effectDic allKeys] firstObject]);
    
      if (status) {
          [subAtt addAttribute:NSBackgroundColorAttributeName value:[UIColor lightGrayColor] range:NSMakeRange(0, subAtt.string.length)];
    
          [attStr replaceCharactersInRange:range withAttributedString:subAtt];
      }else {
    
          [attStr replaceCharactersInRange:range withAttributedString:subAtt];
      }
      self.attributedText = attStr;
    

    } }

  • (void)saveEffectDicWithRange:(NSRange)range { self.effectDic = [NSMutableDictionary dictionary];

    NSAttributedString *subAttribute = [self.attributedText attributedSubstringFromRange:range];

    [self.effectDic setObject:subAttribute forKey:NSStringFromRange(range)]; }

pragma mark - 獲取部分點擊的區域

  • (void)tagRangeActionWithString:(NSArray <NSString > )strings { if (self.attributedText == nil) {

      self.isTapAction = NO;
      return;
    

    }

    self.isTapAction = YES;

    self.isTapEffect = YES;

    __block NSString *totalStr = self.attributedText.string;

    self.attributeStrings = [NSMutableArray array];

    __weak typeof(self) weakSelf = self;

    [strings enumerateObjectsUsingBlock:^(NSString _Nonnull obj, NSUInteger idx, BOOL _Nonnull stop) {

      NSRange range = [totalStr rangeOfString:obj];
    
      if (range.length != 0) {
    
          totalStr = [totalStr stringByReplacingCharactersInRange:range withString:[weakSelf stringWithRange:range]];
    
          XLRichTextModel *model = [XLRichTextModel new];
    
          model.range = range;
    
          model.string = obj;
    
          [weakSelf.attributeStrings addObject:model];
    
      }
    
    

    }]; }

  • (NSString )stringWithRange:(NSRange)range { NSMutableString string = [NSMutableString string];

    for (int i = 0; i < range.length ; i++) {

      [string appendString:@" "];
    

    } return string; }

@end</code></pre>

 

來自:http://www.jianshu.com/p/34369aed6789

 

 本文由用戶 pskz8116 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!