我有一个带字符串的文本视图:
@"The best football player in the world is #OPTION, and the best basketball player is #OPTION?"
这是我必须做的一个例子。我想用下拉列表替换#OPTION,这意味着使用自定义视图。这取决于问题,它只能是一个#OPTION或更多。提前谢谢。
该字符串来自API,它出现在UITextView或UILabel
中答案 0 :(得分:3)
了解您的需求后,您面临的主要问题是不知道在哪里添加选择列表。
我为你的案例创建了两个类别,UILabel和UITextView, 以下这些帖子包含相关答案:
How do I locate the CGRect for a substring of text in a UILabel?
Get X and Y coordinates of a word in UITextView
这些类别可以找到内部字符串的CGRect,这是您应该选择拾取器的位置。
UILabel的下半部分是它没有很好地处理wordWrap换行模式,因此它找不到正确的位置,为了正确处理,你应该在需要时添加换行符以防万一你使用UILabel。
的UILabel:
extension UILabel
{
func rectFor(string str : String, fromIndex: Int = 0) -> (CGRect, NSRange)?
{
// Find the range of the string
guard self.text != nil else { return nil }
let subStringToSearch : NSString = (self.text! as NSString).substring(from: fromIndex) as NSString
var stringRange = subStringToSearch.range(of: str)
if (stringRange.location != NSNotFound)
{
guard self.attributedText != nil else { return nil }
// Add the starting point to the sub string
stringRange.location += fromIndex
let storage = NSTextStorage(attributedString: self.attributedText!)
let layoutManager = NSLayoutManager()
storage.addLayoutManager(layoutManager)
let textContainer = NSTextContainer(size: self.frame.size)
textContainer.lineFragmentPadding = 0
textContainer.lineBreakMode = .byWordWrapping
layoutManager.addTextContainer(textContainer)
var glyphRange = NSRange()
layoutManager.characterRange(forGlyphRange: stringRange, actualGlyphRange: &glyphRange)
let resultRect = layoutManager.boundingRect(forGlyphRange: glyphRange, in:textContainer)
return (resultRect, stringRange)
}
return nil
}
}
用于无限搜索所有可用的子字符串(我建议在viewDidLayoutSubviews()中添加它以防你使用自动布局:
var lastFoundIndex : Int = 0
while let result = self.label.rectFor(string: "#OPTION", fromIndex: lastFoundIndex)
{
let view : UIView = UIView(frame: result.0)
view.backgroundColor = UIColor.red
self.label.addSubview(view)
lastFoundIndex = result.1.location + 1
}
与UITextView相同:
extension UITextView
{
func rectFor(string str : String, fromIndex: Int = 0) -> (CGRect, NSRange)?
{
// Find the range of the string
guard self.text != nil else { return nil }
let subStringToSearch : NSString = (self.text! as NSString).substring(from: fromIndex) as NSString
var stringRange = subStringToSearch.range(of: str)
if (stringRange.location != NSNotFound)
{
guard self.attributedText != nil else { return nil }
// Add the starting point to the sub string
stringRange.location += fromIndex
// Find first position
let startPosition = self.position(from: self.beginningOfDocument, offset: stringRange.location)
let endPosition = self.position(from: startPosition!, offset: stringRange.length)
let resultRange = self.textRange(from: startPosition!, to: endPosition!)
let resultRect = self.firstRect(for: resultRange!)
return (resultRect, stringRange)
}
return nil
}
}
用法:
var lastFoundTextIndex : Int = 0
while let result = self.textView.rectFor(string: "#OPTION", fromIndex: lastFoundTextIndex)
{
let view : UIView = UIView(frame: result.0)
view.backgroundColor = UIColor.red
self.textView.addSubview(view)
lastFoundTextIndex = result.1.location + 1
}
在您的情况下,textview提供最佳结果并使用包含的方法,示例代码使用标签&文本视图,在代码中初始化:
self.label.text = "The best football player in the world is\n#OPTION, and the best basketball player\n is #OPTION?"
self.textView.text = "The best football player in the world is #OPTION, and the best basketball player is #OPTION?"
输出只是在“#OPTION”字符串之上添加了视图:
希望这有帮助
编辑 - 添加了Objective-C变体:
创建2个扩展 - 1个用于UITextView,1个用于UILabel:
的UILabel:
@interface UILabel (UILabel_SubStringRect)
- (NSDictionary*)rectForString:(NSString*)string fromIndex:(int)index;
@end
#import "UILabel+SubStringRect.h"
@implementation UILabel (UILabel_SubStringRect)
- (NSDictionary*)rectForString:(NSString*)string fromIndex:(int)index
{
if (string != nil)
{
NSString* subStringToSearch = [self.text substringFromIndex:index];
NSRange stringRange = [subStringToSearch rangeOfString:string];
if (stringRange.location != NSNotFound)
{
if (self.attributedText != nil)
{
stringRange.location += index;
NSTextStorage* storage = [[NSTextStorage alloc] initWithAttributedString:self.attributedText];
NSLayoutManager* layoutManager = [NSLayoutManager new];
[storage addLayoutManager:layoutManager];
NSTextContainer* textContainer = [[NSTextContainer alloc] initWithSize:self.frame.size];
textContainer.lineFragmentPadding = 0;
textContainer.lineBreakMode = NSLineBreakByWordWrapping;
[layoutManager addTextContainer:textContainer];
NSRange glyphRange;
[layoutManager characterRangeForGlyphRange:stringRange actualGlyphRange:&glyphRange];
CGRect resultRect = [layoutManager boundingRectForGlyphRange:glyphRange inTextContainer:textContainer];
return @{ @"rect" : [NSValue valueWithCGRect:resultRect], @"range" : [NSValue valueWithRange:stringRange] };
}
}
}
return nil;
}
@end
的UITextView:
@interface UITextView (SubStringRect)
- (NSDictionary*)rectForString:(NSString*)string fromIndex:(int)index;
@end
#import "UITextView+SubStringRect.h"
@implementation UITextView (SubStringRect)
- (NSDictionary*)rectForString:(NSString*)string fromIndex:(int)index
{
if (string != nil)
{
NSString* subStringToSearch = [self.text substringFromIndex:index];
NSRange stringRange = [subStringToSearch rangeOfString:string];
if (stringRange.location != NSNotFound)
{
if (self.attributedText != nil)
{
stringRange.location += index;
UITextPosition* startPosition = [self positionFromPosition:self.beginningOfDocument offset:stringRange.location];
UITextPosition* endPosition = [self positionFromPosition:startPosition offset:stringRange.length];
UITextRange* resultRange = [self textRangeFromPosition:startPosition toPosition:endPosition];
CGRect resultRect = [self firstRectForRange:resultRange];
return @{ @"rect" : [NSValue valueWithCGRect:resultRect], @"range" : [NSValue valueWithRange:stringRange] };
}
}
}
return nil;
}
@end
使用示例 - UILabel:
int lastFoundIndex = 0;
NSDictionary* resultDict = nil;
do
{
resultDict = [self.label rectForString:@"#OPTION" fromIndex:lastFoundIndex];
if (resultDict != nil)
{
NSLog(@"result: %@", resultDict[@"rect"]);
UIView* view = [[UIView alloc] initWithFrame:[resultDict[@"rect"] CGRectValue]];
[view setBackgroundColor:[UIColor redColor]];
[self.label addSubview:view];
lastFoundIndex = (int)[resultDict[@"range"] rangeValue].location + 1;
}
} while (resultDict != nil);
的UITextView:
int lastFoundTextIndex = 0;
NSDictionary* resultTextDict = nil;
do
{
resultTextDict = [self.textview rectForString:@"#OPTION" fromIndex:lastFoundTextIndex];
if (resultTextDict != nil)
{
NSLog(@"result: %@", resultTextDict[@"rect"]);
UIView* view = [[UIView alloc] initWithFrame:[resultTextDict[@"rect"] CGRectValue]];
[view setBackgroundColor:[UIColor redColor]];
[self.textview addSubview:view];
lastFoundTextIndex = (int)[resultTextDict[@"range"] rangeValue].location + 1;
}
} while (resultTextDict != nil);