接上文 Flutter PIP 插件 ---- 新增PipActivity,Android 11以下支持自动进入PIP Mode
在之前的界面设计中,还原动画等体验一直不太好,遂优化一下,现在体验效果看起来更好了,
唯一一个还没搞定的是应用内还原的动画,应用内还原的时候,有一个从小到达逐渐拉伸的效果,猜测可能是和图片的渲染有关?有大佬能指点一二不?
不再获取PipViewController
前面也讲到这个比较危险,虽然多方求证似乎也没什么,但还是怕,所以改成查找PipWindow,并在pictureInPictureControllerDidStartPictureInPicture通知中把自渲染View添加到rootView中去
- (void)pictureInPictureControllerDidStartPictureInPicture:
(AVPictureInPictureController *)pictureInPictureController {
PIP_LOG(@"pictureInPictureControllerDidStartPictureInPicture");
#if USE_PIP_VIEW_CONTROLLER
// if you use the pipViewController, you must call this every time to bring
// the content view to the front, otherwise the content view will not be
// visible and covered by the pip host view.
if (_pipViewController) {
[_pipViewController.view bringSubviewToFront:_contentView];
}
#else
// TODO @sylar: check if this is the best way to do this, what will happen if
// we have multiple windows? what if the root view controller is not a
// UIViewController?
UIWindow *window = [[UIApplication sharedApplication] windows].firstObject;
if (window) {
UIViewController *rootViewController = window.rootViewController;
UIView *superview = rootViewController.view.superview;
[self insertContentViewIfNeeded:superview];
} else {
PIP_LOG(
@"pictureInPictureControllerDidStartPictureInPicture: window is nil");
[_pipStateDelegate pipStateChanged:PipStateFailed
error:@"Can not find the pip window"];
return;
}
#endif
_isPipActived = YES;
[_pipStateDelegate pipStateChanged:PipStateStarted error:nil];
}
遗留项是,这个查找PipWindow的方法靠不靠谱?有其他方法但是看起来也不靠谱
不再每次都将自渲染UIView从PipWindow移除
观察到一个现象是,如果是依赖PipViewController在 pictureInPictureControllerWillStartPictureInPicture 中添加UIView,还必须得在 pictureInPictureControllerDidStartPictureInPicture 中调用一次 bringSubviewToFront,否则的话你会比系统自动添加的View早添加,导致你的层级在下面;改用通过获取PipWindow方式后,就不用在bringSubviewToFront,因为不是一个parent了。
另外一些场景下可能会创建一个悬空的UIView用来做渲染,这样的话我们就没必要每次都把他从PipWindow上移除还原到父parent上,可以在PipWindow显示的一瞬间就立即看到渲染的内容
- (void)pictureInPictureControllerDidStopPictureInPicture:
(AVPictureInPictureController *)pictureInPictureController {
PIP_LOG(@"pictureInPictureControllerDidStopPictureInPicture");
// restore the content view in
// pictureInPictureControllerDidStopPictureInPicture will have the best user
// experience.
[self restoreContentViewIfNeeded];
_isPipActived = NO;
[_pipStateDelegate pipStateChanged:PipStateStopped error:nil];
}
- (void)restoreContentViewIfNeeded {
if (_contentView == nil) {
PIP_LOG(@"restoreContentViewIfNeeded: contentView is nil");
return;
}
// do not restore the content view if the original parent view is nil or
// the content view is already in the original parent view.
// keep the content view in the pip view controller will make the user
// experience better, the pip content view will be visible immediately.
if (_contentViewOriginalParentView == nil ||
[_contentViewOriginalParentView.subviews containsObject:_contentView]) {
PIP_LOG(
@"restoreContentViewIfNeeded: _contentViewOriginalParentView is nil or "
@"contentView is already in the original parent view");
return;
}
[_contentView removeFromSuperview];
PIP_LOG(
@"restoreContentViewIfNeeded: contentView is removed from the original "
@"parent view");
if (_contentViewOriginalParentView != nil) {
// in case that the subviews of _contentViewOriginalParentView has been
// changed, we need to get the real index of the content view.
NSUInteger trueIndex = MIN(_contentViewOriginalParentView.subviews.count,
_contentViewOriginalIndex);
[_contentViewOriginalParentView insertSubview:_contentView
atIndex:trueIndex];
PIP_LOG(@"restoreContentViewIfNeeded: contentView is added to the original "
@"parent view "
@"at index: %lu",
trueIndex);
// restore the original frame
_contentView.frame = _contentViewOriginalFrame;
// restore the original constraints
[_contentView removeConstraints:_contentView.constraints.copy];
[_contentView addConstraints:_contentViewOriginalConstraints];
// restore the original translatesAutoresizingMaskIntoConstraints
_contentView.translatesAutoresizingMaskIntoConstraints =
_contentViewOriginalTranslatesAutoresizingMaskIntoConstraints;
// restore the original parent view
[_contentViewOriginalParentView
removeConstraints:_contentViewOriginalParentView.constraints.copy];
[_contentViewOriginalParentView
addConstraints:_contentViewOriginalParentViewConstraints];
}
}
支持动态设置PipWindow窗口大小
这个没什么好说的,修改创建contentSource的时候的sampleBufferDisplayer的大小就可以动态修改PipWindow窗口大小,判断各种对象都已经有了的话就只修改大小而不用重新创建controller就行了
if (options.preferredContentSize.width > 0 &&
options.preferredContentSize.height > 0) {
[_pipView
updateFrameSize:CGSizeMake(options.preferredContentSize.width,
options.preferredContentSize.height)];
}