编辑:我想我应该使用UILabel而不是UITextView,因为我不希望突出显示使用系统范围的蓝色和’copy / select all / define’popover.

我正在尝试构建自定义文本视图,我正在寻找正确方法的一些帮助.我是一个iOS n00b,所以主要是寻找有关如何最好地解决问题的想法.

我想构建一个自定义文本视图,具有以下行为:

>视图从小开始.如果它收到一个点击它会增长(动画)为父视图的大小作为模态窗口(左上图,然后右上图)
>在这个大状态中,如果单击一个单词,则单词以某种方式突出显示,并且委托方法称为传递包含被轻敲的字符串的字符串(左下图)

New Text View http://telliott.net/static/NewTextView.png

我怀疑复杂性将在于识别被点击的单词,所以让我们从那里开始.我可以想到几种尝试这种方法:

> UILabel子类.添加触摸手势识别器.识别触摸时,以某种方式获取触摸点的(x.y)坐标,查看视图显示的字符串,并根据位置确定必须按下哪个字.然而,我可以通过自动换行很快看到这变得非常复杂.我不确定如何获得触摸的(x,y)坐标(虽然我认为这很简单),或者如何获得每个角色等设备相关的文本宽度.我宁愿不去这条路线,除非有人可以说服我这不会太可怕!
> UIView子类,并通过为每个单词添加UILabel来伪造句子.测量每个UILabel的宽度并自己铺设.这似乎是一种更明智的方法,虽然我担心以这种方式布置文本也比我开始尝试时的想法更难.

有更明智的方法吗?你可以用其他方式检索UILabel中触及的单词吗?

如果我选择选项2,那么我认为动画来自小 – >大文本可能很复杂,因为单词将以有趣的方式包装.所以我想要另一个子视图 – 这次是UITextView – 将句子保持在小状态.将此动画设置为大,然后将其隐藏,同时以每个单词的一个视图显示我的UIView.

任何想法都赞赏.提前致谢 :)

解决方法

更新

由于在CoreText中添加了NSLayoutManager,因此iOS 7更容易实现.如果您正在处理UITextView,则可以将布局管理器作为视图的属性进行访问.在我的情况下,我想坚持使用UILabel,所以你必须创建一个大小相同的布局管理器,即:

NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:labelText];
NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
[textStorage addLayoutManager:layoutManager];
CGRect bounds = label.bounds;
NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:bounds.size];
[layoutManager addTextContainer:textContainer];

现在你只需要找到被点击的字符的索引,这很简单!

NSUInteger characterIndex = [layoutManager characterIndexForPoint:location
                                                  inTextContainer:textContainer
                         fractionOfdistanceBetweenInsertionPoints:NULL];

这使得找到这个词本身变得微不足道:

if (characterIndex < textStorage.length) {
  [labelText.string enumerateSubstringsInRange:NSMakeRange(0,textStorage.length)
                                       options:NsstringEnumerationByWords
                                    usingBlock:^(Nsstring *substring,NSRange substringRange,NSRange enclosingRange,BOOL *stop) {
                                      if (NSLocationInRange(characterIndex,enclosingRange)) {
                                        // Do your thing with the word,at range 'enclosingRange'
                                        *stop = YES;
                                      }
                                    }];
}

原始答案,适用于iOS< 7 感谢@JP Hribovsek提供了一些有关此工作的提示,我设法为我的目的解决了这个问题.它感觉有点hacky,对于大型文本可能不会很好,但对于一次一段(这是我需要的),它很好. 我创建了一个简单的UILabel子类,允许我设置插入值:

#import "WWLabel.h"

#define WWLabelDefaultInset 5

@implementation WWLabel

@synthesize topInset,leftInset,bottomInset,rightInset;

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        self.topInset = WWLabelDefaultInset;
        self.bottomInset = WWLabelDefaultInset;
        self.rightInset = WWLabelDefaultInset;
        self.leftInset = WWLabelDefaultInset;
    }
    return self;
}

- (void)drawTextInRect:(CGRect)rect
{
    UIEdgeInsets insets = {self.topInset,self.leftInset,self.bottomInset,self.rightInset};

    return [super drawTextInRect:UIEdgeInsetsInsetRect(rect,insets)];
}

