ฉันจะสร้างลิงก์ที่คลิกได้ใน NSAttributedString ได้อย่างไร


200

มันเป็นเรื่องเล็ก ๆ น้อย ๆ UITextViewที่จะทำให้การเชื่อมโยงหลายมิติที่สามารถคลิกได้ใน คุณเพิ่งตั้งช่องทำเครื่องหมาย "ตรวจสอบลิงก์" ในมุมมองใน IB และตรวจจับลิงก์ HTTP และเปลี่ยนเป็นไฮเปอร์ลิงก์

อย่างไรก็ตามนั่นก็หมายความว่าสิ่งที่ผู้ใช้เห็นคือลิงค์ "ดิบ" ไฟล์ RTF และ HTML ทั้งสองตัวช่วยให้คุณสามารถตั้งค่าสตริงที่ผู้ใช้สามารถอ่านได้พร้อมลิงค์ "behind"

มันง่ายที่จะติดตั้งข้อความประกอบในมุมมองข้อความ (หรือ a UILabelหรือUITextFieldสำหรับเรื่องนั้น) อย่างไรก็ตามเมื่อข้อความประกอบนั้นมีลิงค์อยู่มันไม่สามารถคลิกได้

มีวิธีที่จะทำให้ผู้ใช้สามารถอ่านได้ที่คลิกข้อความในหนึ่งUITextView, UILabelหรือUITextField?

มาร์กอัปนั้นแตกต่างกันใน SO แต่นี่เป็นแนวคิดทั่วไป สิ่งที่ฉันต้องการคือข้อความเช่นนี้:

morph นี้สร้างขึ้นด้วยFace Dancerคลิกเพื่อดูใน app store

สิ่งเดียวที่ฉันจะได้คือ:

morph นี้สร้างขึ้นด้วย Face Dancer คลิกที่http://example.com/facedancerเพื่อดูใน app store


ลองตัวอย่างนี้ .. IFTweetLabelหวังว่ามันจะช่วยให้ ..
Vidhyanand


ทำได้ดีมากที่ผ่านมา 100K ในพริบตา ยินดีต้อนรับสู่สโมสร 100K สมควรดี!
vacawama

@vacawama รอเกิดอะไรขึ้นเมื่อไหร่? ฉันอยู่ที่≈98kครั้งล่าสุดที่ฉันดู! (ฉันได้ยินข่าวลือว่าคุณได้รับความสนุกสนานในฐานะสมาชิกคนหนึ่งของสโมสร 100k หรือไม่)
Duncan C

พวกเขาเปลี่ยน upvotes ตามคำถามจาก +5 เป็น +10 ดังนั้นถ้าคุณมี 800 upvotes คุณจะสุทธิ +4000 ทันที ฉันยังคงรอย้อย 100k (ข้ามในเดือนเมษายน) บางสิ่งบางอย่างเกี่ยวกับการเปลี่ยนผู้ขายย้อย ...
14322

คำตอบ:


156

ใช้NSMutableAttributedString

NSMutableAttributedString * str = [[NSMutableAttributedString alloc] initWithString:@"Google"];
[str addAttribute: NSLinkAttributeName value: @"http://www.google.com" range: NSMakeRange(0, str.length)];
yourTextView.attributedText = str;

แก้ไข :

นี่ไม่ได้เกี่ยวกับคำถามโดยตรง แต่เพื่อชี้แจงUITextFieldและUILabelไม่สนับสนุนการเปิด URL หากคุณต้องการใช้UILabelกับลิงค์คุณสามารถตรวจสอบTTTAttributedLabel TTTAttributedLabel

นอกจากนี้คุณควรกำหนดdataDetectorTypesค่าของคุณUITextViewเป็นUIDataDetectorTypeLinkหรือUIDataDetectorTypeAllเปิด URL เมื่อคลิก หรือคุณสามารถใช้วิธีการมอบหมายตามที่แนะนำในความคิดเห็น


7
ใช่มันใช้งานได้เพียงแค่ใส่ไว้ใน UITextView และวิธีแทนที่ผู้แทน: - (BOOL) textView: (UITextView *) textView ควรอินเทอร์เฟซพร้อม: (NSURL *) url inRange: (NSRange) characterRange
Yunus Nedim Mehel

สิ่งนี้ไม่ทำงานใน UILabel - ไม่มีอะไรเกิดขึ้นเมื่อคุณแตะที่ช่อง
Jack BeNimble

7
@saboehnke คุณหมายถึงการโทรหาวิธีเมื่อคลิกที่ลิงก์หรือไม่ ถ้าเป็นเช่นนั้นใช้วิธีการมอบสิทธิ์ให้ dummy url เป็นแอตทริบิวต์และเรียกวิธีการของคุณใน- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange
ujell

2
ฉันไม่รู้ว่ามันทำงานอย่างไร NSURLค่าแอตทริบิวต์ควรจะประเภทของ ----[str addAttribute: NSLinkAttributeName value: [NSURL URLWithString:@"http://www.google.com"] range: NSMakeRange(0, str.length)];
Nirav Dangi

1
@NiravDangi จากNSAttributedString.h UIKIT_EXTERN NSString * const NSLinkAttributeName NS_AVAILABLE(10_0, 7_0); // NSURL (preferred) or NSString
Ahmed Nawar

