在Mail.app / Three20中重新创build收件人气泡行为

Krumelur 问这个问题是如何创build一个类似于mail.app的收件人泡泡。 请看下面的截图:我的意思是:

Mail.app选取器气泡图片

选定的联系人

我可以创build这个元素的外观(包括当它被选中时的样子),但是当它是UITextField的一部分时,我正在努力获得行为。 你如何让泡泡充当UITextField文本的一部分? 例如,当您按下退格button时,气泡会突出显示,再一次按下将被删除,就好像它是文本的一部分。 移动光标也遇到困难。

最好在Monotouch中答案会很好,但是Objective-C的答案也不胜枚举。 我没有要求确切的代码(尽pipe如果你愿意与它分离,那么我不会说不!),而是如何实现这一点。

我意识到Three20项目有一个类似的元素,但我不能find代码中的实际执行的地方。 对不起,如果这没有什么意义,我还是有点难以把这个问题摆出来,请随时问我任何问题,澄清问题!

我不喜欢Three20有不好的经历试图定制的东西,修复分析器的警告,并使其build立在Xcode 4。将永远不会在一个新的项目中再次使用它。 但在这种情况下,它可能会做你想要的。

不过,你可以简单地制作自己的泡泡。 我希望我可以信任我从这个博客的作者,但这是两年前,现在我无法与谷歌find它。 基本上你select一种颜色,绘制圆形的端盖,在它们之间放一个矩形,然后把所需的文本放在顶端。

 UIGraphicsBeginImageContext(CGSizeMake(SIDELENGTH, SIDELENGTH)); CGContextRef context = UIGraphicsGetCurrentContext(); // the image should have a white background [[UIColor clearColor] set]; CGRect myRect = CGRectMake(0.0f, 0.0f, SIDELENGTH, SIDELENGTH); UIRectFill(myRect); [self.color set]; // Drawing code CGSize textSize = [self.text sizeWithFont:[UIFont boldSystemFontOfSize:[UIFont systemFontSize]]]; double capDiameter = textSize.height; double capRadius = capDiameter / 2.0; double capPadding = capDiameter / 4.0; double textWidth = MAX( capDiameter, textSize.width ) ; CGRect textBounds = CGRectMake(capPadding, 0.0, textWidth, textSize.height); CGRect badgeBounds = CGRectMake(0.0, 0.0, textWidth + (2.0 * capPadding), textSize.height); double offsetX = (CGRectGetMaxX(myRect) - CGRectGetMaxX(badgeBounds)) / 2.0; double offsetY = (CGRectGetMaxY(myRect) - CGRectGetMaxY(badgeBounds)) / 2.0; badgeBounds = CGRectOffset(badgeBounds, offsetX, offsetY); textBounds = CGRectOffset(textBounds, offsetX, offsetY); CGContextFillEllipseInRect(context, CGRectMake(badgeBounds.origin.x, badgeBounds.origin.y, capDiameter, capDiameter)); CGContextFillEllipseInRect(context, CGRectMake(badgeBounds.origin.x + badgeBounds.size.width - capDiameter, badgeBounds.origin.y, capDiameter, capDiameter)); CGContextFillRect(context, CGRectMake(badgeBounds.origin.x + capRadius, badgeBounds.origin.y, badgeBounds.size.width - capDiameter, capDiameter)); if(self.textColor != nil) { const CGFloat* colors = CGColorGetComponents(self.textColor.CGColor); CGColorSpaceRef space = CGColorGetColorSpace(self.textColor.CGColor); CGColorSpaceModel model = CGColorSpaceGetModel(space); if(model == kCGColorSpaceModelMonochrome) // monochrome color space has one grayscale value and one alpha CGContextSetRGBFillColor(context, *(colors + 0), *(colors + 0), *(colors + 0), *(colors + 1)); else // else a R,G,B,A scheme is assumed. CGContextSetRGBFillColor(context, *(colors + 0), *(colors + 1), *(colors + 2), *(colors + 3)); } else // else use plain white CGContextSetRGBFillColor(context, 1.0f, 1.0f, 1.0f, 1.0f); [self.text drawInRect:textBounds withFont:[UIFont boldSystemFontOfSize:[UIFont systemFontSize]] lineBreakMode:UILineBreakModeClip alignment:UITextAlignmentCenter]; UIImage* image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return image; 

你所描述的删除button的行为也非常简单 – 一旦你有一个被选中和接受的匹配,在插入点处绘制气泡并将UITextField的框架更改为在气泡之后开始。 如果您在UITextField框架的开头,并且您得到另一个删除,请删除泡泡UIImageView,将UITextField框架重置为UIImageView用于开始的位置。

或者您可以使用UIWebView作为地址input字段,在其中显示使用随文本显示的代码(请参阅此StackOverflow问题 )创build的气泡图像。 您只需要为委托方法shouldChangeCharactersInRange编写一个处理程序来处理删除添加的地址和气泡图像,如果气泡是删除操作的目标。

这似乎是不可思议的? Three20代码在这里:

TTMessageController.h TTMessageController.m

TTMessageControllerDelegate.h

TTMessageField.h TTMessageField.m

TTMessageRecipientField.h TTMessageRecipientField.m

TTMessageSubjectField.h TTMessageSubjectField.m

TTMessageTextField.h TTMessageTextField.m

当然,你现在应该使用苹果公司的Message UI框架来发布它。