Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

nashyo

macrumors 6502
Original poster
Oct 1, 2010
299
0
Bristol
Hi,

The apple documentation says that the popover class is restricted to iPad. So how do I get this popover effect on the iPhone (see pic)

23kx7uq.png


Regards
Rob
 
You can draw lines quite easily with CGContext.
Also found this on google..
Code:
- (void) drawLine: (CGContextRef) context from: (CGPoint) from to: (CGPoint) to 
{
    double slopy, cosy, siny;
    // Arrow size
    double length = 10.0;  
    double width = 5.0;

    slopy = atan2((from.y - to.y), (from.x - to.x));
    cosy = cos(slopy);
    siny = sin(slopy);

    //draw a line between the 2 endpoint
    CGContextMoveToPoint(context, from.x - length * cosy, from.y - length * siny );
    CGContextAddLineToPoint(context, to.x + length * cosy, to.y + length * siny);
    //paints a line along the current path
    CGContextStrokePath(context);

    //here is the tough part - actually drawing the arrows
    //a total of 6 lines drawn to make the arrow shape
    CGContextMoveToPoint(context, from.x, from.y);
    CGContextAddLineToPoint(context,
                        from.x + ( - length * cosy - ( width / 2.0 * siny )),
                        from.y + ( - length * siny + ( width / 2.0 * cosy )));
    CGContextAddLineToPoint(context,
                        from.x + (- length * cosy + ( width / 2.0 * siny )),
                        from.y - (width / 2.0 * cosy + length * siny ) );
    CGContextClosePath(context);
    CGContextStrokePath(context);

    /*/-------------similarly the the other end-------------/*/
    CGContextMoveToPoint(context, to.x, to.y);
    CGContextAddLineToPoint(context,
                        to.x +  (length * cosy - ( width / 2.0 * siny )),
                        to.y +  (length * siny + ( width / 2.0 * cosy )) );
    CGContextAddLineToPoint(context,
                        to.x +  (length * cosy + width / 2.0 * siny),
                        to.y -  (width / 2.0 * cosy - length * siny) );
    CGContextClosePath(context);
    CGContextStrokePath(context);
}

Maybe that works :)
 
is it difficult to draw the arrow shape?

I'm assuming you are talking about the arrow pointing down from the box that says "English" and "Emoji". The other curved arrows would take a little extra thought.

It is easy. As jnoxx pointed out you need to learn about creating your own drawing. Others might create the image in a graphics program and use it as a background in a view, but that couldn't account for size variances needed in different cases.

You have to think about the layers involved to get the effects. The basic box with the arrow, the shadow effect, and the differing edge colors are some of the effects to think about. Here is what I see.

1. A clear base view big enough to hold the box including the height of the arrow and the shadow.
2. The basic full box with the arrow.
3. The shadow effect that applies to the box. (The bottom shadow looks darker)
4. The upper light blue edging that folds around the two upper corners.
5a. The upper half of the box defined as a path with a fill.
5b. The lower part of the upper box with a darker blue bar across.
6a. The lower half box with the arrow.
6n. the upper part of the lower box with a lighter shade of gray.

That gives you a similar looking view without the buttons. You may insert that view as a subview to a superview that already has custom buttons, or add custom buttons with appropriate actions and display it.

So, that is my thought process.

jnoxx, that sample code isn't appropriate for this scenario. It creates a line with arrows at each end.
 
Here is a hack I did tonight. The project I tested this in is an ARC project, so I don't worry about releasing objects. Also, this has some hardcoded values and is not well tested.

I was able to add this to a UIImageView, add a UIButton to the UIImageView which I had to set userInteractionEnabled to YES so that button would work. I made the button a UIButtonTypeCustom so that only the title that I set would show up.

Take note of the RED text.


I'll use some of this knowledge for something that I am working on.



Code:
[COLOR="Red"]// Place this line into your interface file:[/COLOR]
	static inline double radians (double degrees) {return degrees * M_PI/180;}



