Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Tint Color Support #1

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions GIKPopoverBackgroundView-Example/GIKViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
segueIdentifier = segue.identifier;
popoverController = [(UIStoryboardPopoverSegue *)segue popoverController];
popoverController.popoverBackgroundViewClass = [GIKPopoverBackgroundView class];
// popoverController.popoverBackgroundViewClass = [GIKPopoverBackgroundView class];
popoverController.popoverBackgroundViewClass = [GIKPopoverBackgroundView classWithTintColor:[UIColor redColor]];

if ([segue.identifier isEqualToString:@"popover2"])
{
Expand All @@ -49,9 +50,9 @@ - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
- (void)applyTitleTextAttributesToNavigationBar:(UINavigationBar *)navBar
{
NSDictionary *attributes = @{ UITextAttributeTextColor : [UIColor colorWithRed:122.0/255.0 green:120.0/255.0 blue:114.0/255.0 alpha:1.0],
UITextAttributeTextShadowColor : [UIColor whiteColor],
UITextAttributeTextShadowOffset : [NSValue valueWithCGSize:(CGSize){ .width = 0.0, .height = 1.0}] };

UITextAttributeTextShadowColor : [UIColor whiteColor],
UITextAttributeTextShadowOffset : [NSValue valueWithCGSize:(CGSize){ .width = 0.0, .height = 1.0}] };
[navBar setTitleTextAttributes:attributes];
}

Expand Down
3 changes: 2 additions & 1 deletion GIKPopoverBackgroundView/GIKPopoverBackgroundView.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
// Layout of images will be handled automatically, and it works with all values of UIPopoverArrowDirection.

#import <UIKit/UIKit.h>

#import <QuartzCore/QuartzCore.h>
/**
Image-specific values for calulating the background's layout.
*/
Expand Down Expand Up @@ -60,6 +60,7 @@ static const CGFloat kSecondHalfRightInset = 9.0; // Value for .right i
@property (nonatomic, assign) CGFloat arrowOffset;
@property (nonatomic, assign) UIPopoverArrowDirection arrowDirection;

+ (id)classWithTintColor:(UIColor*)color;
+ (CGFloat)arrowHeight;
+ (CGFloat)arrowBase;
+ (UIEdgeInsets)contentViewInsets;
Expand Down
48 changes: 42 additions & 6 deletions GIKPopoverBackgroundView/GIKPopoverBackgroundView.m
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
//

#import "GIKPopoverBackgroundView.h"
#import <QuartzCore/QuartzCore.h>

