UIPopoverPresentationController 背景が透明で奥のレイヤーが見えるポップオーバーにする

5 min read読了の目安(約3500字

目的

下記のようなアプリがある場合にポップオーバーを表示するとこうなりますよね。

このように緑色のUIViewを透かしたい場合があるのですが、

うっすら見えますけども、透明ではないですよね。

手順

UIPopoverBackgroundViewのサブクラスを追加する。
UIPopoverPresentationControllerのプロパティ.popoverBackgroundViewClassに❶のクラスを指定する。

##実装(Objective-C)


### ViewController.m
#import "ViewController.h"

@interface ViewController ()<UIPopoverPresentationControllerDelegate>

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.
}

// ボタン押下後に呼び出される。
- (IBAction)tapButton:(id)sender {
    TableViewController *vc = [[TableViewController alloc]init];
    [self presentPopOverWithViewController:vc sourceView:sender];
}



- (void)presentPopOverWithViewController:(UIViewController *)viewController sourceView:(UIView *)sourceView
{
    viewController.modalPresentationStyle = UIModalPresentationPopover;
    viewController.preferredContentSize = CGSizeMake(300.0, 44.0 * 5);

    UIPopoverPresentationController *presentationController = viewController.popoverPresentationController;

    //下記記述が重要
    presentationController.popoverBackgroundViewClass = [PopoverBackgroundView class];

    presentationController.delegate = self;
    presentationController.permittedArrowDirections = UIPopoverArrowDirectionUp;
    presentationController.sourceView = sourceView;
    presentationController.sourceRect = sourceView.bounds;

    [self presentViewController:viewController animated:YES completion:NULL];
}

//iPhoneでの描画に大きく関係するのでしっかり追加しておく
- (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller
{
    return UIModalPresentationNone;
}
@end 

PopoverBackgroundView.h

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface PopoverBackgroundView : UIPopoverBackgroundView

@end

NS_ASSUME_NONNULL_END

@end

###PopoverBackgroundView.m

// PopoverBackgroundView.m
#import "PopoverBackgroundView.h"

@interface PopoverBackgroundView ()
{
  CGFloat _arrowOffset;
  UIPopoverArrowDirection _arrowDirection;
}
@end

@implementation PopoverBackgroundView
+ (CGFloat)arrowHeight
{
  return 0.0f;
}

+ (UIEdgeInsets)contentViewInsets
{
  return UIEdgeInsetsMake(0.0f, 0.0f, 0.0f, 0.0f);
}

- (UIPopoverArrowDirection)arrowDirection
{
  return _arrowDirection;
}

- (void)setArrowDirection:(UIPopoverArrowDirection)arrowDirection
{
  _arrowDirection = arrowDirection;
}

- (CGFloat)arrowOffset
{
  return _arrowOffset;
}

- (void)setArrowOffset:(CGFloat)arrowOffset
{
  _arrowOffset = arrowOffset;
}

- (void)layoutSubviews
{
  [super layoutSubviews];
  self.layer.shadowOpacity = 0.0f;
}
@end

変更後は下記スクリーンショットのようになります。
<img width="375" alt="Simulator Screen Shot - iPhone 8 - 2020-03-01 at 17.15.22.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551622/b573a3eb-f1f4-16fd-9c24-d56bc34a35b7.png">

##実際に開発現場でどのように使われてくるか
デザイナーさんが**「ポップオーバーを押下したレイヤーの上に透明に重なるように」という意図を持って、**透過がある画像ファイルを作成してくださった際に、ただポップオーバー上に表示するだけではレイヤーの上に透明に重なるようには実装できません。

なのでポップオーバーの背景自体を透明色を適用する必要があります。

謝辞

下記記事を引用しております。
Xcode11、またUIPopoverPresentationControllerと明記していなかったのでこちらの記事を出させていただきました。
UIPopoverControllerの背景色を透明にする

本記事含め他の記事は「長時間1人で悩んで不安やストレスフルな方を解決したい」という一心で更新しております。少額でも構いませんのでサポートしていただけますと記事更新のモチベーションになりますので、御援助いただけますと助かります。