PDA

View Full Version : Popover menu restricted to iPad?




nashyo
Feb 3, 2012, 12:26 PM
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)

http://i43.tinypic.com/23kx7uq.png

Regards
Rob



xStep
Feb 3, 2012, 03:38 PM
You build a view and place it frontmost of the underlying superview as a subview.

nashyo
Feb 3, 2012, 11:06 PM
You build a view and place it frontmost of the underlying superview as a subview.

is it difficult to draw the arrow shape?

jnoxx
Feb 4, 2012, 07:56 AM
You can draw lines quite easily with CGContext.
Also found this on google..
- (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 :)

xStep
Feb 5, 2012, 03:58 AM
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.

xStep
Feb 5, 2012, 07:13 AM
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.




// Place this line into your interface file:
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]);
// Comment out this line;
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;
}

dejo
Feb 5, 2012, 10:31 AM
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.