Popover menu restricted to iPad?

Discussion in 'iPhone/iPad Programming' started by nashyo, Feb 3, 2012.

  1. macrumors 6502

    nashyo

    Joined:
    Oct 1, 2010
    Location:
    Bristol
    #1
    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)

    [​IMG]

    Regards
    Rob
     
  2. macrumors 68000

    Joined:
    Jan 28, 2003
    Location:
    Less lost in L.A.
    #2
    You build a view and place it frontmost of the underlying superview as a subview.
     
  3. thread starter macrumors 6502

    nashyo

    Joined:
    Oct 1, 2010
    Location:
    Bristol
    #3
    is it difficult to draw the arrow shape?
     
  4. macrumors 65816

    jnoxx

    Joined:
    Dec 29, 2010
    Location:
    Aartselaar // Antwerp // Belgium
    #4
    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 :)
     
  5. macrumors 68000

    Joined:
    Jan 28, 2003
    Location:
    Less lost in L.A.
    #5
    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.
     
  6. xStep, Feb 5, 2012
    Last edited: Feb 5, 2012

    macrumors 68000

    Joined:
    Jan 28, 2003
    Location:
    Less lost in L.A.
    #6
    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;
    }
    
     
  7. Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #7
    It might be possible using stretchable images and cap sizes.
     

Share This Page