7

我正在开发一个儿童读物应用程序,并希望为角色对话动态填充气泡,如随附的屏幕截图所示。屏幕截图来自我猜是使用 Cocos2D(或 3D)开发的 Cinderella 应用程序。但是,我想使用objective-c 和iOS sdk 来实现这个功能。

一种方法是:

计算给定字体和大小的文本大小(使用 NSString 方法 sizeWithFont:constrainedToSize:),然后绘制一个圆角矩形(使用 CALayer)来包围该大小。

要绘制圆角矩形,请设置具有背景颜色、边框宽度和边框颜色以及颜色半径的 CALayer,并将其添加到 UIView 对象。这将很容易产生语音泡沫效应。

现在,我怎样才能得到一个指向角色嘴的角?我如何从角色的嘴里弹出和弹出 CALayer,我将如何实现这个动画?我的主要场景(插图)将是一个 UIImageview,这个对话弹出窗口应该以动画方式从角色的嘴里出现,几秒钟后它应该消失,就好像它回到角色的嘴里一样。您的建议将不胜感激。

如果您在某个地方知道一些示例代码/文章,请相应地路由我。

这是该应用程序的视频链接,显示了角色对话如何以语音气泡的形式弹出和弹出:http ://www.youtube.com/watch?v=umfNJLyrrNg

在此处输入图像描述

4

3 回答 3

15

这是我通过修改这个苹果教程的实现:

https://developer.apple.com/library/ios/samplecode/quartzdemo/Listings/QuartzDemo_QuartzCurves_m.html

- (void)drawRect:(CGRect)rect
{
    CGContextRef context=UIGraphicsGetCurrentContext();
    CGContextSetLineWidth(context, .5f);
    CGContextSetStrokeColorWithColor(context, [UIColor lightGrayColor].CGColor);
    CGContextSetRGBFillColor(context, 1, 1, 1, 1);

    rect.origin.y++;
    CGFloat radius = cornerRadius;

    CGFloat minx = CGRectGetMinX(rect), midx = CGRectGetMidX(rect), maxx = CGRectGetMaxX(rect);
    CGFloat miny = CGRectGetMinY(rect), midy = CGRectGetMidY(rect), maxy = CGRectGetMaxY(rect);

    CGMutablePathRef outlinePath = CGPathCreateMutable();

    if (![User isCurrentUser:message.user])
    {
        minx += 5;
    
        CGPathMoveToPoint(outlinePath, nil, midx, miny);
        CGPathAddArcToPoint(outlinePath, nil, maxx, miny, maxx, midy, radius);
        CGPathAddArcToPoint(outlinePath, nil, maxx, maxy, midx, maxy, radius);
        CGPathAddArcToPoint(outlinePath, nil, minx, maxy, minx, midy, radius);
        CGPathAddLineToPoint(outlinePath, nil, minx, miny + 20);
        CGPathAddLineToPoint(outlinePath, nil, minx - 5, miny + 15);
        CGPathAddLineToPoint(outlinePath, nil, minx, miny + 10);
        CGPathAddArcToPoint(outlinePath, nil, minx, miny, midx, miny, radius);
        CGPathCloseSubpath(outlinePath);
    
        CGContextSetShadowWithColor(context, CGSizeMake(0,1), 1, [UIColor lightGrayColor].CGColor);
        CGContextAddPath(context, outlinePath);
        CGContextFillPath(context);
    
        CGContextAddPath(context, outlinePath);
        CGContextClip(context);
        CGPoint start = CGPointMake(rect.origin.x, rect.origin.y);
        CGPoint end = CGPointMake(rect.origin.x, rect.size.height);
        CGContextDrawLinearGradient(context, [self normalGradient], start, end, 0);
    }
    else
    {
        maxx-=5;
        CGPathMoveToPoint(outlinePath, nil, midx, miny);
        CGPathAddArcToPoint(outlinePath, nil, minx, miny, minx, midy, radius);
        CGPathAddArcToPoint(outlinePath, nil, minx, maxy, midx, maxy, radius);
        CGPathAddArcToPoint(outlinePath, nil, maxx, maxy, maxx, midy, radius);
        CGPathAddLineToPoint(outlinePath, nil, maxx, miny + 20);
        CGPathAddLineToPoint(outlinePath, nil, maxx + 5, miny + 15);
        CGPathAddLineToPoint(outlinePath, nil, maxx, miny + 10);
        CGPathAddArcToPoint(outlinePath, nil, maxx, miny, midx, miny, radius);
        CGPathCloseSubpath(outlinePath);
    
        CGContextSetShadowWithColor(context, CGSizeMake(0,1), 1, [UIColor lightGrayColor].CGColor);
        CGContextAddPath(context, outlinePath);
        CGContextFillPath(context);
    
        CGContextAddPath(context, outlinePath);
        CGContextClip(context);
        CGPoint start = CGPointMake(rect.origin.x, rect.origin.y);
        CGPoint end = CGPointMake(rect.origin.x, rect.size.height);
        CGContextDrawLinearGradient(context, [self greenGradient], start, end, 0);
    }


    CGContextDrawPath(context, kCGPathFillStroke);

}

