I am trying to add a "Floating Button" on top of a scrollview with a lot of subviews. When the button is clicked, UINavigation controller prompts a new viewController to appear. When I dismiss the controller, to go back to the original viewController, I want the button to still be there!
To not deal with constraints conflicts, my solution was to add the UIButton to the UIWindow.
[UIApplication.sharedApplication.keyWindow addSubview:_myButton];
Everything works well. But the problem is when I dismiss the new controller to come back to the controller containing the button:
[self dismissViewControllerAnimated:YES completion:nil];
The button is not immediately "there". Only once the animation finishes (the viewController goes fully down), does the button "re-appear". If I got rid of animation by setting:
[self dismissViewControllerAnimated:NO completion:nil];
Everything works well! The button is IMMEDIATELY there. But I really want to keep this animation.
I was wondering if there was a way to have the button STAY on a viewController, or at the very least appear before the animation fully completes to make it seem like an actual floating button on the screen.
If this is not possible, is there another approach to building floating buttons natively on iOS, without installing any additional pods?
Thanks!
Here is a very simple example.
Because we are adding the button as a sibling of the scroll view (not as a subview), it will "float" in front of the scroll view, and the scroll view's contents will scroll behind it.
When we present - and then dismiss - another VC, the "floating button" won't be going anywhere, so it will still be visible when we return to the main VC.
Initial view:
Scroll view content scrolling "behind" the button:
Code to see it in action:
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
AnotherViewController.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
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.