142

ฉันพบว่ามันมีประโยชน์จริง ๆ แต่ฉันต้องทำในที่ ๆ ค่อนข้างน้อยดังนั้นฉันจึงเข้าใกล้มากขึ้น NSMutableAttributedString :

สวิฟท์ 3

extension NSMutableAttributedString {

    public func setAsLink(textToFind:String, linkURL:String) -> Bool {

        let foundRange = self.mutableString.range(of: textToFind)
        if foundRange.location != NSNotFound {
            self.addAttribute(.link, value: linkURL, range: foundRange)
            return true
        }
        return false
    }
}

สวิฟท์ 2

import Foundation

extension NSMutableAttributedString {

   public func setAsLink(textToFind:String, linkURL:String) -> Bool {

       let foundRange = self.mutableString.rangeOfString(textToFind)
       if foundRange.location != NSNotFound {
           self.addAttribute(NSLinkAttributeName, value: linkURL, range: foundRange)
           return true
       }
       return false
   }
}

ตัวอย่างการใช้งาน:

let attributedString = NSMutableAttributedString(string:"I love stackoverflow!")
let linkWasSet = attributedString.setAsLink("stackoverflow", linkURL: "http://stackoverflow.com")

if linkWasSet {
    // adjust more attributedString properties
}

Objective-C

ฉันเพิ่งต้องการที่จะทำเช่นเดียวกันในโครงการ Objective-C บริสุทธิ์ดังนั้นนี่คือหมวดหมู่ Objective-C

@interface NSMutableAttributedString (SetAsLinkSupport)

- (BOOL)setAsLink:(NSString*)textToFind linkURL:(NSString*)linkURL;

@end


@implementation NSMutableAttributedString (SetAsLinkSupport)

- (BOOL)setAsLink:(NSString*)textToFind linkURL:(NSString*)linkURL {

     NSRange foundRange = [self.mutableString rangeOfString:textToFind];
     if (foundRange.location != NSNotFound) {
         [self addAttribute:NSLinkAttributeName value:linkURL range:foundRange];
         return YES;
     }
     return NO;
}

@end

ตัวอย่างการใช้งาน:

NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:"I love stackoverflow!"];

BOOL linkWasSet = [attributedString setAsLink:@"stackoverflow" linkURL:@"http://stackoverflow.com"];

if (linkWasSet) {
    // adjust more attributedString properties
}

ตรวจสอบให้แน่ใจว่าแอตทริบิวต์ Behavior ของ NSTextField ตั้งเป็น Selectable แอตทริบิวต์ Xcode NSTextField


ตัวอย่างการใช้ / การนำไปปฏิบัติอย่างรวดเร็วของสิ่งนี้จะได้รับการชื่นชมอย่างมาก
ioopl

3
@ioop ฉันได้เพิ่มตัวอย่างเล็ก ๆ ลงในโพสต์ต้นฉบับด้านบนหวังว่าจะช่วยได้
Karl Nosworthy

7
ทำงานอย่างถูกต้อง แค่อยากบอกว่าคุณต้องทำให้ UITextView ของคุณเลือกได้เพื่ออนุญาตให้คลิกลิงก์ได้
lujop

1
@felecia genet ทั้งใน Objective C และ Swift implementations เมธอดจะส่งคืนผลลัพธ์บูลีนเพื่อระบุว่ามีการจับคู่และชุดผลลัพธ์ที่เกิดขึ้นหรือไม่ ข้อผิดพลาดที่คุณเห็นคือเพราะคุณไม่ได้จับผลลัพธ์นั้น - ซึ่งก็ดี คุณสามารถจับผลลัพธ์นั้นโดยการกำหนดให้กับตัวแปรโลคัลหรือปรับวิธีเพื่อหยุดการส่งคืนค่าบูลีนหากเหมาะสมกับความต้องการของคุณมากขึ้น ฉันหวังว่าจะช่วย
Karl Nosworthy

1
ไม่มีปัญหา @feleciagenet ฉันได้เพิ่มการจัดเก็บและตรวจสอบผลลัพธ์ที่ได้จากตัวอย่างของ Swift และ ObjectiveC
Karl Nosworthy

34

ฉันเพิ่งสร้างคลาสย่อยของ UILabel เพื่อระบุกรณีการใช้งานเป็นพิเศษ คุณสามารถเพิ่มหลายลิงค์ได้อย่างง่ายดายและกำหนดตัวจัดการที่แตกต่างกันสำหรับพวกเขา นอกจากนี้ยังรองรับการไฮไลต์ลิงค์ที่กดเมื่อคุณกดลงเพื่อรับความคิดเห็นจากการสัมผัส โปรดดูhttps://github.com/null09264/FRHyperLabel

ในกรณีของคุณรหัสอาจเป็นดังนี้:

FRHyperLabel *label = [FRHyperLabel new];

NSString *string = @"This morph was generated with Face Dancer, Click to view in the app store.";
NSDictionary *attributes = @{NSFontAttributeName: [UIFont preferredFontForTextStyle:UIFontTextStyleHeadline]};

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

[label setLinkForSubstring:@"Face Dancer" withLinkHandler:^(FRHyperLabel *label, NSString *substring){
    [[UIApplication sharedApplication] openURL:aURL];
}];