- (CGGradientRef)normalGradient
{

    NSMutableArray *normalGradientLocations = [NSMutableArray arrayWithObjects:
                                               [NSNumber numberWithFloat:0.0f],
                                               [NSNumber numberWithFloat:1.0f],
                                               nil];


    NSMutableArray *colors = [NSMutableArray arrayWithCapacity:2];

    UIColor *color = [UIColor whiteColor];
    [colors addObject:(id)[color CGColor]];
    color = [StyleView lightColorFromColor:[UIColor cloudsColor]];
    [colors addObject:(id)[color CGColor]];
    NSMutableArray  *normalGradientColors = colors;

    int locCount = [normalGradientLocations count];
    CGFloat locations[locCount];
    for (int i = 0; i < [normalGradientLocations count]; i++)
    {
        NSNumber *location = [normalGradientLocations objectAtIndex:i];
        locations[i] = [location floatValue];
    }
    CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();

    CGGradientRef normalGradient = CGGradientCreateWithColors(space, (__bridge CFArrayRef)normalGradientColors, locations);
    CGColorSpaceRelease(space);

    return normalGradient;
}

导致这... 在此处输入图像描述

于 2013-06-12T01:50:57.543 回答
7

另一种方法是使用带有帽子插图的图像。看一下 UIImage 方法:

resizableImageWithCapInsets:

基本上,您可以创建一个最小尺寸的气泡图像,并让它无限期地拉伸,同时保持“气泡”边界的外观。

下面的代码指定了在拉伸/调整图像大小时保留顶部、左侧、底部和右侧 12 个像素的图像:

UIImage *bubble = [[UIImage imageNamed:@"bubble.png"] 
                            resizableImageWithCapInsets:UIEdgeInsetsMake(12, 12, 12, 12)];
UIImageView *imgView = [[[UIImageView alloc] initWithImage:bubble] autorelease];
imgView.frame = CGRectZero;

动画 UIImageView 的大小变化是免费的:

[UIView animateWithDuration:0.3
                 animations:^(void) {
                     imgView.frame = CGRectMake(50, 50, 200, 100);
                 } completion:^(BOOL finished) {

                 }];
于 2012-06-25T19:43:25.580 回答
3

three20框架(实际上是 Three20Style)有一个名为 TTSpeechBubbleShape 的形状窗口类,基本上就是你要找的。

现在,正如我所见,您有两个选择:

  1. 要么使用 Three20;或者

  2. 分析TTSpeechBubbleShape类以了解它是如何实现的,并在您的应用程序中执行相同的操作。

于 2012-06-25T19:38:24.337 回答