【问题标题】:How do I create a Textfield for Tag-Like-Text Input in iOS?如何在 iOS 中为类似标签的文本输入创建文本字段?
【发布时间】:2015-08-08 18:23:30
【问题描述】:

我正在创建一个应用程序,用户可以通过按几个按钮输入文本(单词或短语)。

文本被插入到 UITextField 中,用户可以在其中输入自己的其他文本。为了简化与已插入文本的交互,我希望有一种类似于标准消息应用程序在搜索联系人以寻找新对话时的行为方式,或者 Evernote 处理标签的方式。

也就是说,插入后,单词或短语只能作为一个整体选择,按键盘上的 Delete-Button 会先选择整个“Tag”,然后在下次按下时将其删除。

有没有办法让标准的 UITextField 表现得像这样,或者有 UITextField 的开源实现吗?

【问题讨论】:

  • 可能是这样的:github.com/venmo/VENTokenField ?
  • @benhameen,非常感谢!这就是我要找的东西;)(我会支持你,但我不能,因为我还没有足够的声誉:)
  • 没问题!不用担心,向上投票的 cmets 只是美学上的。编码愉快!

标签: ios cocoa-touch uitextfield


【解决方案1】:

我需要在 OS X 上进行更多混合,允许混合类似 Facebook 的标签以及普通文本。所以我建立了自己的实现https://github.com/aiman86/ANTaggedTextView,它只负责视图渲染,而不是自动完成或选择(计划很快实现):

  1. 继承 NSTextView 并覆盖 drawRect

    - (void)drawRect:(NSRect)dirtyRect {
        [super drawRect:dirtyRect];
        [self.attributedString enumerateAttributesInRange:(NSRange){0, self.string.length} options:NSAttributedStringEnumerationReverse usingBlock:
         ^(NSDictionary *attributes, NSRange range, BOOL *stop) {
             if ([attributes objectForKey:@"Tag"] != nil)
             {
                 NSDictionary* tagAttributes = [self.attributedString attributesAtIndex:range.location effectiveRange:nil];
                 NSSize oneCharSize = [@"a" sizeWithAttributes:tagAttributes];
                 NSRange activeRange = [self.layoutManager glyphRangeForCharacterRange:range actualCharacterRange:NULL];
                 NSRect tagRect = [self.layoutManager boundingRectForGlyphRange:activeRange inTextContainer:self.textContainer];
                 tagRect.origin.x += self.textContainerOrigin.x;
                 tagRect.origin.y += self.textContainerOrigin.y;
                 tagRect = [self convertRectToLayer:tagRect];
                 NSRect tagBorderRect = (NSRect){ (NSPoint){tagRect.origin.x-oneCharSize.width*0.25, tagRect.origin.y+1}, (NSSize){tagRect.size.width+oneCharSize.width*0.5, tagRect.size.height} };
    
                 [NSGraphicsContext saveGraphicsState];
                 NSBezierPath* path = [NSBezierPath bezierPathWithRoundedRect:tagBorderRect xRadius:3.0f yRadius:3.0f];
                 NSColor* fillColor = [NSColor colorWithCalibratedRed:237.0/255.0 green:243.0/255.0 blue:252.0/255.0 alpha:1];
                 NSColor* strokeColor = [NSColor colorWithCalibratedRed:163.0/255.0 green:188.0/255.0 blue:234.0/255.0 alpha:1];             
                 NSColor* textColor = [NSColor colorWithCalibratedRed:37.0/255.0 green:62.0/255.0 blue:112.0/255.0 alpha:1];
    
                 [path addClip];
                 [fillColor setFill];
                 [strokeColor setStroke];
                 NSRectFillUsingOperation(tagBorderRect, NSCompositeSourceOver);
                 NSAffineTransform *transform = [NSAffineTransform transform];
                 [transform translateXBy: 0.5 yBy: 0.5];
                 [path transformUsingAffineTransform: transform];
                 [path stroke];
                 [transform translateXBy: -1.5 yBy: -1.5];
                 [path transformUsingAffineTransform: transform];
                 [path stroke];
    
                 NSMutableDictionary* attrs = [NSMutableDictionary dictionaryWithDictionary:tagAttributes];
                 NSFont* font = [tagAttributes valueForKey:NSFontAttributeName];
                 font = [[NSFontManager sharedFontManager] convertFont:font toSize:[font pointSize] - 0.25];
                 [attrs addEntriesFromDictionary:@{NSFontAttributeName: font, NSForegroundColorAttributeName: textColor}];
                 [[self.attributedString.string substringWithRange:range] drawInRect:tagRect withAttributes:attrs];
    
                 [NSGraphicsContext restoreGraphicsState];
             }
         }];
    }
    
    1. 现在您可以简单地在 NSAttributedString 中使用属性“Tag”(具有任何值),文本视图将呈现带有类似于 Facebook 类标签外观和感觉的标记文本。

