問題
画面上 (iOS 4) にカスタム ムービー プレーヤー コントローラーを描画するときは、 を使用しAVPlayerLayer
て表示します。プレーヤーの上にいくつかのオーバーレイ (広告バナー、プレーヤー コントロールなど) を合成したいと考えています。現時点では、これは次の階層でまったく問題なく機能します。
UIView(self.view)\ | | UIView(コントロールビュー)\ * | | UIView [一部のムービー プレーヤー コントロール] | | UIView [その他のムービー プレーヤー コントロール] *
はのAVPlayerLayer
サブレイヤですself.view
。プレーヤーの読み込み時に、最初にレイヤーを追加してself.view
を呼び出しbringSubviewToFront:
、controlsView
次にそのレイヤーのタップを検出し、タイマーなどでプログラムで表示/フェードアウトします。ここでは問題ありません。
広告コンテンツの動的な取得と表示をサポートするようになったので、次の階層を設定したいと思います。
UIView(self.view)\ | | UIImageView (広告バナー) | | UIImageView (別の広告バナー) | | ... | | UIView(コントロールビュー)\ * | | UIView [一部のムービー プレーヤー コントロール] | | UIView [その他のムービー プレーヤー コントロール] *
プレーヤーの読み込み時に、適切なタイミングで広告バナーをフェード インおよびフェード アウトする呼び出しをAVPlayer
インスタンスにアタッチします。addBoundaryTimeObserverForTimes:queue:usingBlock:
これを行うとき、明示的な順序付けなしでサブビューとしてUIImageView
sを追加しself.view
ます (したがって、他のすべての上に描画する必要があります) setHidden:YES
。
NSLog
これらのフェード ブロックは正しく実行され、広告バナーでそれぞれ表示と非表示を設定view.alpha = 1.0f
していますが、ビューによって表示されるものを既知の動作するローカル イメージview.alpha = 0.0f
に明示的に設定しても、何も表示されません。UIImage
フレーム に、さらに をに(0, 0, 320, 480)
設定autoresizingMask
UIViewAutoresizingFlexibleTopMargin |
UIViewAutoresizingFlexibleLeftMargin |
UIViewAutoresizingFlexibleRightMargin;
はUIViewContentMode
デフォルトです ( である必要がありますUIViewContentModeScaleToFill
)。
問題に対して私が行った「解決策」
これは実際にはまったく問題に対処していませんが、0% の不透明度の代わりに 0.1% の不透明度を使用しています。問題を引き起こすことなく要素を効果的に非表示にし、フェードイン/フェードアウトがうまく機能しています。
トラブルシューティング
すべての非コントロール ビューの上にムービーを描画していないことを確認するためAVPlayerLayer
に、追加のビューに移動しましたvideoView
。
UIView(self.view)\ | | UIView(ビデオビュー) | | UIImageView (広告バナー) | | UIImageView (別の広告バナー) | | ... | | UIView(コントロールビュー)\ * | | UIView [一部のムービー プレーヤー コントロール] | | UIView [その他のムービー プレーヤー コントロール] *
私は明示的にsendSubviewToBack:videoView
andを呼び出しますbringSubviewToFront:controlsView
が、それでも愛はありません。setHidden:YES
オーバーレイ広告を最初にビュー階層に追加するときに呼び出さなければ、オーバーレイ広告を画面に表示できます。キッカーはこれです:広告も正しいタイミングで(アニメーション ブロックに応答してoverlayImage.alpha = 0.0f
) 消えるので、アニメーション ブロックが問題ないことがわかります。
以下は、ムービー プレーヤーのビューに広告バナーを追加するためのコード スニペットです。
for(MyCustomAdBannerClass *overlay in overlays)
{
UIImageView *overlayImage =
[[UIImageView alloc] initWithImage:
[UIImage initWithData:
[NSData dataWithContentsOfURL:[overlay contentURL]]]];
UIViewAutoresizing autoresizingFlags =
UIViewAutoresizingNone;
CGFloat x, y, width, height;
width = [overlay width];
height = [overlay height];
// <snip> set x, y, autoresizing values of the above vars
[overlayImage setFrame:CGRectMake(x, y, width, height)];
[overlayImage setAutoresizingMask:autoresizingFlags];
[self.view addSubview:overlayImage];
}
for(UIView *subview in self.view.subviews)
{
if(subview == controlsView)
[self.view bringSubviewToFront:subview];
else if(subview == videoView)
[self.view sendSubviewToBack:subview];
else
[subview setHidden:YES];
}
オーバーレイの表示/非表示のコールバックを追加するために使用するコードは次のとおりです (overlay
は、オーバーレイを表示するタイミングと表示時間に関する情報を含むオブジェクトであり、実際の広告バナーが含まれています) overlayImage
。UIImageView
[self.player
addBoundaryTimeObserverForTimes:[NSArray arrayWithObject:
[overlay startTime]]
queue:dispatch_get_main_queue()
usingBlock:^{
[UIView
animateWithDuration:0.7
animations:^{
overlayImage.alpha = 1.0f;
dispatch_time_t popTime =
dispatch_time(DISPATCH_TIME_NOW,
[overlay duration] * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(),
^(void){
[UIView
animateWithDuration:0.7
animations:^{
overlayImage.alpha = 0.0f;
[overlayImage removeFromSuperview];
}];
}];
}];
}];
私が言ったように、そのoverlayImage.alpha = 0.0f;
呼び出しは正しく実行されています。
注:ビューが最初に追加されたときのoverlay.alpha = 0.5f;
代わりに設定を試みました。0.0f
オーバーレイが適切にフェードインするようになりました。そのため、ビューを 100% 非表示にして、後日再び表示されないようにするという奇妙なことが起こっています。クラッシュしないため、解放されたメモリを参照しているだけではありません。
試行された回避策
すべての広告オーバーレイを背後に送信しようとしvideoView
ましたが、それぞれが表示されるときに電話をかけました
[overlayImage removeFromSuperview];
[self.view insertSubview:overlayImage aboveView:videoView];
// dispatch hide animation
まだ表示されませんが、省略しても適切にフェードしますsetHidden:YES
。