ios - 如何向 UIWindow 添加 subview 并防止其在使用 UINavigationController 转换时消失?

标签 ios objective-c uiscrollview floating-action-button uiwindow

我试图在带有很多 subview 的 ScrollView 顶部添加一个“ float 按钮”。单击该按钮时,UINavigation Controller 会提示出现一个新的 viewController。当我关闭 Controller ,返回到原来的 viewController 时,我希望按钮仍然在那里!

为了不处理约束冲突,我的解决方案是将 UIButton 添加到 UIWindow。

[UIApplication.sharedApplication.keyWindow addSubview:_myButton];

一切正常。但问题是当我关闭新 Controller 以返回到包含按钮的 Controller 时:

[self dismissViewControllerAnimated:YES completion:nil];

该按钮不会立即“出现”。只有当动画完成后(viewController 完全下降),按钮才会“重新出现”。如果我通过设置摆脱动画:

[self dismissViewControllerAnimated:NO completion:nil];

一切顺利!该按钮立即就在那里。但我真的很想保留这个动画。

我想知道是否有办法让按钮留在 viewController 上,或者至少在动画完全完成之前出现,使其看起来像屏幕上的实际 float 按钮。

如果这是不可能的,是否有另一种方法可以在 iOS 上本地构建 float 按钮,而无需安装任何额外的 pod?

谢谢!

最佳答案

这是一个非常简单的示例。

  • 为主视图添加 ScrollView
  • 向 ScrollView 添加内容
  • 将按钮添加到主视图 - 添加到 ScrollView
  • 限制 ScrollView 右上角的按钮
  • 为按钮添加触摸操作以呈现另一个 View Controller

因为我们将按钮添加为 ScrollView 的同级(而不是 subview ),所以它将“ float ”在 ScrollView 的前面,并且 ScrollView 的内容将在其后面滚动。

当我们呈现 - 然后关闭 - 另一个 VC 时,“ float 按钮”不会去任何地方,因此当我们返回主 VC 时它仍然可见。

初始 View :

enter image description here

在按钮“后面”滚动查看内容:

enter image description here

查看实际效果的代码:

ViewController.h

//
//  ViewController.h
//  OCSept2019
//
//  Created by Don Mag on 9/12/19.
//

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController
@end

ViewController.c

//
//  ViewController.m
//  OCSept2019
//
//  Created by Don Mag on 9/12/19.
//

#import "ViewController.h"
#import "AnotherViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    // instantiate a scroll view
    UIScrollView *scrollView = [UIScrollView new];
    scrollView.translatesAutoresizingMaskIntoConstraints = NO;
    scrollView.backgroundColor = [UIColor cyanColor];

    // instantiate a stack view
    UIStackView *stackView = [UIStackView new];
    stackView.translatesAutoresizingMaskIntoConstraints = NO;

    stackView.axis = UILayoutConstraintAxisVertical;
    stackView.alignment = UIStackViewAlignmentFill;
    stackView.distribution = UIStackViewDistributionFill;
    stackView.spacing = 40.0;

    // add 20 labels as arrangeed subview of the stack view
    for (int i = 0; i < 20; i++) {
        UILabel *v = [UILabel new];
        v.backgroundColor = [UIColor yellowColor];
        v.text = [NSString stringWithFormat:@"This is label %ld", (long)i + 1];
        v.textAlignment = NSTextAlignmentCenter;
        [stackView addArrangedSubview:v];
    }

    // add the stack view as a subview of the scroll view
    [scrollView addSubview:stackView];

    // add the scroll view as a subview of self.view
    [self.view addSubview:scrollView];

    [NSLayoutConstraint activateConstraints:
     @[

       // constrain the scroll view to all 4 sides of self.view (safe area), with 20-pts "padding"
       [scrollView.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor constant: 20.0],
       [scrollView.bottomAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.bottomAnchor constant: -20.0],
       [scrollView.leadingAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.leadingAnchor constant: 20.0],
       [scrollView.trailingAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.trailingAnchor constant: -20.0],

       // constrain the stack view to all 4 sides of the scroll view, with
       //   8-pts left and right "padding"
       //   40-pts top and bottom "padding"
       [stackView.topAnchor constraintEqualToAnchor:scrollView.topAnchor constant: 40.0],
       [stackView.bottomAnchor constraintEqualToAnchor:scrollView.bottomAnchor constant: -40.0],
       [stackView.leadingAnchor constraintEqualToAnchor:scrollView.leadingAnchor constant: 8.0],
       [stackView.trailingAnchor constraintEqualToAnchor:scrollView.trailingAnchor constant: -8.0],

       // constrain stack view width equal to scroll view width - 16 (to account for 8-pt padding on each side)
       [stackView.widthAnchor constraintEqualToAnchor:scrollView.widthAnchor constant:-16.0],

       ]
     ];

    // instantiate a button with Red background
    UIButton *b = [UIButton new];
    b.translatesAutoresizingMaskIntoConstraints = NO;
    [b setTitle:@"Tap to Present Another VC" forState:UIControlStateNormal];
    b.backgroundColor = [UIColor redColor];
    [b setTitleColor:[UIColor lightGrayColor] forState:UIControlStateHighlighted];

    // add the button as a subview of self.view
    // this will place it *in front of* the scroll view
    [self.view addSubview:b];

    // constrain it at upper-right corner of the scroll view
    [NSLayoutConstraint activateConstraints:
     @[
       [b.topAnchor constraintEqualToAnchor:scrollView.topAnchor constant:8.0],
       [b.trailingAnchor constraintEqualToAnchor:scrollView.trailingAnchor constant:-8.0],
       ]
     ];

    // add a touch up inside action
    [b addTarget:self action:@selector(btnTap) forControlEvents:UIControlEventTouchUpInside];
}

