কোনও ইউআইএলবেলের এনএসএট্রিবিউটেড স্ট্রিংয়ে ট্যাপ-সক্ষম "লিঙ্কগুলি" তৈরি করবেন?


233

আমি কয়েক ঘন্টা ধরে এটি অনুসন্ধান করেছিলাম তবে আমি ব্যর্থ হয়েছি। আমি সম্ভবত জানি না আমার কী সন্ধান করা উচিত।

অনেক অ্যাপ্লিকেশনটির পাঠ্য রয়েছে এবং এই পাঠ্যে গোলাকার আয়তনের ওয়েব হাইপারলিংক রয়েছে। আমি ক্লিক করলে সেগুলি UIWebViewখোলে। আমার কাছে ধাঁধাটি কী তা হ'ল তাদের প্রায়শই কাস্টম লিঙ্ক থাকে, উদাহরণস্বরূপ যদি শব্দ # দিয়ে শুরু হয় তবে এটি ক্লিকযোগ্য এবং অ্যাপ্লিকেশন অন্য ভিউটি খোলার মাধ্যমে সাড়া দেয়। আমি এটা কিভাবে করবো? এটি UILabelকি আমার সাথে বা আমার UITextViewঅন্য কোনও কিছুর সাথে সম্ভব ?


সম্পূর্ণ কার্যক্ষম সমাধানের জন্য দেখুন: stackoverflow.com/questions/50505334/… Swift 4এটি ব্যবহার করে UITextViewতবে এটির মতো আচরণ করে UILabel। আমি এখানে সমাধানগুলি চেষ্টা করেছি এবং সঠিক লিঙ্ক সনাক্তকরণে ব্যর্থ হয়েছি।
ড্যান ব্রে

উত্তর:


208

সাধারণভাবে, যদি আমরা ইউআইএলবেল দ্বারা প্রদর্শিত পাঠ্যে ক্লিকযোগ্য লিঙ্কটি রাখতে চাই, আমাদের দুটি স্বতন্ত্র কাজ সমাধান করতে হবে:

  1. লিঙ্কের মতো দেখতে পাঠ্যের কোনও অংশের চেহারা পরিবর্তন করা
  2. লিঙ্কটিতে স্পর্শগুলি সনাক্ত করা এবং পরিচালনা করা (একটি URL খোলার একটি বিশেষ ঘটনা)

প্রথমটি সহজ। আইওএস 6 থেকে শুরু করে ইউআইএলবেল বিশিষ্ট স্ট্রিংগুলির প্রদর্শন সমর্থন করে। আপনাকে যা করতে হবে তা হ'ল এনএসমেটেবলঅ্যাট্রিবিউটেড স্ট্রিংয়ের একটি উদাহরণ তৈরি এবং কনফিগার করা:

NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:@"String with a link" attributes:nil];
NSRange linkRange = NSMakeRange(14, 4); // for the word "link" in the string above

NSDictionary *linkAttributes = @{ NSForegroundColorAttributeName : [UIColor colorWithRed:0.05 green:0.4 blue:0.65 alpha:1.0],
                                  NSUnderlineStyleAttributeName : @(NSUnderlineStyleSingle) };
[attributedString setAttributes:linkAttributes range:linkRange];

// Assign attributedText to UILabel
label.attributedText = attributedString;

এটাই! উপরের কোডটি ইউআইএলবেলকে একটি লিঙ্ক সহ স্ট্রিং প্রদর্শন করতে সক্ষম করে

এখন আমাদের এই লিঙ্কটির ছোঁয়া সনাক্ত করা উচিত। ইউআইএলবেলের মধ্যে সমস্ত ট্যাপগুলি ধরা এবং নলের অবস্থানটি লিঙ্কটির যথেষ্ট কাছে ছিল কিনা তা খুঁজে বের করার ধারণাটি। ছোঁয়া ধরতে আমরা লেবেলে টোকা অঙ্গভঙ্গি সনাক্তকারী যুক্ত করতে পারি। লেবেলটির জন্য ব্যবহারকারীকে সক্রিয় করতে নিশ্চিত করুন, এটি ডিফল্টরূপে বন্ধ করা আছে:

label.userInteractionEnabled = YES;
[label addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapOnLabel:)]]; 

এখন সর্বাধিক পরিশীলিত স্টাফ: লিংকের অন্য কোনও অংশে লিঙ্কটি প্রদর্শিত হয়েছে এবং সেখানে ট্যাপ ছিল কিনা তা সন্ধান করুন। যদি আমাদের একক-রেখাযুক্ত ইউআইএলবেল থাকে তবে লিংকটি প্রদর্শিত হয় এমন জায়গার সীমানা হার্ডকোড করে এই কাজটি তুলনামূলকভাবে সহজ সমাধান করা যেতে পারে তবে আসুন এই সমস্যাটি আরও মার্চিকভাবে এবং সাধারণ ক্ষেত্রে সমাধান করুন - লিঙ্ক বিন্যাস সম্পর্কে প্রাথমিক জ্ঞান ছাড়াই মাল্টলাইন ইউআইএলবেল।

পদ্ধতির একটি হ'ল আইওএস 7 তে প্রবর্তিত টেক্সট কিট এপিআইয়ের ক্ষমতা ব্যবহার করা:

// Create instances of NSLayoutManager, NSTextContainer and NSTextStorage
NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:CGSizeZero];
NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:attributedString];

// Configure layoutManager and textStorage
[layoutManager addTextContainer:textContainer];
[textStorage addLayoutManager:layoutManager];

// Configure textContainer
textContainer.lineFragmentPadding = 0.0;
textContainer.lineBreakMode = label.lineBreakMode;
textContainer.maximumNumberOfLines = label.numberOfLines;

আপনার শ্রেণীর বৈশিষ্ট্যগুলিতে NSLayoutManager, NSTextContainer এবং NSTextStorage এর তৈরি এবং কনফিগার করা দৃষ্টান্তগুলি সংরক্ষণ করুন (সম্ভবত ইউআইভিউকন্ট্রোলারের বংশধর) - আমাদের অন্যান্য পদ্ধতিতে তাদের প্রয়োজন হবে।

এখন, প্রতিবার লেবেল তার ফ্রেম পরিবর্তন করে, পাঠ্য কনটেনারের আকার আপডেট করে:

- (void)viewDidLayoutSubviews
{
    [super viewDidLayoutSubviews];
    self.textContainer.size = self.label.bounds.size;
}

এবং অবশেষে, লিঙ্কটিতে আলতো চাপছিল কিনা তা সনাক্ত করুন:

- (void)handleTapOnLabel:(UITapGestureRecognizer *)tapGesture
{
    CGPoint locationOfTouchInLabel = [tapGesture locationInView:tapGesture.view];
    CGSize labelSize = tapGesture.view.bounds.size;
    CGRect textBoundingBox = [self.layoutManager usedRectForTextContainer:self.textContainer];
    CGPoint textContainerOffset = CGPointMake((labelSize.width - textBoundingBox.size.width) * 0.5 - textBoundingBox.origin.x,
                                              (labelSize.height - textBoundingBox.size.height) * 0.5 - textBoundingBox.origin.y);
    CGPoint locationOfTouchInTextContainer = CGPointMake(locationOfTouchInLabel.x - textContainerOffset.x,
                                                         locationOfTouchInLabel.y - textContainerOffset.y);
    NSInteger indexOfCharacter = [self.layoutManager characterIndexForPoint:locationOfTouchInTextContainer
                                                            inTextContainer:self.textContainer
                                   fractionOfDistanceBetweenInsertionPoints:nil];
    NSRange linkRange = NSMakeRange(14, 4); // it's better to save the range somewhere when it was originally used for marking link in attributed string
    if (NSLocationInRange(indexOfCharacter, linkRange)) {
        // Open an URL, or handle the tap on the link in any other way
        [[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"https://stackoverflow.com/"]];
    }
}

1
আমি কীভাবে এটিকে সংগঠিত করব cellForRowAtIndexPath? আমি এর মধ্যে উদাহরণগুলি তৈরি এবং কনফিগার করছি এবং এটিতে ফাংশনটি cellForRowAtIndexPathহোস্টিং করছি handleTapOnLabel। কিন্তু cell.textLabel.addGestureRecognizer(UITapGestureRecognizer(target: cell, action: "handleTapOnLabel:")), আমি পেয়ে করছি unrecognized selector
স্লাইডার

13
এই সমাধানটি ধরে নেয় যে লেবেলের textAlignmentবৈশিষ্ট্য সেট করা আছে NSTextAlignmentCenter। আপনি যদি কেন্দ্রবিহীন পাঠ্য ব্যবহার করে থাকেন তবে আপনাকে textContainerOffsetউপরের কোডটিতে আপনার গণনা সামঞ্জস্য করতে হবে ।
ব্র্যাডবি

18
@AndreyM। এর xমান গণনা করার textContainerOffsetসময় ধ্রুবকটি 0.5ব্যবহৃত হয়। এটি সঠিক অবস্থান গণনা করবে NSTextAlignmentCent‌er। বাম, প্রাকৃতিক বা ন্যায়সঙ্গত প্রান্তিককরণের জন্য একটি মান ব্যবহার করুন 0.0। ডান সারিবদ্ধ করতে, ব্যবহার করুন 1.0
ব্র্যাডবি

5
এটি আমার জন্যও কাজ করে তবে কেবল একক লাইনের লেবেলের জন্য। লেবেলে যদি 1 টির বেশি লাইন থাকে তবে এই পদ্ধতিটি সঠিকভাবে কাজ করছে না। যে কেউ তাকে একাধিক লাইনের সাথে একই কাজটি করতে বলতে পারেন
ক্রেজি ডেভেলপার

1
@ ক্রাজি ডেফলার self.textContainer.size = self.label.bounds.size যোগ করুন; হ্যান্ডেলট্যাপঅনল্যাবেলে। এটি আমার পক্ষে কাজ করেছে
রেডিওলগ

58

আমি ব্যাপ্ত করছি @NAlexN মূল বিস্তারিত সমাধান, সঙ্গে @zekel চমৎকার এক্সটেনশন UITapGestureRecognizer, এবং প্রদান সুইফট

UITapGestureR সনাক্তকারীকে প্রসারিত করা হচ্ছে

extension UITapGestureRecognizer {

    func didTapAttributedTextInLabel(label: UILabel, inRange targetRange: NSRange) -> Bool {
        // Create instances of NSLayoutManager, NSTextContainer and NSTextStorage
        let layoutManager = NSLayoutManager()
        let textContainer = NSTextContainer(size: CGSize.zero)
        let textStorage = NSTextStorage(attributedString: label.attributedText!)

        // Configure layoutManager and textStorage
        layoutManager.addTextContainer(textContainer)
        textStorage.addLayoutManager(layoutManager)

        // Configure textContainer
        textContainer.lineFragmentPadding = 0.0
        textContainer.lineBreakMode = label.lineBreakMode
        textContainer.maximumNumberOfLines = label.numberOfLines
        let labelSize = label.bounds.size
        textContainer.size = labelSize

        // Find the tapped character location and compare it to the specified range
        let locationOfTouchInLabel = self.location(in: label)
        let textBoundingBox = layoutManager.usedRect(for: textContainer)
        let textContainerOffset = CGPoint(
            x: (labelSize.width - textBoundingBox.size.width) * 0.5 - textBoundingBox.origin.x,
            y: (labelSize.height - textBoundingBox.size.height) * 0.5 - textBoundingBox.origin.y
        )
        let locationOfTouchInTextContainer = CGPoint(
            x: locationOfTouchInLabel.x - textContainerOffset.x,
            y: locationOfTouchInLabel.y - textContainerOffset.y
        )
        let indexOfCharacter = layoutManager.characterIndex(for: locationOfTouchInTextContainer, in: textContainer, fractionOfDistanceBetweenInsertionPoints: nil)

        return NSLocationInRange(indexOfCharacter, targetRange)
    }

}

