UIGraphicsBeginImageContext和UIGraphicsBeginImageContextWithOptions

UIGraphicsBeginImageContext
创建一个基于位图的上下文(context),并将其设置为当前上下文(context)。方法声明如下:

void UIGraphicsBeginImageContext(CGSize size);

参数size为新创建的位图上下文的大小。它同时是由UIGraphicsGetImageFromCurrentImageContext函数返回的图形大小。
该函数的功能同UIGraphicsBeginImageContextWithOptions的功能相同,相当与UIGraphicsBeginImageContextWithOptions的opaque参数为NO,scale因子为1.0。

UIGraphicsBeginImageContextWithOptions
函数原型为:

void UIGraphicsBeginImageContextWithOptions(CGSize size, BOOL opaque, CGFloat scale);

size——同UIGraphicsBeginImageContext
opaque—透明开关,如果图形完全不用透明,设置为YES以优化位图的存储。
scale—–缩放因子

 

这里需要判断一下UIGraphicsBeginImageContextWithOptions是否为NULL,因为它是iOS 4.0才加入的。

由于JPEG图像是不透明的,所以第二个参数就设为YES。

第三个参数是缩放比例,iPhone 4是2.0,其他是1.0。虽然这里可以用[UIScreen mainScreen].scale来获取,但实际上设为0后,系统就会自动设置正确的比例了。

值得一提的是,图像本身也有缩放比例,普通的图像是1.0(除了UIImage imageNamed:外,大部分API都只能获得这种图像,而且缩放比例是不可更改的),高清图像是2.0。图像的点和屏幕的像素就是依靠2者的缩放比例来计算的,例如普通图像在视网膜显示屏上是1:4,而高清图像在视网膜显示屏上则是1:1。

接下来的drawInRect:把图像画到了当前的image context里,这时就完成了解压缩和重采样的工作了。然后再从image context里获取新的image,这个image的缩放比例也能正确地和设备匹配。

再点下按钮,发现时间已经缩短到12微秒左右了,之后的画图稳定在15微秒左右。

– (UIImage*) takeScreenshot

{

// for the entire screen

// UIWindow *screenWindow = [[UIApplication sharedApplication] keyWindow];

// UIGraphicsBeginImageContext(screenWindow.frame.size);

// [screenWindow.layer renderInContext:UIGraphicsGetCurrentContext()];

 

// for just the current view (self)

if (iosVersionIsAtLeast(4.0))

UIGraphicsBeginImageContextWithOptions(self.frame.size, NO, 0.0);

else

UIGraphicsBeginImageContext(self.frame.size);

 

[self.layer renderInContext:UIGraphicsGetCurrentContext()];

// save to UIImage

UIImage *screenshot = UIGraphicsGetImageFromCurrentImageContext();

UIGraphicsEndImageContext();

return screenshot;

}

takeScreenShot returns a UIImage object that can then be written out to a png, attached to an email, or put into a new UIImageView to be animated.

If you are running iOS 4 or greater and your device has a retina screen, use UIGraphicsBeginImageContextWithOptions instead of UIGraphicsBeginImageContext. Setting the scale (3rd) argument to 0.0 keeps the scale to that of the device’s screen.

Advertisements

Add a parameter

In TasksViewController.h

+ (NSString*)getTypeFilter;

+ (void)setTypeFilter:(NSString*)filter;

 

In TasksVIewController.m

static NSString *typeFilter;

 

+ (void)setTypeFilter:(NSString *)filter {

typeFilter = filter;

}

 

+ (NSString*)getTypeFilter {

return typeFilter;

}

file folder tree Structure

Screen Shot 2013-08-15 at 3.12.46 AM