ภาพตัวอย่าง (ตัวจัดการถูกตั้งค่าให้ป็อปอัพการแจ้งเตือนแทนที่จะเปิด url ในกรณีนี้)

facedancer


ถ้าสมมติว่าข้อความของฉันเป็นเช่นนี้ morph นี้ถูกสร้างขึ้นด้วย Face Dancer คลิกเพื่อดู Face Dancer ใน app store Face Dancer ที่นี่ฉันมี 3 Face Dancer มันไม่ทำงานสำหรับมัน
MANCHIKANTI KRISHNAKISHORE

1
ในกรณีนี้โปรดใช้ API - (void)setLinkForRange:(NSRange)range withLinkHandler:(void(^)(FRHyperLabel *label, NSRange selectedRange))handler; แทน โปรดอ้างอิงถึง readme ในหน้า GitHub
Jinghan Wang

1
FRHyperLabel ดูเหมือนจะไม่ทำงานอีกต่อไป ภายใน "characterIndexForPoint:" จะส่งคืน -1 เสมอ (ไม่พบ)
John Pang

ใช้งานไม่ได้สำหรับฉลากหลายชั้น การตรวจจับตัวอักษรผิด สตริงการเชื่อมโยง 15 ตัวอักษรสามารถคลิกได้ในตัวอักษรตัวแรกเท่านั้นตัวละครอื่น ๆ ไม่ทำอะไรเลย
Accid Bright

27

การปรับปรุงเล็กน้อยสำหรับโซลูชันของ ujell: หากคุณใช้ NSURL แทน NSString คุณสามารถใช้ URL ใดก็ได้ (เช่น URL ที่กำหนดเอง)

NSURL *URL = [NSURL URLWithString: @"whatsapp://app"];
NSMutableAttributedString * str = [[NSMutableAttributedString alloc] initWithString:@"start Whatsapp"];
[str addAttribute: NSLinkAttributeName value:URL range: NSMakeRange(0, str.length)];
yourTextField.attributedText = str;

มีความสุข!


21

สวิฟท์ 4:

var string = "Google"
var attributedString = NSMutableAttributedString(string: string, attributes:[NSAttributedStringKey.link: URL(string: "http://www.google.com")!])

yourTextView.attributedText = attributedString

สวิฟท์ 3.1:

var string = "Google"
var attributedString = NSMutableAttributedString(string: string, attributes:[NSLinkAttributeName: URL(string: "http://www.google.com")!])

yourTextView.attributedText = attributedString

คำตอบนี้ใช้ได้อย่างสมบูรณ์แบบตามที่เป็น ดูเหมือนจะไม่จำเป็นต้องมีการระบายสีหรือคลาสย่อยที่กำหนดเองที่คำตอบอื่นใช้
zeroimpl

19

ฉันก็มีข้อกำหนดที่คล้ายกันในตอนแรกฉันใช้ UILabel แล้วฉันก็รู้ว่า UITextView ดีกว่า ฉันทำให้ UITextView ทำงานเหมือน UILabel โดยปิดการใช้งานการโต้ตอบและการเลื่อนและสร้างวิธีการหมวดหมู่NSMutableAttributedStringเพื่อตั้งค่าลิงก์ไปยังข้อความเหมือนกับสิ่งที่ Karl ทำ (+1 สำหรับสิ่งนั้น) นี่เป็นรุ่น obj ของฉัน

-(void)setTextAsLink:(NSString*) textToFind withLinkURL:(NSString*) url
{
    NSRange range = [self.mutableString rangeOfString:textToFind options:NSCaseInsensitiveSearch];

    if (range.location != NSNotFound) {

        [self addAttribute:NSLinkAttributeName value:url range:range];
        [self addAttribute:NSForegroundColorAttributeName value:[UIColor URLColor] range:range];
    }
}

คุณสามารถใช้ผู้รับมอบสิทธิ์ด้านล่างจากนั้นเพื่อจัดการกับการกระทำ

- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)url inRange:(NSRange)characterRange
{
    // do the task
    return YES;
}

1
เท่าที่ฉันสามารถบอกการตั้งค่าNSForegroundColorAttributeNameในช่วงที่NSLinkAttributeNameใช้ไม่ได้ ไม่ว่าสิ่งที่linkTextAttributesของการUITextViewถูกนำมาใช้แทน ไม่NSForegroundColorAttributeNameทำงานสำหรับคุณ?
Dima

คุณแน่ใจหรือว่าคุณไม่ได้ตั้งlinkTextAttributesสิ่งเดียวกัน หรืออาจtintColor? คุณสามารถสร้างลิงก์ 2 ลิงก์ให้แสดงเป็นสีต่างๆในมุมมองข้อความเดียวกันได้หรือไม่?
Dima

1
นี่คือรหัสการทำงานของ NSRange range = [self.text rangeOfString: ตัวเลือก textToFind: NSCaseInsensitiveSearch]; if (range.location! = NSNotFound) {NSMutableAttributedString * string = [[NSMutableAttributedString จัดสรร] initWithString: self.text]; [สตริง addAttribute: ค่า NSLinkAttributeName: ช่วง url: ช่วง]; [สตริง addAttribute: NSForegroundColorAttributeName ค่า: [ช่วง UIColor blueColor]: ช่วง]; self.text = @ ""; self.attributedText = string; }
Nosov Pavel

