jjzjj

ios - 替换 UIView 时假的推送和弹出动画

coder 2024-01-12 原文

出于某些原因,我必须使用 addSubviewaddChildViewController 来替换 View 而不是推送/弹出 View Controller 。问题是我想在更改 UIViewController(推送/弹出)时完全伪造动画。 这是我的尝试:

RootViewController.m

// switch controller view
currentController = nextViewController;

[self addChildViewController:currentController]; 
[self.view addSubview:currentController.view];

// pop - move down
[currentController.view setFrame:CGRectMake(self.view.frame.size.width, 0, currentController.view.frame.size.width, currentController.view.frame.size.height)];

        [UIView animateWithDuration:0.5
                         animations:^{
                             [currentController.view setFrame:CGRectMake(self.view.frame.size.width, self.view.frame.size.height, currentController.view.frame.size.width, currentController.view.frame.size.height)];
                             [self addConstrainForView];
                         }];


//Push - move up
  [currentController.view setFrame:CGRectMake(0, self.view.frame.size.height, currentController.view.frame.size.width, currentController.view.frame.size.height)];
        [UIView animateWithDuration:0.5
                         animations:^{
                             [currentController.view setFrame:CGRectMake(0, 0, currentController.view.frame.size.width, currentController.view.frame.size.height)];
                             [self addConstrainForView];
                         }];

此代码不作为方面工作,因为下一个 Controller 从底部移动到顶部(推),并且当它移动时,它后面有一个空白背景(根 Controller 的背景).

所以我需要正确的方法来伪造推送和弹出动画(上拉和下拉)。
如有任何帮助,我们将不胜感激。

最佳答案

我在一个应用程序中使用了这个效果。我想要(并且拥有)嵌入到 iPad 应用程序边缘的 iPhone 系列选择屏幕的外观。因此,用户按下列表中的一个按钮,然后屏幕转换(看起来像 UIViewController 前进)到更多选项,尽管它们都在边缘的窗口中(相关内容会在右侧弹出)。这是我使用的代码:

- (void)advanceLevel
{
    UIImageView *screenShot = [self getTableScreenShot];
    [self.tableView.superview addSubview:screenShot];

    // Put screen shot over the whole thing with mask for iPhone style animation
    TableViewMask *mask =
            [[TableViewMask alloc] initWithFrame:CGRectMake(0, 0, 1024, 768) withImage:[Util TakeScreenshot]];
    [self.tableView.superview addSubview:mask];

    tableLevel++;
    [self updateData];

    [UIView animateWithDuration:.6 animations:^
    {
        screenShot.frame =
        CGRectMake(self.tableView.frame.origin.x-self.tableView.frame.size.width, self.tableView.frame.origin.y,
                   self.tableView.frame.size.width, self.tableView.frame.size.height);
        controller.toolbar.backButton.alpha = (tableLevel>1?1:0);
    }
    completion:^(BOOL finished)
    {
        [screenShot removeFromSuperview];
        [mask removeFromSuperview];
        [self updateUI];
    }];
}

- (void)goBackLevel
{
    if(tableLevel==1){ return; }

    if(tableLevel==3 && isEditing==YES)
    {
        // Skip this screen if coming from higher screens
        tableLevel--;
    }

    UIImageView *screenShot = [self getTableScreenShot];
    [self.tableView.superview addSubview:screenShot];

    // Put screen shot over the whole thing with mask for iPhone style animation
    TableViewMask *mask = [[TableViewMask alloc] initWithFrame:CGRectMake(0, 0, 1024, 768) withImage:[Util TakeScreenshot]];
    [self.tableView.superview addSubview:mask];

    tableLevel--;
    [self updateData];

    [UIView animateWithDuration:.6 animations:^
    {
        screenShot.frame =
            CGRectMake(self.tableView.frame.origin.x+self.tableView.frame.size.width, self.tableView.frame.origin.y,
                       self.tableView.frame.size.width, self.tableView.frame.size.height);
        controller.toolbar.backButton.alpha = (tableLevel>1?1:0);
    }
    completion:^(BOOL finished)
    {
        [screenShot removeFromSuperview];
        [mask removeFromSuperview];
        [self updateUI];
    }];
}

...这是截屏者:

+ (UIImage *)TakeScreenshot
{
    CGSize imageSize = [[UIScreen mainScreen] bounds].size;

    UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0);

    CGContextRef context = UIGraphicsGetCurrentContext();

    // Iterate over every window from back to front
    for (UIWindow *window in [[UIApplication sharedApplication] windows])
    {
        if (![window respondsToSelector:@selector(screen)] || [window screen] == [UIScreen mainScreen])
        {
            // -renderInContext: renders in the coordinate space of the layer,
            // so we must first apply the layer's geometry to the graphics context
            CGContextSaveGState(context);
            // Center the context around the window's anchor point
            CGContextTranslateCTM(context, [window center].x, [window center].y);
            // Apply the window's transform about the anchor point
            CGContextConcatCTM(context, [window transform]);
            // Offset by the portion of the bounds left of and above the anchor point
            CGContextTranslateCTM(context,
                                  -[window bounds].size.width * [[window layer] anchorPoint].x,
                                  -[window bounds].size.height * [[window layer] anchorPoint].y);

            // Render the layer hierarchy to the current context
            [[window layer] renderInContext:context];

            // Restore the context
            CGContextRestoreGState(context);
        }
    }

    // Retrieve the screenshot image
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    return image;
}

.. 最后是 TableViewMask:

@implementation TableViewMask

UIImage *screenShotImage;
- (instancetype)initWithFrame:(CGRect)frame withImage:(UIImage *)_screenShotImage
{
    self = [super initWithFrame:frame];
    if(self)
    {
        self.backgroundColor = [UIColor clearColor];

        screenShotImage = _screenShotImage;

        [self setNeedsDisplay];
    }
    return self;
}

- (void)drawRect:(CGRect)rect
{
    CGContextRef context = UIGraphicsGetCurrentContext();

    [screenShotImage drawInRect:rect];

    CGRect intersection = CGRectIntersection( CGRectMake(10.2, 130, 299.6, 600), rect );
    if( CGRectIntersectsRect( intersection, rect ) )
    {
        CGContextFillRect(context, CGRectMake(10, 130, 300, 600));
        CGContextClearRect(context, intersection);
        CGContextSetFillColorWithColor( context, [UIColor clearColor].CGColor );
        CGContextFillRect( context, intersection);
    }
}

@end

我留下了一些我独有的东西,因为你可能需要类似的电话。例如 [self updateData] 会考虑系统状态来更新模型并设置任何其他基于状态的调用。当屏幕应该被跳过时也有一个异常(exception)我已经留下了。你可以安全地删除那些,尽管你可能需要类似的变体(因为你并没有真正改变 UIViewController 的)。

对此我唯一要注意的是,除非你有像我这样的极端情况——在 iPad 或类似的东西上的弹出 View 中模仿 iPhone——最好只使用真正的 UIVewController。

关于ios - 替换 UIView 时假的推送和弹出动画,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29349172/