- (UIImage *) arrowBox
{
   
    size_t width = 240;
	size_t height = 160;
    CGFloat arrowLength = 10.0;
    CGFloat arrowWidth = 20.0;
	size_t bytesPerPixel = 4;
	size_t bytesPerRow = width * bytesPerPixel;

	static CGColorSpaceRef colorSpace = NULL;
	if (colorSpace == NULL) {
		colorSpace = CGColorSpaceCreateDeviceRGB();
		if (colorSpace == NULL) {
			NSLog(@"EMPTY COLORSPACE!!");
			return nil;
		}
	}
    
    CGContextRef context = CGBitmapContextCreate(NULL, width, height, 8, 
				bytesPerRow, colorSpace, 
				kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst); 
    
    if (context == 0) NSLog(@"arrowBox context is nil");

    CGRect tempRect;
    tempRect = CGRectMake( 0.0, 0.0, width, height);
	CGContextSetFillColorWithColor (context, [[UIColor yellowColor] CGColor]);
[COLOR="Red"]// Comment out this line;[/COLOR]
	CGContextFillRect (context, tempRect);

    CGFloat cornerRadius = 12.0;
    CGSize offset = {0,-2};
    CGFloat blur = 5.0;
    //CGContextSetShadow (context, offset, blur);
    CGContextSetShadowWithColor (context, offset, 5.0, [[UIColor blackColor] CGColor]);

    CGFloat xPos = offset.width + blur;
    CGFloat yPos = blur + arrowLength; //offset.height + blur;
    CGFloat boxWidth = width - (xPos * 2.0);
    CGFloat boxHeight = height - arrowLength - (blur * 2.0);
    tempRect = CGRectMake( xPos, yPos, boxWidth, boxHeight);
	CGContextSetFillColorWithColor (context, [[UIColor grayColor] CGColor]);
    
    
    // Start with drawing arrow
    CGContextBeginPath(context);
    CGPoint arrowStartPoint = CGPointMake(xPos + cornerRadius + 3.0, yPos);
    CGPoint arrowEndPoint = CGPointMake(arrowStartPoint.x + arrowWidth, yPos);
    CGPoint arrowTipPoint = CGPointMake(arrowStartPoint.x + (arrowWidth / 2.0), yPos - arrowLength);
    
    CGContextMoveToPoint(context, arrowStartPoint.x, arrowStartPoint.y);
    CGContextAddLineToPoint (context, arrowTipPoint.x, arrowTipPoint.y);
    CGContextAddLineToPoint (context, arrowEndPoint.x, arrowEndPoint.y);

    // Lower right corner
    CGContextAddArc (context,
                     xPos + boxWidth - cornerRadius,
                     arrowEndPoint.y + cornerRadius,
                     cornerRadius,
                     radians(-90.0),
                     radians(0.0),
                     0
                     );

    // Upper right corner
    CGContextAddArc (context,
                     xPos + boxWidth - cornerRadius,
                     arrowEndPoint.y + boxHeight - cornerRadius,
                     cornerRadius,
                     radians(0.0),
                     radians(90.0),
                     0
                     );

    // Upper left corner
    CGContextAddArc (context,
                     xPos + cornerRadius,
                     yPos + boxHeight - cornerRadius,
                     cornerRadius,
                     radians(90.0),
                     radians(180.0),
                     0
                     );

    // Lower left corner
    CGContextAddArc (context,
                     xPos + cornerRadius,
                     yPos + cornerRadius,
                     cornerRadius,
                     radians(180.0),
                     radians(270.0),
                     0
                     );

    CGContextAddLineToPoint (context, arrowStartPoint.x, arrowStartPoint.y);    

    CGContextFillPath(context);


    // ---------------------------------------------------------------------------------------    
    // Upper light blue

    CGContextBeginPath(context);
    //offset = {0,0};
    CGContextSetShadowWithColor (context, offset, 0.0, [[UIColor clearColor] CGColor]);
    
    UIColor * lightBlueColor = [UIColor colorWithRed: 0.0 green: 0.6 blue: 0.8 alpha: 1.0];
    CGContextSetStrokeColorWithColor (context, [lightBlueColor CGColor]);
    CGContextSetFillColorWithColor (context, [lightBlueColor CGColor]);
    CGContextSetLineWidth(context, 1.0);

//    CGContextMoveToPoint(context, xPos + boxWidth, arrowEndPoint.y + boxHeight - cornerRadius);

    // Upper right corner
    CGContextAddArc (context,
                     xPos + boxWidth - cornerRadius,
                     arrowEndPoint.y + boxHeight - cornerRadius,
                     cornerRadius,
                     radians(0.0),
                     radians(90.0),
                     0
                     );
    
    // Upper left corner
    CGContextAddArc (context,
                     xPos + cornerRadius,
                     yPos + boxHeight - cornerRadius,
                     cornerRadius,
                     radians(90.0),
                     radians(180.0),
                     0
                     );

    CGContextFillPath(context);

    
    

    // ---------------------------------------------------------------------------------------    
    // Upper dark blue

    CGContextBeginPath(context);
    //offset = {0,0};
    CGContextSetShadowWithColor (context, offset, 0.0, [[UIColor clearColor] CGColor]);
    
    UIColor * darkBlueColor = [UIColor colorWithRed: 0.0 green: 0.5 blue: 0.8 alpha: 1.0];
    CGContextSetStrokeColorWithColor (context, [darkBlueColor CGColor]);
    CGContextSetFillColorWithColor (context, [darkBlueColor CGColor]);
    CGContextSetLineWidth(context, 1.0);
    
    CGContextMoveToPoint(context, xPos + boxWidth, yPos + (boxHeight / 2.0));
    
    // Upper right corner
    CGContextAddArc (context,
                     xPos + boxWidth - cornerRadius,
                     arrowEndPoint.y + boxHeight - cornerRadius - 2,
                     cornerRadius,
                     radians(0.0),
                     radians(90.0),
                     0
                     );
    
    // Upper left corner
    CGContextAddArc (context,
                     xPos + cornerRadius,
                     yPos + boxHeight - cornerRadius - 2,
                     cornerRadius,
                     radians(90.0),
                     radians(180.0),
                     0
                     );

    CGContextAddLineToPoint(context, xPos, yPos + (boxHeight / 2.0));

    CGContextFillPath(context);

    
    
    
  
    // ---------------------------------------------------------------------------------------
    // Dividing lines
    
    CGContextBeginPath(context);
    CGContextSetLineWidth(context, 2.0);
    UIColor * darkerBlueColor = [UIColor colorWithRed: 0.0 green: 0.2 blue: 0.8 alpha: 1.0];
    CGContextSetStrokeColorWithColor (context, [darkerBlueColor CGColor]);
    CGContextMoveToPoint(context, xPos, ((yPos + boxHeight) / 2.0) + 7.0);
    CGContextAddLineToPoint(context, xPos + boxWidth, ((yPos + boxHeight) / 2.0) + 7.0);    
    CGContextStrokePath(context);
    
    CGContextBeginPath(context);
    CGContextSetLineWidth(context, 2.0);
    CGContextSetStrokeColorWithColor (context, [[UIColor lightGrayColor] CGColor]);
    CGContextMoveToPoint(context, xPos, ((yPos + boxHeight) / 2.0) + 4.0);
    CGContextAddLineToPoint(context, xPos + boxWidth, ((yPos + boxHeight) / 2.0) + 4.0);    
    CGContextStrokePath(context);
    

    
    // Output to a UIImage
    CGImageRef cgImage = CGBitmapContextCreateImage(context); 
	if (!cgImage) NSLog(@"we did NOT get a gcImage ref for startButtonImage");
	UIImage * arrowBoxImage = [[UIImage alloc] initWithCGImage: cgImage];
	CGContextRelease(context);
	CGColorSpaceRelease(colorSpace);
	CGImageRelease(cgImage);
	
	return arrowBoxImage;
}
 
Last edited:
It is easy. As jnoxx pointed out you need to learn about creating your own drawing. Others might create the image in a graphics program and use it as a background in a view, but that couldn't account for size variances needed in different cases.

It might be possible using stretchable images and cap sizes.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.