如何在iPhone上以编程方式绘制椭圆形语音泡泡?

时间:2011-09-22 03:50:09

标签: iphone objective-c core-graphics

similar question中显示的技术是矩形气泡。如何画一个椭圆形?即:

enter image description here

2 个答案:

答案 0 :(得分:8)

我会在两次迭代中完成。
首先获取上下文并开始路径。填充椭圆,然后填充包含三行三角形的自定义路径。我假设以下尺寸:70宽度,62高度。覆盖UIView的子类中的draw rect并在子类UIViewController中实例化:

-(void)drawRect:(CGRect)rect {
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    CGContextSetRGBFillColor(ctx, 0.0, 0.0, 1.0, 1.0);
    CGContextFillEllipseInRect(ctx, CGRectMake(0.0, 0.0, 70.0, 50.0)); //oval shape
    CGContextBeginPath(ctx);
    CGContextMoveToPoint(ctx, 8.0, 40.0);
    CGContextAddLineToPoint(ctx, 6.0, 50.0);
    CGContextAddLineToPoint(ctx, 18.0, 45.0);
    CGContextClosePath(ctx);
    CGContextFillPath(ctx);
}

在灰色背景下添加时,在iPhone模拟器中生成此内容:

enter image description here

这第二个代码示例几乎会复制您在上面生成的内容。我使用灵活的大小实现了这个,当你实例化它时可以提供给UIView框架。基本上,讲话气泡的白色部分是用黑色笔划绘制的。

-(void)drawRect:(CGRect)rect {
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    CGRect aRect = CGRectMake(2.0, 2.0, (self.bounds.size.width * 0.95f), (self.bounds.size.width * 0.60f)); // set the rect with inset.
    CGContextSetRGBFillColor(ctx, 1.0, 1.0, 1.0, 1.0); //white fill
    CGContextSetRGBStrokeColor(ctx, 0.0, 0.0, 0.0, 1.0); //black stroke
    CGContextSetLineWidth(ctx, 2.0); 


    CGContextFillEllipseInRect(ctx, aRect); 
    CGContextStrokeEllipseInRect(ctx, aRect);    

    CGContextBeginPath(ctx);
    CGContextMoveToPoint(ctx, (self.bounds.size.width * 0.10), (self.bounds.size.width * 0.48f));
    CGContextAddLineToPoint(ctx, 3.0, (self.bounds.size.height *0.80f));
    CGContextAddLineToPoint(ctx, 20.0, (self.bounds.size.height *0.70f));
    CGContextClosePath(ctx);
    CGContextFillPath(ctx);

    CGContextBeginPath(ctx);
    CGContextMoveToPoint(ctx, (self.bounds.size.width * 0.10), (self.bounds.size.width * 0.48f));
    CGContextAddLineToPoint(ctx, 3.0, (self.bounds.size.height *0.80f));
    CGContextStrokePath(ctx);

    CGContextBeginPath(ctx);
    CGContextMoveToPoint(ctx, 3.0, (self.bounds.size.height *0.80f));
    CGContextAddLineToPoint(ctx, 20.0, (self.bounds.size.height *0.70f));
    CGContextStrokePath(ctx);
 }

enter image description here

答案 1 :(得分:0)

我有另一种方式 - 但我没有时间妥善解释它。

但是,我的示例是用.NET编写的,用于Windows应用程序。

我的版本将整个语音气泡创建为2D多边形网格,并且可以部分自定义。它是单个绘制路径而不是多个部分。