ব্যবহার

এতে UIGestureRecognizerক্রিয়াকলাপ প্রেরণের জন্য সেটআপ করুন tapLabel:এবং লক্ষ্য সনাক্তকরণের সীমাটি টেপ করা হচ্ছে কিনা তা আপনি সনাক্ত করতে পারবেন myLabel

@IBAction func tapLabel(gesture: UITapGestureRecognizer) {
    if gesture.didTapAttributedTextInLabel(myLabel, inRange: targetRange1) {
        print("Tapped targetRange1")
    } else if gesture.didTapAttributedTextInLabel(myLabel, inRange: targetRange2) {
        print("Tapped targetRange2")
    } else {
        print("Tapped none")
    }
}

গুরুত্বপূর্ণ: UILabelলাইন ব্রেক ব্রেকটি শব্দ / চর দ্বারা মোড়ানোর জন্য সেট করা আবশ্যক। একরকম, NSTextContainerধরে নেওয়া হবে যে লাইন ব্রেক ব্রেক মোড অন্যথায় পাঠ্যটি কেবলমাত্র একক লাইন।



@ কোইন এটি একাধিক লিঙ্কের সাথে কাজ করে। সঙ্গে উদাহরণস্বরূপ ব্যবহার দেখুন targetRange1এবং targetRange2
সামাইজ করুন

2
একাধিক লাইন বা ভুল ব্যাপ্তির সমস্যা নিয়ে এখনও যে কারও সমস্যা রয়েছে, আপনার ইউআইএলবেলকে অ্যাট্রিবিউটেড সেট করুন , তারপরে ওয়ার্ড মোড়কের অনুমতি দিন এবং লেবেলের NSMutableAttributedString(attributedString: text)NSAttributedString
বিশিষ্ট

@ মোফে-হেন্দিজেগি এখনও মাল্টি লাইন পাঠ্য নিয়ে আমার সমস্যা আছে। আমি ইউইলবেল প্রস্থে সীমাবদ্ধতা সহ স্বয়ংক্রিয় বিন্যাস ব্যবহার করছি। ব্যাপার কি?
কেনো

গুণিত মানটি পাঠ্যলাইনমেন্ট বামে কাজ না করায় আমাকে ম্যানুয়ালি textContainerOffset.x 0 তে সেট করতে হয়েছিল। এটি কি আপনার জন্য কাজ করছে? আমি মনে করি গণনা মানটি সঠিক ছিল যদি প্রান্তিককরণটি কেন্দ্র ছিল।
বি কে

51

পুরানো প্রশ্ন তবে যদি কেউ এর UITextViewপরিবর্তে একটি ব্যবহার করতে পারে UILabelতবে এটি সহজ। স্ট্যান্ডার্ড ইউআরএল, ফোন নম্বর ইত্যাদি স্বয়ংক্রিয়ভাবে সনাক্ত হবে (এবং ক্লিকযোগ্য হবে)।

তবে, যদি আপনার কাস্টম সনাক্তকরণের প্রয়োজন হয়, এটির অর্থ যদি কোনও ব্যবহারকারী নির্দিষ্ট শব্দটিতে ক্লিক করার পরে কোনও কাস্টম পদ্ধতিতে কল করতে সক্ষম হতে চান তবে আপনাকে এমন NSAttributedStringsএকটি NSLinkAttributeNameবৈশিষ্ট্য ব্যবহার করতে হবে যা কাস্টম ইউআরএল স্কিমকে নির্দেশ করবে (এর বিপরীতে ডিফল্টরূপে url স্কিম থাকা)। রে ওেন্ডারলিচ এটি এখানে আবৃত করেছেন

পূর্বোক্ত লিঙ্কটি থেকে কোডটি উদ্ধৃত করা হচ্ছে:

NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:@"This is an example by @marcelofabri_"];
[attributedString addAttribute:NSLinkAttributeName
                     value:@"username://marcelofabri_"
                     range:[[attributedString string] rangeOfString:@"@marcelofabri_"]];

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

// assume that textView is a UITextView previously created (either by code or Interface Builder)
textView.linkTextAttributes = linkAttributes; // customizes the appearance of links
textView.attributedText = attributedString;
textView.delegate = self;

এই লিঙ্ক ক্লিকগুলি সনাক্ত করতে, এটি প্রয়োগ করুন:

- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange {
    if ([[URL scheme] isEqualToString:@"username"]) {
        NSString *username = [URL host]; 
        // do something with this username
        // ...
        return NO;
    }
    return YES; // let the system open this URL
}

পিএস: নিশ্চিত হন যে আপনার UITextViewআছে selectable


এটি গ্রহণ করা উচিত। আমি @ এনএলএক্সএন দ্বারা কাজ করে কোড পাওয়ার চেষ্টা করে অনেক সময় ব্যয় করেছি এবং তারপরে এটি 5 মিনিটের মধ্যে ইউআইটিেক্সটভিউ দিয়ে প্রয়োগ করেছিলাম।
চারলাগ

এর সাথে সমস্যা হ'ল যদি আপনি বিভিন্ন লিঙ্কগুলির জন্য জেনেরিক করতে চান তবে উপযুক্ত ব্যবস্থা গ্রহণের জন্য ইউআরএল কী তা পরীক্ষা করতে হবে
hariszaman

33

আপনি যদি এটির জন্য কোনও চিত্র সেট না করেন তবে ইউআইবাটন টাইপকাস্টমটি ক্লিকযোগ্য লেবেল।


22
কেবলমাত্র পুরো পাঠ্যটি ক্লিকযোগ্য এবং কেবলমাত্র একটি লিঙ্ক।
জন প্যাং

33

(আমার উত্তর @ এনএলএক্সএন এর দুর্দান্ত উত্তরের উপর ভিত্তি করে । আমি এখানে প্রতিটি পদক্ষেপের তার বিশদ ব্যাখ্যাটি নকল করব না))

UITapGestureRecognizer এ বিভাগ হিসাবে ট্যাপ-সক্ষম UILabel পাঠ্যের জন্য সমর্থন যুক্ত করা আমি সবচেয়ে সুবিধাজনক এবং সোজা বলে মনে করি। (আপনি না আছে UITextView ডেটা ডিটেক্টর ব্যবহার করতে, যেমন কিছু উত্তর সুপারিশ।)

আপনার UITapGestureRecognizer বিভাগে নিম্নলিখিত পদ্ধতিটি যুক্ত করুন:

/**
 Returns YES if the tap gesture was within the specified range of the attributed text of the label.
 */
- (BOOL)didTapAttributedTextInLabel:(UILabel *)label inRange:(NSRange)targetRange {
    NSParameterAssert(label != nil);

    CGSize labelSize = label.bounds.size;
    // create instances of NSLayoutManager, NSTextContainer and NSTextStorage
    NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
    NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:CGSizeZero];
    NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:label.attributedText];

    // configure layoutManager and textStorage
    [layoutManager addTextContainer:textContainer];
    [textStorage addLayoutManager:layoutManager];

    // configure textContainer for the label
    textContainer.lineFragmentPadding = 0.0;
    textContainer.lineBreakMode = label.lineBreakMode;
    textContainer.maximumNumberOfLines = label.numberOfLines;
    textContainer.size = labelSize;

    // find the tapped character location and compare it to the specified range
    CGPoint locationOfTouchInLabel = [self locationInView:label];
    CGRect textBoundingBox = [layoutManager usedRectForTextContainer:textContainer];
    CGPoint textContainerOffset = CGPointMake((labelSize.width - textBoundingBox.size.width) * 0.5 - textBoundingBox.origin.x,
                                              (labelSize.height - textBoundingBox.size.height) * 0.5 - textBoundingBox.origin.y);
    CGPoint locationOfTouchInTextContainer = CGPointMake(locationOfTouchInLabel.x - textContainerOffset.x,
                                                         locationOfTouchInLabel.y - textContainerOffset.y);
    NSInteger indexOfCharacter = [layoutManager characterIndexForPoint:locationOfTouchInTextContainer
                                                            inTextContainer:textContainer
                                   fractionOfDistanceBetweenInsertionPoints:nil];
    if (NSLocationInRange(indexOfCharacter, targetRange)) {
        return YES;
    } else {
        return NO;
    }
}

উদাহরণ কোড

// (in your view controller)    
// create your label, gesture recognizer, attributed text, and get the range of the "link" in your label
myLabel.userInteractionEnabled = YES;
[myLabel addGestureRecognizer:
   [[UITapGestureRecognizer alloc] initWithTarget:self 
                                           action:@selector(handleTapOnLabel:)]]; 

// create your attributed text and keep an ivar of your "link" text range
NSAttributedString *plainText;
NSAttributedString *linkText;
plainText = [[NSMutableAttributedString alloc] initWithString:@"Add label links with UITapGestureRecognizer"
                                                   attributes:nil];
linkText = [[NSMutableAttributedString alloc] initWithString:@" Learn more..."
                                                  attributes:@{
                                                      NSForegroundColorAttributeName:[UIColor blueColor]
                                                  }];
NSMutableAttributedString *attrText = [[NSMutableAttributedString alloc] init];
[attrText appendAttributedString:plainText];
[attrText appendAttributedString:linkText];

// ivar -- keep track of the target range so you can compare in the callback
targetRange = NSMakeRange(plainText.length, linkText.length);

অঙ্গভঙ্গি কলব্যাক

// handle the gesture recognizer callback and call the category method
- (void)handleTapOnLabel:(UITapGestureRecognizer *)tapGesture {
    BOOL didTapLink = [tapGesture didTapAttributedTextInLabel:myLabel
                                            inRange:targetRange];
    NSLog(@"didTapLink: %d", didTapLink);

}

1
এই কাজটি প্রায় হয়েছে - তবে আমি লিঙ্কটেক্সট.লোকেশন নিয়ে সমস্যায় পড়ছি - আমার এনএসএট্রিবিউটড স্ট্রিংয়ের এই সম্পত্তি নেই?
ম্যাট বোল্ট

1
@ ম্যাটবোল্ট ওফস, এটি একটি ভুল ছিল। লিঙ্ক পাঠ্যের এটি সূচনা সূচি হওয়া উচিত, এই উদাহরণে এটি হওয়া উচিত plainText.length
জেকেল

সিজিপয়েন্ট পোস্টে ত্রুটি ঘটেছেঅফটচআইএনএলবেল = [স্ব অবস্থান: আইভিউ: লেবেল];
মনিকা প্যাটেল

@ জেকেল এই সমাধানের জন্য আপনাকে অনেক ধন্যবাদ। তবে আপনি "আপনার ইউআইটিপগ্রেশারআরসিগনাইজার ক্যাটাগরিতে নিম্নলিখিত পদ্ধতিটি যুক্ত করুন" এর অর্থ কী আপনি বোঝাতে পারেন? আমার এখানে কী করা উচিত তা নিশ্চিত নয়।
eivindML

@eivindml আপনি যা যেমন শ্রেণীর আপনি লেখেননি, সঙ্গে কাজ জন্য দরকারী বিদ্যমান ক্লাস, পদ্ধতি যোগ করার জন্য বিভাগ ব্যবহার করতে পারেন UITapGestureRecognizer। বিভাগগুলি যুক্ত করার জন্য এখানে কিছু তথ্য
জেকেল

20

UITextViewOS3.0-তে ডেটা-ডিটেক্টরকে সমর্থন করে, যদিও UILabelতা করে না।

আপনি যদি ডেটা-ডিটেক্টরগুলিকে সক্ষম করে থাকেন UITextViewএবং আপনার পাঠ্যে ইউআরএল, ফোন নম্বর ইত্যাদি রয়েছে তবে তারা লিঙ্ক হিসাবে উপস্থিত হবে।