- (void) btnTap {
    // instantiate another view controller
    AnotherViewController *vc = [AnotherViewController new];
    // present it
    [self presentViewController:vc animated:YES completion:nil];
}

@end

AnotherViewController.h

//
//  AnotherViewController.h
//  OCSept2019
//
//  Created by Don Mag on 9/12/19.
//

#import <UIKit/UIKit.h>

@interface AnotherViewController : UIViewController
@end

另一个ViewController.m

//
//  AnotherViewController.m
//  OCSept2019
//
//  Created by Don Mag on 9/12/19.
//

#import "AnotherViewController.h"

@interface AnotherViewController ()

@end

@implementation AnotherViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    // green background
    self.view.backgroundColor = [UIColor greenColor];

    // instantiate a button with Blue background
    UIButton *b = [UIButton new];
    b.translatesAutoresizingMaskIntoConstraints = NO;
    [b setTitle:@"Tap to Dismiss" forState:UIControlStateNormal];
    b.backgroundColor = [UIColor blueColor];
    [b setTitleColor:[UIColor lightGrayColor] forState:UIControlStateHighlighted];

    // add it as a subview of self.view
    [self.view addSubview:b];

    // constrain it centered X and Y
    [NSLayoutConstraint activateConstraints:
     @[
       [b.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor],
       [b.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor],
       ]
     ];

    // add a touch up inside action
    [b addTarget:self action:@selector(btnTap) forControlEvents:UIControlEventTouchUpInside];
}

- (void) btnTap {
    // dismiss this view controller
    [self dismissViewControllerAnimated:YES completion:nil];
}

@end

关于ios - 如何向 UIWindow 添加 subview 并防止其在使用 UINavigationController 转换时消失?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57908965/

相关文章:

ios - push viewcontroller 是一个实例变量,pop 时不会调用 dealloc 方法

objective-c - NSMutableDictionary 中的编辑条目失败,错误为 : "unrecognized selector sent to instance"

ios - 如何在 Swift 中设置返回按钮文本

ios - 所有 iPhone 模拟器的 ScrollView

android - 从商店停用 iOS 和 Android 商店,但使其可重置

ios - 将包含 AM/PM 的 NSString 转换为 NSDate

ios - 非圆形发光的 CGContextDrawRadialGradient

ios - 使用 Swift 读取 Xcode 项目中的文件

iphone - 如何将 UIScrollView 和文本字段放置在其中?

ios - 在 VC 中包含具有动态高度的项目,并具有可滚动功能