16

ใช้ UITextView รองรับลิงค์ที่คลิกได้ สร้างสตริงที่ประกอบโดยใช้รหัสต่อไปนี้

NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:strSomeTextWithLinks];

จากนั้นตั้งค่าข้อความ UITextView ดังนี้

NSDictionary *linkAttributes = @{NSForegroundColorAttributeName: [UIColor redColor],

                                 NSUnderlineColorAttributeName: [UIColor blueColor],

                                 NSUnderlineStyleAttributeName: @(NSUnderlinePatternSolid)};

customTextView.linkTextAttributes = linkAttributes; // customizes the appearance of links
textView.attributedText = attributedString;

ตรวจสอบให้แน่ใจว่าคุณเปิดใช้งานพฤติกรรม "เลือกได้" ของ UITextView ใน XIB


15
ฉันคิดว่านี่เป็นทางออกที่ดีที่สุด! หมายเหตุเกี่ยวกับการเปิดใช้งานSelectableเป็นสิ่งสำคัญ!
LunaCodeGirl

สิ่งนี้ไม่ได้ขีดเส้นใต้ลิงก์สำหรับฉัน (iOS 7, 8) ฉันต้องการใช้ NSUnderlineStyleAttributeName: [NSNumber numberWithInt: NSUnderlineStyleSingle]
prewett

1
การเลือกให้เป็นข้อมูลที่สำคัญที่สุดและไม่ง่ายเลย!
Nicolas Massart

13

หัวใจของคำถามของฉันคือฉันต้องการที่จะสามารถสร้างลิงก์แบบคลิกได้ในมุมมองข้อความ / ฟิลด์ / ป้ายกำกับโดยไม่ต้องเขียนรหัสที่กำหนดเองเพื่อจัดการกับข้อความและเพิ่มลิงค์ ฉันอยากให้มันขับเคลื่อนด้วยข้อมูล

ในที่สุดฉันก็รู้วิธีการทำ ปัญหาคือ IB ไม่ให้เกียรติลิงก์ที่ฝังไว้

นอกจากนี้เวอร์ชั่น iOS ของNSAttributedStringไม่อนุญาตให้คุณเริ่มต้นสตริงประกอบจากไฟล์ RTF เวอร์ชั่น OS X ของNSAttributedString นั้นมี initializer ที่ใช้ไฟล์ RTF เป็นอินพุต

NSAttributedString เป็นไปตามโปรโตคอล NSCoding ดังนั้นคุณสามารถแปลงเป็น / จาก NSData

ฉันสร้างเครื่องมือบรรทัดคำสั่ง OS X ที่ใช้ไฟล์ RTF เป็นอินพุตและเอาต์พุตไฟล์ที่มีนามสกุล. data ที่มี NSData จาก NSCoding จากนั้นฉันใส่ไฟล์. data ลงในโครงการของฉันและเพิ่มโค้ดสองสามบรรทัดที่โหลดข้อความลงในมุมมอง โค้ดมีลักษณะดังนี้ (โครงการนี้อยู่ใน Swift):

/*
If we can load a file called "Dates.data" from the bundle and convert it to an attributed string,
install it in the dates field. The contents contain clickable links with custom URLS to select
each date.
*/
if
  let datesPath = NSBundle.mainBundle().pathForResource("Dates", ofType: "data"),
  let datesString = NSKeyedUnarchiver.unarchiveObjectWithFile(datesPath) as? NSAttributedString
{
  datesField.attributedText = datesString
}

สำหรับแอพที่ใช้ข้อความที่มีการจัดรูปแบบจำนวนมากฉันสร้างกฎการสร้างที่บอก Xcode ว่าไฟล์. rtf ทั้งหมดในโฟลเดอร์ที่กำหนดเป็นแหล่งที่มาและไฟล์. data เป็นผลลัพธ์ เมื่อฉันทำเช่นนั้นฉันเพียงแค่เพิ่มไฟล์. rtf ลงในไดเรกทอรีที่กำหนด (หรือแก้ไขไฟล์ที่มีอยู่) และกระบวนการสร้างระบุว่าเป็นใหม่ / อัปเดตเรียกใช้เครื่องมือบรรทัดคำสั่งและคัดลอกไฟล์ลงในชุดแอป มันใช้งานได้อย่างสวยงาม

ฉันเขียนบทความในบล็อกที่เชื่อมโยงไปยังโครงการตัวอย่าง (Swift) ที่สาธิตเทคนิค คุณสามารถดูได้ที่นี่:

การสร้าง URL ที่คลิกได้ใน UITextField ที่เปิดในแอปของคุณ


11

ตัวอย่าง Swift 3 เพื่อตรวจจับการกระทำของก๊อกข้อความ

https://stackoverflow.com/a/44226491/5516830

let termsAndConditionsURL = TERMS_CONDITIONS_URL;
let privacyURL            = PRIVACY_URL;