হ্যাঁ, আমি এটি সম্পর্কে জানি, তবে আমার কাস্টম সনাক্তকরণও প্রয়োজন, উদাহরণস্বরূপ # প্রশ্ন_শব্দটি আমার প্রশ্নে উল্লিখিত হয়েছে
লোপ

@ লপ আপনি এখনও এটি করতে পারেন, কেবল তাদের মতো একটি কাস্টম ইউআরএল-পরিকল্পনা hashtag://বা অন্য কিছু নির্ধারণ করুন , তারপরে textView(_:shouldInteractWith:in:interaction:)এটি সনাক্ত করতে ব্যবহার করুন । : নীচের উত্তর দেখার stackoverflow.com/a/34014655/1161906
bcattle

14

@ সামউইজের এক্সটেনশনটি সুইফট 4 এ অনুবাদ করা:

extension UITapGestureRecognizer {
    func didTapAttributedTextInLabel(label: UILabel, inRange targetRange: NSRange) -> Bool {
        guard let attrString = label.attributedText else {
            return false
        }

        let layoutManager = NSLayoutManager()
        let textContainer = NSTextContainer(size: .zero)
        let textStorage = NSTextStorage(attributedString: attrString)

        layoutManager.addTextContainer(textContainer)
        textStorage.addLayoutManager(layoutManager)

        textContainer.lineFragmentPadding = 0
        textContainer.lineBreakMode = label.lineBreakMode
        textContainer.maximumNumberOfLines = label.numberOfLines
        let labelSize = label.bounds.size
        textContainer.size = labelSize

        let locationOfTouchInLabel = self.location(in: label)
        let textBoundingBox = layoutManager.usedRect(for: textContainer)
        let textContainerOffset = CGPoint(x: (labelSize.width - textBoundingBox.size.width) * 0.5 - textBoundingBox.origin.x, y: (labelSize.height - textBoundingBox.size.height) * 0.5 - textBoundingBox.origin.y)
        let locationOfTouchInTextContainer = CGPoint(x: locationOfTouchInLabel.x - textContainerOffset.x, y: locationOfTouchInLabel.y - textContainerOffset.y)
        let indexOfCharacter = layoutManager.characterIndex(for: locationOfTouchInTextContainer, in: textContainer, fractionOfDistanceBetweenInsertionPoints: nil)
        return NSLocationInRange(indexOfCharacter, targetRange)
    }
}

সনাক্তকারী সেট আপ করতে (একবার আপনি টেক্সট এবং স্টাফ রঙ করুন):

lblTermsOfUse.isUserInteractionEnabled = true
lblTermsOfUse.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleTapOnLabel(_:))))

... তারপর অঙ্গভঙ্গি সনাক্তকারী:

@objc func handleTapOnLabel(_ recognizer: UITapGestureRecognizer) {
    guard let text = lblAgreeToTerms.attributedText?.string else {
        return
    }

    if let range = text.range(of: NSLocalizedString("_onboarding_terms", comment: "terms")),
        recognizer.didTapAttributedTextInLabel(label: lblAgreeToTerms, inRange: NSRange(range, in: text)) {
        goToTermsAndConditions()
    } else if let range = text.range(of: NSLocalizedString("_onboarding_privacy", comment: "privacy")),
        recognizer.didTapAttributedTextInLabel(label: lblAgreeToTerms, inRange: NSRange(range, in: text)) {
        goToPrivacyPolicy()
    }
}

6
আমার জন্য কাজ করছে না। একটি আর্গুমেন্ট হিসাবে একটি didTapAttributedTextInLabelপ্রয়োজন NSRangeতবে rangeTermsভিন্ন কিছু ফেরত দেয়। এছাড়াও handleTapOnLabelফাংশনটি @objcসুইফট 4
শান্তিমূলক

10

যেমনটি আমি এই পোস্টে উল্লেখ করেছি , এখানে একটি হালকা-ভারী গ্রন্থাগার রয়েছে যা আমি ইউআইএলবেল এফআরহাইপারলেবেলে লিঙ্কগুলির জন্য বিশেষভাবে তৈরি করেছি

এর মতো প্রভাব অর্জন করতে:

আপনার পছন্দসই কাজটি করতে পারবেন না। প্লেইনটেস্ক কুইস ব্লেন্ডিট ইওরোজ, সিটি অ্যাটমিনে যান। নাম আর্ন নিকেক। মেইনাস এসি সেম ইইউ সেম পোর্টে ডাইম নেম ওয়েল টেলস।

কোড ব্যবহার করুন:

//Step 1: Define a normal attributed string for non-link texts
NSString *string = @"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque quis blandit eros, sit amet vehicula justo. Nam at urna neque. Maecenas ac sem eu sem porta dictum nec vel tellus.";
NSDictionary *attributes = @{NSFontAttributeName: [UIFont preferredFontForTextStyle:UIFontTextStyleHeadline]};

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


//Step 2: Define a selection handler block
void(^handler)(FRHyperLabel *label, NSString *substring) = ^(FRHyperLabel *label, NSString *substring){
    NSLog(@"Selected: %@", substring);
};


//Step 3: Add link substrings
[label setLinksForSubstrings:@[@"Lorem", @"Pellentesque", @"blandit", @"Maecenas"] withLinkHandler:handler];

1
লেবেল পাঠ্যটি যদি এপিআই থেকে ডায়নামিক হয় এবং আপনি পাঠ্যের দৈর্ঘ্য জানেন না তবে কীভাবে কোনও লিঙ্ক তৈরি করবেন what
সুভাষ শর্মা

পাশাপাশি সুইফট 4 এ সূক্ষ্মভাবে কাজ করে।
হোলা সোয় এদু ফেলিজ নাভিদাদ

7

আমি UILabel উপশ্রেণী নামে নির্মিত ResponsiveLabel যা textkit এপিআই চালু আইওএস 7 এটি একই পদ্ধতির দ্বারা প্রস্তাবিত ব্যবহার উপর ভিত্তি করে তৈরি NAlexN । এটি পাঠ্যে সন্ধানের জন্য একটি প্যাটার্ন নির্দিষ্ট করতে নমনীয়তা সরবরাহ করে। যে কোনও প্যাটার্নগুলিতে প্রয়োগ করার জন্য শৈলীর পাশাপাশি নিদর্শনগুলিতে আলতো চাপানোর জন্য ক্রিয়া করা যেতে পারে।

//Detects email in text

 NSString *emailRegexString = @"[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}";
 NSError *error;
 NSRegularExpression *regex = [[NSRegularExpression alloc]initWithPattern:emailRegexString options:0 error:&error];
 PatternDescriptor *descriptor = [[PatternDescriptor alloc]initWithRegex:regex withSearchType:PatternSearchTypeAll withPatternAttributes:@{NSForegroundColorAttributeName:[UIColor redColor]}];
 [self.customLabel enablePatternDetection:descriptor];

আপনি যদি স্ট্রিংকে ক্লিকযোগ্য করে তুলতে চান তবে আপনি এইভাবে করতে পারেন। এই কোডটি "পাঠ্য" স্ট্রিংয়ের প্রতিটি ঘটনার জন্য গুণাবলী প্রয়োগ করে।

PatternTapResponder tapResponder = ^(NSString *string) {
    NSLog(@"tapped = %@",string);
};

[self.customLabel enableStringDetection:@"text" withAttributes:@{NSForegroundColorAttributeName:[UIColor redColor],
                                                                 RLTapResponderAttributeName: tapResponder}];

রেসপন্সাল লেবেলটি কাজ করার জন্য ভাল উপাদানগুলি বলে মনে হচ্ছে তবে কোনও কারণে আমি ক্লিকযোগ্য টেক্সটের জন্য রঙ নির্ধারণ করতে পারি না এবং ক্লিকযোগ্য স্ট্রিংগুলির অ্যারে সেট করতে পারি না।
মাতরোসভ আলেকজান্ডার

@ মাতরোসোভ অ্যালেক্সান্দার এখনই, রেসপন্সিবলবেলে এমন কোনও পদ্ধতি নেই যা স্ট্রিংয়ের একটি অ্যারে নেয় এবং সেগুলি ক্লিকযোগ্য করে তোলে। আপনি গিথুব এ একটি সমস্যা তৈরি করতে পারেন এবং আমি শীঘ্রই এটি বাস্তবায়ন করব।
hsusmita

হ্যাঁ এটি কোনও সমস্যা নয়, তবে অ্যারে লাগে এমন পদ্ধতিটি থাকা ভাল।
মাতরোসভ আলেকজান্ডার

6

পুরো কোডটি এখানে আটকান, সুইফ্ট 3 এ কাজ করেছেন

    //****Make sure the textview 'Selectable' = checked, and 'Editable = Unchecked'

import UIKit

class ViewController: UIViewController, UITextViewDelegate {

    @IBOutlet var theNewTextView: UITextView!
    override func viewDidLoad() {
        super.viewDidLoad()

        //****textview = Selectable = checked, and Editable = Unchecked

        theNewTextView.delegate = self

        let theString = NSMutableAttributedString(string: "Agree to Terms")
        let theRange = theString.mutableString.range(of: "Terms")

        theString.addAttribute(NSLinkAttributeName, value: "ContactUs://", range: theRange)

        let theAttribute = [NSForegroundColorAttributeName: UIColor.blue, NSUnderlineStyleAttributeName: NSUnderlineStyle.styleSingle.rawValue] as [String : Any]

        theNewTextView.linkTextAttributes = theAttribute

     theNewTextView.attributedText = theString             

theString.setAttributes(theAttribute, range: theRange)

    }

    func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {

        if (URL.scheme?.hasPrefix("ContactUs://"))! {

            return false //interaction not allowed
        }

        //*** Set storyboard id same as VC name
        self.navigationController!.pushViewController((self.storyboard?.instantiateViewController(withIdentifier: "TheLastViewController"))! as UIViewController, animated: true)

        return true
    }

}

এটি নতুন এপিআই, কেবল সুইফট 10 এবং
তদূর্ধের

1
@ t4nhpt আপনার অর্থ আইওএস 10 ;-)
অস্বীকার করুন

6

হাইপারলিংক ইউআইএলবেলের উদাহরণ কোড এখানে: উত্স: http://sickprogrammersarea.blogspot.in/2014/03/adding-links-to-uilabel.html

#import "ViewController.h"
#import "TTTAttributedLabel.h"

@interface ViewController ()
@end

