Воссоздайте поведение пузыря получателя в Mail.app / Three20 - PullRequest
15 голосов
/ 09 марта 2011

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

Mail.app picker bubble picture

Selected contact

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

Желательно, чтобы ответ был великолепен в Monotouch, но ответы на Objective-C также более чем оценены. Я не спрашиваю точный код (хотя, если вы готовы с ним расстаться, я не скажу «нет!»), А скорее как этого добиться.

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

Ответы [ 2 ]

18 голосов
/ 15 марта 2011

Мне не нравится, что у 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, сбросьте фрейм UITextField туда, где раньше использовался UIImageView.

Или вы можете использовать UIWebView в качестве ввода адресаполе, в котором вы отображаете пузырьковые изображения, созданные с кодом, показанным вместе с текстом (см. этот вопрос StackOverflow ) при его редактировании.Вам просто нужно написать обработчик для метода делегата shouldChangeCharactersInRange для обработки удаления добавленного адреса и изображения пузырька, если пузырем является элемент, на который нацелено действие удаления.

4 голосов
/ 09 марта 2011
...