有关ios - 替换 UIView 时假的推送和弹出动画的更多相关文章

  1. ruby - 多次弹出/移动 ruby​​ 数组 - 2

    我的代码目前看起来像这样numbers=[1,2,3,4,5]defpop_threepop=[]3.times{pop有没有办法在一行中完成pop_three方法中的内容?我基本上想做类似numbers.slice(0,3)的事情,但要删除切片中的数组项。嗯...嗯,我想我刚刚意识到我可以试试slice! 最佳答案 是numbers.pop(3)或者numbers.shift(3)如果你想要另一边。 关于ruby-多次弹出/移动ruby​​数组,我们在StackOverflow上找到一

  2. ruby 正则表达式 - 如何替换字符串中匹配项的第 n 个实例 - 2

    在我的应用程序中,我需要能够找到所有数字子字符串,然后扫描每个子字符串,找到第一个匹配范围(例如5到15之间)的子字符串,并将该实例替换为另一个字符串“X”。我的测试字符串s="1foo100bar10gee1"我的初始模式是1个或多个数字的任何字符串,例如,re=Regexp.new(/\d+/)matches=s.scan(re)给出["1","100","10","1"]如果我想用“X”替换第N个匹配项,并且只替换第N个匹配项,我该怎么做?例如,如果我想替换第三个匹配项“10”(匹配项[2]),我不能只说s[matches[2]]="X"因为它做了两次替换“1fooX0barXg

  3. ruby-on-rails - 在 ruby​​ 中使用 gsub 函数替换单词 - 2

    我正在尝试用ruby​​中的gsub函数替换字符串中的某些单词,但有时效果很好,在某些情况下会出现此错误?这种格式有什么问题吗NoMethodError(undefinedmethod`gsub!'fornil:NilClass):模型.rbclassTest"replacethisID1",WAY=>"replacethisID2andID3",DELTA=>"replacethisID4"}end另一个模型.rbclassCheck 最佳答案 啊,我找到了!gsub!是一个非常奇怪的方法。首先,它替换了字符串,所以它实际上修改了

  4. ruby - 如何验证 IO.copy_stream 是否成功 - 2

    这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下

  5. Ruby 文件 IO 定界符? - 2

    我正在尝试解析一个文本文件,该文件每行包含可变数量的单词和数字,如下所示:foo4.500bar3.001.33foobar如何读取由空格而不是换行符分隔的文件?有什么方法可以设置File("file.txt").foreach方法以使用空格而不是换行符作为分隔符? 最佳答案 接受的答案将slurp文件,这可能是大文本文件的问题。更好的解决方案是IO.foreach.它是惯用的,将按字符流式传输文件:File.foreach(filename,""){|string|putsstring}包含“thisisanexample”结果的

  6. Unity 3D 制作开关门动画,旋转门制作,推拉门制作,门把手动画制作 - 2

    Unity自动旋转动画1.开门需要门把手先动,门再动2.关门需要门先动,门把手再动3.中途播放过程中不可以再次进行操作觉得太复杂?查看我的文章开关门简易进阶版效果:如果这个门可以直接打开的话,就不需要放置"门把手"如果门把手还有钥匙需要旋转,那就可以把钥匙放在门把手的"门把手",理论上是可以无限套娃的可调整参数有:角度,反向,轴向,速度运行时点击Test进行测试自己写的代码比较垃圾,命名与结构比较拉,高手轻点喷,新手有类似的需求可以拿去做参考上代码usingSystem.Collections;usingSystem.Collections.Generic;usingUnityEngine;u

  7. Get https://registry-1.docker.io/v2/: net/http: request canceled while waiting - 2

    1.错误信息:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)或者:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:TLShandshaketimeout2.报错原因:docker使用的镜像网址默认为国外,下载容易超时,需要修改成国内镜像地址(首先阿里

  8. ruby - Ruby gsub 替换中的行为不一致? - 2

    两个gsub产生不同的结果。谁能解释一下为什么?代码也可在https://gist.github.com/franklsf95/6c0f8938f28706b5644d获得.ver=9999str="\tCFBundleDevelopmentRegion\n\ten\n\tCFBundleVersion\n\t0.1.190\n\tAppID\n\t000000000000000"putsstr.gsub/(CFBundleVersion\n\t.*\.).*()/,"#{$1}#{ver}#{$2}"puts'--------'putsstr.gsub/(CFBundleVersio

  9. ruby-on-rails - 在这种情况下我如何模拟一个对象?没有明显的方法可以用模拟替换对象 - 2

    假设我在Store的模型中有这个非常简单的方法:defgeocode_addressloc=Store.geocode(address)self.lat=loc.latself.lng=loc.lngend如果我想编写一些不受地理编码服务影响的测试脚本,这些脚本可能已关闭、有限制或取决于我的互联网连接,我该如何模拟地理编码服务?如果我可以将地理编码对象传递到该方法中,那将很容易,但我不知道在这种情况下该怎么做。谢谢!特里斯坦 最佳答案 使用内置模拟和stub的rspecs,你可以做这样的事情:setupdo@subject=MyCl

  10. ruby - 如何搜索、递增和替换 Ruby 字符串中的整数子字符串? - 2

    我有很多这样的文档:foo_1foo_2foo_3bar_1foo_4...我想通过获取foo_[X]的所有实例并将它们中的每一个替换为foo_[X+1]来转换它们。在这个例子中:foo_2foo_3foo_4bar_1foo_5...我可以用gsub和一个block来做到这一点吗?如果不是,最干净的方法是什么?我真的在寻找一个优雅的解决方案,因为我总是可以暴力破解它,但我觉得有一些正则表达式技巧值得学习。 最佳答案 我(完全)不懂Ruby,但类似这样的东西应该可以工作:"foo_1foo_2".gsub(/(foo_)(\d+)/

随机推荐