override func viewDidLoad() {
    super.viewDidLoad()

    self.txtView.delegate = self
    let str = "By continuing, you accept the Terms of use and Privacy policy"
    let attributedString = NSMutableAttributedString(string: str)
    var foundRange = attributedString.mutableString.range(of: "Terms of use") //mention the parts of the attributed text you want to tap and get an custom action
    attributedString.addAttribute(NSLinkAttributeName, value: termsAndConditionsURL, range: foundRange)
    foundRange = attributedString.mutableString.range(of: "Privacy policy")
    attributedString.addAttribute(NSLinkAttributeName, value: privacyURL, range: foundRange)
    txtView.attributedText = attributedString
}

func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange) -> Bool {
    let storyboard = UIStoryboard(name: "Main", bundle: nil)
    let vc = storyboard.instantiateViewController(withIdentifier: "WebView") as! SKWebViewController

    if (URL.absoluteString == termsAndConditionsURL) {
        vc.strWebURL = TERMS_CONDITIONS_URL
        self.navigationController?.pushViewController(vc, animated: true)
    } else if (URL.absoluteString == privacyURL) {
        vc.strWebURL = PRIVACY_URL
        self.navigationController?.pushViewController(vc, animated: true)
    }
    return false
}

อย่างชาญฉลาดคุณสามารถเพิ่มการกระทำใด ๆ ที่คุณต้องการด้วย shouldInteractWith URLวิธีการ UITextFieldDelegate

ไชโย !!


7

คำตอบอย่างรวดเร็วคือการใช้ UITextView แทน UILabel คุณต้องเปิดSelectableใช้งานและปิดการใช้งานEditableและปิดการใช้งาน

จากนั้นปิดการใช้งานตัวบ่งชี้การเลื่อนและการตีกลับ

สกรีนช็อต

สกรีนช็อต

โซลูชันของฉันใช้NSMutableAttributedStringจากสตริง htmlNSHTMLTextDocumentType

NSString *s = @"<p><a href='https://itunes.apple.com/us/app/xxxx/xxxx?mt=8'>https://itunes.apple.com/us/app/xxxx/xxxx?mt=8</a></p>";

NSMutableAttributedString *text = [[NSMutableAttributedString alloc]
                                           initWithData: [s dataUsingEncoding:NSUnicodeStringEncoding]
                                           options: @{ NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType }
                                           documentAttributes: nil
                                           error: nil
                                           ];

cell.content.attributedText = text;

นี้. ฉันสามารถอ่านไฟล์ RTF จากบันเดิลทรัพยากรของฉันแปลงเป็นNSAttributedStringตั้งค่าเป็นattributedTextของฉันUITextViewและไฮเปอร์ลิงก์ทำงานได้! มันเป็นงานที่ต้องทำมากมายเพื่อหาช่วงของไฮเปอร์ลิงก์แต่ละอันและตั้งค่าโดยใช้แอตทริบิวต์
Nicolas Miari

6

ฉันได้เขียนวิธีการที่เพิ่มลิงค์ (linkString) เพื่อสตริง (fullString) ด้วย url บางอย่าง (urlString):

- (NSAttributedString *)linkedStringFromFullString:(NSString *)fullString withLinkString:(NSString *)linkString andUrlString:(NSString *)urlString
{
    NSRange range = [fullString rangeOfString:linkString options:NSLiteralSearch];
    NSMutableAttributedString *str = [[NSMutableAttributedString alloc] initWithString:fullString];

    NSMutableParagraphStyle *paragraphStyle = NSMutableParagraphStyle.new;
    paragraphStyle.alignment = NSTextAlignmentCenter;
    NSDictionary *attributes = @{NSForegroundColorAttributeName:RGB(0x999999),
                                 NSFontAttributeName:[UIFont fontWithName:@"HelveticaNeue-Light" size:10],
                                 NSParagraphStyleAttributeName:paragraphStyle};
    [str addAttributes:attributes range:NSMakeRange(0, [str length])];
    [str addAttribute: NSLinkAttributeName value:urlString range:range];

    return str;
}

คุณควรเรียกมันว่า:

NSString *fullString = @"A man who bought the Google.com domain name for $12 and owned it for about a minute has been rewarded by Google for uncovering the flaw.";
NSString *linkString = @"Google.com";
NSString *urlString = @"http://www.google.com";

_youTextView.attributedText = [self linkedStringFromFullString:fullString withLinkString:linkString andUrlString:urlString];

สามารถคลิกได้ แต่ไม่ได้เปิดลิงก์หรืออะไรเลย มันเพียงคลิกเหมือนปุ่มที่ไม่ทำอะไรเลย
Reza.Ab

5

ฉันจำเป็นต้องใช้ UILabel ที่บริสุทธิ์ต่อไปจึงเรียกสิ่งนี้จากตัวรู้จำการแตะของฉัน (นี่ขึ้นอยู่กับการตอบสนองของ malex ที่นี่: ดัชนีตัวอักษรที่จุดสัมผัสสำหรับ UILabel )

UILabel* label = (UILabel*)gesture.view;
CGPoint tapLocation = [gesture locationInView:label];

// create attributed string with paragraph style from label

NSMutableAttributedString* attr = [label.attributedText mutableCopy];
NSMutableParagraphStyle* paragraphStyle = [NSMutableParagraphStyle new];
paragraphStyle.alignment = label.textAlignment;

[attr addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange(0, label.attributedText.length)];

