{"id":18270533,"url":"https://github.com/GiK/GIKPopoverBackgroundView","last_synced_at":"2025-04-05T01:30:42.108Z","repository":{"id":6263300,"uuid":"7496349","full_name":"GiK/GIKPopoverBackgroundView","owner":"GiK","description":"GIKPopoverBackgroundView is a UIPopoverBackgroundView subclass which shows how to customise the background of a UIPopoverController.","archived":false,"fork":false,"pushed_at":"2016-04-25T20:38:50.000Z","size":1004,"stargazers_count":526,"open_issues_count":5,"forks_count":48,"subscribers_count":30,"default_branch":"master","last_synced_at":"2025-04-02T17:52:13.161Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Objective-C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/GiK.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2013-01-08T05:46:51.000Z","updated_at":"2024-06-13T09:39:53.000Z","dependencies_parsed_at":"2022-09-12T21:21:40.334Z","dependency_job_id":null,"html_url":"https://github.com/GiK/GIKPopoverBackgroundView","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GiK%2FGIKPopoverBackgroundView","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GiK%2FGIKPopoverBackgroundView/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GiK%2FGIKPopoverBackgroundView/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GiK%2FGIKPopoverBackgroundView/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/GiK","download_url":"https://codeload.github.com/GiK/GIKPopoverBackgroundView/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247276022,"owners_count":20912285,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-05T11:38:41.985Z","updated_at":"2025-04-05T01:30:41.018Z","avatar_url":"https://github.com/GiK.png","language":"Objective-C","readme":"# GIKPopoverBackgroundView\n\nGIKPopoverBackgroundView is a UIPopoverBackgroundView subclass which uses images similar to those found in UIKit to customise the background of a UIPopoverController.\n\nUnlike most other third-party implementations, GIKPopoverBackgroundView doesn't use separate background and arrow images, so the  appearance is seamless for all orientations. Images can be rendered by using a border color, a gradient from color, and a gradient to color, or they can be provided as files.\n\n## Source Images\n\nThe figure below shows the background images used by Apple's default implementation:\n\n\u003cimg src=\"https://github.com/GiK/GIKPopoverBackgroundView/raw/gh-pages/AppleDefaultBackgroundImages.png\" alt=\"Images making up Apple's default UIPopoverController background\" title=\"Shared artwork images\" style=\"display:block; margin: 10px auto 30px auto;\" class=\"center\"\u003e\n\nThe DownRight, UpRight, SideBottom, and SideTop images are used when the popover is anchored to a control or rect in the corner or edge of a view. A point in the solid dark blue area is defined as the stretchable region using standard `UIEdgeInsets`.\n\nThe Down, Up, and Side images require special handling. To draw a background with an up arrow centered horizontally, the Up image must be stretched twice - once on either side of the arrow.\n\n## Photoshop Source\n\nArrows were created using shape layers and layer styles in Photoshop. The .PSD contains both 1x and 2x shapes for each arrow. Notes for each layer document the Gradient Overlay style's colour stops and values.\n\nThe file is [Slicy](http://macrabbit.com/slicy/) ready for easy exporting to .PNG.\n\n## In Action\n\n[This short screencast](http://d.pr/v/49MN) of the example app demonstrates popovers drawn in a number of orientations from various anchor points. The navigation bar and toolbar of a popover controller take on the appearance of the background view with no additional development effort.\n\n## Implementation Details\n\n### To render or not to render\n\nThe default behavior of GIKPopoverBackgroundView is to render the images needed using three colors. You can change the colors used by creating a custom subclass and overriding the following methods:\n\n``` objective-c\n- (UIColor *)popoverBorderColor;\n- (UIColor *)popoverGradientFromColor;\n- (UIColor *)popoverGradientToColor;\n```\n\nAlternatively, if you would rather provide custom artwork for the images instead of rendering them you can override the following methods in your subclass:\n\n``` objective-c\n- (UIImage *)arrowUpImage;\n- (UIImage *)arrowUpRightImage;\n- (UIImage *)arrowDownImage;\n- (UIImage *)arrowDownRightImage;\n- (UIImage *)arrowSideImage;\n- (UIImage *)arrowSideTopImage;\n- (UIImage *)arrowSideBottomImage;\n\n```\n\nIf you do provide your own image files, and they do not match the dimensions of the rendered images, you will need to override some or all of the following methods:\n\n```objective-c\n+ (CGFloat)arrowHeight;\n+ (CGFloat)arrowBase;\n+ (UIEdgeInsets)contentViewInsets;\n\n- (CGFloat)popoverCornerRadius;\n- (CGFloat)sideArrowCenterOffset;\n\n- (UIEdgeInsets)arrowUpInsets;\n- (UIEdgeInsets)arrowUpRightInsets;\n- (UIEdgeInsets)arrowDownInsets;\n- (UIEdgeInsets)arrowDownRightInsets;\n- (UIEdgeInsets)arrowSideInsets;\n- (UIEdgeInsets)arrowSideTopInsets;\n- (UIEdgeInsets)arrowSideBottomInsets;\n\n- (CGFloat)secondHalfBottomInset;\n- (CGFloat)secondHalfRightInset;\n```\n\n### Measure once, stretch twice\n\nUnsurprisingly, judicious use of UIImage's `-resizableImageWithCapInsets:` method is made throughout. For popovers which require two stretching operations, naively applying cap insets twice won't work. Specifying a stretchable region doesn't affect the underlying image until the image is drawn into a context or a view.\n\nThe approach taken in GIKPopoverBackgroundView is to draw a stretchable image into a bitmap-based graphics context with appropriate size:\n\n``` objective-c\n- (UIImage *)imageFromImageContextWithSourceImage:(UIImage *)image size:(CGSize)size\n{\n  UIGraphicsBeginImageContextWithOptions(size, NO, 0.0);\n  [image drawInRect:(CGRect){ .origin = CGPointZero, .size = size }];\n  UIImage *result = UIGraphicsGetImageFromCurrentImageContext();\n  UIGraphicsEndImageContext();\n  return result;\n}\n```\n\nA second set of cap insets are added to the resultant image and it's this new resizable image which is applied to the popover background's `UIImageView`.\n\n### Mirror, mirror\n\nThe same technique is used for popover backgrounds with any left-facing 'Side' arrows, 'UpLeft', or 'DownLeft' arrows. The source image is flipped horizontally and drawn into a bitmap-based graphics context before having cap insets applied:\n\n``` objective-c\n- (UIImage *)mirroredImage:(UIImage *)image\n{\n  UIImage *mirror = [UIImage imageWithCGImage:image.CGImage scale:[[UIScreen mainScreen] scale] orientation:UIImageOrientationUpMirrored];\n  return [self imageFromImageContextWithSourceImage:mirror size:mirror.size];\n}\n```\n\n### Drop shadows and iOS 5.x\n\nBackground drop shadows don't work on subclasses of UIPopoverBackgroundView if the deployment target is iOS 5.x. If iOS 5 is detected, the drop shadow is drawn using the `shadowPath` of the background layer.\n\nFurther complicating matters on iOS 5, the `shadowPath` property of `CALayer` doesn't respond to implicit animations such as changes to a layer's bounds. If the popover's geometry changes, an explicit animation must be added to the background layer to animate the shadow.\n\nThe documentation for `UIPopoverBackgroundView` states that `-setArrowOffset:` is called inside an animation block managed by the UIPopoverController. This would seem to be the ideal place to sync  the bounds and shadowPath animations. When `-setArrowOffset:` is called, we check the `animationKeys` array of the layer for the existance of a `bounds` key. If found, we know the background's frame is changing - possibly as the result of the keyboard appearing or disappearing. We apply the `timingFunction` and `duration` properties of the bounds animation to a new `CABasicAnimation` for the `shadowPath`.\n\n``` objective-c\n- (void)addShadowPathAnimationIfNecessary:(CGPathRef)pathRef\n{\n  NSArray *animationKeys = [self.popoverBackground.layer animationKeys];\n  if ([animationKeys containsObject:@\"bounds\"])\n  {\n\t  CAAnimation *boundsAnimation = [self.popoverBackground.layer animationForKey:@\"bounds\"];\n\t  CABasicAnimation *shadowPathAnimation = [CABasicAnimation animationWithKeyPath:@\"shadowPath\"];\n\t  shadowPathAnimation.toValue = [NSValue valueWithPointer:pathRef];\n\t  shadowPathAnimation.timingFunction = boundsAnimation.timingFunction;\n\t  shadowPathAnimation.duration = boundsAnimation.duration;\n\t  [self.popoverBackground.layer addAnimation:shadowPathAnimation forKey:@\"shadowPath\"];\n  }\n}\n```\n\n## Usage\n\nTo 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:\n\n``` objective-c\npopoverController = [(UIStoryboardPopoverSegue *)segue popoverController];\npopoverController.popoverBackgroundViewClass = [GIKPopoverBackgroundView class];\n```\n\nTo change the colors of the rendered images, or to use image files, simply subclass GIKPopoverBackgroundView and override the appropriate methods.\n\n## Sample Project\n\nThe included sample project covers a number of scenarios where source images are stretched twice, mirrored, and animated in response to keyboard appearance. It also demonstrates the use of subclassing to override the colors used in rendering, or to override the images used for the popover background.\n\n## Requirements\n\nGIKPopoverBackgroundView uses ARC and requires iOS 5.0 or above.\n\n## //TODO:\n\n- ~~Add source .PSD files for the backgrounds to the repository.~~\n- Discuss how cap insets were chosen to effect two-stage stretching.\n\n## Credits\n\nGIKPopoverBackgroundView was created by [Gordon Hughes](https://github.com/gik/).\n\n## Contact\n\n[Gordon Hughes](https://github.com/gik/)\n\n[@gordonhughes](http://twitter.com/gordonhughes)\n\n## License\n\nGIKPopoverBackgroundView is available under the MIT license. See the LICENSE file for more information.\n","funding_links":[],"categories":["etc"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FGiK%2FGIKPopoverBackgroundView","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FGiK%2FGIKPopoverBackgroundView","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FGiK%2FGIKPopoverBackgroundView/lists"}