gpt4 book ai didi

ios - 自定义转换导致黑屏或屏幕无响应

转载 作者:行者123 更新时间:2023-11-29 02:17:46 26 4
gpt4 key购买 nike

我创建了一个自定义的 UIViewControllerAnimatedTransition(代码如下所示)。关闭 View 时,过渡将仅关注动画。当我关闭 View 时出现黑屏,master 在消失之前会短暂显示。请看代码bel

#import "GCSplitDismissTransition.h"

@implementation GCSplitDismissTransition

#pragma mark - UIViewControllerAnimatedTransitioning protocol

-(void) animateTransition: (id < UIViewControllerContextTransitioning > ) transitionContext {
UIViewController * fromVC = [transitionContext viewControllerForKey: UITransitionContextFromViewControllerKey];
UIViewController * toVC = [transitionContext viewControllerForKey: UITransitionContextToViewControllerKey];
UIView * inView = [transitionContext containerView];
UIView * masterView = toVC.view;
UIView * detailView = fromVC.view;
masterView.frame = [transitionContext finalFrameForViewController: toVC];


// add the to VC's view to the intermediate view (where it has to be at the
// end of the transition anyway). We'll hide it during the transition with
// a blank view. This ensures that renderInContext of the 'To' view will
// always render correctly
[inView addSubview: toVC.view];

// if the detail view is a UIScrollView (eg a UITableView) then
// get its content offset so we get the snapshot correctly
CGPoint detailContentOffset = CGPointMake(.0, .0);
if ([detailView isKindOfClass: [UIScrollView class]]) {
detailContentOffset = ((UIScrollView * ) detailView).contentOffset;
}

// if the master view is a UIScrollView (eg a UITableView) then
// get its content offset so we get the snapshot correctly and
// so we can correctly calculate the split point for the zoom effect
CGPoint masterContentOffset = CGPointMake(.0, .0);
if ([masterView isKindOfClass: [UIScrollView class]]) {
masterContentOffset = ((UIScrollView * ) masterView).contentOffset;
}

// Take a snapshot of the detail view
// use renderInContext: instead of the new iOS7 snapshot API as that
// only works for views that are currently visible in the view hierarchy
UIGraphicsBeginImageContextWithOptions(detailView.bounds.size, detailView.opaque, 0);
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(ctx, 0, -detailContentOffset.y);
[detailView.layer renderInContext: ctx];
UIImage * detailSnapshot = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

// take a snapshot of the master view
// use renderInContext: instead of the new iOS7 snapshot API as that
// only works for views that are currently visible in the view hierarchy
UIGraphicsBeginImageContextWithOptions(masterView.bounds.size, masterView.opaque, 0);
ctx = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(ctx, 0, -masterContentOffset.y);
[masterView.layer renderInContext: ctx];
UIImage * masterSnapshot = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

// get the rect of the source cell in the coords of the from view
CGRect sourceRect = [masterView convertRect: self.sourceView.bounds fromView: self.sourceView];
CGFloat splitPoint = sourceRect.origin.y + sourceRect.size.height - masterContentOffset.y;
CGFloat scale = [UIScreen mainScreen].scale;

// split the master view snapshot into two parts, splitting
// below the master view (usually a UITableViewCell) that originated the transition
CGImageRef masterImgRef = masterSnapshot.CGImage;
CGImageRef topImgRef = CGImageCreateWithImageInRect(masterImgRef, CGRectMake(0, 0, masterSnapshot.size.width * scale, splitPoint * scale));
UIImage * topImage = [UIImage imageWithCGImage: topImgRef scale: scale orientation: UIImageOrientationUp];
CGImageRelease(topImgRef);

CGImageRef bottomImgRef = CGImageCreateWithImageInRect(masterImgRef, CGRectMake(0, splitPoint * scale, masterSnapshot.size.width * scale, (masterSnapshot.size.height - splitPoint) * scale));
UIImage * bottomImage = [UIImage imageWithCGImage: bottomImgRef scale: scale orientation: UIImageOrientationUp];
CGImageRelease(bottomImgRef);

// create views for the top and bottom parts of the master view
UIImageView * masterTopView = [
[UIImageView alloc] initWithImage: topImage
];
UIImageView * masterBottomView = [
[UIImageView alloc] initWithImage: bottomImage
];
CGRect bottomFrame = masterBottomView.frame;
bottomFrame.origin.y = splitPoint;
masterBottomView.frame = bottomFrame;

// setup the inital and final frames for the master view top and bottom
// views depending on whether we're doing a push or a pop transition
CGRect masterTopEndFrame = masterTopView.frame;
CGRect masterBottomEndFrame = masterBottomView.frame;

CGRect masterTopStartFrame = masterTopView.frame;
masterTopStartFrame.origin.y = -(masterTopStartFrame.size.height - sourceRect.size.height);
masterTopView.frame = masterTopStartFrame;

CGRect masterBottomStartFrame = masterBottomView.frame;
masterBottomStartFrame.origin.y += masterBottomStartFrame.size.height;
masterBottomView.frame = masterBottomStartFrame;


CGFloat initialAlpha = 1.0;
CGFloat finalAlpha = .0;

// create views to cover the master top and bottom views so that
// we can fade them in / out
UIView * masterTopFadeView = [
[UIView alloc] initWithFrame: masterTopView.frame
];
masterTopFadeView.backgroundColor = masterView.backgroundColor;
masterTopFadeView.alpha = initialAlpha;

UIView * masterBottomFadeView = [
[UIView alloc] initWithFrame: masterBottomView.frame
];
masterBottomFadeView.backgroundColor = masterView.backgroundColor;
masterBottomFadeView.alpha = initialAlpha;

// create snapshot view of the to view
UIImageView * detailSmokeScreenView = [
[UIImageView alloc] initWithImage: detailSnapshot
];


// create a background view so that we don't see the actual VC
// views anywhere - start with a blank canvas.
UIView * backgroundView = [
[UIView alloc] initWithFrame: inView.frame
];
backgroundView.backgroundColor = [UIColor lightGrayColor];

// add all the views to the transition view
[inView addSubview: backgroundView];
[inView addSubview: detailSmokeScreenView];
[inView addSubview: masterTopView];
[inView addSubview: masterTopFadeView];
[inView addSubview: masterBottomView];
[inView addSubview: masterBottomFadeView];

NSTimeInterval totalDuration = [self transitionDuration: transitionContext];

[UIView animateKeyframesWithDuration: totalDuration
delay: 0
options: UIViewKeyframeAnimationOptionCalculationModeLinear
animations: ^ {
// move the master view top and bottom views (and their
// respective fade views) to where we wna them to end up
masterTopView.frame = masterTopEndFrame;
masterTopFadeView.frame = masterTopEndFrame;
masterBottomView.frame = masterBottomEndFrame;
masterBottomFadeView.frame = masterBottomEndFrame;

detailSmokeScreenView.layer.transform = CATransform3DMakeAffineTransform(CGAffineTransformMakeScale(.1, .1));


// fade out (or in) the master view top and bottom views
// want the fade out animation to happen near the end of the transition
// and the fade in animation to happen at the start of the transition
CGFloat fadeStartTime = .0;
[UIView addKeyframeWithRelativeStartTime: fadeStartTime relativeDuration: .5 animations: ^ {
masterTopFadeView.alpha = finalAlpha;
masterBottomFadeView.alpha = finalAlpha;
}];
}
completion: ^ (BOOL finished) {
// remove all the intermediate views from the heirarchy
[backgroundView removeFromSuperview];
[detailSmokeScreenView removeFromSuperview];
[masterTopView removeFromSuperview];
[masterTopFadeView removeFromSuperview];
[masterBottomView removeFromSuperview];
[masterBottomFadeView removeFromSuperview];


[transitionContext completeTransition: YES];

}
];
}