@implementation ViewController
{
    UITextField *loc;
    TTTAttributedLabel *data;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    UILabel *lbl = [[UILabel alloc] initWithFrame:CGRectMake(5, 20, 80, 25) ];
    [lbl setText:@"Text:"];
    [lbl setFont:[UIFont fontWithName:@"Verdana" size:16]];
    [lbl setTextColor:[UIColor grayColor]];
    loc=[[UITextField alloc] initWithFrame:CGRectMake(4, 20, 300, 30)];
    //loc.backgroundColor = [UIColor grayColor];
    loc.borderStyle=UITextBorderStyleRoundedRect;
    loc.clearButtonMode=UITextFieldViewModeWhileEditing;
    //[loc setText:@"Enter Location"];
    loc.clearsOnInsertion = YES;
    loc.leftView=lbl;
    loc.leftViewMode=UITextFieldViewModeAlways;
    [loc setDelegate:self];
    [self.view addSubview:loc];
    [loc setRightViewMode:UITextFieldViewModeAlways];
    CGRect frameimg = CGRectMake(110, 70, 70,30);
    UIButton *srchButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    srchButton.frame=frameimg;
    [srchButton setTitle:@"Go" forState:UIControlStateNormal];
    [srchButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
    srchButton.backgroundColor=[UIColor clearColor];
    [srchButton addTarget:self action:@selector(go:) forControlEvents:UIControlEventTouchDown];
    [self.view addSubview:srchButton];
    data = [[TTTAttributedLabel alloc] initWithFrame:CGRectMake(5, 120,self.view.frame.size.width,200) ];
    [data setFont:[UIFont fontWithName:@"Verdana" size:16]];
    [data setTextColor:[UIColor blackColor]];
    data.numberOfLines=0;
    data.delegate = self;
    data.enabledTextCheckingTypes=NSTextCheckingTypeLink|NSTextCheckingTypePhoneNumber;
    [self.view addSubview:data];
}
- (void)attributedLabel:(TTTAttributedLabel *)label didSelectLinkWithURL:(NSURL *)url
{
    NSString *val=[[NSString alloc]initWithFormat:@"%@",url];
    if ([[url scheme] hasPrefix:@"mailto"]) {
              NSLog(@" mail URL Selected : %@",url);
        MFMailComposeViewController *comp=[[MFMailComposeViewController alloc]init];
        [comp setMailComposeDelegate:self];
        if([MFMailComposeViewController canSendMail])
        {
            NSString *recp=[[val substringToIndex:[val length]] substringFromIndex:7];
            NSLog(@"Recept : %@",recp);
            [comp setToRecipients:[NSArray arrayWithObjects:recp, nil]];
            [comp setSubject:@"From my app"];
            [comp setMessageBody:@"Hello bro" isHTML:NO];
            [comp setModalTransitionStyle:UIModalTransitionStyleCrossDissolve];
            [self presentViewController:comp animated:YES completion:nil];
        }
    }
    else{
        [[UIApplication sharedApplication] openURL:[NSURL URLWithString:val]];
    }
}
-(void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error{
    if(error)
    {
        UIAlertView *alrt=[[UIAlertView alloc]initWithTitle:@"Erorr" message:@"Some error occureed" delegate:nil cancelButtonTitle:@"" otherButtonTitles:nil, nil];
        [alrt show];
        [self dismissViewControllerAnimated:YES completion:nil];
    }
    else{
        [self dismissViewControllerAnimated:YES completion:nil];
    }
}

- (void)attributedLabel:(TTTAttributedLabel *)label didSelectLinkWithPhoneNumber:(NSString *)phoneNumber
{
    NSLog(@"Phone Number Selected : %@",phoneNumber);
    UIDevice *device = [UIDevice currentDevice];
    if ([[device model] isEqualToString:@"iPhone"] ) {
        [[UIApplication sharedApplication] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"tel:%@",phoneNumber]]];
    } else {
        UIAlertView *Notpermitted=[[UIAlertView alloc] initWithTitle:@"Alert" message:@"Your device doesn't support this feature." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
        [Notpermitted show];
    }
}
-(void)go:(id)sender
{
    [data setText:loc.text];
}

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    NSLog(@"Reached");
    [loc resignFirstResponder];
}

6

এনএএলএক্সএন এর উত্তরের একটি দ্রুত সংস্করণ এখানে is

class TapabbleLabel: UILabel {

let layoutManager = NSLayoutManager()
let textContainer = NSTextContainer(size: CGSize.zero)
var textStorage = NSTextStorage() {
    didSet {
        textStorage.addLayoutManager(layoutManager)
    }
}

var onCharacterTapped: ((label: UILabel, characterIndex: Int) -> Void)?

let tapGesture = UITapGestureRecognizer()

override var attributedText: NSAttributedString? {
    didSet {
        if let attributedText = attributedText {
            textStorage = NSTextStorage(attributedString: attributedText)
        } else {
            textStorage = NSTextStorage()
        }
    }
}

override var lineBreakMode: NSLineBreakMode {
    didSet {
        textContainer.lineBreakMode = lineBreakMode
    }
}

override var numberOfLines: Int {
    didSet {
        textContainer.maximumNumberOfLines = numberOfLines
    }
}

/**
 Creates a new view with the passed coder.

 :param: aDecoder The a decoder

 :returns: the created new view.
 */
required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    setUp()
}

/**
 Creates a new view with the passed frame.

 :param: frame The frame

 :returns: the created new view.
 */
override init(frame: CGRect) {
    super.init(frame: frame)
    setUp()
}

/**
 Sets up the view.
 */
func setUp() {
    userInteractionEnabled = true
    layoutManager.addTextContainer(textContainer)
    textContainer.lineFragmentPadding = 0
    textContainer.lineBreakMode = lineBreakMode
    textContainer.maximumNumberOfLines = numberOfLines
    tapGesture.addTarget(self, action: #selector(TapabbleLabel.labelTapped(_:)))
    addGestureRecognizer(tapGesture)
}

override func layoutSubviews() {
    super.layoutSubviews()
    textContainer.size = bounds.size
}

func labelTapped(gesture: UITapGestureRecognizer) {
    guard gesture.state == .Ended else {
        return
    }

    let locationOfTouch = gesture.locationInView(gesture.view)
    let textBoundingBox = layoutManager.usedRectForTextContainer(textContainer)
    let textContainerOffset = CGPoint(x: (bounds.width - textBoundingBox.width) / 2 - textBoundingBox.minX,
                                      y: (bounds.height - textBoundingBox.height) / 2 - textBoundingBox.minY)        
    let locationOfTouchInTextContainer = CGPoint(x: locationOfTouch.x - textContainerOffset.x,
                                                 y: locationOfTouch.y - textContainerOffset.y)
    let indexOfCharacter = layoutManager.characterIndexForPoint(locationOfTouchInTextContainer,
                                                                inTextContainer: textContainer,
                                                                fractionOfDistanceBetweenInsertionPoints: nil)

    onCharacterTapped?(label: self, characterIndex: indexOfCharacter)
}
}

তারপরে আপনি নিজের viewDidLoadপদ্ধতির অভ্যন্তরে এই শ্রেণীর উদাহরণ তৈরি করতে পারেন :

let label = TapabbleLabel()
label.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(label)
view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-[view]-|",
                                               options: [], metrics: nil, views: ["view" : label]))
view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-[view]-|",
                                               options: [], metrics: nil, views: ["view" : label]))

let attributedString = NSMutableAttributedString(string: "String with a link", attributes: nil)
let linkRange = NSMakeRange(14, 4); // for the word "link" in the string above

let linkAttributes: [String : AnyObject] = [
    NSForegroundColorAttributeName : UIColor.blueColor(), NSUnderlineStyleAttributeName : NSUnderlineStyle.StyleSingle.rawValue,
    NSLinkAttributeName: "http://www.apple.com"]
attributedString.setAttributes(linkAttributes, range:linkRange)

label.attributedText = attributedString

label.onCharacterTapped = { label, characterIndex in
    if let attribute = label.attributedText?.attribute(NSLinkAttributeName, atIndex: characterIndex, effectiveRange: nil) as? String,
        let url = NSURL(string: attribute) {
        UIApplication.sharedApplication().openURL(url)
    }
}

কোনও চরিত্রটি টেপ করা হলে ব্যবহার করার জন্য একটি কাস্টম বৈশিষ্ট্য থাকা ভাল। এখন, এটি হ'ল NSLinkAttributeNameতবে কিছু হতে পারে এবং আপনি কোনও মানটি ইউআরএল খোলার ব্যতীত অন্য কিছু করতেও ব্যবহার করতে পারেন, আপনি যে কোনও কাস্টম ক্রিয়া করতে পারেন।


এটা অসাধারণ! আমি টেপগাস্টারআর সনাক্তকারীকে একটি লংপ্রেসআর সনাক্তকারী সাথে প্রতিস্থাপন করেছি এবং এটি টেবিলভিউ স্ক্রোলিংকে ভেঙে দেয়। কীভাবে কোনও অঙ্গভঙ্গি সনাক্তকারীকে টেবিলভিউ স্ক্রোলিং ভাঙ্গা থেকে রোধ করবেন? ধন্যবাদ !!!
লুসিউস ডিজেয়ার

আপনি ব্যবহার করতে পারেনসিজনেগসিমিউল ডেভেলপার।
mohamede1945

4

এর সাথে লেনদেন করতে আমার বেশ কষ্ট হয়েছিল ... উল্লিখিত পাঠ্যের উপর লিঙ্কগুলি সহ ইউআইনাবেল ... এটি কেবল একটি মাথা ব্যাথা যা আমি ZSWTappableLabel ব্যবহার করে শেষ করেছি


ধন্যবাদ। এটা সত্যিই আমার ক্ষেত্রে কাজ করে। এটি ইমেল আইডি, ফোন নম্বর এবং লিঙ্কটি সনাক্ত করবে।
ইলিশ

4

পূর্বের উত্তরে যেমন জানা গেছে যে ইউআইটিেক্সটভিউ লিঙ্কগুলিতে স্পর্শগুলি পরিচালনা করতে সক্ষম। লিঙ্ক হিসাবে পাঠ্যের অন্যান্য অংশগুলিকে তৈরি করে এটি সহজেই বাড়ানো যেতে পারে। অ্যাট্রিবিউটেডটেক্সটভিউ লাইব্রেরি একটি ইউআইটিেক্সটভিউ সাবক্লাস যা এগুলি পরিচালনা করা খুব সহজ করে তোলে। আরও তথ্যের জন্য দেখুন: https://github.com/evermeer/AtribribTTxtView

আপনি পাঠ্যের যে কোনও অংশকে এভাবে ইন্টারঅ্যাক্ট করতে পারেন (যেখানে টেক্সটভিউ 1 একটি ইউআইটিেক্সটভিউ আইবিউটলেট):

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 })
    }

3

আমি মাল্টি-লাইন ইউআইএলবেল হ্যান্ডেল করার জন্য @ সামউইজের উত্তরটি প্রসারিত করছি এবং ইউআইবাটনটির জন্য ব্যবহারের জন্য একটি উদাহরণ দিচ্ছি

extension UITapGestureRecognizer {

    func didTapAttributedTextInButton(button: UIButton, inRange targetRange: NSRange) -> Bool {
        guard let label = button.titleLabel else { return false }
        return didTapAttributedTextInLabel(label, inRange: targetRange)
    }

    func didTapAttributedTextInLabel(label: UILabel, inRange targetRange: NSRange) -> Bool {
        // Create instances of NSLayoutManager, NSTextContainer and NSTextStorage
        let layoutManager = NSLayoutManager()
        let textContainer = NSTextContainer(size: CGSize.zero)
        let textStorage = NSTextStorage(attributedString: label.attributedText!)

        // Configure layoutManager and textStorage
        layoutManager.addTextContainer(textContainer)
        textStorage.addLayoutManager(layoutManager)

        // Configure textContainer
        textContainer.lineFragmentPadding = 0.0
        textContainer.lineBreakMode = label.lineBreakMode
        textContainer.maximumNumberOfLines = label.numberOfLines
        let labelSize = label.bounds.size
        textContainer.size = labelSize

        // Find the tapped character location and compare it to the specified range
        let locationOfTouchInLabel = self.locationInView(label)
        let textBoundingBox = layoutManager.usedRectForTextContainer(textContainer)
        let textContainerOffset = CGPointMake((labelSize.width - textBoundingBox.size.width) * 0.5 - textBoundingBox.origin.x,
                                              (labelSize.height - textBoundingBox.size.height) * 0.5 - textBoundingBox.origin.y);
        let locationOfTouchInTextContainer = CGPointMake((locationOfTouchInLabel.x - textContainerOffset.x),
                                                         0 );
        // Adjust for multiple lines of text
        let lineModifier = Int(ceil(locationOfTouchInLabel.y / label.font.lineHeight)) - 1
        let rightMostFirstLinePoint = CGPointMake(labelSize.width, 0)
        let charsPerLine = layoutManager.characterIndexForPoint(rightMostFirstLinePoint, inTextContainer: textContainer, fractionOfDistanceBetweenInsertionPoints: nil)

        let indexOfCharacter = layoutManager.characterIndexForPoint(locationOfTouchInTextContainer, inTextContainer: textContainer, fractionOfDistanceBetweenInsertionPoints: nil)
        let adjustedRange = indexOfCharacter + (lineModifier * charsPerLine)

        return NSLocationInRange(adjustedRange, targetRange)
    }

}