// init text storage

NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:attr];
NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
[textStorage addLayoutManager:layoutManager];

// init text container

NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:CGSizeMake(label.frame.size.width, label.frame.size.height+100) ];
textContainer.lineFragmentPadding  = 0;
textContainer.maximumNumberOfLines = label.numberOfLines;
textContainer.lineBreakMode        = label.lineBreakMode;

[layoutManager addTextContainer:textContainer];

// find tapped character

NSUInteger characterIndex = [layoutManager characterIndexForPoint:tapLocation
                                                  inTextContainer:textContainer
                         fractionOfDistanceBetweenInsertionPoints:NULL];

// process link at tapped character

[attr enumerateAttributesInRange:NSMakeRange(characterIndex, 1)
                                         options:0
                                      usingBlock:^(NSDictionary<NSString *,id> * _Nonnull attrs, NSRange range, BOOL * _Nonnull stop) {
                                          if (attrs[NSLinkAttributeName]) {
                                              NSString* urlString = attrs[NSLinkAttributeName];
                                              NSURL* url = [NSURL URLWithString:urlString];
                                              [[UIApplication sharedApplication] openURL:url];
                                          }
                                      }];

สิ่งนี้มีประโยชน์มากฉันไม่สามารถรับดัชนีจากตัวละครในบรรทัดสุดท้าย รหัสของคุณมี +100 ใน textContainer เมื่อเริ่มต้น CGSize ซึ่งไม่สมเหตุสมผลกับฉันมากนัก แต่มันก็ใช้กลอุบาย
blueether

4

ปรับปรุง:

คำถามของฉันมี 2 ส่วน:

  1. วิธีสร้างลิงก์ที่ข้อความที่แสดงสำหรับลิงค์ที่คลิกได้นั้นแตกต่างจากลิงค์จริงที่ถูกเรียกใช้:
  2. วิธีตั้งค่าลิงค์โดยไม่ต้องใช้รหัสที่กำหนดเองเพื่อตั้งค่าคุณสมบัติในข้อความ

ปรากฎว่า iOS 7 เพิ่มความสามารถในการโหลดข้อความประกอบจาก NSDataเพิ่มความสามารถในการโหลดข้อความประกอบจาก

ฉันสร้างคลาสย่อยที่กำหนดเองUITextViewซึ่งใช้ประโยชน์จาก@IBInspectableแอตทริบิวต์และให้คุณโหลดเนื้อหาจากไฟล์ RTF โดยตรงใน IB คุณเพียงแค่พิมพ์ชื่อไฟล์ลงใน IB และคลาสที่กำหนดเองทำส่วนที่เหลือ

นี่คือรายละเอียด:

ใน iOS 7 ได้รับวิธีการที่NSAttributedString initWithData:options:documentAttributes:error:วิธีการดังกล่าวช่วยให้คุณโหลด NSAttributedString จากวัตถุ NSData คุณสามารถโหลดไฟล์ RTF ลงใน NSData ก่อนจากนั้นใช้initWithData:options:documentAttributes:error:เพื่อโหลด NSData นั้นลงในมุมมองข้อความของคุณ (โปรดทราบว่ายังมีวิธีinitWithFileURL:options:documentAttributes:error:ที่จะโหลดสตริงที่เชื่อมโยงโดยตรงจากไฟล์ แต่วิธีการนั้นเลิกใช้แล้วใน iOS 9 มันปลอดภัยกว่าที่จะใช้วิธีinitWithData:options:documentAttributes:error:ที่ไม่ได้คัดค้าน

ฉันต้องการวิธีที่ให้ฉันติดตั้งลิงก์แบบคลิกได้ในมุมมองข้อความโดยไม่ต้องสร้างรหัสใด ๆ กับลิงก์ที่ฉันใช้

วิธีการแก้ปัญหาที่ฉันมาด้วยคือการสร้าง subclass กำหนดเองของ UITextView ฉันโทรRTF_UITextViewและให้มันคุณสมบัติที่เรียกว่า@IBInspectable RTF_Filenameกำลังเพิ่ม@IBInspectableคุณสมบัติให้กับคุณสมบัติทำให้ตัวสร้างส่วนต่อประสานแสดงคุณสมบัติดังกล่าวใน "แอททริบิวผู้ตรวจสอบ" จากนั้นคุณสามารถตั้งค่านั้นจากรหัสที่กำหนดเองโดย IB

ฉันยังเพิ่ม@IBDesignableคุณสมบัติให้กับคลาสที่กำหนดเองของฉัน @IBDesignableแอตทริบิวต์บอก Xcode ว่ามันควรจะติดตั้งสำเนาการทำงานของระดับมุมมองที่กำหนดเองของคุณลงในการสร้างการเชื่อมต่อเพื่อให้คุณสามารถเห็นมันในการแสดงผลกราฟิกของลำดับชั้นมุมมองของคุณ () น่าเสียดายสำหรับคลาสนี้@IBDesignableคุณสมบัติดูเหมือนจะไม่สม่ำเสมอ ใช้งานได้เมื่อฉันเพิ่มครั้งแรก แต่จากนั้นฉันลบเนื้อหาข้อความล้วนของมุมมองข้อความและลิงก์ที่คลิกได้ในมุมมองของฉันหายไปและฉันไม่สามารถนำกลับคืนมาได้)