– (NSMutableArray *)listItemsAtPath:(NSString *)path {

// NSArray* MessageList = @[@”Message”,@”Discussion”,@”FYI”];
// NSArray* ToDoList = @[@”To Do”,@”Action”,@”Approval”];

NSArray* MessageList = @[TYPE_OPTION_MESSAGE_LS, TYPE_OPTION_DISCUSSION_LS, TYPE_OPTION_FYI_LS];
NSArray* ToDoList = @[TYPE_OPTION_TODO_LS, TYPE_OPTION_ACTION_LS, TYPE_OPTION_APPROVAL_LS];

NSMutableArray* strings = [NSMutableArray array];
[strings addObject:TYPE_OPTION_ALL_LS];
[strings addObject:TYPE_OPTION_MAIL_LS];
[strings addObject:TYPE_OPTION_CHAT_LS];
[strings addObject:TYPE_OPTION_APPROVAL_LS];
// [strings addObject:@”All”];
// [strings addObject:@”Mail”];
// [strings addObject:@”Chat”];

// [strings addObject:@”Announcement”];
[strings addObject:MessageList];
[strings addObject:ToDoList];
item0 = [[CVBaseMenuTreeItem alloc] init];
[item0 setBase:[strings objectAtIndex:0]];
[item0 setPath:@”/”];
[item0 setSubmersionLevel:0];
[item0 setParentSelectingItem:nil];
[item0 setAncestorSelectingItems:[NSMutableArray arrayWithObjects:item1, item2, item3, item4, item5, nil]];
[item0 setNumberOfSubitems:5];

item1 = [[CVBaseMenuTreeItem alloc] init];
[item1 setBase:[strings objectAtIndex:1]];
[item1 setPath:[NSString stringWithFormat:@”/%@”,[strings objectAtIndex:0]]];
[item1 setSubmersionLevel:1];
[item1 setParentSelectingItem:item0];
[item1 setAncestorSelectingItems:[NSMutableArray array]];
[item1 setNumberOfSubitems:0];

item2 = [[CVBaseMenuTreeItem alloc] init];
[item2 setBase:[strings objectAtIndex:2]];
[item2 setPath:[NSString stringWithFormat:@”/%@”,[strings objectAtIndex:0]]];
[item2 setSubmersionLevel:1];
[item2 setParentSelectingItem:item0];
[item2 setAncestorSelectingItems:[NSMutableArray array]];
[item2 setNumberOfSubitems:0];

item3 = [[CVBaseMenuTreeItem alloc] init];
[item3 setBase:[strings objectAtIndex:3]];
[item3 setPath:[NSString stringWithFormat:@”/%@”,[strings objectAtIndex:0]]];
[item3 setSubmersionLevel:1];
[item3 setParentSelectingItem:item0];
[item3 setAncestorSelectingItems:[NSMutableArray array]];
[item3 setNumberOfSubitems:0];

item4 = [[CVBaseMenuTreeItem alloc] init];
[item4 setBase:[[strings objectAtIndex:4] objectAtIndex:0]];
[item4 setPath:[NSString stringWithFormat:@”/%@”,[strings objectAtIndex:0]]];
[item4 setSubmersionLevel:1];
[item4 setParentSelectingItem:item0];
[item4 setAncestorSelectingItems:[NSMutableArray arrayWithObjects:item4_1, item4_2, nil]];
[item4 setNumberOfSubitems:2];

item4_1 = [[CVBaseMenuTreeItem alloc] init];
[item4_1 setBase:[[strings objectAtIndex:4] objectAtIndex:1]];
[item4_1 setPath:[NSString stringWithFormat:@”/%@/%@”,[strings objectAtIndex:0], [[strings objectAtIndex:4] objectAtIndex:0]]];
[item4_1 setSubmersionLevel:2];
[item4_1 setParentSelectingItem:item4];
[item4_1 setAncestorSelectingItems:[NSMutableArray array]];
[item4_1 setNumberOfSubitems:0];

item4_2 = [[CVBaseMenuTreeItem alloc] init];
[item4_2 setBase:[[strings objectAtIndex:4] objectAtIndex:2]];
[item4_2 setPath:[NSString stringWithFormat:@”/%@/%@”,[strings objectAtIndex:0], [[strings objectAtIndex:4] objectAtIndex:0]]];
[item4_2 setSubmersionLevel:2];
[item4_2 setParentSelectingItem:item4];
[item4_2 setAncestorSelectingItems:[NSMutableArray array]];
[item4_2 setNumberOfSubitems:0];

item5 = [[CVBaseMenuTreeItem alloc] init];
[item5 setBase:[[strings objectAtIndex:5] objectAtIndex:0]];
[item5 setPath:[NSString stringWithFormat:@”/%@”,[strings objectAtIndex:0]]];
[item5 setSubmersionLevel:1];
[item5 setParentSelectingItem:item0];
[item5 setAncestorSelectingItems:[NSMutableArray arrayWithObjects:item5_1, item5_2, nil]];
[item5 setNumberOfSubitems:2];

item5_1 = [[CVBaseMenuTreeItem alloc] init];
[item5_1 setBase:[[strings objectAtIndex:5] objectAtIndex:1]];
[item5_1 setPath:[NSString stringWithFormat:@”/%@/%@”,[strings objectAtIndex:0], [[strings objectAtIndex:5] objectAtIndex:0]]];
[item5_1 setSubmersionLevel:2];
[item5_1 setParentSelectingItem:item5];
[item5_1 setAncestorSelectingItems:[NSMutableArray array]];
[item5_1 setNumberOfSubitems:0];

item5_2 = [[CVBaseMenuTreeItem alloc] init];
[item5_2 setBase:[[strings objectAtIndex:5] objectAtIndex:2]];
[item5_2 setPath:[NSString stringWithFormat:@”/%@/%@”,[strings objectAtIndex:0], [[strings objectAtIndex:5] objectAtIndex:0]]];
[item5_2 setSubmersionLevel:2];
[item5_2 setParentSelectingItem:item5];
[item5_2 setAncestorSelectingItems:[NSMutableArray array]];
[item5_2 setNumberOfSubitems:0];

NSLog(@”%@”, path);
if ([path isEqualToString:@”/”]) {
return [NSMutableArray arrayWithObject:item0];
} else if ([path isEqualToString:[NSString stringWithFormat:@”/%@”,[strings objectAtIndex:0]]]) {
return [NSMutableArray arrayWithObjects:item1, item2, item3, item4, item5, nil];
} else if ([path isEqualToString:[NSString stringWithFormat:@”/%@/%@”,[strings objectAtIndex:0], [[strings objectAtIndex:4] objectAtIndex:0]]]) {
return [NSMutableArray arrayWithObjects:item4_1, item4_2, nil];
} else if ([path isEqualToString:[NSString stringWithFormat:@”/%@/%@”,[strings objectAtIndex:0], [[strings objectAtIndex:5] objectAtIndex:0]]]) {
return [NSMutableArray arrayWithObjects:item5_1, item5_2, nil];
} else {
return [NSMutableArray array];
}
}