虽然我们的平台不一样 - 该技术使用常见的数学例程和程序循环。我相信这种技术可以翻译成其他编程语言或平台。

 Private Sub Generate(ByVal Resolution As Integer, Optional ByVal SpeachPointerAngle As Integer = (45 * 3), Optional ByVal PointerBend As Decimal = 15)

        'Generated the same way we create vector (wireframe) mesh for an Ellipse but...
        '... at a predefined defined angle we create 

        'the size of the Pointer TIP/Corner portion of the speach bubble
        'in relation to the EDGE of the ELLIPSE (average)
        Dim SpeachPointerSize As Integer = 30

        If PointerBend > 10 Then PointerBend = 10
        If PointerBend < -10 Then PointerBend = -10

        'as a variable offset that should be limited to max +/-   -15 to 15 degrees relative to current angle as a safe range
        '- were speach pointer angle determins which side the the pointer appears
        Dim PointerOffsetValue As Decimal = PointerBend
        Dim ActualPointerAngle As Decimal

        'SpeachPointerAngle = 360 - SpeachPointerAngle ' adjust orientation so that 0 degrees is SOUTH

        'Ellipse Size:
        Dim Size_X As Decimal = 80
        Dim Size_Y As Decimal = 50

        If Resolution < 30 Then Resolution = 30

        Dim Result As Vector2()

        'size of each angle step based on resolution (number of vectors ) - Mesh Quality in otherwords.
        Dim _Step As Decimal = 360 / Resolution

        'Our current angle as we step through  the loop
        Dim _CurrentAngle As Decimal = 0

        'rounded values
        Dim _LastAngle As Decimal = 0
        Dim _NextAngle As Decimal = _Step

        Dim SpeachDrawn As Boolean = False ' prevent creating more than 1 point to be safe

        Dim I2 As Integer = 0 'need a stepper because of skipped IDS 

        'build the ellipse mesh 
        For i = 0 To Resolution - 1

            _LastAngle = _CurrentAngle - 15
            _NextAngle = _CurrentAngle + 15

            ActualPointerAngle = _CurrentAngle 'side
            ActualPointerAngle += PointerOffsetValue ' acual angle of point

            Dim EX As Decimal = System.Math.Cos(Math.Deg2Rad(_CurrentAngle)) * Size_X
            Dim EY As Decimal = System.Math.Sin(Math.Deg2Rad(_CurrentAngle)) * Size_Y

            'Point extrusion size ( trying to be even size all around )
            Dim ExtrudeX As Decimal = System.Math.Cos(Math.Deg2Rad(_CurrentAngle)) * (Size_X + SpeachPointerSize)
            Dim ExtrudeY As Decimal = System.Math.Sin(Math.Deg2Rad(_CurrentAngle)) * (Size_Y + SpeachPointerSize)

            'is Pointer angle between Last and Next?
            If SpeachPointerAngle > _LastAngle And SpeachPointerAngle < _NextAngle Then
                If (SpeachDrawn = False) Then
                    ' the point for the speachbubble tip
                    Array.Resize(Result, I2 + 1)

                    Result(I2) = New Vector2(ExtrudeX, ExtrudeY)
                    SpeachDrawn = True
                    I2 += 1
                Else
                    'skip
                End If
            Else
                'normal ellipse vector
                Array.Resize(Result, I2 + 1)
                Result(I2) = New Vector2(EX, EY)
                I2 += 1
            End If

            _CurrentAngle += _Step

        Next

        _Vectors = Result
    End Sub

上面的代码生成了这个 - 使用GDI + [DrawPolygon / FillPolygon]绘制到位图:  https://fbcdn-sphotos-a.akamaihd.net/hphotos-ak-ash4/380262_10151202393414692_590995900_n.jpg

(对不起 - 我不能直接在这里发布图片,因为我以前从未在这里发布。我还没有声誉)

这是我正在为.NET开发的图形程序集中的原语,它使用我自己的Vector2。

此Speach气泡在绘制时支持透明度 - 因为它是单个多边形形状而不是多个形状。

基本上我们以编程方式绘制椭圆,然后在椭圆的所需边上拉出一个说明点。

可以使用PointF结构来应用类似的方法。

代码中的所有形状都是在Origin 0,0周围生成的。

当添加矢量时,阵列也会逐渐调整大小,以防止阵列中的间隙。

EG - 说话气泡的中心是Origin 0.0。

我为没有正确解释我的代码而道歉 - 我只是没有时间。  但它可能不太难理解。