While back button pressed in my viewcontroller animation problem occurs.The problem is in the video at the below link:
app.bowerchat.com/images/117_1438022757542.mp4
- (IBAction)backChatBtnPressed:(id)sender
{
[self.navigationController popViewControllerAnimated:NO];
}
You can fix it by setting "clipsToBounds" property to YES (true) on base view of your view controller with messages:
Probably in viewWillAppear:
\\ View controller with messages (Swift)
override viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
self.view.clipsToBounds = true
}
Related
I was looking for a way to dismiss all the modally presented viewControllers in a UINavigationController hierarchically without knowing the name of them. so I ended up to the while loop as follow:
Swift
while(navigationController.topViewController != navigationController.presentedViewController) {
navigationController.presentedViewController?.dismiss(animated: true, completion: nil)
}
Objective-c
while(![self.navigationController.topViewController isEqual:self.navigationController.presentedViewController]) {
[self.navigationController.presentedViewController dismissViewControllerAnimated:YES completion:nil];
}
I want to dismiss all the presentedControllers one by one till the presentedViewController and topViewcontroller become equal.
the problem is that the navVC.presentedViewController doesn't changed even after dismissing.
It remains still the same even after dismissing and I end up to an infiniteLoop.
Does anyone knows where is the problem?
In my case nothing works but:
func dismissToSelf(completion: (() -> Void)?) {
// Collecting presented
var presentedVCs: [UIViewController] = []
var vc: UIViewController? = presentedViewController
while vc != nil {
presentedVCs.append(vc!)
vc = vc?.presentedViewController
}
// Dismissing all but first
while presentedVCs.count > 1 {
presentedVCs.last?.dismiss(animated: false, completion: nil)
presentedVCs.removeLast()
}
// Dismissing first with animation and completion
presentedVCs.first?.dismiss(animated: true, completion: completion)
}
I've found the answer. I can dismiss all presentedViewControllers on a navigationController by:
navigationController.dismiss(animated: true, completion: nil)
It keeps the topViewController and dismiss all other modals.
Form your question I understood that you want to dismiss all view controllers above the root view controller. For that you can do it like this:
self.view.window!.rootViewController?.dismiss(animated: false, completion: nil)
Not need to used self.navigationController.presentedViewController.
Might be help! my code is as follows:
Objective-c
[self dismissViewControllerAnimated:YES completion:^{
}];
// Or using this
dispatch_async(dispatch_get_main_queue(), ^{
[self dismissViewControllerAnimated:YES completion:nil];
});
Please check this code
-(void)dismissModalStack {
UIViewController *vc = self.window.rootViewController;
while (vc.presentedViewController) {
vc = vc.presentedViewController;
[vc dismissViewControllerAnimated:false completion:nil];
}
}
Glad to see you have found the answer, and I've done this by another way.
You can create a BaseViewController(actually lots of app do that), and defined a property like 'presentingController' in appdelegate that indicate the presenting ViewController, then in the viewWillAppear method, set the property so that it always indicate the top view controller.
-(void)viewWillAppear:(BOOL)animated{
AppDelegate *delegate=(AppDelegate *)[[UIApplication sharedApplication]delegate];
delegate.presentingController = self;
}
All the class inherited from BaseViewController will call it. When you want to dismiss all the controller, just loop as follow:
- (void)clickButton:(id)sender {
AppDelegate *delegate=(AppDelegate *)[[UIApplicationsharedApplication]delegate];
if (delegate.presentingController)
{
UIViewController *vc =self.presentingViewController;
if ( !vc.presentingViewController ) return;
while (vc.presentingViewController)
{
vc = vc.presentingViewController;
}
[vc dismissViewControllerAnimated:YEScompletion:^{
}];
}
}
Hope this will help you :)
I had a similar issue of deleting/dismissing existing/previous push notification when a new push notification arrives where different pictures are sent as a push notification.
In my situation, using Swift 5, I wanted to delete/dismiss previous push notification and display a new push notification all by itself regardless whether the user acknowledged the previous notification or not (i.e. without user's acknowledgement).
I tried Kadian's recommendation with a minor change and it worked flawlessly.
Here is my NotificationDelegate.swift
import UIKit
import UserNotifications
extension AppDelegate: UNUserNotificationCenterDelegate {
func userNotificationCenter(
_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.alert, .sound, .badge])
}
func userNotificationCenter(
_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: #escaping () -> Void) {
UNUserNotificationCenter.current().removeAllDeliveredNotifications()
defer { completionHandler() }
guard response.actionIdentifier == UNNotificationDefaultActionIdentifier else {return}
let payload = response.notification.request.content
let pn = payload.body
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: pn)
//***Below cmd will erase previous push alert***
self.window!.rootViewController?.dismiss(animated: false, completion: nil)
//Below cmd will display a newly received push notification
self.window!.rootViewController!.present(vc, animated: false)
}
}
I have searchBar that presents the keyboard when a user taps the searchBar and disables the keyboard when the user taps outside.
However, the tap gesture interacts with the tableView content. How can I disable interaction with the tableView while the keyboard is present?
override func viewDidLoad() {
super.viewDidLoad()
// dismiss keyboard if tapped outside of search
let tapGesture = UITapGestureRecognizer(target: self, action: Selector("hideKeyboard"))
tapGesture.cancelsTouchesInView = true //false doesn't work
tableView.addGestureRecognizer(tapGesture)
}
func hideKeyboard() {
searchBar.resignFirstResponder()
}
Add a transparent UIView when keyboard is present and remove it when keyboard is dismissed.
var searchBackgroundView = UIView()
func searchBarTextDidBeginEditing(searchBar: UISearchBar) {
searchBackgroundView = UIView(frame: CGRectMake(tableView.frame.origin.x, tableView.frame.origin.y, tableView.frame.width, tableView.frame.height))
tableView.addSubview(searchBackgroundView)
}
func searchBarTextDidEndEditing(searchBar: UISearchBar) {
searchBackgroundView.removeFromSuperview()
}
Two quick ideas:
present a transparent button over the entire scrollview instead of using the gesture recognizer, this would catch the events and block interaction with the scroll (table) view
store-off the gesture recognizers on the scrollview class and restore them when you are done.
You can try it by checking whether the searchController is active or not. Just like..
if searchController.active {
tableView.userInteractionEnabled = false
}
else {
tableView.userInteractionEnabled = true
}
Or another way that you choose :
func searchBarTextDidBeginEditing(searchBar: UISearchBar) {
self.tableView.userInteractionEnabled = false
}
func searchBarTextDidEndEditing(searchBar: UISearchBar) {
tableView.userInteractionEnabled = true
}
Is there a simple way to disable scrolling of an NSTableView.
It seems there isn't any property on
[myTableView enclosingScrollView] or [[myTableView enclosingScrollView] contentView] to disable it.
This works for me: subclass NSScrollView, setup and override via:
- (id)initWithFrame:(NSRect)frameRect; // in case you generate the scroll view manually
- (void)awakeFromNib; // in case you generate the scroll view via IB
- (void)hideScrollers; // programmatically hide the scrollers, so it works all the time
- (void)scrollWheel:(NSEvent *)theEvent; // disable scrolling
#interface MyScrollView : NSScrollView
#end
#import "MyScrollView.h"
#implementation MyScrollView
- (id)initWithFrame:(NSRect)frameRect
{
self = [super initWithFrame:frameRect];
if (self) {
[self hideScrollers];
}
return self;
}
- (void)awakeFromNib
{
[self hideScrollers];
}
- (void)hideScrollers
{
// Hide the scrollers. You may want to do this if you're syncing the scrolling
// this NSScrollView with another one.
[self setHasHorizontalScroller:NO];
[self setHasVerticalScroller:NO];
}
- (void)scrollWheel:(NSEvent *)theEvent
{
// Do nothing: disable scrolling altogether
}
#end
I hope this helps.
Here's the best solution in my opinion:
Swift 5
import Cocoa
#IBDesignable
#objc(BCLDisablableScrollView)
public class DisablableScrollView: NSScrollView {
#IBInspectable
#objc(enabled)
public var isEnabled: Bool = true
public override func scrollWheel(with event: NSEvent) {
if isEnabled {
super.scrollWheel(with: event)
}
else {
nextResponder?.scrollWheel(with: event)
}
}
}
Simply replace any NSScrollView with DisablableScrollView (or BCLDisablableScrollView if you still use ObjC) and you're done. Simply set isEnabled in code or in IB and it will work as expected.
The main advantage that this has is for nested scroll views; disabling children without sending the event to the next responder will also effectively disable parents while the cursor is over the disabled child.
Here are all advantages of this approach listed out:
✅ Disables scrolling
✅ Does so programmatically, behaving normally by default
✅ Does not interrupt scrolling a parent view
✅ Interface Builder integration
✅ Drop-in replacement for NSScrollView
✅ Swift and Objective-C Compatible
Thanks to #titusmagnus for the answer, but I made one modification so as not to break scrolling when when the "disabled" scrollView is nested within another scrollView: You can't scroll the outer scrollView while the cursor is within the bounds of the inner scrollView. If you do this...
- (void)scrollWheel:(NSEvent *)theEvent
{
[self.nextResponder scrollWheel:theEvent];
// Do nothing: disable scrolling altogether
}
...then the "disabled" scrollView will pass the scroll event up to the outer scrollView and its scrolling will not get stuck down inside its subviews.
Works for me:
- (void)scrollWheel:(NSEvent *)theEvent
{
[super scrollWheel:theEvent];
if ([theEvent deltaY] != 0)
{
[[self nextResponder] scrollWheel:theEvent];
}
}
There is no simple direct way (meaning, there's no property like UITableView's scrollEnabled that you can set), but i found this answer helpful in the past.
One other thing you could try (not sure about this) is subclassing NSTableView and override -scrollWheel and -swipeWithEvent so they do nothing. Hope this helps
This may sound a newbie question, however I'm new t iOS dev.
I've a view pushed in navigationController, let say it is the 3rd pushed view.
In that view I set self.navigationController.delegate = self;. I've changed delegate because I need to handle case when user goes to previous view i.e. pops from current view.
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
if ([[viewController class] isEqual:[MainViewController class]]) {
...
}
}
It works OK, but when I pop the current view and press navigation back button again (i.e. switching to first pushed view) I'm getting bad access error.
So what I'm missing ?
What is the correct way to handle navigation back button press ?
It's because navigation controller sends a message to popped and deallocated view controller, you have to set the delegate each time you do the popping and pushing. Also add self.navigationController.delegate = nil; to dealloc method of your viewController.
Place below in the Viewcontroller in which you assigning self.navigationController.delegate = self
-(void) viewWillDisappear:(BOOL) animated
{
[super viewWillDisappear:animated];
if ([self isMovingFromParentViewController])
{
if (self.navigationController.delegate == self)
{
self.navigationController.delegate = nil;
}
}
}
in my iOS project I use InAppSettings. This is missing a delegate in the modal view controller for willDismiss.
So when the modal view gets dismissed I want a method to be called in my main view controller. How can I do this? Is there a method in a view controller that gets triggered whe the view is in focus again?
You could try something like this
BOOL settingsLaunched = NO;
-(void)presentInAppSettingsViewController
{
//Show the settings modal view controller here
//Set our flag
settingsLaunched = YES;
}
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
if(settingsLaunched)
{
//Your code here
}
}
these will get called on the view after dismissing a modal dialog it presents
- (void) viewWillAppear
- (void) viewDidAppear:(BOOL)animated