আমি আপনার মাল্টি লাইন UILabel এর জন্য সমাধানটি চেষ্টা করেছি এবং এটি সত্যিই আমার পক্ষে কার্যকর হয় না। স্পর্শটি সর্বদা আমার ইউআইবিবেলের শেষ লাইনে নিবন্ধভুক্ত থাকে।
খ্রিস্টান শোবার

1
@ ক্রিশ্চিয়ানসচোবারের কি আপনার কাস্টম ফন্ট বা লাইনের উচ্চতা আছে?
টিম্বব্রোডার

আসলেই নয়, আমরা হেলভেটিকানিউ এবং স্ট্যান্ডার্ড হাইটগুলি ব্যবহার করি
ক্রিশ্চিয়ান শোবার

1
লাইনের
ব্রেকটি

আমার কাছে ডিফল্ট ফন্ট রয়েছে তবে লাইন ফাঁকা আছে এবং কোনও কাজ হয়নি?
জোসেফ আস্ট্রাহান

3

আমি এই সংস্করণটি অনুসরণ করি,

সুইফট 4:

import Foundation

class AELinkedClickableUILabel: UILabel {

    typealias YourCompletion = () -> Void

    var linkedRange: NSRange!
    var completion: YourCompletion?

    @objc func linkClicked(sender: UITapGestureRecognizer){

        if let completionBlock = completion {

            let textView = UITextView(frame: self.frame)
            textView.text = self.text
            textView.attributedText = self.attributedText
            let index = textView.layoutManager.characterIndex(for: sender.location(in: self),
                                                              in: textView.textContainer,
                                                              fractionOfDistanceBetweenInsertionPoints: nil)

            if linkedRange.lowerBound <= index && linkedRange.upperBound >= index {

                completionBlock()
            }
        }
    }

/**
 *  This method will be used to set an attributed text specifying the linked text with a
 *  handler when the link is clicked
 */
    public func setLinkedTextWithHandler(text:String, link: String, handler: @escaping ()->()) -> Bool {

        let attributextText = NSMutableAttributedString(string: text)
        let foundRange = attributextText.mutableString.range(of: link)

        if foundRange.location != NSNotFound {
            self.linkedRange = foundRange
            self.completion = handler
            attributextText.addAttribute(NSAttributedStringKey.link, value: text, range: foundRange)
            self.isUserInteractionEnabled = true
            self.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(linkClicked(sender:))))
            return true
        }
        return false
    }
}

কল উদাহরণ:

button.setLinkedTextWithHandler(text: "This website (stackoverflow.com) is awesome", link: "stackoverflow.com") 
{
    // show popup or open to link
}

3

আমি অন্য একটি সমাধান খুঁজে পেয়েছি:

আমি এইচটিএমএল পাঠ্যে লিঙ্কটি সনাক্ত করার একটি উপায় খুঁজে পেয়েছি যা আপনি ইন্টারনেট থেকে সন্ধান করেন এটির মাধ্যমে এটি এটিকে nsattributeString এ রূপান্তর করুন:

func htmlAttributedString(fontSize: CGFloat = 17.0) -> NSAttributedString? {
            let fontName = UIFont.systemFont(ofSize: fontSize).fontName
            let string = self.appending(String(format: "<style>body{font-family: '%@'; font-size:%fpx;}</style>", fontName, fontSize))
            guard let data = string.data(using: String.Encoding.utf16, allowLossyConversion: false) else { return nil }

            guard let html = try? NSMutableAttributedString (
                data: data,
                options: [NSAttributedString.DocumentReadingOptionKey.documentType: NSAttributedString.DocumentType.html],
                documentAttributes: nil) else { return nil }
            return html
        }

আমার পদ্ধতি আপনাকে হাইপারলিংকগুলি নির্দিষ্ট না করে সনাক্ত করতে দেয়।

  • প্রথমে আপনি টেপজেস্টেরেকনাইজারের একটি এক্সটেনশন তৈরি করুন:

    extension UITapGestureRecognizer {
    func didTapAttributedTextInLabel(label: UILabel, inRange targetRange: NSRange) -> Bool {
        guard let attrString = label.attributedText else {
            return false
        }
    
        let layoutManager = NSLayoutManager()
        let textContainer = NSTextContainer(size: .zero)
        let textStorage = NSTextStorage(attributedString: attrString)
    
        layoutManager.addTextContainer(textContainer)
        textStorage.addLayoutManager(layoutManager)
    
        textContainer.lineFragmentPadding = 0
        textContainer.lineBreakMode = label.lineBreakMode
        textContainer.maximumNumberOfLines = label.numberOfLines
        let labelSize = label.bounds.size
        textContainer.size = labelSize
    
        let locationOfTouchInLabel = self.location(in: label)
        let textBoundingBox = layoutManager.usedRect(for: textContainer)
        let textContainerOffset = CGPoint(x: (labelSize.width - textBoundingBox.size.width) * 0.5 - textBoundingBox.origin.x, y: (labelSize.height - textBoundingBox.size.height) * 0.5 - textBoundingBox.origin.y)
        let locationOfTouchInTextContainer = CGPoint(x: locationOfTouchInLabel.x - textContainerOffset.x, y: locationOfTouchInLabel.y - textContainerOffset.y)
        let indexOfCharacter = layoutManager.characterIndex(for: locationOfTouchInTextContainer, in: textContainer, fractionOfDistanceBetweenInsertionPoints: nil)
        return NSLocationInRange(indexOfCharacter, targetRange)
    }

    }

তারপরে আপনি কন্ট্রোলারটি দেখেন আপনি সমস্ত লিঙ্ক এবং বৈশিষ্ট্য পাঠ্যের মধ্যে থাকা পরিসীমা সংরক্ষণের জন্য url এবং ব্যাপ্তির একটি তালিকা তৈরি করেছেন:

var listurl : [String] = []
    var listURLRange : [NSRange] = []

ইউআরএল এবং ইউআরএল-রেঞ্জ খুঁজে পেতে আপনি ব্যবহার করতে পারেন:

    fun findLinksAndRange(attributeString : NSAttributeString){
        notification.enumerateAttribute(NSAttributedStringKey.link , in: NSMakeRange(0, notification.length), options: [.longestEffectiveRangeNotRequired]) { value, range, isStop in
                    if let value = value {
                        print("\(value) found at \(range.location)")
                        let stringValue = "\(value)"
                        listurl.append(stringValue)
                        listURLRange.append(range)
                    }
                }

            westlandNotifcationLabel.addGestureRecognizer(UITapGestureRecognizer(target : self, action: #selector(handleTapOnLabel(_:))))

    }

তারপরে আপনি হ্যান্ডেল ট্যাপটি প্রয়োগ করছেন:

@objc func handleTapOnLabel(_ recognizer: UITapGestureRecognizer) {
        for index in 0..<listURLRange.count{
            if recognizer.didTapAttributedTextInLabel(label: westlandNotifcationLabel, inRange: listURLRange[index]) {
                goToWebsite(url : listurl[index])
            }
        }
    }

    func goToWebsite(url : String){
        if let websiteUrl = URL(string: url){
            if #available(iOS 10, *) {
                UIApplication.shared.open(websiteUrl, options: [:],
                                          completionHandler: {
                                            (success) in
                                            print("Open \(websiteUrl): \(success)")
                })
            } else {
                let success = UIApplication.shared.openURL(websiteUrl)
                print("Open \(websiteUrl): \(success)")
            }
        }
    }

এবং আমরা এখানে!

আমি আশা করি যে এই সমাধানটি আপনাকে আমার পছন্দ করতে পছন্দ করবে।


2

সম্পূর্ণ কাস্টম লিঙ্কগুলির জন্য, আপনাকে একটি ইউআইবিউবভিউ ব্যবহার করতে হবে - আপনি কলগুলি বন্ধ করতে পারেন, যাতে কোনও লিঙ্ক চাপলে পরিবর্তে আপনি আপনার অ্যাপ্লিকেশানের অন্য কোনও অংশে যেতে পারেন।


3
ইউআইওয়েবভিউগুলি বরাদ্দ করার সময় তত দ্রুত হয় না, সুতরাং ফ্যানসিএলবেল বা টিটিটিএটিটিগ্রিবিউটেড লেবেলের মতো একটি ইউআইএলবেল বা ইউআইটিএক্সফিল্ড লাইব্রেরি ব্যবহার করা যদি আপনি এটি থেকে দূরে সরে যেতে পারেন তবে এটি আরও ভাল। এটি বিশেষত যদি আপনি tableview কোষ ইত্যাদি অন্তর্ভূক্ত যোগ্য লিংঙ্ক দরকার প্রাসঙ্গিক হয়
নিয়াল ম্যাককোর্মাক

2

এখানে একটি ড্রপ-ইন উদ্দেশ্য-সি বিভাগ রয়েছে যা UILabel.attributedTextবিদ্যমান NSLinkAttributeNameবৈশিষ্ট্যটিকে কাজে লাগিয়ে বিদ্যমান স্ট্রিংগুলিতে ক্লিকযোগ্য লিঙ্কগুলিকে সক্ষম করে ।

@interface UILabel (GSBClickableLinks) <UIGestureRecognizerDelegate>
@property BOOL enableLinks;
@end

#import <objc/runtime.h>
static const void *INDEX;
static const void *TAP;

@implementation UILabel (GSBClickableLinks)

- (void)setEnableLinks:(BOOL)enableLinks
{
    UITapGestureRecognizer *tap = objc_getAssociatedObject(self, &TAP); // retreive tap
    if (enableLinks && !tap) { // add a gestureRegonzier to the UILabel to detect taps
        tap = [UITapGestureRecognizer.alloc initWithTarget:self action:@selector(openLink)];
        tap.delegate = self;
        [self addGestureRecognizer:tap];
        objc_setAssociatedObject(self, &TAP, tap, OBJC_ASSOCIATION_RETAIN_NONATOMIC); // save tap
    }
    self.userInteractionEnabled = enableLinks; // note - when false UILAbel wont receive taps, hence disable links
}

- (BOOL)enableLinks
{
    return (BOOL)objc_getAssociatedObject(self, &TAP); // ie tap != nil
}

// First check whether user tapped on a link within the attributedText of the label.
// If so, then the our label's gestureRecogizer will subsequently fire, and open the corresponding NSLinkAttributeName.
// If not, then the tap will get passed along, eg to the enclosing UITableViewCell...
// Note: save which character in the attributedText was clicked so that we dont have to redo everything again in openLink.
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
    if (gestureRecognizer != objc_getAssociatedObject(self, &TAP)) return YES; // dont block other gestures (eg swipe)

    // Re-layout the attributedText to find out what was tapped
    NSTextContainer *textContainer = [NSTextContainer.alloc initWithSize:self.frame.size];
    textContainer.lineFragmentPadding = 0;
    textContainer.maximumNumberOfLines = self.numberOfLines;
    textContainer.lineBreakMode = self.lineBreakMode;
    NSLayoutManager *layoutManager = NSLayoutManager.new;
    [layoutManager addTextContainer:textContainer];
    NSTextStorage *textStorage = [NSTextStorage.alloc initWithAttributedString:self.attributedText];
    [textStorage addLayoutManager:layoutManager];

    NSUInteger index = [layoutManager characterIndexForPoint:[gestureRecognizer locationInView:self]
                                             inTextContainer:textContainer
                    fractionOfDistanceBetweenInsertionPoints:NULL];
    objc_setAssociatedObject(self, &INDEX, @(index), OBJC_ASSOCIATION_RETAIN_NONATOMIC); // save index

    return (BOOL)[self.attributedText attribute:NSLinkAttributeName atIndex:index effectiveRange:NULL]; // tapped on part of a link?
}

- (void)openLink
{
    NSUInteger index = [objc_getAssociatedObject(self, &INDEX) unsignedIntegerValue]; // retrieve index
    NSURL *url = [self.attributedText attribute:NSLinkAttributeName atIndex:index effectiveRange:NULL];
    if (url && [UIApplication.sharedApplication canOpenURL:url]) [UIApplication.sharedApplication openURL:url];
}