Delegate example

Target: PolldownMenuViewController (popover) pass a value to TasksViewController.

1.  In PolldownMenuViewControllerDelegate.h file, create a protocol and its property.

     @protocol PolldownMenuViewControllerDelegate <NSObject>

     – (void)didSelectTypeFilter:(NSString*)filter;

     @end

     @property (nonatomic, unsafe_unretained) id<PolldownMenuViewControllerDelegate> delegate;

Then, trigger the delegate function to require popover pass it to TasksViewController

     – (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
     BaseMenuTreeTableViewCell* cell = (BaseMenuTreeTableViewCell*)[tableView cellForRowAtIndexPath:indexPath];
     if (_delegate && [_delegate respondsToSelector:@selector(didSelectTypeFilter:)])
           [_delegate didSelectTypeFilter:cell.treeItem.base];

 

2.  In TasksViewController.m file, declare need PolldownMenu~Delegate and implement delegate function.

     @interface TasksViewController () <UIActionSheetDelegate, CVDataModelDelegate, UITableViewDelegate, UISearchBarDelegate, RowItemDelegate, PolldownMenuViewControllerDelegate>

     #pragma mark – 
     #pragma mark PolldownMenuViewControllerDelegate

     – (void)didSelectTypeFilter:(NSString*)filter {

          if ([filter isEqualToString:TYPE_OPTION_ALL_LS]) {
                [_model updateWithType:TASK_TYPE_ALL];
          } else if ([filter isEqualToString:TYPE_OPTION_MESSAGE_LS]) {
                [_model updateWithType:TASK_TYPE_MESSAGE];
          } else if ([filter isEqualToString:TYPE_OPTION_MAIL_LS]) {
                [_model updateWithType:TASK_TYPE_MAIL];
          } else if ([filter isEqualToString:TYPE_OPTION_DISCUSSION_LS]) {
                [_model updateWithType:TASK_TYPE_DISCUSSION];
          } else if ([filter isEqualToString:TYPE_OPTION_FYI_LS]) {
                [_model updateWithType:TASK_TYPE_FYI];
          } else if ([filter isEqualToString:TYPE_OPTION_CHAT_LS]) {
                [_model updateWithType:TASK_TYPE_CHAT];
          } else if ([filter isEqualToString:TYPE_OPTION_TODO_LS]) {
                [_model updateWithType:TASK_TYPE_TODO];
          } else if ([filter isEqualToString:TYPE_OPTION_ACTION_LS]) {
                [_model updateWithType:TASK_TYPE_ACTION];
          }else if ([filter isEqualToString:TYPE_OPTION_APPROVAL_LS]) {
                [_model updateWithType:TASK_TYPE_APPROVAL];
          } else {
                [_model updateWithType:TASK_TYPE_ALL];
          }
          [_typeButton setTitle:filter forState:UIControlStateNormal];
          [self showLoading:YES];

          [_popoverForSource dismissPopoverAnimated:YES];      //cause in property, there is a 

@property(nonatomic, retain) UIPopoverController* popoverForSource;, we could use it directly.

          return;
     }

3.   We also need to set a delegate for PolldownViewController side. Since we have never set a delegate for polldownViewController.

    – (void) typeItemTouched {

          _nav = [[PolldownMenuViewController alloc]initWithDelegate:self];

For PolldownMenuViewController.h, add: 

     – (id)initWithDelegate:(id<CVPolldownMenuViewControllerDelegate>)delegate;

For PolldownMenuViewController.m, add:

     – (id)initWithDelegate:(id<CVPolldownMenuViewControllerDelegate>)delegate {
          if (self = [super init])
                self.delegate = delegate;
     return self;
    }

Result:

 

 

Image

Image

Customizing UIPopover with UIPopoverBackgroundView 1-1

requirement: iOS SDK 5.0 or later.

UIPopoverBackgroundView class

Example code:

1
2
yourPopoverController.popoverBackgroundViewClass
    = [YourCustomPopoverBackgorundView class];

Properties and class methods

Class methods:

  • arrowHeight – the height of the arrow (measured in points) from its base to its tip.
  • arrowBase – the width of the arrow triangle at its base.
  • contentViewInsets – the insets for the content portion of the popover.

Properties:

  • arrowOffset – the distance (measured in points) from the center of the view to the center line of the arrow (arrowOffset has negative value if left from center, positive if right from center)
  • arrowDirection – the direction in which the popover arrow is pointing: UIPopoverArrowDirection(Up / Down / Left / Right / Any / Unknown)

Example code:

 
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
+ (CGFloat)arrowBase
{
    return ARROW_WIDTH;
}

+ (CGFloat)arrowHeight
{
    return ARROW_HEIGHT;
}
+ (UIEdgeInsets)contentViewInsets{
    return UIEdgeInsetsMake(TOP_CONTENT_INSET, LEFT_CONTENT_INSET,
                            BOTTOM_CONTENT_INSET, RIGHT_CONTENT_INSET);
}

// Custom setters

// Whenever arrow changes direction or position layout subviews
// will be called in order to update arrow and backgorund images frames

-(void) setArrowOffset:(CGFloat)arrowOffset
{
    _arrowOffset = arrowOffset;
    [self setNeedsLayout];
}

-(void) setArrowDirection:(UIPopoverArrowDirection)arrowDirection
{
    _arrowDirection = arrowDirection;
    [self setNeedsLayout];
}

Additional properties and iVars

There are two properties of UIImageView in my subclass implementation. I use them to layout stretchable background images (arrow + background)

Example code:

1
2
@property (nonatomic, strong) UIImageView *arrowImageView;
@property (nonatomic, strong) UIImageView *popoverBackgroundImageView;
They are initialized in initWithFrame: method.

Example code:

 
01
02
03
04
05
06
07
08
09
10
UIImage *popoverBackgroundImage
    = [[UIImage imageNamed:@"popover-black-bcg-image.png"]
            resizableImageWithCapInsets:UIEdgeInsetsMake(49, 46, 49, 45)];

self.popoverBackgroundImageView
           = [[UIImageView alloc] initWithImage:popoverBackgroundImage];
[self addSubview:self.popoverBackgroundImageView];

self.arrowImageView = [[UIImageView alloc] init];
[self addSubview:self.arrowImageView];

Additionally, in my class implementation file I made private interface with 4 UIImage iVars. One of  images is going to be set as arrowImageView.image later in layoutSubviews method, when I calculate other frames using arrowDirection property.

Example code:

1
2
3
4
5
6
7
8
9
@interface GTPopoverBackgorundView ()
{
    UIImage *_topArrowImage;
    UIImage *_leftArrowImage;
    UIImage *_rightArrowImage;
    UIImage *_bottomArrowImage;
}

@end
UIImage iVars are initialized in initWithFrame: method with appropriate images.

Example code:

 
1
2
3
4
_topArrowImage = [UIImage imageNamed:@"popover-black-top-arrow-image.png"];
_leftArrowImage = [UIImage imageNamed:@"popover-black-left-arrow-image.png"];
_bottomArrowImage = [UIImage imageNamed:@"popover-black-bottom-arrow-image.png"];
_rightArrowImage = [UIImage imageNamed:@"popover-black-right-arrow-image.png"];

layoutSubviews

The most important part of subclass is layoutSubviews method. It layouts arrow and background images according to popover size (self.bounds.size), arrow position (arrowOffset) and arrow direction (arrowDirection). Also popover arrow image is changed here for appropriate direction.

Example code:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
-(void)layoutSubviews
{
    CGFloat popoverImageOriginX = 0;
    CGFloat popoverImageOriginY = 0;

    CGFloat popoverWidth = self.bounds.size.width;
    CGFloat popoverHeight = self.bounds.size.height;

    CGFloat arrowImageOriginX = 0;
    CGFloat arrowImageOriginY = 0;

    CGFloat arrowImageWidth = ARROW_WIDTH;
    CGFloat arrowImageHeight = ARROW_HEIGHT;

    // Radius value you used to make rounded corners
    // in your popover background image
    CGFloat cornerRadius = 9;

    switch (self.arrowDirection) {

        case UIPopoverArrowDirectionUp:

            popoverImageOriginY = ARROW_HEIGHT - 2;
            popoverImageHeight = self.bounds.size.height - ARROW_HEIGHT;

            // Calculating arrow x position using arrow offset,
            // arrow width and popover width
            arrowImageOriginX = roundf((self.bounds.size.width
                                         - ARROW_WIDTH) / 2 + self.arrowOffset);

            // If arrow image exceeds rounded corner,
            // arrow image x postion is adjusted
            if (arrowImageOriginX + ARROW_WIDTH
                             > self.bounds.size.width - cornerRadius)
            {
                arrowImageOriginX -= cornerRadius;
            }

            if (arrowImageOriginX < cornerRadius)
            {
                arrowImageOriginX += cornerRadius;
            }

            // Setting arrow image for current arrow direction
            self.arrowImageView.image = _topArrowImage;

            break;

        case UIPopoverArrowDirectionDown:

            // Similar like in UIPopoverArrowDirectionUp case

            break;

        case UIPopoverArrowDirectionLeft:

            // Similar like in UIPopoverArrowDirectionUp case

            break;

        case UIPopoverArrowDirectionRight:

            // Similar like in UIPopoverArrowDirectionUp case

            break;

        default:

            // For popovers without arrows (Thanks Martin!)

            popoverImageHeight = self.bounds.size.height - ARROW_HEIGHT + 2;
            break;
    }

    self.popoverBackgroundImageView.frame = CGRectMake(popoverImageOriginX,
             popoverImageOriginY, popoverWidth, popoverHeight);
    self.arrowImageView.frame = CGRectMake(arrowImageOriginX,
             arrowImageOriginY, arrowImageWidth, arrowImageHeight);
}

Result

BTW,

popover size_____

_nav.contentSizeForViewInPopover=CGSizeMake(200, 420);
_popoverForSource = [[UIPopoverController alloc]initWithContentViewController:_nav];

ocean-coding-family