รหัสสำหรับฉันนั้นRTF_UITextViewง่ายมาก นอกเหนือจากการเพิ่มแอ@IBDesignableททริบิวและRTF_Filenameคุณสมบัติที่มีแอ@IBInspectableททริบิวต์แล้วฉันยังเพิ่มdidSet()วิธีในRTF_Filenameคุณสมบัติ didSet()วิธีการได้รับเรียกว่าเวลาใด ๆ ค่าของRTF_Filenameการเปลี่ยนแปลงสถานที่ให้บริการ รหัสสำหรับdidSet()วิธีการค่อนข้างง่าย:

@IBDesignable
class RTF_UITextView: UITextView
{
  @IBInspectable
  var RTF_Filename: String?
    {
    didSet(newValue)
    {
      //If the RTF_Filename is nil or the empty string, don't do anything
      if ((RTF_Filename ?? "").isEmpty)
      {
        return
      }
      //Use optional binding to try to get an URL to the
      //specified filename in the app bundle. If that succeeds, try to load
      //NSData from the file.
      if let fileURL = NSBundle.mainBundle().URLForResource(RTF_Filename, withExtension: "rtf"),
        
        //If the fileURL loads, also try to load NSData from the URL.
        let theData = NSData(contentsOfURL: fileURL)
      {
        var aString:NSAttributedString
        do
        {
          //Try to load an NSAttributedString from the data
          try
            aString = NSAttributedString(data: theData,
              options: [:],
              documentAttributes:  nil
          )
          //If it succeeds, install the attributed string into the field.
          self.attributedText = aString;
        }
        catch
        {
          print("Nerp.");
        }
      }
      
    }
  }
}

โปรดทราบว่าหากคุณสมบัติ @IBDesignable ไม่น่าเชื่อถือจะช่วยให้คุณดูตัวอย่างข้อความสไตล์ของคุณในเครื่องมือสร้างอินเตอร์เฟสคุณควรตั้งรหัสข้างต้นเป็นส่วนขยายของ UITextView แทนที่จะเป็นคลาสย่อยที่กำหนดเอง ด้วยวิธีนี้คุณสามารถใช้มันในมุมมองข้อความใดก็ได้โดยไม่ต้องเปลี่ยนมุมมองข้อความเป็นคลาสที่กำหนดเอง

ดูคำตอบอื่น ๆ ของฉันหากคุณต้องการสนับสนุน iOS เวอร์ชันก่อน iOS 7

คุณสามารถดาวน์โหลดตัวอย่างโครงการที่มีคลาสใหม่นี้จาก gitHub:

โครงการสาธิต DatesInSwiftบน Github


3

เพียงค้นหาโซลูชันที่ไม่มีรหัสสำหรับ UITextView: ป้อนคำอธิบายรูปภาพที่นี่

เปิดใช้งานการตรวจจับ -> ตัวเลือกลิงก์ URL และอีเมลจะถูกตรวจจับและคลิกได้!


3
ทำให้ลิงก์สามารถคลิกได้ ฉันต้องการมีข้อความที่ผู้ใช้อ่านได้ซึ่งมีลิงค์อยู่ด้านหลัง ดูตัวอย่างในคำถามเดิมของฉัน
Duncan C

ใช่คำตอบของฉันจะใช้กับกรณีที่ลิงก์นั้นเหมือนกับข้อความ หากลิงก์เป็นอีกสิ่งหนึ่งฉันจะทำตามคำตอบของ @ ujell
Bill Chan

3
คำถามของฉันเกี่ยวกับข้อความที่คลิกได้ซึ่งแสดงสิ่งอื่นนอกเหนือจาก URL โดยเฉพาะ คุณไม่ได้ทำอะไรมากไปกว่าการเหลียวมองคำถามใช่ไหม?
Duncan C

1
ไม่ได้ให้บริการเพื่อวัตถุประสงค์อื่น ๆ แต่แน่นอนว่านี่คือสิ่งที่ฉันได้มาเพื่อค้นหา ... วิธีสร้างลิงก์ในแอปพลิเคชันแชทของฉันที่คลิกได้ Bingo ฉันพบบทความนี้ ... ขอบคุณ! ต้องการรหัส xcode จะอนุญาตให้เปิดใช้งาน twitter และ hash tag
MizAkita

สิ่งนี้ใช้ได้แม้กับข้อความที่กำหนดเองซึ่งเชื่อมโยงกับดิบ อย่าลืมเลือกพฤติกรรม -> เลือกได้และตรวจจับ -> ลิงค์
krlbsk

3

เวอร์ชั่นสวิฟท์:

    // Attributed String for Label
    let plainText = "Apkia"
    let styledText = NSMutableAttributedString(string: plainText)
    // Set Attribuets for Color, HyperLink and Font Size
    let attributes = [NSFontAttributeName: UIFont.systemFontOfSize(14.0), NSLinkAttributeName:NSURL(string: "http://apkia.com/")!, NSForegroundColorAttributeName: UIColor.blueColor()]
    styledText.setAttributes(attributes, range: NSMakeRange(0, plainText.characters.count))
    registerLabel.attributedText = styledText

3

