Восстановить поведение пузырьков получателей в Mail.app/Three20

Krumelur задал этот вопрос о том, как создать пузырь получателя, похожий на mail.app. Ниже вы можете увидеть скриншоты о том, что я имею в виду:

Mail.app picker bubble picture

Selected contact

Я могу создать внешний вид этого элемента (включая внешний вид, когда он был выбран), но я боюсь получать поведение, когда оно является частью UITextField. Как вы получаете пузырь, чтобы действовать как часть текста UITextField? Например, когда вы нажимаете кнопку backspace достаточно, пузырь становится подсвеченным и после того, как еще одно нажатие будет удалено, как если бы оно было частью текста. У меня также были трудности с перемещением курсора.

Желательно, чтобы ответ был замечательным в Monotouch, но ответы Objective-C более чем оценены. Я не прошу о точном коде (хотя, если вы согласны расстаться с ним, тогда я не буду говорить "нет": D), а скорее, как это сделать.

Мне известно о проекте Three20, у которого есть похожий элемент, но я не могу найти, где это происходит в коде, который фактически выполняется. Извините, если это не имеет особого смысла, я как-то изо всех сил старался поставить этот вопрос, пожалуйста, не стесняйтесь задавать мне какие-либо вопросы, разъясняющие вопрос!

Ответы

Ответ 1

Мне не нравится, что у Three20 были плохие впечатления, пытаясь настроить что-то, исправить предупреждения анализатора и сделать его встроенным в Xcode 4. Никогда не будет использовать его снова в новом проекте. Но это, вероятно, сделает то, что вы хотите в этом случае.

Однако вы можете сделать свои собственные пузыри довольно просто. Хотелось бы, чтобы я мог отдать должное автору блога, из которого я получил это, но это было два года назад, и теперь я не могу найти его с Google. В основном вы выбираете цвет, рисуете круглые концы, помещая прямоугольник между ними, а затем помещаете требуемый текст поверх.

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;

Поведение кнопки "Удалить" довольно просто: если вы выбрали и приняли совпадение, нарисуйте пузырь в точке ввода и измените кадр UITextField, чтобы начать после пузыря. Если вы находитесь в начале кадра UITextField и получаете другое удаление, удалите пузырь UIImageView, reset кадр UITextField, где начинался UIImageView.

Или вы можете использовать UIWebView в качестве поля ввода адреса, в котором отображаются изображения пузырьков, созданные с помощью кода, показанного вместе с текстом (см. fooobar.com/questions/172537/...), поскольку вы отредактируйте его. Вам просто нужно написать обработчик для метода делегата shouldChangeCharactersInRange для обработки удаления добавленного адреса и изображения пузырька, если пузырь - это элемент, на который нацелено действие удаления.

Ответ 2

Кажется волшебным, не так ли? Код три20:

TTMessageController.h TTMessageController.m

TTMessageControllerDelegate.h

TTMessageField.h TTMessageField.m

TTMessageRecipientField.h TTMessageRecipientField.m

TTMessageSubjectField.h TTMessageSubjectField.m

TTMessageTextField.h TTMessageTextField.m

Конечно, вы должны просто использовать Интерфейс пользовательского интерфейса сообщений от Apple теперь, когда они его выпустили.