// A struct containing the min and max horizontal and vertical positions for the popover arrow. If the arrow's position exceeds these limits, the PopoverBackgroundArrow[UpRight|DownRight|SideTop|SideBottom].png images are drawn.
struct GIKPopoverExtents {
Expand All @@ -27,6 +26,7 @@ @interface GIKPopoverBackgroundView () {

@end

static UIColor *tintColor = nil;

@implementation GIKPopoverBackgroundView

Expand All @@ -36,6 +36,15 @@ @implementation GIKPopoverBackgroundView

#pragma mark - UIPopoverBackgroundView required values

+ (id)classWithTintColor:(UIColor*)color
{
Class class = [super class];
if (class) {
tintColor = color;
}
return class;
}

+ (UIEdgeInsets)contentViewInsets
{
return kPopoverEdgeInsets;
Expand Down Expand Up @@ -119,7 +128,7 @@ - (void)addDropShadowIfNecessary
- (void)layoutSubviews
{
[super layoutSubviews];

_popoverExtents = (GIKPopoverExtents){
.left = CGRectGetMinX(self.bounds) + kPopoverCornerRadius,
.right = CGRectGetMaxX(self.bounds) - kPopoverCornerRadius,
Expand All @@ -134,7 +143,7 @@ - (void)layoutSubviews
self.popoverBackground.center = self.center;
self.popoverBackground.bounds = self.bounds;

self.popoverBackground.image = [self wantsUpOrDownArrow] ? [self upOrDownArrowImage] : [self sideArrowImage];
self.popoverBackground.image = [self wantsUpOrDownArrow] ? [self upOrDownArrowImage] : [self sideArrowImage];
}


Expand Down Expand Up @@ -220,7 +229,7 @@ - (BOOL)isArrowAtBottomEdgeOfPopover { return (_arrowCenter + _halfBase > _popov

- (void)adjustCentersIfNecessary
{
// fix centers of left-pointing popovers so that their shadows are drawn correctly.
// fix centers of left-pointing popovers so that their shadows are drawn correctly.
if (self.arrowDirection == UIPopoverArrowDirectionLeft)
{
self.center = (CGPoint){ .x = self.center.x + [GIKPopoverBackgroundView arrowHeight], .y = self.center.y };
Expand All @@ -233,13 +242,13 @@ - (void)adjustCentersIfNecessary

- (UIImage *)stretchableImageNamed:(NSString *)name insets:(UIEdgeInsets)insets mirrored:(BOOL)mirrored
{
UIImage *image = [UIImage imageNamed:name];
UIImage *image = (tintColor) ? [self tintedImage:[UIImage imageNamed:name] usingColor:tintColor] : [UIImage imageNamed:name];
return (mirrored) ? [[self mirroredImage:image] resizableImageWithCapInsets:[self mirroredInsets:insets]] : [image resizableImageWithCapInsets:insets];
}

- (UIImage *)twoPartStretchableImageNamed:(NSString *)name insets:(UIEdgeInsets)insets
{
UIImage *image = [UIImage imageNamed:name];
UIImage *image = (tintColor) ? [self tintedImage:[UIImage imageNamed:name] usingColor:tintColor] : [UIImage imageNamed:name];

if (self.arrowDirection == UIPopoverArrowDirectionLeft)
{
Expand Down Expand Up @@ -300,4 +309,31 @@ - (UIImage *)imageFromImageContextWithSourceImage:(UIImage *)image size:(CGSize)
return result;
}

- (UIImage *)tintedImage:(UIImage*)image usingColor:(UIColor *)tintColor;
{
UIGraphicsBeginImageContextWithOptions(image.size, NO, 1.0);
CGContextRef context = UIGraphicsGetCurrentContext();
CGRect rect = CGRectMake(0, 0, image.size.width, image.size.height);

// draw original image
[image drawInRect:rect blendMode:kCGBlendModeNormal alpha:1.0f];

// tint image (loosing alpha).
// kCGBlendModeOverlay is the closest I was able to match the
// actual process used by apple in navigation bar
// kCGBlendModeMultiply is used currently because it provides
// the best replacement of image. The overlay mode will create
// just that an overlay, the color will seem washed out.
CGContextSetBlendMode(context, kCGBlendModeMultiply);
[tintColor setFill];
CGContextFillRect(context, rect);

// mask by alpha values of original image
[image drawInRect:rect blendMode:kCGBlendModeDestinationIn alpha:1.0f];

UIImage *tintedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return tintedImage;
}

@end
54 changes: 54 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,40 @@ The documentation for `UIPopoverBackgroundView` states that `-setArrowOffset:` i
}
```

### Tint support

PopoverControls have historically never supported tinting of the view. This fork contains the ability to use the tint function added.

Tinting was achieved by adding a method to modify the images that are included on the fly.

``` objective-c
- (UIImage *)tintedImage:(UIImage*)image usingColor:(UIColor *)tintColor;
{
UIGraphicsBeginImageContextWithOptions(image.size, NO, 1.0);
CGContextRef context = UIGraphicsGetCurrentContext();
CGRect rect = CGRectMake(0, 0, image.size.width, image.size.height);

// draw original image
[image drawInRect:rect blendMode:kCGBlendModeNormal alpha:1.0f];

// tint image (loosing alpha).
// kCGBlendModeOverlay is the closest I was able to match the
// actual process used by apple in navigation bar
CGContextSetBlendMode(context, kCGBlendModeMultiply);
[tintColor setFill];
CGContextFillRect(context, rect);

// mask by alpha values of original image
[image drawInRect:rect blendMode:kCGBlendModeDestinationIn alpha:1.0f];

UIImage *tintedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return tintedImage;
}
```

From the method above we can see that we are modifying the image by setting the blend mode of the image to multiply for a better color replacement. Overlay mode is included but commented out because it creates a more washed out image.

## Usage

To use, add GIKPopoverBackgroundView.h and GIKPopoverBackgroundView.m to your Xcode project. Feel free to use the supplied images (found in the example project) and their default `UIEdgeInsets` values. In the view controller which manages your popover controller, set the popover controller's `popoverBackgroundViewClass` property:
Expand All @@ -84,9 +118,23 @@ popoverController = [(UIStoryboardPopoverSegue *)segue popoverController];
popoverController.popoverBackgroundViewClass = [GIKPopoverBackgroundView class];
```

to use the tint option, add GIKPopoverBackgroundView.h and .m as you would before.

``` objective-c
popoverController = [(UIStoryboardPopoverSegue *)segue popoverController];
popoverController.popoverBackgroundViewClass = [GIKPopoverBackgroundView classWithTintColor:(UIColor*)];
```

## Sample Project

The included sample project covers a number of scenarios where source images are stretched twice, mirrored, and animated in response to keyboard appearance.
The original images can be seen by uncommenting the line in the GIKViewController.m

```objective-c
popoverController.popoverBackgroundViewClass = [GIKPopoverBackgroundView class];
```



## Requirements

Expand All @@ -101,12 +149,18 @@ GIKPopoverBackgroundView uses ARC and requires iOS 5.0 or above.

GIKPopoverBackgroundView was created by [Gordon Hughes](https://github.com/gik/).

Tint Support Added By [Eric Rolf](https://github.com/xrolfex/).

## Contact

[Gordon Hughes](https://github.com/gik/)

[@gordonhughes](http://twitter.com/gordonhughes)

[Eric Rolf](https://github.com/xrolfex/)

[@Eric_Rolf](https://twitter.com/eric_rolf)

## License

GIKPopoverBackgroundView is available under the MIT license. See the LICENSE file for more information.