Git Product home page Git Product logo

zswtappablelabel's Introduction

ZSWTappableLabel

Version License Platform

ZSWTappableLabel is a UILabel subclass powered by NSAttributedStrings which allows you to tap on certain regions, with optional highlight behavior. It does not draw text itself and executes a minimal amount of code unless the user is interacting with a tappable region.

A basic, tappable link

Let's create a string that's entirely tappable and shown with an underline:

NSString *s = NSLocalizedString(@"Privacy Policy", nil);
NSDictionary *a = @{
  ZSWTappableLabelTappableRegionAttributeName: @YES,
  ZSWTappableLabelHighlightedBackgroundAttributeName: [UIColor lightGrayColor],
  ZSWTappableLabelHighlightedForegroundAttributeName: [UIColor whiteColor],
  NSForegroundColorAttributeName: [UIColor blueColor],
  NSUnderlineStyleAttributeName: @(NSUnderlineStyleSingle),

  // You could use NSLinkAttributeName, but this forces foreground color
  @"URL": [NSURL URLWithString:@"http://imgur.com/gallery/VgXCk"],
};

label.attributedText = [[NSAttributedString alloc] initWithString:s attributes:a];

This results in a label which renders like:

Privacy Policy

Setting your controller as the tapDelegate of the label results in the following method call when tapped:

- (void)tappableLabel:(ZSWTappableLabel *)tappableLabel
        tappedAtIndex:(NSInteger)idx
       withAttributes:(NSDictionary *)attributes {
  [[UIApplication sharedApplication] openURL:attributes[@"URL"]];
}

Data detectors

Let's use NSDataDetector to find the substrings in a given string that we might want to turn into links:

NSString *string = @"check google.com or call 415-555-5555? how about friday at 5pm?";

NSDataDetector *detector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingAllSystemTypes error:NULL];
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:string attributes:nil];
// the next line throws an exception if string is nil - make sure you check
[detector enumerateMatchesInString:string options:0 range:NSMakeRange(0, string.length) usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
  NSMutableDictionary *attributes = [NSMutableDictionary dictionary];
  attributes[ZSWTappableLabelTappableRegionAttributeName] = @YES;
  attributes[ZSWTappableLabelHighlightedBackgroundAttributeName] = [UIColor lightGrayColor];
  attributes[ZSWTappableLabelHighlightedForegroundAttributeName] = [UIColor whiteColor];
  attributes[NSUnderlineStyleAttributeName] = @(NSUnderlineStyleSingle);
  attributes[@"NSTextCheckingResult"] = result;
  [attributedString addAttributes:attributes range:result.range];
}];
label.attributedText = attributedString;

This results in a label which renders like:

check google.com or call 415-555-5555? how about friday at 5pm?

We can wire up the tapDelegate to receive the checking result and handle each result type when the user taps on the link:

- (void)tappableLabel:(ZSWTappableLabel *)tappableLabel
        tappedAtIndex:(NSInteger)idx
       withAttributes:(NSDictionary *)attributes {
  NSTextCheckingResult *result = attributes[@"NSTextCheckingResult"];
  if (result) {
    switch (result.resultType) {
      case NSTextCheckingTypeAddress:
        NSLog(@"Address components: %@", result.addressComponents);
        break;
          
      case NSTextCheckingTypePhoneNumber:
        NSLog(@"Phone number: %@", result.phoneNumber);
        break;
          
      case NSTextCheckingTypeDate:
        NSLog(@"Date: %@", result.date);
        break;
          
      case NSTextCheckingTypeLink:
        NSLog(@"Link: %@", result.URL);
        break;

      default:
        break;
    }
  }
}

Substring linking

For substring linking, I suggest you use ZSWTaggedString which creates these attributed strings painlessly and localizably. Let's create a more advanced 'privacy policy' link using this library:

View our Privacy Policy or Terms of Service

You can create such a string using a simple ZSWTaggedString:

ZSWTaggedStringOptions *options = [ZSWTaggedStringOptions options];
[options setDynamicAttributes:^NSDictionary *(NSString *tagName, 
                                              NSDictionary *tagAttributes,
                                              NSDictionary *existingStringAttributes) {
  NSURL *URL;
  if ([tagAttributes[@"type"] isEqualToString:@"privacy"]) {
    URL = [NSURL URLWithString:@"http://google.com/search?q=privacy"];
  } else if ([tagAttributes[@"type"] isEqualToString:@"tos"]) {
    URL = [NSURL URLWithString:@"http://google.com/search?q=tos"];
  }

  if (!URL) {
    return nil;
  }

  return @{
    ZSWTappableLabelTappableRegionAttributeName: @YES,
    ZSWTappableLabelHighlightedBackgroundAttributeName: [UIColor lightGrayColor],
    ZSWTappableLabelHighlightedForegroundAttributeName: [UIColor whiteColor],
    NSForegroundColorAttributeName: [UIColor blueColor],
    NSUnderlineStyleAttributeName: @(NSUnderlineStyleSingle),
    @"URL": URL
  };
} forTagName:@"link"];

NSString *string = NSLocalizedString(@"View our <link type='privacy'>Privacy Policy</link> or <link type='tos'>Terms of Service</link>", nil);
label.attributedText = [[ZSWTaggedString stringWithString:string] attributedStringWithOptions:options];

VoiceOver

ZSWTappableLabel is an accessibility container, which exposes the substrings in your attributed string as distinct elements. For example, the above string breaks down into:

  1. View our (static text)
  2. Privacy Policy (link)
  3. or (static text)
  4. Terms of Service (link)

Interaction with gesture recognizers

ZSWTappableLabel uses gesture recognizers internally and works well with other gesture recognizers:

  • If there are no tappable regions, internal gesture recognizers are disabled.
  • If a touch occurs within a tappable region, all other gesture recognizers are failed if the label is interested in them.
  • If a touch occurs outside a tappable region, internal gesture recognizers fail themselves.

For example, if you place a UITapGestureRecognizer on the label, it will only fire when the user does not interact with a tappable region.

Installation

ZSWTappableLabel is available through CocoaPods. To install it, simply add the following line to your Podfile:

pod "ZSWTappableLabel", "~> 1.1"

License

ZSWTappableLabel is available under the MIT license. This library was created while working on Free who allowed this to be open-sourced.

zswtappablelabel's People

Contributors

zacwest avatar

Watchers

MohsinAli avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.