@end 

এটি কোনও ইউআইএলবেল সাবক্লাসের মাধ্যমে করা কিছুটা ক্লিনার হয়ে উঠবে (অর্থাত্ আপত্তি_সেট অ্যাসোসিয়েটেডঅবজেক্ট মেসের কোনওটি নয়) তবে আপনি যদি আমার মতো হন তবে বিদ্যমান ইউআইকিট ক্লাসে কিছু অতিরিক্ত ফাংশন যুক্ত করার জন্য আপনি অপ্রয়োজনীয় (তৃতীয় পক্ষ) সাবক্লাসগুলি করা এড়াতে পছন্দ করেন। এছাড়াও, এটির এমন সৌন্দর্য রয়েছে যা এটি বিদ্যমান যে কোনও ইউআইবিবেলে ক্লিকযোগ্য-লিঙ্ক যুক্ত করে , যেমন বিদ্যমান UITableViewCells!

NSLinkAttributeNameএনএসএট্রিবিউটেড স্ট্রিংয়ে বিদ্যমান বৈশিষ্ট্যযুক্ত জিনিসগুলি ইতিমধ্যে উপলব্ধ ব্যবহার করে এটি যতটা সম্ভব ন্যূনতম আক্রমণাত্মক করার চেষ্টা করেছি । সুতরাং এটি একটি সহজ:

NSURL *myURL = [NSURL URLWithString:@"http://www.google.com"];
NSMutableAttributedString *myString = [NSMutableAttributedString.alloc initWithString:@"This string has a clickable link: "];
[myString appendAttributedString:[NSAttributedString.alloc initWithString:@"click here" attributes:@{NSLinkAttributeName:myURL}]];
...
myLabel.attributedText = myString;
myLabel.enableLinks = YES; // yes, that's all! :-)

মূলত, এটি UIGestureRecognizerআপনার ইউআইএলবেলে একটি যুক্ত করে কাজ করে । কঠোর gestureRecognizerShouldBegin:পরিশ্রমটি সম্পন্ন হয়েছে , কোন চরিত্রটিতে ট্যাপ লাগানো হয়েছিল তা নির্ধারণের জন্য বৈশিষ্ট্যযুক্ত পাঠ্য স্ট্রিংটিকে পুনরায় বিন্যাস করে। যদি এই চরিত্রটি কোনও এনএসলিঙ্কঅ্যাট্রিবিউটনেমের অংশ ছিল তবে অঙ্গভঙ্গি সনাক্তকারী পরবর্তী সময়ে গুলি চালিয়ে যাবে, সংশ্লিষ্ট ইউআরএল পুনরুদ্ধার করবে (এনএসলিঙ্কঅ্যাট্রিবিউটনেম মান থেকে) এবং স্বাভাবিক [UIApplication.sharedApplication openURL:url]প্রক্রিয়া অনুযায়ী লিঙ্কটি খুলবে ।

দ্রষ্টব্য - এই সমস্ত কিছু করে gestureRecognizerShouldBegin:, আপনি যদি লেবেলের কোনও লিঙ্কে ট্যাপ করতে না চান, ইভেন্টটি পাশ হয়ে যায়। সুতরাং, উদাহরণস্বরূপ, আপনার ইউআইটিএবলভিউসেল লিঙ্কগুলিতে ট্যাপগুলি ক্যাপচার করবে, তবে অন্যথায় সাধারণত আচরণ করবে (ঘর নির্বাচন করুন, নির্বাচন না করা, স্ক্রোল নির্বাচন করুন ...)।

আমি এটি এখানে একটি গিটহাবের সংগ্রহস্থলে রেখেছি । কাই বার্গার্ড্টের এসও পোস্টিং থেকে এখানে রূপান্তরিত ।


1

নিম্নলিখিত .h এবং .m ফাইলগুলি সহ শ্রেণি তৈরি করুন। .M ফাইলটিতে নিম্নলিখিত ফাংশন রয়েছে

 - (void)linkAtPoint:(CGPoint)location

এই ফাংশনের অভ্যন্তরে আমরা সাবস্ট্রাস্টিংগুলির ব্যাপ্তি যাচাই করব যার জন্য আমাদের ক্রিয়া দেওয়া দরকার। আপনার ব্যাপ্তি স্থাপন করতে আপনার নিজস্ব যুক্তি ব্যবহার করুন।

এবং নীচে সাবক্লাস ব্যবহার করা হল

TaggedLabel *label = [[TaggedLabel alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
[self.view addSubview:label];
label.numberOfLines = 0;
NSMutableAttributedString *attributtedString = [[NSMutableAttributedString alloc] initWithString : @"My name is @jjpp" attributes : @{ NSFontAttributeName : [UIFont systemFontOfSize:10],}];                                                                                                                                                                              
//Do not forget to add the font attribute.. else it wont work.. it is very important
[attributtedString addAttribute:NSForegroundColorAttributeName
                        value:[UIColor redColor]
                        range:NSMakeRange(11, 5)];//you can give this range inside the .m function mentioned above

নীচের .h ফাইল

#import <UIKit/UIKit.h>

@interface TaggedLabel : UILabel<NSLayoutManagerDelegate>

@property(nonatomic, strong)NSLayoutManager *layoutManager;
@property(nonatomic, strong)NSTextContainer *textContainer;
@property(nonatomic, strong)NSTextStorage *textStorage;
@property(nonatomic, strong)NSArray *tagsArray;
@property(readwrite, copy) tagTapped nameTagTapped;

@end   

নিম্নলিখিত .m ফাইল

#import "TaggedLabel.h"
@implementation TaggedLabel

- (id)initWithFrame:(CGRect)frame
{
 self = [super initWithFrame:frame];
 if (self)
 {
  self.userInteractionEnabled = YES;
 }
return self;
}

- (id)initWithCoder:(NSCoder *)aDecoder
{
 self = [super initWithCoder:aDecoder];
if (self)
{
 self.userInteractionEnabled = YES;
}
return self;
}

- (void)setupTextSystem
{
 _layoutManager = [[NSLayoutManager alloc] init];
 _textContainer = [[NSTextContainer alloc] initWithSize:CGSizeZero];
 _textStorage = [[NSTextStorage alloc] initWithAttributedString:self.attributedText];
 // Configure layoutManager and textStorage
 [_layoutManager addTextContainer:_textContainer];
 [_textStorage addLayoutManager:_layoutManager];
 // Configure textContainer
 _textContainer.lineFragmentPadding = 0.0;
 _textContainer.lineBreakMode = NSLineBreakByWordWrapping;
 _textContainer.maximumNumberOfLines = 0;
 self.userInteractionEnabled = YES;
 self.textContainer.size = self.bounds.size;
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
 if (!_layoutManager)
 {
  [self setupTextSystem];
 }
 // Get the info for the touched link if there is one
 CGPoint touchLocation = [[touches anyObject] locationInView:self];
 [self linkAtPoint:touchLocation];
}

- (void)linkAtPoint:(CGPoint)location
{
 // Do nothing if we have no text
 if (_textStorage.string.length == 0)
 {
  return;
 }
 // Work out the offset of the text in the view
 CGPoint textOffset = [self calcGlyphsPositionInView];
 // Get the touch location and use text offset to convert to text cotainer coords
 location.x -= textOffset.x;
 location.y -= textOffset.y;
 NSUInteger touchedChar = [_layoutManager glyphIndexForPoint:location inTextContainer:_textContainer];
 // If the touch is in white space after the last glyph on the line we don't
 // count it as a hit on the text
 NSRange lineRange;
 CGRect lineRect = [_layoutManager lineFragmentUsedRectForGlyphAtIndex:touchedChar effectiveRange:&lineRange];
 if (CGRectContainsPoint(lineRect, location) == NO)
 {
  return;
 }
 // Find the word that was touched and call the detection block
    NSRange range = NSMakeRange(11, 5);//for this example i'm hardcoding the range here. In a real scenario it should be iterated through an array for checking all the ranges
    if ((touchedChar >= range.location) && touchedChar < (range.location + range.length))
    {
     NSLog(@"range-->>%@",self.tagsArray[i][@"range"]);
    }
}

- (CGPoint)calcGlyphsPositionInView
{
 CGPoint textOffset = CGPointZero;
 CGRect textBounds = [_layoutManager usedRectForTextContainer:_textContainer];
 textBounds.size.width = ceil(textBounds.size.width);
 textBounds.size.height = ceil(textBounds.size.height);

 if (textBounds.size.height < self.bounds.size.height)
 {
  CGFloat paddingHeight = (self.bounds.size.height - textBounds.size.height) / 2.0;
  textOffset.y = paddingHeight;
 }

 if (textBounds.size.width < self.bounds.size.width)
 {
  CGFloat paddingHeight = (self.bounds.size.width - textBounds.size.width) / 2.0;
  textOffset.x = paddingHeight;
 }
 return textOffset;
 }

@end

1

আমি দৃ strongly়ভাবে এমন একটি লাইব্রেরি ব্যবহারের পরামর্শ দেব যা ইউআরএলগুলিকে স্বয়ংক্রিয়ভাবে পাঠ্যে সনাক্ত করে এবং লিঙ্কগুলিতে রূপান্তর করে। চেষ্টা করুন:

দু'জনই এমআইটি লাইসেন্সের আওতাধীন।


আপনি পূর্ববর্তী উত্তরগুলি নকল করছেন।
সিউর

1

চার্লস গ্যাম্বল উত্তরের উপর ভিত্তি করে, আমি এটিই ব্যবহার করেছি (আমি এমন কিছু লাইন সরিয়েছি যা আমাকে বিভ্রান্ত করেছিল এবং আমাকে ভুল সূচক দিয়েছে):

- (BOOL)didTapAttributedTextInLabel:(UILabel *)label inRange:(NSRange)targetRange TapGesture:(UIGestureRecognizer*) gesture{
    NSParameterAssert(label != nil);

    // create instances of NSLayoutManager, NSTextContainer and NSTextStorage
    NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
    NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:label.attributedText];

    // configure layoutManager and textStorage
    [textStorage addLayoutManager:layoutManager];

    // configure textContainer for the label
    NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:CGSizeMake(label.frame.size.width, label.frame.size.height)];

    textContainer.lineFragmentPadding = 0.0;
    textContainer.lineBreakMode = label.lineBreakMode;
    textContainer.maximumNumberOfLines = label.numberOfLines;

    // find the tapped character location and compare it to the specified range
    CGPoint locationOfTouchInLabel = [gesture locationInView:label];
    [layoutManager addTextContainer:textContainer]; //(move here, not sure it that matter that calling this line after textContainer is set

    NSInteger indexOfCharacter = [layoutManager characterIndexForPoint:locationOfTouchInLabel
                                                           inTextContainer:textContainer
                                  fractionOfDistanceBetweenInsertionPoints:nil];
    if (NSLocationInRange(indexOfCharacter, targetRange)) {
        return YES;
    } else {
        return NO;
    }
}

1

একটি বিভাগ হিসাবে এইভাবে ড্রপ-ইন সমাধান UILabel(এটি ধরে নিয়েছে যে এটিতে আপনার UILabelকয়েকটি NSLinkAttributeNameবৈশিষ্ট্যের সাথে একটি বিশিষ্ট স্ট্রিং ব্যবহার করা হয়েছে):

@implementation UILabel (Support)