然后我创建了一个包含我的自定义标签的UIView子类,然后在标签上构建了标签中每个单词的文本大小,直到大小超过了点击位置的大小 – 这是被点击的单词.这不是完美的,但现在效果还不错.

然后我使用一个简单的NSAttributedString来突出显示文本:

#import "WWPhoneticTextView.h"
#import "WWLabel.h"

#define WWPhoneticTextViewInset 5
#define WWPhoneticTextViewDefaultColor [UIColor blackColor]
#define WWPhoneticTextViewHighlightColor [UIColor yellowColor]

#define UILabelMagicTopMargin 5
#define UILabelMagicLeftMargin -5

@implementation WWPhoneticTextView {
    WWLabel *label;
    NSMutableAttributedString *labelText;
    NSRange tappedRange;
}

// ... skipped init methods,very simple,just call through to configureView

- (void)configureView
{
    if(!label) {
        tappedRange.location = NSNotFound;
        tappedRange.length = 0;

        label = [[WWLabel alloc] initWithFrame:[self bounds]];
        [label setLineBreakMode:NSLineBreakByWordWrapping];
        [label setNumberOfLines:0];
        [label setBackgroundColor:[UIColor clearColor]];
        [label setTopInset:WWPhoneticTextViewInset];
        [label setLeftInset:WWPhoneticTextViewInset];
        [label setBottomInset:WWPhoneticTextViewInset];
        [label setRightInset:WWPhoneticTextViewInset];

        [self addSubview:label];
    }


    // Setup tap handling
    UITapGestureRecognizer *singleFingerTap = [[UITapGestureRecognizer alloc]
                                               initWithTarget:self action:@selector(handleSingleTap:)];
    singleFingerTap.numberOfTapsrequired = 1;
    [self addGestureRecognizer:singleFingerTap];
}

- (void)setText:(Nsstring *)text
{
    labelText = [[NSMutableAttributedString alloc] initWithString:text];
    [label setAttributedText:labelText];
}

- (void)handleSingleTap:(UITapGestureRecognizer *)sender
{
    if (sender.state == UIGestureRecognizerStateEnded)
    {
        // Get the location of the tap,and normalise for the text view (no margins)
        CGPoint tapPoint = [sender locationInView:sender.view];
        tapPoint.x = tapPoint.x - WWPhoneticTextViewInset - UILabelMagicLeftMargin;
        tapPoint.y = tapPoint.y - WWPhoneticTextViewInset - UILabelMagicTopMargin;

        // Iterate over each word,and check if the word contains the tap point in the correct line
        __block Nsstring *partialString = @"";
        __block Nsstring *linestring = @"";
        __block int currentLineHeight = label.font.pointSize;
        [label.text enumerateSubstringsInRange:NSMakeRange(0,[label.text length]) options:NsstringEnumerationByWords usingBlock:^(Nsstring* word,NSRange wordRange,BOOL* stop){

            CGSize sizeforText = CGSizeMake(label.frame.size.width-2*WWPhoneticTextViewInset,label.frame.size.height-2*WWPhoneticTextViewInset);
            partialString = [Nsstring stringWithFormat:@"%@ %@",partialString,word];

            // Find the size of the partial string,and stop if we've hit the word
            CGSize partialStringSize  = [partialString sizeWithFont:label.font constrainedToSize:sizeforText lineBreakMode:label.lineBreakMode];

            if (partialStringSize.height > currentLineHeight) {
                // Text wrapped to new line
                currentLineHeight = partialStringSize.height;
                linestring = @"";
            }
            linestring = [Nsstring stringWithFormat:@"%@ %@",linestring,word];

            CGSize linestringSize  = [linestring sizeWithFont:label.font constrainedToSize:label.frame.size lineBreakMode:label.lineBreakMode];
            linestringSize.width = linestringSize.width + WWPhoneticTextViewInset;

            if (tapPoint.x < linestringSize.width && tapPoint.y > (partialStringSize.height-label.font.pointSize) && tapPoint.y < partialStringSize.height) {
                NSLog(@"Tapped word %@",word);
                if (tappedRange.location != NSNotFound) {
                    [labelText addAttribute:NSForegroundColorAttributeName value:[UIColor blackColor] range:tappedRange];
                }

                tappedRange = wordRange;
                [labelText addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:tappedRange];
                [label setAttributedText:labelText];
                *stop = YES;
            }
        }];        
    }
}

