`
jsntghf
  • 浏览: 2528593 次
  • 性别: Icon_minigender_1
  • 来自: 苏州
社区版块
存档分类
最新评论

Popup view的实现

    博客分类:
  • iOS
阅读更多

以前写过一篇文章:UIPopoverController的定位,这篇文章实现了类似的功能。

 

首先,导入CoreGraphics.framework和QuartzCore.framework。

 

pch文件:

 

#ifdef __OBJC__
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#endif

#if TARGET_IPHONE_SIMULATOR
#import <objc/objc-runtime.h>
#else
#import <objc/runtime.h>
#endif

#ifdef	_DEBUG
#define	DNSLog(...);	NSLog(__VA_ARGS__);
#define DNSLogMethod	NSLog(@"[%s] %@", class_getName([self class]), NSStringFromSelector(_cmd));
#define DNSLogPoint(p)	NSLog(@"%f,%f", p.x, p.y);
#define DNSLogSize(p)	NSLog(@"%f,%f", p.width, p.height);
#define DNSLogRect(p)	NSLog(@"%f,%f %f,%f", p.origin.x, p.origin.y, p.size.width, p.size.height);

CFAbsoluteTime startTime;
#define D_START			startTime=CFAbsoluteTimeGetCurrent();
#define D_END			DNSLog(@"[%s] %@ %f seconds", class_getName([self class]), NSStringFromSelector(_cmd), CFAbsoluteTimeGetCurrent() - startTime );
#else
#define DNSLog(...);	 NSLog(__VA_ARGS__);
#define DNSLogMethod	 NSLog(@"[%s] %@", class_getName([self class]), NSStringFromSelector(_cmd) );
#define DNSLogPoint(p)	 NSLog(@"%f,%f", p.x, p.y);
#define DNSLogSize(p)	 NSLog(@"%f,%f", p.width, p.height);
#define DNSLogRect(p)	 NSLog(@"%f,%f %f,%f", p.origin.x, p.origin.y, p.size.width, p.size.height);

#define D_START			 CFAbsoluteTime startTime=CFAbsoluteTimeGetCurrent();
#define D_END			 DNSLog(@"New %f seconds", CFAbsoluteTimeGetCurrent() - startTime );
#endif

#define SAFE_FREE(p) { if(p) { free(p); (p)=NULL; } }

  

SNPopupView.h

 

#import <UIKit/UIKit.h>

#define SHADOW_OFFSET					CGSizeMake(10, 10)
#define CONTENT_OFFSET					CGSizeMake(10, 10)
#define POPUP_ROOT_SIZE					CGSizeMake(20, 10)

#define HORIZONTAL_SAFE_MARGIN			30

#define POPUP_ANIMATION_DURATION		0.3
#define DISMISS_ANIMATION_DURATION		0.2

#define DEFAULT_TITLE_SIZE				20

#define ALPHA							0.6

#define BAR_BUTTON_ITEM_UPPER_MARGIN	10
#define BAR_BUTTON_ITEM_BOTTOM_MARGIN	5

@class TouchPeekView;

typedef enum {
	SNPopupViewUp		= 1,
	SNPopupViewDown		= 2,
	SNPopupViewRight	= 1 << 8,
	SNPopupViewLeft		= 2 << 8,
} SNPopupViewDirection;

@class SNPopupView;

@protocol SNPopupViewModalDelegate <NSObject>

- (void)didDismissModal:(SNPopupView *)popupview;

@end

@interface SNPopupView : UIView {
	CGGradientRef gradient;
	CGGradientRef gradient2;
	
	CGRect		contentRect;
	CGRect		contentBounds;
	
	CGRect		popupRect;
	CGRect		popupBounds;
	
	CGRect		viewRect;
	CGRect		viewBounds;
	
	CGPoint		pointToBeShown;
	
	NSString	*title;
	UIImage		*image;
	float		fontSize;
	
	UIView		*contentView;
	
	float		horizontalOffset;
	SNPopupViewDirection	direction;
	id			target;
	SEL			action;
	
	TouchPeekView	*peekView;
	id<SNPopupViewModalDelegate>delegate;
	
	BOOL		animatedWhenAppering;
}

@property (nonatomic, readonly) NSString *title;
@property (nonatomic, readonly) UIImage *image;
@property (nonatomic, readonly) UIView *contentView;
@property (nonatomic, assign) id <SNPopupViewModalDelegate> delegate;

- (id)initWithString:(NSString *)newValue withFontOfSize:(float)newFontSize;
- (id)initWithString:(NSString *)newValue;
- (id)initWithImage:(UIImage *)newImage;
- (id)initWithContentView:(UIView *)newContentView contentSize:(CGSize)contentSize;

- (void)showAtPoint:(CGPoint)p inView:(UIView *)inView;
- (void)showAtPoint:(CGPoint)p inView:(UIView *)inView animated:(BOOL)animated;

- (void)presentModalAtPoint:(CGPoint)p inView:(UIView *)inView;
- (void)presentModalAtPoint:(CGPoint)p inView:(UIView *)inView animated:(BOOL)animated;

- (BOOL)shouldBeDismissedFor:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)dismiss;
- (void)dismiss:(BOOL)animtaed;
- (void)dismissModal;

- (void)addTarget:(id)target action:(SEL)action;
@end

 

SNPopupView.m

 

#import "SNPopupView.h"

#import <QuartzCore/QuartzCore.h>

@interface TouchPeekView : UIView {
	SNPopupView *delegate;
}

@property (nonatomic, assign) SNPopupView *delegate;

@end

@interface SNPopupView(Private)

- (void)popup;

@end

@implementation TouchPeekView

@synthesize delegate;

- (id)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        [self setBackgroundColor:[UIColor clearColor]];
    }
    return self;
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
	DNSLogMethod
	if ([delegate shouldBeDismissedFor:touches withEvent:event])
		[delegate dismissModal];
}

@end

@implementation SNPopupView

@synthesize title, image, contentView, delegate;

#pragma mark - Prepare

- (void)setupGradientColors {		
	CGColorSpaceRef rgb = CGColorSpaceCreateDeviceRGB();
	CGFloat colors[] =
	{
		155.0 / 255.0, 155.0 / 255.0, 155.0 / 255.0, ALPHA,
		70.0 / 255.0, 70.0 / 255.0, 70.0 / 255.0, ALPHA,
	};
	gradient = CGGradientCreateWithColorComponents(rgb, colors, NULL, sizeof(colors)/(sizeof(colors[0]) * 4));
	
	CGFloat colors2[] =
	{
		20.0 / 255.0, 20.0 / 255.0, 20.0 / 255.0, ALPHA,
		0.0 / 255.0, 0.0 / 255.0, 0.0 / 255.0, ALPHA,
	};
	gradient2 = CGGradientCreateWithColorComponents(rgb, colors2, NULL, sizeof(colors2) / (sizeof(colors2[0]) * 4));
	CGColorSpaceRelease(rgb);
}

- (id) initWithString:(NSString *)newValue {
	return [self initWithString:newValue withFontOfSize:DEFAULT_TITLE_SIZE];
}

- (id) initWithString:(NSString *)newValue withFontOfSize:(float)newFontSize {
	self = [super init];
	if (self != nil) {
		title = [newValue copy];
		
		[self setBackgroundColor:[UIColor clearColor]];
		
		fontSize = newFontSize;
		UIFont *font = [UIFont boldSystemFontOfSize:fontSize];
		
		CGSize titleRenderingSize = [title sizeWithFont:font];
		
		contentBounds = CGRectMake(0, 0, 0, 0);
		contentBounds.size = titleRenderingSize;
		
		[self setupGradientColors];		
	}
	return self;
}

- (id) initWithImage:(UIImage *)newImage {
	self = [super init];
	if (self != nil) {
		image = [newImage retain];
		
		[self setBackgroundColor:[UIColor clearColor]];
		
		contentBounds = CGRectMake(0, 0, 0, 0);
		contentBounds.size = image.size;
		
		[self setupGradientColors];	
	}
	return self;
}

- (id) initWithContentView:(UIView *)newContentView contentSize:(CGSize)contentSize {
	self = [super init];
	if (self != nil) {
		contentView = [newContentView retain];
        
		[self setBackgroundColor:[UIColor clearColor]];
		
		contentBounds = CGRectMake(0, 0, 0, 0);
		contentBounds.size = contentSize;
		
		[self setupGradientColors];
	}
	return self;
}

- (void)addTarget:(id)newTarget action:(SEL)newAction {
	if ([newTarget respondsToSelector:newAction]) {
		target = newTarget;
		action = newAction;
	}
}

#pragma mark - Present modal

- (void)createAndAttachTouchPeekView {
	UIWindow *window = [[UIApplication sharedApplication] keyWindow];
    
	[peekView removeFromSuperview];
	[peekView release];
	peekView = nil;
	peekView = [[TouchPeekView alloc] initWithFrame:window.frame];
	[peekView setDelegate:self];
	
	[window addSubview:peekView];
}

- (void)presentModalAtPoint:(CGPoint)p inView:(UIView *)inView {
	animatedWhenAppering = YES;
	[self createAndAttachTouchPeekView];
	[self showAtPoint:[inView convertPoint:p toView:[[UIApplication sharedApplication] keyWindow]] inView:[[UIApplication sharedApplication] keyWindow]];
}

- (void)presentModalAtPoint:(CGPoint)p inView:(UIView *)inView animated:(BOOL)animated {
	animatedWhenAppering = animated;
	[self createAndAttachTouchPeekView];
	[self showAtPoint:[inView convertPoint:p toView:[[UIApplication sharedApplication] keyWindow]] inView:[[UIApplication sharedApplication] keyWindow] animated:animated];
}

#pragma mark - Show as normal view

- (void)showAtPoint:(CGPoint)p inView:(UIView *)inView {
	[self showAtPoint:p inView:inView animated:NO];
}

- (void)showAtPoint:(CGPoint)p inView:(UIView *)inView animated:(BOOL)animated {
	if ((p.y - contentBounds.size.height - POPUP_ROOT_SIZE.height - 2 * CONTENT_OFFSET.height - SHADOW_OFFSET.height) < 0) {
		direction = SNPopupViewDown;
	}
	else {
		direction = SNPopupViewUp;
	}
	
	if (direction & SNPopupViewUp) {
        
		pointToBeShown = p;
		
		contentRect.origin.x = p.x - (int)contentBounds.size.width / 2;
		contentRect.origin.y = p.y - CONTENT_OFFSET.height - POPUP_ROOT_SIZE.height - contentBounds.size.height;
		contentRect.size = contentBounds.size;
		
		popupBounds.origin = CGPointMake(0, 0);
		popupBounds.size.width = contentBounds.size.width + CONTENT_OFFSET.width + CONTENT_OFFSET.width;
		popupBounds.size.height = contentBounds.size.height + CONTENT_OFFSET.height + CONTENT_OFFSET.height + POPUP_ROOT_SIZE.height;
		
		popupRect.origin.x = contentRect.origin.x - CONTENT_OFFSET.width;
		popupRect.origin.y = contentRect.origin.y - CONTENT_OFFSET.height;
		popupRect.size = popupBounds.size;
		
		viewBounds.origin = CGPointMake(0, 0);
		viewBounds.size.width = popupRect.size.width + SHADOW_OFFSET.width + SHADOW_OFFSET.width;
		viewBounds.size.height = popupRect.size.height + SHADOW_OFFSET.height + SHADOW_OFFSET.height;
		
		viewRect.origin.x = popupRect.origin.x - SHADOW_OFFSET.width;
		viewRect.origin.y = popupRect.origin.y - SHADOW_OFFSET.height;
		viewRect.size = viewBounds.size;
        
		float left_viewRect = viewRect.origin.x + viewRect.size.width;
		
		if (viewRect.origin.x < 0) {
			direction = direction | SNPopupViewRight;
			horizontalOffset = viewRect.origin.x;
			
			if (viewRect.origin.x - horizontalOffset < pointToBeShown.x - HORIZONTAL_SAFE_MARGIN) {
			}
			else {
				pointToBeShown.x = HORIZONTAL_SAFE_MARGIN;
			}
			viewRect.origin.x -= horizontalOffset;
			contentRect.origin.x -= horizontalOffset;
			popupRect.origin.x -= horizontalOffset;
		}
		else if (left_viewRect > inView.frame.size.width) {
			direction = direction | SNPopupViewLeft;
			horizontalOffset = inView.frame.size.width - left_viewRect;
			
			if (left_viewRect + horizontalOffset > pointToBeShown.x + HORIZONTAL_SAFE_MARGIN) {
			}
			else {
				pointToBeShown.x = inView.frame.size.width - HORIZONTAL_SAFE_MARGIN;
			}
			viewRect.origin.x += horizontalOffset;
			contentRect.origin.x += horizontalOffset;
			popupRect.origin.x += horizontalOffset;
		}
	}
	else {
		pointToBeShown = p;
		
		contentRect.origin.x = p.x - (int)contentBounds.size.width / 2;
		contentRect.origin.y = p.y + CONTENT_OFFSET.height + POPUP_ROOT_SIZE.height;
		contentRect.size = contentBounds.size;
		
		popupBounds.origin = CGPointMake(0, 0);
		popupBounds.size.width = contentBounds.size.width + CONTENT_OFFSET.width + CONTENT_OFFSET.width;
		popupBounds.size.height = contentBounds.size.height + CONTENT_OFFSET.height + CONTENT_OFFSET.height + POPUP_ROOT_SIZE.height;
		
		popupRect.origin.x = contentRect.origin.x - CONTENT_OFFSET.width;
		popupRect.origin.y = contentRect.origin.y - CONTENT_OFFSET.height - POPUP_ROOT_SIZE.height;
		popupRect.size = popupBounds.size;
		
		viewBounds.origin = CGPointMake(0, 0);
		viewBounds.size.width = popupRect.size.width + SHADOW_OFFSET.width + SHADOW_OFFSET.width;
		viewBounds.size.height = popupRect.size.height + SHADOW_OFFSET.height + SHADOW_OFFSET.height;
		
		viewRect.origin.x = popupRect.origin.x - SHADOW_OFFSET.width;
		viewRect.origin.y = popupRect.origin.y - SHADOW_OFFSET.height;
		viewRect.size = viewBounds.size;
		
		float left_viewRect = viewRect.origin.x + viewRect.size.width;
		
		if (viewRect.origin.x < 0) {
			direction = direction | SNPopupViewRight;
			horizontalOffset = viewRect.origin.x;
			
			if (viewRect.origin.x - horizontalOffset < pointToBeShown.x - HORIZONTAL_SAFE_MARGIN) {
			}
			else {
				pointToBeShown.x = HORIZONTAL_SAFE_MARGIN;
			}
			viewRect.origin.x -= horizontalOffset;
			contentRect.origin.x -= horizontalOffset;
			popupRect.origin.x -= horizontalOffset;
		}
		else if (left_viewRect > inView.frame.size.width) {
			direction = direction | SNPopupViewLeft;
			horizontalOffset = inView.frame.size.width - left_viewRect;
			
			if (left_viewRect + horizontalOffset > pointToBeShown.x + HORIZONTAL_SAFE_MARGIN) {
			}
			else {
				pointToBeShown.x = inView.frame.size.width - HORIZONTAL_SAFE_MARGIN;
			}
			viewRect.origin.x += horizontalOffset;
			contentRect.origin.x += horizontalOffset;
			popupRect.origin.x += horizontalOffset;
		}
	}
	
	contentRect.origin.x -= viewRect.origin.x;
	contentRect.origin.y -= viewRect.origin.y;
	popupRect.origin.x -= viewRect.origin.x;
	popupRect.origin.y -= viewRect.origin.y;
	pointToBeShown.x -= viewRect.origin.x;
	pointToBeShown.y -= viewRect.origin.y;
	
	BOOL isAlreadyShown = (self.superview == inView);
	
	if (isAlreadyShown) {
		[self setNeedsDisplay];
		
		if (animated) {
			[UIView beginAnimations:@"move" context:nil];
			[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
		}
		self.frame = viewRect;
		if (animated) {
			[UIView commitAnimations];
		}
	}
	else {
		[inView addSubview:self];
		self.frame = viewRect;		
		
		if (contentView) {
			[self addSubview:contentView];
			[contentView setFrame:contentRect];
		}
		
		if (animated)
			[self popup];
	}
}

#pragma mark - Core Animation call back

- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag {
	[self removeFromSuperview];
}

#pragma mark - Make CoreAnimation object

- (CAKeyframeAnimation *)getAlphaAnimationForPopup {
	
	CAKeyframeAnimation *alphaAnimation = [CAKeyframeAnimation	animationWithKeyPath:@"opacity"];
	alphaAnimation.removedOnCompletion = NO;
	alphaAnimation.values = [NSArray arrayWithObjects:
							 [NSNumber numberWithFloat:0],
							 [NSNumber numberWithFloat:0.7],
							 [NSNumber numberWithFloat:1],
							 nil];
	alphaAnimation.keyTimes = [NSArray arrayWithObjects:
							   [NSNumber numberWithFloat:0],
							   [NSNumber numberWithFloat:0.1],
							   [NSNumber numberWithFloat:1],
							   nil];
	return alphaAnimation;
}

- (CAKeyframeAnimation *)getPositionAnimationForPopup {	
	float r1 = 0.1;
	float r2 = 1.4;
	float r3 = 1;
	float r4 = 0.8;
	float r5 = 1;
	
	float y_offset =  (popupRect.size.height / 2 - POPUP_ROOT_SIZE.height);
	
	CAKeyframeAnimation *positionAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform"];
	CATransform3D tm1, tm2, tm3, tm4, tm5;
	
	if (direction & SNPopupViewUp) {
		if (direction & SNPopupViewLeft)
			horizontalOffset = -horizontalOffset;
		tm1 = CATransform3DMakeTranslation(horizontalOffset * (1 - r1), y_offset * (1 - r1), 0);
		tm2 = CATransform3DMakeTranslation(horizontalOffset * (1 - r2), y_offset * (1 - r2), 0);
		tm3 = CATransform3DMakeTranslation(horizontalOffset * (1 - r3), y_offset * (1 - r3), 0);
		tm4 = CATransform3DMakeTranslation(horizontalOffset * (1 - r4), y_offset * (1 - r4), 0);
		tm5 = CATransform3DMakeTranslation(horizontalOffset * (1 - r5), y_offset * (1 - r5), 0);
	}
	else {
		if (direction & SNPopupViewLeft)
			horizontalOffset = -horizontalOffset;		
		tm1 = CATransform3DMakeTranslation(horizontalOffset * (1 - r1), -y_offset * (1 - r1), 0);
		tm2 = CATransform3DMakeTranslation(horizontalOffset * (1 - r2), -y_offset * (1 - r2), 0);
		tm3 = CATransform3DMakeTranslation(horizontalOffset * (1 - r3), -y_offset * (1 - r3), 0);
		tm4 = CATransform3DMakeTranslation(horizontalOffset * (1 - r4), -y_offset * (1 - r4), 0);
		tm5 = CATransform3DMakeTranslation(horizontalOffset * (1 - r5), -y_offset * (1 - r5), 0);
	}
	tm1 = CATransform3DScale(tm1, r1, r1, 1);
	tm2 = CATransform3DScale(tm2, r2, r2, 1);
	tm3 = CATransform3DScale(tm3, r3, r3, 1);
	tm4 = CATransform3DScale(tm4, r4, r4, 1);
	tm5 = CATransform3DScale(tm5, r5, r5, 1);
	
	positionAnimation.values = [NSArray arrayWithObjects:
								[NSValue valueWithCATransform3D:tm1],
								[NSValue valueWithCATransform3D:tm2],
								[NSValue valueWithCATransform3D:tm3],
								[NSValue valueWithCATransform3D:tm4],
								[NSValue valueWithCATransform3D:tm5],
								nil];
	positionAnimation.keyTimes = [NSArray arrayWithObjects:
								  [NSNumber numberWithFloat:0.0],
								  [NSNumber numberWithFloat:0.2],
								  [NSNumber numberWithFloat:0.4],
								  [NSNumber numberWithFloat:0.7], 
								  [NSNumber numberWithFloat:1.0],
								  nil];
	return positionAnimation;
}

#pragma mark - Popup and dismiss

- (void)popup {	
	CAKeyframeAnimation *positionAnimation = [self getPositionAnimationForPopup];
	CAKeyframeAnimation *alphaAnimation = [self getAlphaAnimationForPopup];
	
	CAAnimationGroup *group = [CAAnimationGroup animation];
	group.animations = [NSArray arrayWithObjects:positionAnimation, alphaAnimation, nil];
	group.duration = POPUP_ANIMATION_DURATION;
	group.removedOnCompletion = YES;
	group.fillMode = kCAFillModeForwards;
	
	[self.layer addAnimation:group forKey:@"hoge"];
}

- (BOOL)shouldBeDismissedFor:(NSSet *)touches withEvent:(UIEvent *)event {
	UITouch *touch = [touches anyObject];
	
	CGPoint p = [touch locationInView:self];
	return !CGRectContainsPoint(contentRect, p);
}

- (void)dismissModal {
	if ([peekView superview]) 
		[delegate didDismissModal:self];
	[peekView removeFromSuperview];
	
	[self dismiss:animatedWhenAppering];
}

- (void)dismiss:(BOOL)animtaed {
	if (animtaed)
		[self dismiss];
	else {
		[self removeFromSuperview];
	}
}

- (void)dismiss {
	CAKeyframeAnimation *positionAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform"];
	
	float r1 = 1.0;
	float r2 = 0.1;
	
	float y_offset =  (popupRect.size.height/2 - POPUP_ROOT_SIZE.height);
	
	CAKeyframeAnimation *alphaAnimation = [CAKeyframeAnimation	animationWithKeyPath:@"opacity"];
	alphaAnimation.removedOnCompletion = NO;
	alphaAnimation.values = [NSArray arrayWithObjects:
							 [NSNumber numberWithFloat:1],
							 [NSNumber numberWithFloat:0],
							 nil];
	alphaAnimation.keyTimes = [NSArray arrayWithObjects:
							   [NSNumber numberWithFloat:0],
							   [NSNumber numberWithFloat:1],
							   nil];
	
	CATransform3D tm1, tm2;
	if (direction & SNPopupViewUp) {
		tm1 = CATransform3DMakeTranslation(horizontalOffset * (1 - r1), y_offset * (1 - r1), 0);
		tm2 = CATransform3DMakeTranslation(horizontalOffset * (1 - r2), y_offset * (1 - r2), 0);
	}
	else {	
		tm1 = CATransform3DMakeTranslation(horizontalOffset * (1 - r1), -y_offset * (1 - r1), 0);
		tm2 = CATransform3DMakeTranslation(horizontalOffset * (1 - r2), -y_offset * (1 - r2), 0);
		
	}
	tm1 = CATransform3DScale(tm1, r1, r1, 1);
	tm2 = CATransform3DScale(tm2, r2, r2, 1);
	
	positionAnimation.values = [NSArray arrayWithObjects:
								[NSValue valueWithCATransform3D:tm1],
								[NSValue valueWithCATransform3D:tm2],
								nil];
	positionAnimation.keyTimes = [NSArray arrayWithObjects:
								  [NSNumber numberWithFloat:0],
								  [NSNumber numberWithFloat:1.0],
								  nil];
	
	CAAnimationGroup *group = [CAAnimationGroup animation];
	group.animations = [NSArray arrayWithObjects:positionAnimation, alphaAnimation, nil];
	group.duration = DISMISS_ANIMATION_DURATION;
	group.removedOnCompletion = NO;
	group.fillMode = kCAFillModeForwards;
	group.delegate = self;
	
	[self.layer addAnimation:group forKey:@"hoge"];
}

#pragma mark - Drawing

- (void)makePathCircleCornerRect:(CGRect)rect radius:(float)radius popPoint:(CGPoint)popPoint {
    CGContextRef context = UIGraphicsGetCurrentContext();
	
	if (direction & SNPopupViewUp) {
		rect.size.height -= POPUP_ROOT_SIZE.height;
        
		CGFloat minx = CGRectGetMinX( rect ), midx = CGRectGetMidX( rect ), maxx = CGRectGetMaxX( rect );
		CGFloat miny = CGRectGetMinY( rect ), midy = CGRectGetMidY( rect ), maxy = CGRectGetMaxY( rect );
		
		CGFloat popRightEdgeX = popPoint.x + (int)POPUP_ROOT_SIZE.width / 2;
		CGFloat popRightEdgeY = maxy;
		
		CGFloat popLeftEdgeX = popPoint.x - (int)POPUP_ROOT_SIZE.width / 2;
		CGFloat popLeftEdgeY = maxy;
		
		CGContextMoveToPoint(context, minx, midy);
		CGContextAddArcToPoint(context, minx, miny, midx, miny, radius);
		CGContextAddArcToPoint(context, maxx, miny, maxx, midy, radius);
		
		
		CGContextAddArcToPoint(context, maxx, maxy, popRightEdgeX, popRightEdgeY, radius);
		CGContextAddLineToPoint(context, popRightEdgeX, popRightEdgeY);
		CGContextAddLineToPoint(context, popPoint.x, popPoint.y);
		CGContextAddLineToPoint(context, popLeftEdgeX, popLeftEdgeY);
		CGContextAddArcToPoint(context, minx, maxy, minx, midy, radius);
		CGContextAddLineToPoint(context, minx, midy);
		
	}
	else {
		rect.origin.y += POPUP_ROOT_SIZE.height;
		rect.size.height -= POPUP_ROOT_SIZE.height;
        
		CGFloat minx = CGRectGetMinX( rect ), midx = CGRectGetMidX( rect ), maxx = CGRectGetMaxX( rect );
		CGFloat miny = CGRectGetMinY( rect ), midy = CGRectGetMidY( rect ), maxy = CGRectGetMaxY( rect );
		
		CGFloat popRightEdgeX = popPoint.x + (int)POPUP_ROOT_SIZE.width / 2;
		CGFloat popRightEdgeY = miny;
		
		CGFloat popLeftEdgeX = popPoint.x - (int)POPUP_ROOT_SIZE.width / 2;
		CGFloat popLeftEdgeY = miny;
		
		CGContextMoveToPoint(context, minx, midy);
		CGContextAddArcToPoint(context, minx, miny, midx, miny, radius);
		CGContextAddLineToPoint(context, popLeftEdgeX, popLeftEdgeY);
		CGContextAddLineToPoint(context, popPoint.x, popPoint.y);
		CGContextAddLineToPoint(context, popRightEdgeX, popRightEdgeY);
		CGContextAddArcToPoint(context, maxx, miny, maxx, midy, radius);
		CGContextAddArcToPoint(context, maxx, maxy, midx, maxy, radius);
		CGContextAddArcToPoint(context, minx, maxy, minx, midy, radius);
	}
}

- (void)makeGrowingPathCircleCornerRect:(CGRect)rect radius:(float)radius {
	CGContextRef context = UIGraphicsGetCurrentContext();
	
	rect.origin.y += 1;
	rect.origin.x += 1;
	rect.size.width -= 2;
    
    CGFloat minx = CGRectGetMinX( rect ), midx = CGRectGetMidX( rect ), maxx = CGRectGetMaxX( rect );
    CGFloat miny = CGRectGetMinY( rect ), midy = CGRectGetMidY( rect );
	
	CGFloat rightEdgeX = minx;
	CGFloat rightEdgeY = midy - 10;
	
	CGFloat leftEdgeX = maxx;
	CGFloat leftEdgeY = midy - 10;
	
    CGContextMoveToPoint(context, rightEdgeX, rightEdgeY);
    CGContextAddArcToPoint(context, minx, miny, midx, miny, radius);
    CGContextAddArcToPoint(context, maxx, miny, maxx, midy, radius);
    CGContextAddLineToPoint(context, leftEdgeX, leftEdgeY);
}

#pragma mark - Override

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
	DNSLogMethod
	
	if ([self shouldBeDismissedFor:touches withEvent:event] && peekView != nil) {
		[self dismissModal];
		return;
	}
	
	if ([target respondsToSelector:action]) {
		[target performSelector:action withObject:self];
	}
}

- (void)drawRect:(CGRect)rect {	
	CGContextRef context = UIGraphicsGetCurrentContext();
    
#ifdef _CONFIRM_REGION
	CGContextFillRect(context, rect);
	CGContextSetRGBFillColor(context, 1, 0, 0, 1);
	CGContextFillRect(context, popupRect);
	CGContextSetRGBFillColor(context, 1, 1, 0, 1);
	CGContextFillRect(context, contentRect);
#endif
    
	CGContextSaveGState(context);
	
	CGContextSetRGBFillColor(context, 0.1, 0.1, 0.1, ALPHA);
	CGContextSetShadowWithColor (context, CGSizeMake(0, 2), 2, [[UIColor colorWithRed:0 green:0 blue:0 alpha:0.5] CGColor]);
	[self makePathCircleCornerRect:popupRect radius:10 popPoint:pointToBeShown];
	CGContextClosePath(context);
	CGContextFillPath(context);
	CGContextRestoreGState(context);
    
	CGContextSaveGState(context);
	[self makePathCircleCornerRect:popupRect radius:10 popPoint:pointToBeShown];
	CGContextClip(context);
	if (direction & SNPopupViewUp) {
		CGContextDrawLinearGradient(context, gradient, CGPointMake(0, popupRect.origin.y), CGPointMake(0, popupRect.origin.y + (int)(popupRect.size.height-POPUP_ROOT_SIZE.height) / 2), 0);
		CGContextDrawLinearGradient(context, gradient2, CGPointMake(0, popupRect.origin.y + (int)(popupRect.size.height-POPUP_ROOT_SIZE.height) / 2), CGPointMake(0, popupRect.origin.y + popupRect.size.height-POPUP_ROOT_SIZE.height), 0);
	}
	else {
		int h = (int)(popupRect.size.height - POPUP_ROOT_SIZE.height);
		CGContextDrawLinearGradient(context, gradient, CGPointMake(0, popupRect.origin.y + POPUP_ROOT_SIZE.height), CGPointMake(0, popupRect.origin.y + h / 2 + POPUP_ROOT_SIZE.height), 0);
		CGContextDrawLinearGradient(context, gradient2, CGPointMake(0, popupRect.origin.y + h / 2 + POPUP_ROOT_SIZE.height), CGPointMake(0, popupRect.origin.y + popupRect.size.height), 0);
	}
	CGContextRestoreGState(context);
    
	if ([title length]) {
		CGContextSetRGBFillColor(context, 1, 1, 1, 1);
		UIFont *font = [UIFont boldSystemFontOfSize:fontSize];
		[title drawInRect:contentRect withFont:font];
	}
	if (image) {
		[image drawInRect:contentRect];
	}
}

#pragma mark - dealloc

- (void)dealloc {
	DNSLogMethod
	CGGradientRelease(gradient);
	CGGradientRelease(gradient2);
	
	[peekView release];
	[title release];
	[image release];
	[contentView release];
    [super dealloc];
}

@end

 

SNPopupView+UsingPrivateMethod.h

 

#import "SNPopupView.h"

@interface SNPopupView(UsingPrivateMethod)

- (void)showFromBarButtonItem:(UIBarButtonItem *)barButtonItem inView:(UIView *)inView;
- (void)showFromBarButtonItem:(UIBarButtonItem *)barButtonItem inView:(UIView *)inView animated:(BOOL)animated;

- (void)presentModalFromBarButtonItem:(UIBarButtonItem *)barButtonItem inView:(UIView *)inView;
- (void)presentModalFromBarButtonItem:(UIBarButtonItem *)barButtonItem inView:(UIView *)inView animated:(BOOL)animated;

@end

 

SNPopupView+UsingPrivateMethod.m

 

#import "SNPopupView+UsingPrivateMethod.h"

@interface SNPopupView(UsingPrivateMethod_Private)

- (void)createAndAttachTouchPeekView;

@end

@implementation SNPopupView(UsingPrivateMethod)

- (void)presentModalFromBarButtonItem:(UIBarButtonItem *)barButtonItem inView:(UIView *)inView {
	animatedWhenAppering = YES;
	[self createAndAttachTouchPeekView];
	[self showFromBarButtonItem:barButtonItem inView:[[UIApplication sharedApplication] keyWindow]];
}

- (void)presentModalFromBarButtonItem:(UIBarButtonItem *)barButtonItem inView:(UIView *)inView animated:(BOOL)animated {
	animatedWhenAppering = animated;
	[self createAndAttachTouchPeekView];
	[self showFromBarButtonItem:barButtonItem inView:[[UIApplication sharedApplication] keyWindow] animated:animated];
}

- (void)showFromBarButtonItem:(UIBarButtonItem *)barButtonItem inView:(UIView *)inView {
	[self showFromBarButtonItem:barButtonItem inView:inView animated:YES];
}

- (void)showFromBarButtonItem:(UIBarButtonItem *)barButtonItem inView:(UIView *)inView animated:(BOOL)animated {
	
	if(![barButtonItem respondsToSelector:@selector(view)]) {
		return;
	}
	
	UIView *targetView = (UIView *)[barButtonItem performSelector:@selector(view)];
	UIView *targetSuperview = [targetView superview];
	
	BOOL isOnNavigationBar = YES;
	
	if ([targetSuperview isKindOfClass:[UINavigationBar class]]) {
		isOnNavigationBar = YES;
	}
	else if ([targetSuperview isKindOfClass:[UIToolbar class]]) {
		isOnNavigationBar = NO;
	}
	else {
		return;
	}
	
	CGRect rect = [targetSuperview convertRect:targetView.frame toView:inView];
	
	CGPoint p;
	p.x = rect.origin.x + (int)rect.size.width / 2;
	
	if (isOnNavigationBar)
		p.y = rect.origin.y + rect.size.height + BAR_BUTTON_ITEM_UPPER_MARGIN;
	else
		p.y = rect.origin.y - BAR_BUTTON_ITEM_BOTTOM_MARGIN;
	
	[self showAtPoint:p inView:inView animated:animated];
}

@end

 

示例:

 

PopupViewTestViewController.h

 

#import <UIKit/UIKit.h>

#import "SNPopupView.h"
#import "SNPopupView+UsingPrivateMethod.h"

@interface PopupViewTestViewController : UIViewController <SNPopupViewModalDelegate> {
	SNPopupView		*popup;
	int				currentMessageIndex;
	IBOutlet UIView *testContentView;
	
	IBOutlet UISwitch *animationSwitch;
	IBOutlet UISwitch *modalSwitch;
}

- (IBAction)pushButton:(id)sender;
- (void)didDismissModal:(SNPopupView *)popupview;
- (void)didTouchPopupView:(SNPopupView *)sender;
@end

 

PopupViewTestViewController.m

 

#import "PopupViewTestViewController.h"

@implementation PopupViewTestViewController

- (IBAction)pushButton:(id)sender {
	DNSLogMethod
	
	if (popup == nil) {
		if (currentMessageIndex == 0) {
			popup = [[SNPopupView alloc] initWithContentView:testContentView contentSize:CGSizeMake(203, 63)];
			currentMessageIndex++;
		}
		else if (currentMessageIndex == 1) {
			popup = [[SNPopupView alloc] initWithString:@"test message" withFontOfSize:29];
			currentMessageIndex++;
		}
		else if (currentMessageIndex == 2) {
			popup = [[SNPopupView alloc] initWithImage:[UIImage imageNamed:@"2tchSmall.png"]];
			currentMessageIndex = 0;
		}
		if (modalSwitch.on)
			[popup presentModalFromBarButtonItem:sender inView:self.view animated:animationSwitch.on];
		else
			[popup showFromBarButtonItem:sender inView:self.view animated:animationSwitch.on];
		[popup addTarget:self action:@selector(didTouchPopupView:)];
		[popup release];
		[popup setDelegate:self];
	}
	else if (!modalSwitch.on) {
		[popup dismiss:animationSwitch.on];
		popup = nil;
	}
}

- (void)didTouchPopupView:(SNPopupView *)sender {
	DNSLogMethod
	DNSLog(@"%@", sender);
}

- (void)didDismissModal:(SNPopupView *)popupview {
	DNSLogMethod
	if (popupview == popup) {
		popup = nil;
	}
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
	UITouch *touch = [touches anyObject];
	
	if (popup == nil) {
		if (currentMessageIndex == 0) {
			popup = [[SNPopupView alloc] initWithImage:[UIImage imageNamed:@"2tchSmall.png"]];
			currentMessageIndex++;
		}
		else if (currentMessageIndex == 1) {
			popup = [[SNPopupView alloc] initWithString:@"test message" withFontOfSize:16];
			currentMessageIndex++;
		}
		else if (currentMessageIndex == 2) {
			popup = [[SNPopupView alloc] initWithContentView:testContentView contentSize:CGSizeMake(203, 63)];
			currentMessageIndex = 0;
		}
		if (modalSwitch.on)
			[popup presentModalAtPoint:[touch locationInView:self.view] inView:self.view animated:animationSwitch.on];
		else
			[popup showAtPoint:[touch locationInView:self.view] inView:self.view animated:animationSwitch.on];
		[popup addTarget:self action:@selector(didTouchPopupView:)];
		[popup release];
		[popup setDelegate:self];
	}
	else if (!modalSwitch.on) {
		[popup dismiss:animationSwitch.on];
		popup = nil;
	}
}

@end

 

分享到:
评论

相关推荐

    Popup例子 实现弹出窗口的关闭

    "Popup例子 实现弹出窗口的关闭"这个主题聚焦于如何在WP应用中设计并实现一个功能完善的弹出窗口(Popup),并且允许用户通过点击弹出窗口外部的任何地方来关闭它。下面我们将详细探讨这一技术。 首先,Popup是...

    ios开发(Popup View)效果源码分享

    本文将详细探讨如何在iOS应用中实现Popup View,并分享相关的源码。 首先,Popup View的核心在于自定义视图控制器。你需要创建一个新的UIViewController子类,并在这个子类中定义弹出视图的布局和内容。这可能包括...

    ios开发(Popup View) 效果源码分享

    本文将详细讲解如何在iOS应用中实现Popup View,并分享相关的源码。 首先,Popup View的设计原理是基于UIView的自定义子类,通过动画效果来实现其出现和消失。我们可以使用Auto Layout来控制Popup View的布局,使其...

    使用ArcGISAPI实现多个弹窗弹出;多个Popup窗体弹出,亲测可用。

    本篇将详细讲解如何使用ArcGIS API 实现多个弹窗(Popup)的弹出功能,这对于展示地图上的详细信息、提供用户交互体验至关重要。 首先,ArcGIS API 提供了Popup类,用于在地图上创建弹窗。Popup对象可以包含图层的...

    iOS-Github上15种弹出视图(Popup View)源码

    在iOS开发中,弹出视图(Popup View)是一种常见的用户界面元素,它通常用于显示临时的通知、选项菜单或者模态对话框。本资源集合包含了从GitHub上精选的15种不同的弹出视图源码,这对于开发者来说是一个宝贵的参考...

    android popup实现

    View popupView = LayoutInflater.from(context).inflate(R.layout.popup_layout, null); // 实例化PopupWindow,传入View和宽度、高度 PopupWindow popupWindow = new PopupWindow(popupView, ViewGroup....

    分享popup实现.zip

    这个"分享popup实现.zip"压缩包文件很可能包含了一个关于如何在Android应用中实现分享功能的PopupWindow实例。现在,我们将深入探讨PopupWindow的原理、使用方法以及如何在实际项目中实现分享功能。 首先,...

    android 分享popup实现源码.rar

    在Android开发中,"分享popup实现源码"通常是指如何创建一个弹出式窗口(PopupWindow)来展示分享选项,让用户能够将内容分享到不同的应用或平台。PopupWindow是Android SDK提供的一种轻量级的弹出组件,它可以悬浮...

    安卓源码分享popup实现.zip

    这份“安卓源码分享popup实现.zip”压缩包很可能包含了一个关于如何在Android应用中实现PopupWindow的示例代码。 PopupWindow的使用主要包括以下几个关键步骤: 1. **创建PopupWindow实例**:首先,你需要创建一个...

    点击按钮后,出现一个popup

    View popupView = inflater.inflate(R.layout.popup_list, null); PopupWindow popupWindow = new PopupWindow(popupView, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); ``` 3. ...

    (0060)-iOS/iPhone/iPAD/iPod源代码-弹出视图(Popup View)-TableView Within Alert

    本资源"(0060)-iOS/iPhone/iPAD/iPod源代码-弹出视图(Popup View)-TableView Within Alert"提供了一个在弹出对话框中集成UITableView的实现方式,使得用户可以在一个警告视图(UIAlertView)内进行选择操作...

    (0095)-iOS/iPhone/iPAD/iPod源代码-弹出视图(Popup View)-Hidden Option Panel

    在本资源"(0095)-iOS/iPhone/iPAD/iPod源代码-弹出视图(Popup View)-Hidden Option Panel"中,开发者提供了一种实现这一功能的方法。 首先,让我们深入理解核心概念: 1. **Panel(面板)**:在iOS中,...

    C#自定义控件--Popup窗口提醒完整源码__0525).rar

    本资源“C#自定义控件--Popup窗口提醒完整源码__0525).rar”提供了一种具体的自定义控件实现,即Popup窗口提醒功能的源代码。Popup窗口在许多应用中都十分常见,通常用来显示临时通知、提示或者菜单。 Popup窗口在...

    qml stackview实现安卓back键返回 和正常状态下的双击退出(全局过滤)

    本篇文章将深入探讨如何使用QML的StackView组件来实现Android的back键返回功能,以及在正常状态下通过双击退出应用的全局过滤器。我们将主要关注QML和Qt for Android的相关技术。 首先,让我们了解QML的StackView...

    分享popup实现.zip项目安卓应用源码下载

    在"分享popup实现.zip"项目中,我们可以深入学习如何在安卓应用中有效地使用PopupWindow。 首先,PopupWindow的基本使用涉及到以下几个关键步骤: 1. **创建PopupWindow对象**:你需要通过`new PopupWindow(view, ...

    Android 分享popup实现-IT计算机-毕业设计.zip

    为了实现分享popup,我们需要先创建一个布局文件,其中包含一个ListView或者RecyclerView,用于显示可选择的分享应用列表。然后,将这个布局加载到PopupWindow中,并设置其位置、大小等属性。 对于ListView或...

    仿微信popup window

    在Android应用开发中,...总的来说,“仿微信popup window”的实现涉及到Android的PopupWindow类、自定义动画、布局设计以及触摸事件处理等多个方面,理解并掌握这些知识点对于提升Android应用的用户体验具有重要意义。

    (0124)-iOS/iPhone/iPAD/iPod源代码-弹出视图(Popup View)-UITextField within Alert Prompt

    标题提到的"iOS/iPhone/iPAD/iPod源代码-弹出视图(Popup View)-UITextField within Alert Prompt"着重于在弹出视图,特别是`UIAlertView`中添加文本输入字段(`UITextField`),以实现如登录框这样的功能。...

    Android-Android开发使用PupopWindow在指定View的上下左右动态显示菜单列表

    View popupView = inflater.inflate(R.layout.popup_menu, null); PopupWindow popupWindow = new PopupWindow(popupView, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); ``` 接着...

Global site tag (gtag.js) - Google Analytics