iOS UIPopoverController透明度/ alpha
我正在制作一个iPad应用,客户想要一个透明度(alpha)的popoverview。 他们给了我一个示例应用程序,截图可以在这里找到
我已经读过UIPopoverController是最糟糕的事情,因为只有几个属性可以设置。 链接和链接
我尝试了降低子视图的alpha,但随后视图的内容也变得透明。
我错过了一个选项,或做错了什么来做到这一点?
此外,我对子类化的经验很少,所以任何建议,如果这样的情况将不仅仅是赞赏。
-碧玉
我为你创建了一个UIView的子类,它应该适用于你需要的东西……
PopoverView.h:
// // PopoverView.h // popovertest // // Created by Richard Ross III on 12/7/11. // Copyright (c) 2011 Ultimate Computer Services Inc. All rights reserved. // #import #import @interface PopoverView : UIView { UIColor *backgroundColor; CGSize contentSize; UIViewController *contentViewController; CGSize borders; } @property(nonatomic, retain) UIColor *backgroundColor; @property(readonly, assign) CGSize contentSize; @property(nonatomic, retain) UIViewController *contentViewController; @property(nonatomic, assign) CGSize borders; @end
PopoverView.m
// // PopoverView.m // popovertest // // Created by Richard Ross III on 12/7/11. // Copyright (c) 2011 Ultimate Computer Services Inc. All rights reserved. // #import "PopoverView.h" @implementation PopoverView @synthesize backgroundColor, borders, contentSize, contentViewController; -(void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if ([keyPath isEqualToString:@"frame"] || [keyPath isEqualToString:@"borders"]) { contentSize = CGRectInset(self.frame, borders.width, borders.height).size; contentViewController.view.frame = CGRectMake(borders.width, borders.height, contentSize.width, contentSize.height); } } - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { // Initialization code self.opaque = NO; self.clipsToBounds = NO; self.backgroundColor = [UIColor colorWithRed:50/256 green:50/256 blue:50/256 alpha:0.75f]; self.borders = CGSizeMake(25, 25); contentSize = CGRectInset(frame, borders.width * 2, borders.height * 2).size; self.userInteractionEnabled = YES; [self addObserver:self forKeyPath:@"frame" options:kNilOptions context:nil]; [self addObserver:self forKeyPath:@"borders" options:kNilOptions context:nil]; } return self; } -(void) setContentViewController:(UIViewController *)contentViewController_ { if (contentViewController_ != self->contentViewController) { [self->contentViewController.view removeFromSuperview]; self->contentViewController = contentViewController_; [self addSubview:contentViewController_.view]; contentViewController_.view.frame = CGRectMake(borders.width, borders.height, contentSize.width, contentSize.height); } } void CGContextDrawRoundedRect(CGContextRef context, CGColorRef color, CGRect bounds, CGFloat radius); void CGContextDrawRoundedRect(CGContextRef context, CGColorRef color, CGRect bounds, CGFloat radius) { CGContextSetFillColorWithColor(context, color); // If you were making this as a routine, you would probably accept a rectangle // that defines its bounds, and a radius reflecting the "rounded-ness" of the rectangle. CGRect rrect = bounds; // NOTE: At this point you may want to verify that your radius is no more than half // the width and height of your rectangle, as this technique degenerates for those cases. // In order to draw a rounded rectangle, we will take advantage of the fact that // CGContextAddArcToPoint will draw straight lines past the start and end of the arc // in order to create the path from the current position and the destination position. // In order to create the 4 arcs correctly, we need to know the min, mid and max positions // on the x and y lengths of the given rectangle. CGFloat minx = CGRectGetMinX(rrect), midx = CGRectGetMidX(rrect), maxx = CGRectGetMaxX(rrect); CGFloat miny = CGRectGetMinY(rrect), midy = CGRectGetMidY(rrect), maxy = CGRectGetMaxY(rrect); // Next, we will go around the rectangle in the order given by the figure below. // minx midx maxx // miny 2 3 4 // midy 1 9 5 // maxy 8 7 6 // Which gives us a coincident start and end point, which is incidental to this technique, but still doesn't // form a closed path, so we still need to close the path to connect the ends correctly. // Thus we start by moving to point 1, then adding arcs through each pair of points that follows. // You could use a similar tecgnique to create any shape with rounded corners. // Start at 1 CGContextMoveToPoint(context, minx, midy); // Add an arc through 2 to 3 CGContextAddArcToPoint(context, minx, miny, midx, miny, radius); // Add an arc through 4 to 5 CGContextAddArcToPoint(context, maxx, miny, maxx, midy, radius); // Add an arc through 6 to 7 CGContextAddArcToPoint(context, maxx, maxy, midx, maxy, radius); // Add an arc through 8 to 9 CGContextAddArcToPoint(context, minx, maxy, minx, midy, radius); // Close the path CGContextClosePath(context); // Fill the path CGContextDrawPath(context, kCGPathFill); } - (void)drawRect:(CGRect)rect { CGContextRef currentContext = UIGraphicsGetCurrentContext(); CGColorRef color = [backgroundColor CGColor]; CGContextDrawRoundedRect(currentContext, color, CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height), 10); } @end
ArrowView.h:
// // ArrowView.h // popovertest // // Created by Richard Ross III on 12/7/11. // Copyright (c) 2011 Ultimate Computer Services Inc. All rights reserved. // #import @interface ArrowView : UIView { UIColor *arrowColor; } @property(nonatomic, retain) UIColor *arrowColor; @end
ArrowView.m:
// // ArrowView.m // popovertest // // Created by Richard Ross III on 12/7/11. // Copyright (c) 2011 Ultimate Computer Services Inc. All rights reserved. // #import "ArrowView.h" #define CGRectCenter(rect) CGPointMake(CGRectGetMidX(rect), CGRectGetMidY(rect)) #define CGSizeDiv(size, div) CGSizeMake(size.width / div, size.height / div) @implementation ArrowView @synthesize arrowColor; - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { // Initialization code self.opaque = NO; } return self; } // Only override drawRect: if you perform custom drawing. // An empty implementation adversely affects performance during animation. - (void)drawRect:(CGRect)rect { // Drawing code CGContextRef currentContext = UIGraphicsGetCurrentContext(); CGContextSetFillColorWithColor(currentContext, arrowColor.CGColor); CGPoint arrowLocation = CGRectCenter(self.bounds); CGSize arrowSize = CGSizeDiv(self.frame.size, 1); CGPoint arrowTip = CGPointMake(arrowLocation.x, arrowLocation.y + (arrowSize.height / 2)); CGPoint arrowLeftFoot = CGPointMake(arrowLocation.x - (arrowSize.width / 2), arrowLocation.y - (arrowSize.height / 2)); CGPoint arrowRightFoot = CGPointMake(arrowLocation.x + (arrowSize.width / 2), arrowLocation.y - (arrowSize.height / 2)); // now we draw the triangle CGContextMoveToPoint(currentContext, arrowTip.x, arrowTip.y); CGContextAddLineToPoint(currentContext, arrowLeftFoot.x, arrowLeftFoot.y); CGContextAddLineToPoint(currentContext, arrowRightFoot.x, arrowRightFoot.y); CGContextClosePath(currentContext); CGContextDrawPath(currentContext, kCGPathFill); } @end
PopoverViewController.h:
// // PopoverViewController.h // popovertest // // Created by Richard Ross III on 12/7/11. // Copyright (c) 2011 Ultimate Computer Services Inc. All rights reserved. // #import #import "PopoverView.h" #import "ArrowView.h" @interface PopoverViewController : UIViewController { PopoverView *popover; ArrowView *arrow; UIPopoverArrowDirection arrowDirection; UIViewController *parentViewController; } // for managing the content @property(readonly, retain) PopoverView *popover; // the arrow @property(readonly, retain) ArrowView *arrow; @property(nonatomic, assign) UIPopoverArrowDirection arrowDirection; -(void) presentModallyInViewController:(UIViewController *) controller animated:(BOOL) animated; -(void) dismissModallyFromViewController:(UIViewController *) controller animated:(BOOL) animated; -(void) dismiss; @end
PopoverViewController.m:
// // PopoverViewController.m // popovertest // // Created by Richard Ross III on 12/7/11. // Copyright (c) 2011 Ultimate Computer Services Inc. All rights reserved. // #import "PopoverViewController.h" #define degreestoradians(x) (M_PI * x / 180) @implementation PopoverViewController @synthesize arrowDirection, arrow, popover; -(void) updateArrowPosition { if (arrowDirection & UIPopoverArrowDirectionUp) { arrow.frame = CGRectMake((popover.frame.origin.x) + (popover.frame.size.width / 2) - (arrow.frame.size.width / 2), popover.frame.origin.y - (arrow.frame.size.height), arrow.frame.size.width, arrow.frame.size.height); arrow.transform = CGAffineTransformMakeRotation(degreestoradians(180)); } else if (arrowDirection & UIPopoverArrowDirectionLeft) { arrow.frame = CGRectMake((popover.frame.origin.x) - (arrow.frame.size.width), (popover.frame.origin.y) + (popover.frame.size.height / 2) - (arrow.frame.size.height / 2), arrow.frame.size.width, arrow.frame.size.height); arrow.transform = CGAffineTransformMakeRotation(degreestoradians(90)); } else if (arrowDirection & UIPopoverArrowDirectionRight) { arrow.frame = CGRectMake((popover.frame.origin.x) + (popover.frame.size.width), (popover.frame.origin.y) + (popover.frame.size.height / 2) - (arrow.frame.size.height / 2), arrow.frame.size.width, arrow.frame.size.height); arrow.transform = CGAffineTransformMakeRotation(degreestoradians(-90)); } else if (arrowDirection & UIPopoverArrowDirectionDown) { arrow.frame = CGRectMake((popover.frame.origin.x) + (popover.frame.size.width / 2) - (arrow.frame.size.width / 2), popover.frame.origin.y + popover.frame.size.height, arrow.frame.size.width, arrow.frame.size.height); } else { NSLog(@"unknown direction %i", arrowDirection); } } -(void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { [self updateArrowPosition]; } -(void) dismiss { [self dismissModallyFromViewController:parentViewController animated:YES]; } -(void) presentModallyInViewController:(UIViewController *)controller animated:(BOOL)animated { [controller.view addSubview:self.view]; if (animated) { self.view.alpha = 0.0f; [UIView beginAnimations:@"Modal Entrance" context:nil]; [UIView setAnimationDuration:0.25]; self.view.alpha = 1.0f; [UIView commitAnimations]; } } -(void) dismissModallyFromViewController:(UIViewController *)controller animated:(BOOL)animated { if (animated) { [UIView animateWithDuration:0.25 animations:^{ self.view.alpha = 0.0f; } completion:^(BOOL finished) { [controller dismissModalViewControllerAnimated:NO]; }]; } else { [controller dismissModalViewControllerAnimated:NO]; } } -(id) init { if (self = [super init]) { popover = [PopoverView new]; arrow = [ArrowView new]; popover.backgroundColor = [UIColor colorWithRed:50/255 green:50/255 blue:50/255 alpha:0.75]; arrow.arrowColor = [UIColor colorWithRed:50/255 green:50/255 blue:50/255 alpha:0.75]; arrow.frame = CGRectMake(0, 0, 20, 20); [self addObserver:self forKeyPath:@"arrowDirection" options:kNilOptions context:nil]; [popover addObserver:self forKeyPath:@"frame" options:kNilOptions context:nil]; [self.view addSubview:popover]; [self.view addSubview:arrow]; arrowDirection = UIPopoverArrowDirectionRight; } return self; } -(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { [self dismiss]; } @end
用法示例:
PopoverViewController *popController = [[PopoverViewController alloc] init]; UIButton *contentView = [UIButton buttonWithType:UIButtonTypeRoundedRect]; [contentView setTitle:@"Hello World!" forState:UIControlStateNormal]; UIViewController *controller = [[UIViewController alloc] init]; controller.view = contentView; popController.popover.contentViewController = controller; popController.popover.frame = CGRectMake(100, 100, 300, 400); [popController presentModallyInViewController:self animated:YES];
请注意,这是在启用ARC的情况下完成的,因此如果您使用引用计数,则此代码需要进行一些调整。
为方便起见,我将整个项目放在我的Dropbox中,供您下载: http : //dl.dropbox.com/u/25258177/personal/popovertest.zip