objective c - iOS UITextView or UILabel with clickable links to actions -


this question has answer here:

i want make uilabel or uitextview text 2 clickable links in it. not links webpages want link 2 links actions uibutton. examples i've seen links webviews dont want that. well, text translated in other languages positions have dynamic.

want make this:

enter image description here

i needed solve exact same problem: similar text 2 links in it, on multiple lines, , needing able translated in language (including different word orders, etc). solved it, let me share how did it.

initially thinking should create attributed text , map tap's touch location regions within text. while think doable, think it's complicated approach.

this ended doing instead:

summary:

  • have basic custom markup in english message can parse out different pieces
  • instruct translators leave markup in , translate rest
  • have uiview can serve container of message
  • break english message in pieces separate regular text clickable text
  • for each piece create uilabel on container uiview
  • for clickable pieces, set styling, allow user interaction , create tap gesture recognizer
  • do basic bookkeeping place words across lines

detail:

in view controller's viewdidload placed this:

[self buildagreetextviewfromstring:nslocalizedstring(@"i agree #<ts>terms of service# , #<pp>privacy policy#",                                                       @"please note: please translate \"terms of service\" , \"privacy policy\" well, , leave #<ts># , #<pp># around translations in english version of message.")]; 

i'm calling method build message. note markup came with. can of course invent own, key mark ends of each clickable region because span on multiple words.

here's method puts message -- see below. first break english message on # character (or rather @"#" string). way each piece need create label separately. loop on them , basic markup of <ts> , <pp> detect pieces links what. if chunk of text i'm working link, style bit , set tap gesture recogniser it. strip out markup characters of course. think easy way it.

note subtleties how handle spaces: take spaces (localised) string. if there no spaces (chinese, japanese), there won't spaces between chunks either. if there spaces, automatically space out chunks needed (e.g. english). when have place word @ start of next line though, need make sure strip of white space prefix text, because otherwise doesn't align properly.

- (void)buildagreetextviewfromstring:(nsstring *)localizedstring {   // 1. split localized string on # sign:   nsarray *localizedstringpieces = [localizedstring componentsseparatedbystring:@"#"];    // 2. loop through pieces:   nsuinteger msgchunkcount = localizedstringpieces ? localizedstringpieces.count : 0;   cgpoint wordlocation = cgpointmake(0.0, 0.0);   (nsuinteger = 0; < msgchunkcount; i++)   {     nsstring *chunk = [localizedstringpieces objectatindex:i];     if ([chunk isequaltostring:@""])     {       continue;     // skip loop if chunk empty     }      // 3. determine type of word is:     bool istermsofservicelink = [chunk hasprefix:@"<ts>"];     bool isprivacypolicylink  = [chunk hasprefix:@"<pp>"];     bool islink = (bool)(istermsofservicelink || isprivacypolicylink);      // 4. create label, styling dependent on whether it's link:     uilabel *label = [[uilabel alloc] init];     label.font = [uifont systemfontofsize:15.0f];     label.text = chunk;     label.userinteractionenabled = islink;      if (islink)     {       label.textcolor = [uicolor colorwithred:110/255.0f green:181/255.0f blue:229/255.0f alpha:1.0];       label.highlightedtextcolor = [uicolor yellowcolor];        // 5. set tap gesture clickable text:       sel selectoraction = istermsofservicelink ? @selector(tapontermsofservicelink:) : @selector(taponprivacypolicylink:);       uitapgesturerecognizer *tapgesture = [[uitapgesturerecognizer alloc] initwithtarget:self                                                                                    action:selectoraction];       [label addgesturerecognizer:tapgesture];        // trim markup characters label:       if (istermsofservicelink)          label.text = [label.text stringbyreplacingoccurrencesofstring:@"<ts>" withstring:@""];       if (isprivacypolicylink)           label.text = [label.text stringbyreplacingoccurrencesofstring:@"<pp>" withstring:@""];     }     else     {       label.textcolor = [uicolor whitecolor];     }      // 6. lay out labels forms complete sentence again:      // if word doesn't fit @ end of line, move next     // line , make sure leading spaces stripped off aligns nicely:      [label sizetofit];      if (self.agreetextcontainerview.frame.size.width < wordlocation.x + label.bounds.size.width)     {       wordlocation.x = 0.0;                       // move word way left...       wordlocation.y += label.frame.size.height;  // ...on next line        // , trim of leading white space:       nsrange startingwhitespacerange = [label.text rangeofstring:@"^\\s*"                                                           options:nsregularexpressionsearch];       if (startingwhitespacerange.location == 0)       {         label.text = [label.text stringbyreplacingcharactersinrange:startingwhitespacerange                                                          withstring:@""];         [label sizetofit];       }     }      // set location label:     label.frame = cgrectmake(wordlocation.x,                              wordlocation.y,                              label.frame.size.width,                              label.frame.size.height);     // show label:     [self.agreetextcontainerview addsubview:label];      // update horizontal position next word:     wordlocation.x += label.frame.size.width;   } } 

and here methods handle detected taps on links.

- (void)tapontermsofservicelink:(uitapgesturerecognizer *)tapgesture {   if (tapgesture.state == uigesturerecognizerstateended)   {     nslog(@"user tapped on terms of service link");   } }   - (void)taponprivacypolicylink:(uitapgesturerecognizer *)tapgesture {   if (tapgesture.state == uigesturerecognizerstateended)   {     nslog(@"user tapped on privacy policy link");   } } 

hope helps. i'm sure there smarter , more elegant ways this, able come , works nicely.

here's how looks in app:

simulator screenshot of end result

good luck! :-)

erik


Comments

Popular posts from this blog

Magento/PHP - Get phones on all members in a customer group -

php - .htaccess mod_rewrite for dynamic url which has domain names -

Website Login Issue developed in magento -