如果您有兴趣在表格视图中使用它,我在 github 上的实现还提供了 NSTextField 和 NSTextFieldCell 实现:

希望对遇到类似情况的人有所帮助,如果您发现不足之处,请随时发表评论,我是 Cocoa 应用程序开发的新手。

【讨论】:

    【解决方案2】:

    我的 OS X 应用程序需要类似的东西。他们在那里使用名为NSTokenField 的东西,但不幸的是,iOS 平台上没有类似的东西。因此,您基本上只能创建自己的令牌或使用现有的第三方库。如果您需要有关如何创建自定义令牌的详细信息,请告诉我。

    附:创建自定义标记需要覆盖 drawRect 方法和一些贝塞尔路径的使用。

    扩展答案: 我将向您展示如何在 NSTextView(包含文本,但也可以包含 NSTextAttachment)上创建标记。此外,代码可以在 Cocoa 上运行(但只需稍加调整,同样可以在 Cocoa Touch 中实现。

    1.) 创建扩展NSTextAttachmentCell的类

    2.) 覆盖方法-(void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView

    - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
    {
        [self drawWithFrame:cellFrame inView:controlView characterIndex:NSNotFound layoutManager:nil];
    }
    

    - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView characterIndex:(NSUInteger)charIndex layoutManager:(NSLayoutManager *)layoutManager 的实现是这样的:

    - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView     characterIndex:(NSUInteger)charIndex layoutManager:(NSLayoutManager *)layoutManager
    {
       NSColor* bgColor = [NSColor redColor];
       NSColor* borderColor = [NSColor blackColor];
       NSRect frame = cellFrame;
       CGFloat radius = ceilf([self cellSize].height / 2.f);
       NSBezierPath* roundedRectanglePath = [NSBezierPath bezierPathWithRoundedRect: NSMakeRect(NSMinX(frame) + 0.5, NSMinY(frame) + 3.5, NSWidth(frame) - 1, NSHeight(frame) - 1) xRadius: radius yRadius: radius];
       [bgColor setFill];
       [roundedRectanglePath fill];
       [borderColor setStroke];
       [roundedRectanglePath setLineWidth: 1];
       [roundedRectanglePath stroke];
       CGSize size = [[self stringValue] sizeWithAttributes:@{NSFontAttributeName:defaultFont}];
    CGRect textFrame = CGRectMake(cellFrame.origin.x + (cellFrame.size.width - size.width)/2,
                                  cellFrame.origin.y + 2.f,
                                  size.width,
                                  size.height);
       [[self stringValue] drawInRect:textFrame withAttributes:@{NSFontAttributeName:defaultFont, NSForegroundColorAttributeName:     [NSColor whiteColor]}];
    

    }

    所有代码都应该是不言自明的,但是如果您有任何问题,请提出。希望对您有所帮助。

    【讨论】:

    • 感谢您指出 drawRect,这将对我的应用程序所做的其他一些事情很有用。没有系统解决方案真的很遗憾,但我想我会使用VENTokenField,正如@benhameen 在 cmets 中所建议的那样。再次感谢您;)
    • 另外,我想支持这个答案,但我还没有足够的声誉。
    • 是的,我也建议。但是我找不到类似的 OS X 库,所以我不得不自己做:) 我会扩展答案,也许有人会觉得它有用:)
    猜你喜欢
    • 2012-05-31
    • 2020-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-10
    • 2021-04-19
    • 2015-10-21
    • 1970-01-01
    相关资源
    最近更新 更多