ใช้ UITextView และตั้ง dataDetectorTypes สำหรับ Link

แบบนี้:

testTextView.editable = false 
testTextView.dataDetectorTypes = .link

หากคุณต้องการตรวจจับลิงค์หมายเลขโทรศัพท์ที่อยู่ ฯลฯ จากนั้น

testTextView.dataDetectorTypes = .all

3
ไม่ได้สิ่งนี้จะช่วยให้คุณสร้างลิงก์ที่คลิกได้เท่านั้น คำถามของฉันเฉพาะกับการสร้างข้อความที่กำหนดเองเช่น "คลิกที่นี่" คลิกได้ไม่ใช่ URL อย่างเช่นhttp://somedomain/someurl?param=value
Duncan C

2

การเพิ่มคำอธิบายดั้งเดิมของ Duncan C อย่างรวดเร็วนอกจากนี้ยังมีการทำงานของ vis-á-vie IB เขาเขียนว่า: "มันเป็นเรื่องง่ายที่จะทำให้ไฮเปอร์ลิงก์สามารถคลิกได้ใน UITextView คุณเพิ่งตั้งช่องทำเครื่องหมาย" ตรวจสอบลิงก์ "ในมุมมองใน IB และตรวจจับลิงก์ http และเปลี่ยนเป็นไฮเปอร์ลิงก์"

ประสบการณ์ของฉัน (อย่างน้อยใน xcode 7) คือคุณต้องเลิกคลิกที่พฤติกรรม "แก้ไขได้" เพื่อตรวจพบ URL และคลิกได้


2

ในกรณีที่คุณมีปัญหากับสิ่งที่ @Karl Nosworthy และ @esilver ให้ไว้ข้างต้นฉันได้อัปเดตส่วนขยาย NSMutableAttributedString เป็น Swift 4

extension NSMutableAttributedString {

public func setAsLink(textToFind:String, linkURL:String) -> Bool {

    let foundRange = self.mutableString.range(of: textToFind)
    if foundRange.location != NSNotFound {
         _ = NSMutableAttributedString(string: textToFind)
        // Set Attribuets for Color, HyperLink and Font Size
        let attributes = [NSFontAttributeName: UIFont.bodyFont(.regular, shouldResize: true), NSLinkAttributeName:NSURL(string: linkURL)!, NSForegroundColorAttributeName: UIColor.blue]

        self.setAttributes(attributes, range: foundRange)
        return true
    }
    return false
  }
}


0

หากคุณต้องการใช้ NSLinkAttributeName ใน UITextView คุณอาจพิจารณาใช้ไลบรารี AttributedTextView มันเป็นคลาสย่อย UITextView ที่ทำให้จัดการกับสิ่งเหล่านี้ได้ง่ายมาก สำหรับข้อมูลเพิ่มเติมดูที่: https://github.com/evermeer/AttributedTextView

คุณสามารถทำให้ส่วนใดส่วนหนึ่งของข้อความโต้ตอบเช่นนี้ (โดยที่ textView1 เป็น UITextView IBoutlet):

textView1.attributer =
    "1. ".red
    .append("This is the first test. ").green
    .append("Click on ").black
    .append("evict.nl").makeInteract { _ in
        UIApplication.shared.open(URL(string: "http://evict.nl")!, options: [:], completionHandler: { completed in })
    }.underline
    .append(" for testing links. ").black
    .append("Next test").underline.makeInteract { _ in
        print("NEXT")
    }
    .all.font(UIFont(name: "SourceSansPro-Regular", size: 16))
    .setLinkColor(UIColor.purple) 

และสำหรับการจัดการแฮชแท็กและกล่าวถึงคุณสามารถใช้รหัสดังนี้:

textView1.attributer = "@test: What #hashtags do we have in @evermeer #AtributedTextView library"
    .matchHashtags.underline
    .matchMentions
    .makeInteract { link in
        UIApplication.shared.open(URL(string: "https://twitter.com\(link.replacingOccurrences(of: "@", with: ""))")!, options: [:], completionHandler: { completed in })
    }

0

ถ้าคุณต้องการซับสตริงที่ใช้งานใน UITextView ของคุณคุณสามารถใช้ TextView เพิ่มเติมของฉัน ... มันสั้นและง่าย คุณสามารถแก้ไขได้ตามที่คุณต้องการ

ผลลัพธ์: ป้อนคำอธิบายรูปภาพที่นี่

รหัส: https://github.com/marekmand/ActiveSubstringTextView


0
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:strSomeTextWithLinks];

NSDictionary *linkAttributes = @{NSForegroundColorAttributeName: [UIColor redColor],   
                                 NSUnderlineColorAttributeName: [UIColor blueColor],
                                 NSUnderlineStyleAttributeName: @(NSUnderlinePatternSolid)};

customTextView.linkTextAttributes = linkAttributes; // customizes the appearance of links
textView.attributedText = attributedString;

จุดสำคัญ:

  • ตรวจสอบให้แน่ใจว่าคุณเปิดใช้งานพฤติกรรม "เลือกได้" ของ UITextView ใน XIB
  • ตรวจสอบให้แน่ใจว่าคุณปิดใช้งานพฤติกรรม "แก้ไขได้" ของ UITextView ใน XIB
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.