- (BOOL)openTappedLinkAtLocation:(CGPoint)location {
  CGSize labelSize = self.bounds.size;

  NSTextContainer* textContainer = [[NSTextContainer alloc] initWithSize:CGSizeZero];
  textContainer.lineFragmentPadding = 0.0;
  textContainer.lineBreakMode = self.lineBreakMode;
  textContainer.maximumNumberOfLines = self.numberOfLines;
  textContainer.size = labelSize;

  NSLayoutManager* layoutManager = [[NSLayoutManager alloc] init];
  [layoutManager addTextContainer:textContainer];

  NSTextStorage* textStorage = [[NSTextStorage alloc] initWithAttributedString:self.attributedText];
  [textStorage addAttribute:NSFontAttributeName value:self.font range:NSMakeRange(0, textStorage.length)];
  [textStorage addLayoutManager:layoutManager];

  CGRect textBoundingBox = [layoutManager usedRectForTextContainer:textContainer];
  CGPoint textContainerOffset = CGPointMake((labelSize.width - textBoundingBox.size.width) * 0.5 - textBoundingBox.origin.x,
                                            (labelSize.height - textBoundingBox.size.height) * 0.5 - textBoundingBox.origin.y);
  CGPoint locationOfTouchInTextContainer = CGPointMake(location.x - textContainerOffset.x, location.y - textContainerOffset.y);
  NSInteger indexOfCharacter = [layoutManager characterIndexForPoint:locationOfTouchInTextContainer inTextContainer:textContainer fractionOfDistanceBetweenInsertionPoints:nullptr];
  if (indexOfCharacter >= 0) {
    NSURL* url = [textStorage attribute:NSLinkAttributeName atIndex:indexOfCharacter effectiveRange:nullptr];
    if (url) {
      [[UIApplication sharedApplication] openURL:url];
      return YES;
    }
  }
  return NO;
}

@end

1

এখানে একটি সুইফ্ট বাস্তবায়ন যা যতটা সম্ভব ন্যূনতম হ'ল এতে স্পর্শ প্রতিক্রিয়াও অন্তর্ভুক্ত। আদেশ সহকারে:

  1. আপনাকে অবশ্যই আপনার এনএসএট্রিবিউটেড স্ট্রিংয়ে ফন্ট সেট করতে হবে
  2. আপনি কেবল এনএসএট্রিবিউটেড স্ট্রিংস ব্যবহার করতে পারেন!
  3. আপনাকে অবশ্যই নিশ্চিত করতে হবে যে আপনার লিঙ্কগুলি মোড়াতে পারে না (অবিচ্ছিন্ন স্পেস ব্যবহার করুন "\u{a0}":)
  4. আপনি পাঠ্যটি সেট করার পরে লাইনব্রেইকমোড বা নম্বর অফলাইনগুলি পরিবর্তন করতে পারবেন না
  5. আপনি .linkকীগুলির সাথে বৈশিষ্ট্য যুক্ত করে লিঙ্কগুলি তৈরি করেন

public class LinkLabel: UILabel {
    private var storage: NSTextStorage?
    private let textContainer = NSTextContainer()
    private let layoutManager = NSLayoutManager()
    private var selectedBackgroundView = UIView()

    override init(frame: CGRect) {
        super.init(frame: frame)
        textContainer.lineFragmentPadding = 0
        layoutManager.addTextContainer(textContainer)
        textContainer.layoutManager = layoutManager
        isUserInteractionEnabled = true
        selectedBackgroundView.isHidden = true
        selectedBackgroundView.backgroundColor = UIColor(white: 0, alpha: 0.3333)
        selectedBackgroundView.layer.cornerRadius = 4
        addSubview(selectedBackgroundView)
    }

    public required convenience init(coder: NSCoder) {
        self.init(frame: .zero)
    }

    public override func layoutSubviews() {
        super.layoutSubviews()
        textContainer.size = frame.size
    }

    public override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        super.touchesBegan(touches, with: event)
        setLink(for: touches)
    }

    public override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        super.touchesMoved(touches, with: event)
        setLink(for: touches)
    }

    private func setLink(for touches: Set<UITouch>) {
        if let pt = touches.first?.location(in: self), let (characterRange, _) = link(at: pt) {
            let glyphRange = layoutManager.glyphRange(forCharacterRange: characterRange, actualCharacterRange: nil)
            selectedBackgroundView.frame = layoutManager.boundingRect(forGlyphRange: glyphRange, in: textContainer).insetBy(dx: -3, dy: -3)
            selectedBackgroundView.isHidden = false
        } else {
            selectedBackgroundView.isHidden = true
        }
    }

    public override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
        super.touchesCancelled(touches, with: event)
        selectedBackgroundView.isHidden = true
    }

    public override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        super.touchesEnded(touches, with: event)
        selectedBackgroundView.isHidden = true

        if let pt = touches.first?.location(in: self), let (_, url) = link(at: pt) {
            UIApplication.shared.open(url)
        }
    }

    private func link(at point: CGPoint) -> (NSRange, URL)? {
        let touchedGlyph = layoutManager.glyphIndex(for: point, in: textContainer)
        let touchedChar = layoutManager.characterIndexForGlyph(at: touchedGlyph)
        var range = NSRange()
        let attrs = attributedText!.attributes(at: touchedChar, effectiveRange: &range)
        if let urlstr = attrs[.link] as? String {
            return (range, URL(string: urlstr)!)
        } else {
            return nil
        }
    }

    public override var attributedText: NSAttributedString? {
        didSet {
            textContainer.maximumNumberOfLines = numberOfLines
            textContainer.lineBreakMode = lineBreakMode
            if let txt = attributedText {
                storage = NSTextStorage(attributedString: txt)
                storage!.addLayoutManager(layoutManager)
                layoutManager.textStorage = storage
                textContainer.size = frame.size
            }
        }
    }
}

1

এই জেনেরিক পদ্ধতিটিও কার্যকর!

func didTapAttributedTextInLabel(gesture: UITapGestureRecognizer, inRange targetRange: NSRange) -> Bool {

        let layoutManager = NSLayoutManager()
        let textContainer = NSTextContainer(size: CGSize.zero)
        guard let strAttributedText = self.attributedText else {
            return false
        }

        let textStorage = NSTextStorage(attributedString: strAttributedText)

        // Configure layoutManager and textStorage
        layoutManager.addTextContainer(textContainer)
        textStorage.addLayoutManager(layoutManager)

        // Configure textContainer
        textContainer.lineFragmentPadding = Constants.lineFragmentPadding
        textContainer.lineBreakMode = self.lineBreakMode
        textContainer.maximumNumberOfLines = self.numberOfLines
        let labelSize = self.bounds.size
        textContainer.size = CGSize(width: labelSize.width, height: CGFloat.greatestFiniteMagnitude)

        // Find the tapped character location and compare it to the specified range
        let locationOfTouchInLabel = gesture.location(in: self)

        let xCordLocationOfTouchInTextContainer = locationOfTouchInLabel.x
        let yCordLocationOfTouchInTextContainer = locationOfTouchInLabel.y
        let locOfTouch = CGPoint(x: xCordLocationOfTouchInTextContainer ,
                                 y: yCordLocationOfTouchInTextContainer)

        let indexOfCharacter = layoutManager.characterIndex(for: locOfTouch, in: textContainer, fractionOfDistanceBetweenInsertionPoints: nil)

        guard let strLabel = text else {
            return false
        }

        let charCountOfLabel = strLabel.count

        if indexOfCharacter < (charCountOfLabel - 1) {
            return NSLocationInRange(indexOfCharacter, targetRange)
        } else {
            return false
        }
    }

এবং আপনি এই পদ্ধতিতে কল করতে পারেন

let text = yourLabel.text
let termsRange = (text as NSString).range(of: fullString)
if yourLabel.didTapAttributedTextInLabel(gesture: UITapGestureRecognizer, inRange: termsRange) {
            showCorrespondingViewController()
        }

আপনার কোড ব্যবহারের উদাহরণে, UITapGestureRecognizerকোথা থেকে এসেছে? এটি একটি আউটলেট? একটি সম্পত্তি আপনি সেটআপ?
মার্ক Moeykens

1

এখানে আমার উত্তর @Luca Davanzo এর উপর ভিত্তি করে উত্তর উপেক্ষা না touchesBeganএকটি কল অঙ্গভঙ্গি পরিবর্তে ইভেন্ট:

import UIKit

public protocol TapableLabelDelegate: NSObjectProtocol {
   func tapableLabel(_ label: TapableLabel, didTapUrl url: String, atRange range: NSRange)
}

public class TapableLabel: UILabel {

private var links: [String: NSRange] = [:]
private(set) var layoutManager = NSLayoutManager()
private(set) var textContainer = NSTextContainer(size: CGSize.zero)
private(set) var textStorage = NSTextStorage() {
    didSet {
        textStorage.addLayoutManager(layoutManager)
    }
}

public weak var delegate: TapableLabelDelegate?

public override var attributedText: NSAttributedString? {
    didSet {
        if let attributedText = attributedText {
            textStorage = NSTextStorage(attributedString: attributedText)
        } else {
            textStorage = NSTextStorage()
            links = [:]
        }
    }
}

public override var lineBreakMode: NSLineBreakMode {
    didSet {
        textContainer.lineBreakMode = lineBreakMode
    }
}

public override var numberOfLines: Int {
    didSet {
        textContainer.maximumNumberOfLines = numberOfLines
    }
}


public override init(frame: CGRect) {
    super.init(frame: frame)
    setup()
}

public required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    setup()
}

public override func layoutSubviews() {
    super.layoutSubviews()
    textContainer.size = bounds.size
}


/// addLinks
///
/// - Parameters:
///   - text: text of link
///   - url: link url string
public func addLink(_ text: String, withURL url: String) {
    guard let theText = attributedText?.string as? NSString else {
        return
    }

    let range = theText.range(of: text)

    guard range.location !=  NSNotFound else {
        return
    }

    links[url] = range
}

private func setup() {
    isUserInteractionEnabled = true
    layoutManager.addTextContainer(textContainer)
    textContainer.lineFragmentPadding = 0
    textContainer.lineBreakMode = lineBreakMode
    textContainer.maximumNumberOfLines  = numberOfLines
}

public override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    guard let locationOfTouch = touches.first?.location(in: self) else {
        return
    }

    textContainer.size = bounds.size
    let indexOfCharacter = layoutManager.glyphIndex(for: locationOfTouch, in: textContainer)

    for (urlString, range) in links {
        if NSLocationInRange(indexOfCharacter, range), let url = URL(string: urlString) {
            delegate?.tapableLabel(self, didTapUrl: urlString, atRange: range)
        }
    }
}}

0

ট্যাগগুলি # Swift2.0

আমি উত্সাহ নিয়েছি - দুর্দান্ত - @ এনএএলএক্সএন এর উত্তর এবং আমি নিজেই ইউআইএলবেলের একটি মোড়ক লেখার সিদ্ধান্ত নিয়েছি।
আমি টিটিটিএটিগ্রিবিউটেড লেবেল চেষ্টা করেছিলাম কিন্তু আমি এটি কার্যকর করতে পারি না।

আশা করি আপনি এই কোডটির প্রশংসা করতে পারবেন, কোনও পরামর্শ স্বাগত!

import Foundation

@objc protocol TappableLabelDelegate {
    optional func tappableLabel(tabbableLabel: TappableLabel, didTapUrl: NSURL, atRange: NSRange)
}

/// Represent a label with attributed text inside.
/// We can add a correspondence between a range of the attributed string an a link (URL)
/// By default, link will be open on the external browser @see 'openLinkOnExternalBrowser'

class TappableLabel: UILabel {

    // MARK: - Public properties -

    var links: NSMutableDictionary = [:]
    var openLinkOnExternalBrowser = true
    var delegate: TappableLabelDelegate?

    // MARK: - Constructors -