如果我注释掉这一行:[transitionContext completeTransition: YES]; 那么黑色 View 不会出现,但是 master 没有响应。这个想法改编自 https://github.com/mluisbrown/LCZoomTransition

如果有任何问题,请告诉我,希望我提供的足够多。

更新

import "GCSplitPresentTransition.h"

@implementation GCSplitPresentTransition


-(void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext{

UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
UIView *inView = [transitionContext containerView];
UIView *masterView = fromVC.view;
UIView *detailView = toVC.view;


detailView.frame = [transitionContext finalFrameForViewController:toVC];


// add the to VC's view to the intermediate view (where it has to be at the
// end of the transition anyway). We'll hide it during the transition with
// a blank view. This ensures that renderInContext of the 'To' view will
// always render correctly
[inView addSubview:toVC.view];

// if the detail view is a UIScrollView (eg a UITableView) then
// get its content offset so we get the snapshot correctly
CGPoint detailContentOffset = CGPointMake(.0, .0);
if ([detailView isKindOfClass:[UIScrollView class]]) {
detailContentOffset = ((UIScrollView *)detailView).contentOffset;
}

// if the master view is a UIScrollView (eg a UITableView) then
// get its content offset so we get the snapshot correctly and
// so we can correctly calculate the split point for the zoom effect
CGPoint masterContentOffset = CGPointMake(.0, .0);
if ([masterView isKindOfClass:[UIScrollView class]]) {
masterContentOffset = ((UIScrollView *) masterView).contentOffset;
}

// Take a snapshot of the detail view
// use renderInContext: instead of the new iOS7 snapshot API as that
// only works for views that are currently visible in the view hierarchy
UIGraphicsBeginImageContextWithOptions(detailView.bounds.size, detailView.opaque, 0);
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(ctx, 0, -detailContentOffset.y);
[detailView.layer renderInContext:ctx];
UIImage *detailSnapshot = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

// take a snapshot of the master view
// use renderInContext: instead of the new iOS7 snapshot API as that
// only works for views that are currently visible in the view hierarchy
UIGraphicsBeginImageContextWithOptions(masterView.bounds.size, masterView.opaque, 0);
ctx = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(ctx, 0, -masterContentOffset.y);
[masterView.layer renderInContext:ctx];
UIImage *masterSnapshot = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

// get the rect of the source cell in the coords of the from view
CGRect sourceRect = [masterView convertRect:self.sourceView.bounds fromView:self.sourceView];
CGFloat splitPoint = sourceRect.origin.y + sourceRect.size.height - masterContentOffset.y;
CGFloat scale = [UIScreen mainScreen].scale;

// split the master view snapshot into two parts, splitting
// below the master view (usually a UITableViewCell) that originated the transition
CGImageRef masterImgRef = masterSnapshot.CGImage;
CGImageRef topImgRef = CGImageCreateWithImageInRect(masterImgRef, CGRectMake(0, 0, masterSnapshot.size.width * scale, splitPoint * scale));
UIImage *topImage = [UIImage imageWithCGImage:topImgRef scale:scale orientation:UIImageOrientationUp];
CGImageRelease(topImgRef);

CGImageRef bottomImgRef = CGImageCreateWithImageInRect(masterImgRef, CGRectMake(0, splitPoint * scale, masterSnapshot.size.width * scale, (masterSnapshot.size.height - splitPoint) * scale));
UIImage *bottomImage = [UIImage imageWithCGImage:bottomImgRef scale:scale orientation:UIImageOrientationUp];
CGImageRelease(bottomImgRef);

// create views for the top and bottom parts of the master view
UIImageView *masterTopView = [[UIImageView alloc] initWithImage:topImage];
UIImageView *masterBottomView = [[UIImageView alloc] initWithImage:bottomImage];
CGRect bottomFrame = masterBottomView.frame;
bottomFrame.origin.y = splitPoint;
masterBottomView.frame = bottomFrame;

// setup the inital and final frames for the master view top and bottom
// views depending on whether we're doing a push or a pop transition
CGRect masterTopEndFrame = masterTopView.frame;
CGRect masterBottomEndFrame = masterBottomView.frame;

masterTopEndFrame.origin.y = -(masterTopEndFrame.size.height - sourceRect.size.height);
masterBottomEndFrame.origin.y += masterBottomEndFrame.size.height;

CGFloat initialAlpha = 1.0;
CGFloat finalAlpha = 1.0;

// create views to cover the master top and bottom views so that
// we can fade them in / out
UIView *masterTopFadeView = [[UIView alloc] initWithFrame:masterTopView.frame];
masterTopFadeView.backgroundColor = masterView.backgroundColor;
masterTopFadeView.alpha = initialAlpha;

UIView *masterBottomFadeView = [[UIView alloc] initWithFrame:masterBottomView.frame];
masterBottomFadeView.backgroundColor = masterView.backgroundColor;
masterBottomFadeView.alpha = initialAlpha;

// create snapshot view of the to view
UIImageView *detailSmokeScreenView = [[UIImageView alloc] initWithImage:detailSnapshot];
// for a push transition, make the detail view small, to be zoomed in
// for a pop transition, the detail view will be zoomed out, so it starts without
// a transform


// create a background view so that we don't see the actual VC
// views anywhere - start with a blank canvas.
UIView *backgroundView = [[UIView alloc] initWithFrame:inView.frame];
//backgroundView.backgroundColor = self.transitionBackgroundColor;

// add all the views to the transition view
[inView addSubview:backgroundView];
[inView addSubview:detailSmokeScreenView];
[inView addSubview:masterTopView];
[inView addSubview:masterTopFadeView];
[inView addSubview:masterBottomView];
[inView addSubview:masterBottomFadeView];

NSTimeInterval totalDuration = [self transitionDuration:transitionContext];

[UIView animateKeyframesWithDuration:totalDuration
delay:0
options:UIViewKeyframeAnimationOptionCalculationModeLinear
animations:^{
// move the master view top and bottom views (and their
// respective fade views) to where we wna them to end up
masterTopView.frame = masterTopEndFrame;
masterTopFadeView.frame = masterTopEndFrame;
masterBottomView.frame = masterBottomEndFrame;
masterBottomFadeView.frame = masterBottomEndFrame;
// zoom the detail view in or out, depending on whether we're doing a push
// or pop transition

detailSmokeScreenView.layer.transform = CATransform3DMakeAffineTransform(CGAffineTransformIdentity);


// fade out (or in) the master view top and bottom views
// want the fade out animation to happen near the end of the transition
// and the fade in animation to happen at the start of the transition
CGFloat fadeStartTime = .5 ;
[UIView addKeyframeWithRelativeStartTime:fadeStartTime relativeDuration:.5 animations:^{
masterTopFadeView.alpha = finalAlpha;
masterBottomFadeView.alpha = finalAlpha;
}];
}
completion:^(BOOL finished) {
// remove all the intermediate views from the heirarchy
[backgroundView removeFromSuperview];
[detailSmokeScreenView removeFromSuperview];
[masterTopView removeFromSuperview];
[masterTopFadeView removeFromSuperview];
[masterBottomView removeFromSuperview];
[masterBottomFadeView removeFromSuperview];

if ([transitionContext transitionWasCancelled]) {
// we added this at the start, so we have to remove it
// if the transition is canccelled
[toVC.view removeFromSuperview];
[transitionContext completeTransition:NO];
} else {
[fromVC.view removeFromSuperview];
[transitionContext completeTransition:YES];
}
}];

}

-(NSTimeInterval) transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext{

return 0.3;
}

@end

更新 2

这就是我呈现过渡的方式:

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{

NSIndexPath *selectedIndexPath = [tableView indexPathForSelectedRow];
UITableViewCell * cell = [self.tableView cellForRowAtIndexPath:selectedIndexPath];

self.transition.sourceView=cell;
self.dismissTransition.sourceView=cell;

DetailViewController * detailViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"detail"];
detailViewController.modalPresentationStyle = UIModalPresentationCustom;
detailViewController.transitioningDelegate = self;


[self presentViewController:detailViewController animated:YES completion:NULL];

}


-(id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source{

//return new instance of custom transition
return self.transition;
}

-(id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed{

return self.dismissTransition;
}

最佳答案

当您使用 LCZoomTransition 代码时,就出现了这个问题,该代码是为导航推送-弹出转换而编写的。您需要自定义模式转换动画的代码。两者是不同的,也可以阅读这些文章来了解一下事情的味道。

http://www.objc.io/issue-5/view-controller-transitions.html

http://www.objc.io/issue-12/custom-container-view-controller-transitions.html

要解决您遇到的问题,您只需删除添加和删除主视图 Controller View 的代码即可。因为它是一个呈现 View Controller ,所以它的 View 应该保留在层次结构中。

在文件 GCSplitPresentTransition 中,删除行

[fromVC.view removeFromSuperview];

在动画完成处理程序中。

并且在文件 GCSplitDismissTransition 中,删除行

[inView addSubview: toVC.view];

-animateTransition 方法的开头。

关于ios - 自定义转换导致黑屏或屏幕无响应,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28558882/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com