ios – 在UITextView中选择一个单词的更多相关文章

  1. ios – 在Swift的UIView中找到UILabel

    我正在尝试在我的UIViewControllers的超级视图中找到我的UILabels.这是我的代码:这是在Objective-C中推荐的方式,但是在Swift中我只得到UIViews和CALayer.我肯定在提供给这个方法的视图中有UILabel.我错过了什么?我的UIViewController中的调用:解决方法使用函数式编程概念可以更轻松地实现这一目标.

  2. ios – Reactive Cocoa – 以编程方式设置文本时不会调用UITextView的rac_textSignal

    我正在实现一个聊天UI,并使用ReactiveCocoa根据用户的类型调整聊天气泡的大小.目前,我正在基于textview的rac_textSignal更新UI的布局.一切都很好–除了一点:当用户发送消息时,我以编程方式清除文本字段:…我是否需要拥有一个持有currentTypedString的Nsstring,并在该字符串更新时驱动UI更改?

  3. ios – 将UIViewController视图属性设置为不带有storyboard / nib的自定义UIView类

    或者上面的代码片段是推荐的吗?

  4. 在iOS App中使用CoreAnimation / QuartzCore动画UILabel

    我实际上在我的iOS应用程序中设置了动画UILabel的问题.在网上搜索代码片段2天后,仍然没有结果.我找到的每个样本都是关于如何为UIImage制作动画,将它作为子视图添加到UIView中.有没有关于动画UILabel的好例子?我通过设置alpha属性为闪烁动画找到了一个很好的解决方案,如下所示:我的功能:在UILabel上调用我的函数:但是pulse或缩放动画呢?另一个注意事项–可以在here找到CALayer动画属性的完整列表.快乐的补间!

  5. 如何让我的UITextView在iOS 7下的屏幕高度减去键盘?

    我的代码在iOS6下运行正常,但在iOS7下我似乎无法使我的UITextView设备屏幕的高度减去键盘(换句话说,当键盘启动时,让UITextView仍然是全屏,但是不要去键盘下面).首先,当我将UITextView放入我的视图控制器(嵌入在导航控制器中)时,它也必须位于导航栏下,否则它会开始太远.从那里我尝试了所有这些例子:每个键盘的位置仍然会在某些点上超过textview.我也试过设置一个高度

  6. iOS – UIToolBar作为UITextView的inputAccessoryView

    这是我的代码:解决方法如果工具栏中没有其他附近的按钮,工具栏似乎会将按钮的活动区域扩展到其边界之外.Apple工程师必须认为最好是猜测用户打算按哪个而不是根本不做出反应.

  7. ios – colorWithPatternImage在io6中不起作用?

    我正在使用colorWithPatternImage来更改UITextView的文本颜色.它在IO7中工作正常,但在IO6中不起作用.这是我的代码:–解决方法UITextView的内部在iOS6和7之间发生了巨大的变化.在iOS7之前,UITextView不支持文本颜色的图案颜色.有几个组件在iOS7中获得了对图案颜色的支持,而UITextView就是其中之一.

  8. uitableview – UILabel和UILabel在iOS 7中的省略号颜色变化

    提前谢谢你的帮助!

  9. UITextView startInteractionWithLinkAtPoint仅崩溃iOS 11

    因此,当用户与URL链接进行交互时,我在UItextview中遇到崩溃.所有崩溃报告仅限iOS版本11.这看起来像iOS9中众所周知的bug,但是没有单个报告iOS版本低于11,而且在报告中我发现有趣的行:iOS11(http://developer.limneos.net/?ios=11.0&framework=UIKit.framework&header=UITextGestureCluste

  10. ios – Swift,移动键盘后面的内容在关闭后不会重置

    我在我的一个VC中有一个uiscrollview.在scrollView中,我有多个TF,按钮等.我使用下面的代码,根据Apple文档,在调用键盘通知时向上移动scrollView,以推高隐藏的文本字段.但是,当我关闭键盘时,scrollView不会重置或向下移动,它只是停留在“向上移动”的位置.我在这里错过了什么吗?我有一个名为的类的成员变量:我是否正确使用了委托方法?解决方法我这样做了,它对我有用.似乎比你的方式容易多了.我为我的项目使用了UITextView.但它应该与UITextField一样.–

随机推荐

  1. iOS实现拖拽View跟随手指浮动效果

    这篇文章主要为大家详细介绍了iOS实现拖拽View跟随手指浮动,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  2. iOS – genstrings:无法连接到输出目录en.lproj

    使用我桌面上的项目文件夹,我启动终端输入:cd然后将我的项目文件夹拖到终端,它给了我路径.然后我将这行代码粘贴到终端中找.-name*.m|xargsgenstrings-oen.lproj我在终端中收到此错误消息:genstrings:无法连接到输出目录en.lproj它多次打印这行,然后说我的项目是一个目录的路径?没有.strings文件.对我做错了什么的想法?

  3. iOS 7 UIButtonBarItem图像没有色调

    如何确保按钮图标采用全局色调?解决方法只是想将其转换为根注释,以便为“回答”复选标记提供更好的上下文,并提供更好的格式.我能想出这个!

  4. ios – 在自定义相机层的AVFoundation中自动对焦和自动曝光

    为AVFoundation定制图层相机创建精确的自动对焦和曝光的最佳方法是什么?

  5. ios – Xcode找不到Alamofire,错误:没有这样的模块’Alamofire’

    我正在尝试按照github(https://github.com/Alamofire/Alamofire#cocoapods)指令将Alamofire包含在我的Swift项目中.我创建了一个新项目,导航到项目目录并运行此命令sudogeminstallcocoapods.然后我面临以下错误:搜索后我设法通过运行此命令安装cocoapodssudogeminstall-n/usr/local/bin

  6. ios – 在没有iPhone6s或更新的情况下测试ARKit

    我在决定下载Xcode9之前.我想玩新的框架–ARKit.我知道要用ARKit运行app我需要一个带有A9芯片或更新版本的设备.不幸的是我有一个较旧的.我的问题是已经下载了新Xcode的人.在我的情况下有可能运行ARKit应用程序吗?那个或其他任何模拟器?任何想法或我将不得不购买新设备?解决方法任何iOS11设备都可以使用ARKit,但是具有高质量AR体验的全球跟踪功能需要使用A9或更高版本处理器的设备.使用iOS11测试版更新您的设备是必要的.

  7. 将iOS应用移植到Android

    我们制作了一个具有2000个目标c类的退出大型iOS应用程序.我想知道有一个最佳实践指南将其移植到Android?此外,由于我们的应用程序大量使用UINavigation和UIView控制器,我想知道在Android上有类似的模型和实现.谢谢到目前为止,guenter解决方法老实说,我认为你正在计划的只是制作难以维护的糟糕代码.我意识到这听起来像很多工作,但从长远来看它会更容易,我只是将应用程序的概念“移植”到android并从头开始编写.

  8. ios – 在Swift中覆盖Objective C类方法

    我是Swift的初学者,我正在尝试在Swift项目中使用JSONModel.我想从JSONModel覆盖方法keyMapper,但我没有找到如何覆盖模型类中的Objective-C类方法.该方法的签名是:我怎样才能做到这一点?解决方法您可以像覆盖实例方法一样执行此操作,但使用class关键字除外:

  9. ios – 在WKWebView中获取链接URL

    我想在WKWebView中获取tapped链接的url.链接采用自定义格式,可触发应用中的某些操作.例如HTTP://我的网站/帮助#深层链接对讲.我这样使用KVO:这在第一次点击链接时效果很好.但是,如果我连续两次点击相同的链接,它将不报告链接点击.是否有解决方法来解决这个问题,以便我可以检测每个点击并获取链接?任何关于这个的指针都会很棒!解决方法像这样更改addobserver在observeValue函数中,您可以获得两个值

  10. ios – 在Swift的UIView中找到UILabel

    我正在尝试在我的UIViewControllers的超级视图中找到我的UILabels.这是我的代码:这是在Objective-C中推荐的方式,但是在Swift中我只得到UIViews和CALayer.我肯定在提供给这个方法的视图中有UILabel.我错过了什么?我的UIViewController中的调用:解决方法使用函数式编程概念可以更轻松地实现这一目标.

返回
顶部