    override func awakeFromNib() {
        super.awakeFromNib()
        self.enableInteraction()
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
        self.enableInteraction()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    private func enableInteraction() {
        self.userInteractionEnabled = true
        self.addGestureRecognizer(UITapGestureRecognizer(target: self, action: Selector("didTapOnLabel:")))
    }

    // MARK: - Public methods -

    /**
    Add correspondence between a range and a link.

    - parameter url:   url.
    - parameter range: range on which couple url.
    */
    func addLink(url url: String, atRange range: NSRange) {
        self.links[url] = range
    }

    // MARK: - Public properties -

    /**
    Action rised on user interaction on label.

    - parameter tapGesture: gesture.
    */
    func didTapOnLabel(tapGesture: UITapGestureRecognizer) {
        let labelSize = self.bounds.size;

        let layoutManager = NSLayoutManager()
        let textContainer = NSTextContainer(size: CGSizeZero)
        let textStorage = NSTextStorage(attributedString: self.attributedText!)

        // configure textContainer for the label
        textContainer.lineFragmentPadding = 0
        textContainer.lineBreakMode = self.lineBreakMode
        textContainer.maximumNumberOfLines = self.numberOfLines
        textContainer.size = labelSize;

        // configure layoutManager and textStorage
        layoutManager.addTextContainer(textContainer)
        textStorage.addLayoutManager(layoutManager)

        // find the tapped character location and compare it to the specified range
        let locationOfTouchInLabel = tapGesture.locationInView(self)

        let textBoundingBox = layoutManager.usedRectForTextContainer(textContainer)
        let textContainerOffset = CGPointMake((labelSize.width - textBoundingBox.size.width) * 0.5 - textBoundingBox.origin.x,
            (labelSize.height - textBoundingBox.size.height) * 0.5 - textBoundingBox.origin.y)
        let locationOfTouchInTextContainer = CGPointMake(locationOfTouchInLabel.x - textContainerOffset.x,
            locationOfTouchInLabel.y - textContainerOffset.y)
        let indexOfCharacter = layoutManager.characterIndexForPoint(locationOfTouchInTextContainer,
            inTextContainer:textContainer,
            fractionOfDistanceBetweenInsertionPoints: nil)

        for (url, value) in self.links {
            if let range = value as? NSRange {
                if NSLocationInRange(indexOfCharacter, range) {
                    let url = NSURL(string: url as! String)!
                    if self.openLinkOnExternalBrowser {
                        UIApplication.sharedApplication().openURL(url)
                    }
                    self.delegate?.tappableLabel?(self, didTapUrl: url, atRange: range)
                }
            }
        }
    }

}

আমার ক্ষেত্রে, অক্ষরের সূচক গণনা করার জন্য কেবল একটি লাইন পাঠ্যের সাথে একটি অদ্ভুত ফলাফল হয়েছিল, এটি সর্বদা 0কারণটি locationOfTouchInTextContainer.x নেতিবাচক বলে প্রত্যাবর্তন করে । আমি let indexOfCharacter = layoutManager.glyphIndex(for: locationOfTouch, in: textContainer)পরিবর্তে ব্যবহার করার চেষ্টা করি , এবং ভাল কাজ করে।
হামগুই

0
- (BOOL)didTapAttributedTextInLabel:(UILabel *)label inRange:(NSRange)targetRange{
    NSLayoutManager *layoutManager = [NSLayoutManager new];
    NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:CGSizeZero];
    NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:label.attributedText];

    [layoutManager addTextContainer:textContainer];
    [textStorage addLayoutManager:layoutManager];

    textContainer.lineFragmentPadding = 0.0;
    textContainer.lineBreakMode = label.lineBreakMode;
    textContainer.maximumNumberOfLines = label.numberOfLines;
    CGSize labelSize = label.bounds.size;
    textContainer.size = labelSize;

    CGPoint locationOfTouchInLabel = [self locationInView:label];
    CGRect textBoundingBox = [layoutManager usedRectForTextContainer:textContainer];
    CGPoint textContainerOffset = CGPointMake((labelSize.width - textBoundingBox.size.width) * 0.5 - textBoundingBox.origin.x,
                                              (labelSize.height - textBoundingBox.size.height) * 0.5 - textBoundingBox.origin.y);
    CGPoint locationOfTouchInTextContainer = CGPointMake(locationOfTouchInLabel.x - textContainerOffset.x,
                                                         locationOfTouchInLabel.y - textContainerOffset.y);
    NSUInteger indexOfCharacter =[layoutManager characterIndexForPoint:locationOfTouchInTextContainer inTextContainer:textContainer fractionOfDistanceBetweenInsertionPoints:nil];

    return NSLocationInRange(indexOfCharacter, targetRange);
}

0

Swift4.2 এর জন্য একাধিক লাইন সঠিকভাবে পরিচালনা করতে @ টিমব্রোডার কোডটি পরিবর্তিত হয়েছে

extension UITapGestureRecognizer {

    func didTapAttributedTextInLabel(label: UILabel, inRange targetRange: NSRange) -> Bool {
        // Create instances of NSLayoutManager, NSTextContainer and NSTextStorage
        let layoutManager = NSLayoutManager()
        let textContainer = NSTextContainer(size: CGSize.zero)
        let textStorage = NSTextStorage(attributedString: label.attributedText!)

        // Configure layoutManager and textStorage
        layoutManager.addTextContainer(textContainer)
        textStorage.addLayoutManager(layoutManager)

        // Configure textContainer
        textContainer.lineFragmentPadding = 0.0
        textContainer.lineBreakMode = label.lineBreakMode
        textContainer.maximumNumberOfLines = label.numberOfLines
        let labelSize = label.bounds.size
        textContainer.size = labelSize

        // Find the tapped character location and compare it to the specified range
        let locationOfTouchInLabel = self.location(in: label)
        let textBoundingBox = layoutManager.usedRect(for: textContainer)
        let textContainerOffset = CGPoint(x: (labelSize.width - textBoundingBox.size.width) * 0.5 - textBoundingBox.origin.x,
                                          y: (labelSize.height - textBoundingBox.size.height) * 0.5 - textBoundingBox.origin.y);
        let locationOfTouchInTextContainer = CGPoint(x: (locationOfTouchInLabel.x - textContainerOffset.x),
                                                     y: 0 );
        // Adjust for multiple lines of text
        let lineModifier = Int(ceil(locationOfTouchInLabel.y / label.font.lineHeight)) - 1
        let rightMostFirstLinePoint = CGPoint(x: labelSize.width, y: 0)
        let charsPerLine = layoutManager.characterIndex(for: rightMostFirstLinePoint, in: textContainer, fractionOfDistanceBetweenInsertionPoints: nil)

        let indexOfCharacter = layoutManager.characterIndex(for: locationOfTouchInTextContainer, in: textContainer, fractionOfDistanceBetweenInsertionPoints: nil)
        let adjustedRange = indexOfCharacter + (lineModifier * charsPerLine)
        var newTargetRange = targetRange
        if lineModifier > 0 {
            newTargetRange.location = targetRange.location+(lineModifier*Int(ceil(locationOfTouchInLabel.y)))
        }
        return NSLocationInRange(adjustedRange, newTargetRange)
    }
}

ইউআইএলবেল কোড

let tapAction = UITapGestureRecognizer(target: self, action: #selector(self.tapLabel(gesture:)))

let quote = "For full details please see our privacy policy and cookie policy."
let attributedString = NSMutableAttributedString(string: quote)

let string1: String = "privacy policy", string2: String = "cookie policy"

// privacy policy
let rangeString1 = quote.range(of: string1)!
let indexString1: Int = quote.distance(from: quote.startIndex, to: rangeString1.lowerBound)
attributedString.addAttributes(
            [.font: <UIfont>,
             .foregroundColor: <UI Color>,
             .underlineStyle: 0, .underlineColor:UIColor.clear
        ], range: NSRange(location: indexString1, length: string1.count));

// cookie policy
let rangeString2 = quote.range(of: string2)!
let indexString2: Int = quote.distance(from: quote.startIndex, to: rangeString2.lowerBound )

attributedString.addAttributes(
            [.font: <UIfont>,
             .foregroundColor: <UI Color>,
             .underlineStyle: 0, .underlineColor:UIColor.clear
        ], range: NSRange(location: indexString2, length: string2.count));

let label = UILabel()
label.frame = CGRect(x: 20, y: 200, width: 375, height: 100)
label.isUserInteractionEnabled = true
label.addGestureRecognizer(tapAction)
label.attributedText = attributedString

আলতো চাপতে কোডটি

 @objc
  func tapLabel(gesture: UITapGestureRecognizer) {
     if gesture.didTapAttributedTextInLabel(label: <UILabel>, inRange: termsLabelRange {
            print("Terms of service")
     } else if gesture.didTapAttributedTextInLabel(label:<UILabel> inRange: privacyPolicyLabelRange) {
            print("Privacy policy")
     } else {
            print("Tapped none")
     }
    }

0

এটি কেদারির উত্তরের উপর ভিত্তি করে একটি এক্সআরমিন.আইওএস সি # বাস্তবায়ন ।

ShouldInteractWithUrlওভাররাইড সহ MyClickableTextViewWithCustomUll স্কিম বাস্তবায়ন :

// Inspired from https://stackoverflow.com/a/44112932/15186
internal class MyClickableTextViewWithCustomUrlScheme : UITextView, IUITextViewDelegate
{
    public MyClickableTextViewWithCustomUrlScheme()
    {
        Initialize();
    }

    public MyClickableTextViewWithCustomUrlScheme(Foundation.NSCoder coder) : base(coder)
    {
        Initialize();
    }

    public MyClickableTextViewWithCustomUrlScheme(Foundation.NSObjectFlag t) : base(t)
    {
        Initialize();
    }

    public MyClickableTextViewWithCustomUrlScheme(IntPtr handle) : base(handle)
    {
        Initialize();
    }

    public MyClickableTextViewWithCustomUrlScheme(CoreGraphics.CGRect frame) : base(frame)
    {
        Initialize();
    }

    public MyClickableTextViewWithCustomUrlScheme(CoreGraphics.CGRect frame, NSTextContainer textContainer) : base(frame, textContainer)
    {
        Initialize();
    }

    void Initialize()
    {
        Delegate = this;
    }

    [Export("textView:shouldInteractWithURL:inRange:")]
    public new bool ShouldInteractWithUrl(UITextView textView, NSUrl URL, NSRange characterRange)
    {
        if (URL.Scheme.CompareTo(@"username") == 0)
        {
            // Launch the Activity
            return false;
        }
        // The system will handle the URL
        return base.ShouldInteractWithUrl(textView, URL, characterRange);
    }
}

সি # তে রূপান্তরিত উদ্দেশ্য-সি কোড হয়ে যায়:

MyClickableTextViewWithCustomUrlScheme uiHabitTile = new MyClickableTextViewWithCustomUrlScheme();
uiHabitTile.Selectable = true;
uiHabitTile.ScrollEnabled = false;
uiHabitTile.Editable = false;

// https://stackoverflow.com/a/34014655/15186
string wholeTitle = @"This is an example by marcelofabri";

NSMutableAttributedString attributedString = new NSMutableAttributedString(wholeTitle);
attributedString.AddAttribute(UIStringAttributeKey.Link,
   new NSString("username://marcelofabri"),
   attributedString.Value.RangeOfString(@"marcelofabri")
);
NSMutableDictionary<NSString, NSObject> linkAttributes = new NSMutableDictionary<NSString, NSObject>();
linkAttributes[UIStringAttributeKey.ForegroundColor] = UIColor.Green;
linkAttributes[UIStringAttributeKey.UnderlineColor] = UIColor.LightGray;
linkAttributes[UIStringAttributeKey.UnderlineStyle] = new NSNumber((short)NSUnderlineStyle.PatternSolid);

uiHabitTile.AttributedText = attributedString;

লিঙ্কটি ক্লিক করতে সক্ষম হওয়ার জন্য সম্পাদনযোগ্য = মিথ্যা এবং নির্বাচনযোগ্য = সত্য সেট করার বিষয়টি নিশ্চিত করুন।

এছাড়াও স্ক্রোলএনবলড = সত্য পাঠ্যদর্শনকে এর উচ্চতাটি সঠিকভাবে মাপতে দেয়।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.