How to know if there is a UIActionSheet showing in view Hierarchy? - ios

How to know if there is a UIActionSheet showing in View Hierarchy?
Also I want to get a reference to that UIActionSheet, any good idea?

Notice that on iOS6, you need a recursive search to finde the UIActionSheet, it is not a direct subview of UIWindow now.
static UIView *actionSheet = nil;
-(void)findActionSheetInSubviewsOfView:(id)view
{
if (actionSheet) {
return;
}
if ([[view valueForKey:#"subviews"] count] != 0) {
for (id subview in [view valueForKey:#"subviews"]) {
if ([subview isKindOfClass:[UIActionSheet class]]) {
actionSheet = subview;
}
else
[self findActionSheetInSubviewsOfView:subview];
}
}
}
-(UIActionSheet*) actionSheetShowing {
actionSheet = nil;
for (UIWindow* window in [UIApplication sharedApplication].windows) {
[self findActionSheetInSubviewsOfView:window];
}
if (actionSheet) {
return (UIActionSheet*)actionSheet;
}
return nil;
}

Related

iOS, UIImagePickerController, is there a way to detect when user taps the take picture button without implementing custom controls?

Xcode 7.3, iOS 9.3.1
I want to use two custom overlay views for when the user is about to take a picture and after while editing the picture. To change the overlay I would like to know if there is a callback method from the UIImagePickerControllerDelegate that will let me know when the user starts editing the picture, or when the user has tapped the take picture button.
The only methods I know of are:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
I have looked here: UIImagePickerController with cameraOverlayView focusses when button in overlay is tapped, How to know I tap "taking photo button" with UIImagePicker and iOS - Taking A Picture After Button Tap in UIImagePickerController CustomOverlayView.
Or perhaps there is a way to get the tap event from the standard button by adding an observer.
Please help! Thanks in advance.
you could use the UINavigationControllerDelegate that you also have to implement when using UIImagePickerController. implementing the delegate method [...]didShowViewController[...] like this
- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
NSLog(#"%#", [viewController class]);
}
produces the following output (using the simulator, choosing UIImagePickerControllerSourceTypePhotoLibrary as the sourceType and navigating like this: photo albums overview > specific album > editing specific photo):
2016-04-08 00:19:36.882 ImagePicker[44578:4705834] PUUIAlbumListViewController
2016-04-08 00:19:41.341 ImagePicker[44578:4705834] PUUIMomentsGridViewController
2016-04-08 00:19:47.929 ImagePicker[44578:4705834] PUUIImageViewController
hope that helps!
UIImagePickerControllerDelegate is quite poor but you can handle it by adding an observer:
Swift 3:
NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: "_UIImagePickerControllerUserDidCaptureItem"), object:nil, queue:nil, using: { note in
//Do something
})
Objective-C:
[[NSNotificationCenter defaultCenter] addObserverForName:#"_UIImagePickerControllerUserDidCaptureItem" object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {
//Do something
}];
Xcode 8.2.1, iOS10.2.1
Before implementing please read the solution for earlier version to understand the basics. Thanks! The problem was that some of the names for various subviews have changed from iOS 9.3.1 to iOS 10.2.1.
Here is the complete code (see below where to insert), that replaces "//Code goes here" below:
for (UIView *subviewImagePickerControllerView in self.imagePickerController.view.subviews)
{
if ([subviewImagePickerControllerView.class.description isEqualToString:#"UINavigationTransitionView"])
{
for (UIView *subviewUINavigationTransitionView in subviewImagePickerControllerView.subviews)
{
if ([subviewUINavigationTransitionView.class.description isEqualToString:#"UIViewControllerWrapperView"])
{
for (UIView *subviewUIViewControllerWrapperView in subviewUINavigationTransitionView.subviews)
{
if ([subviewUIViewControllerWrapperView.class.description isEqualToString:#"CAMCameraViewControllerContainerView"])
{
for (UIView *subviewCAMCameraViewControllerContainerView in subviewUIViewControllerWrapperView.subviews)
{
if ([subviewCAMCameraViewControllerContainerView.class.description isEqualToString:#"CAMViewfinderView"])
{
for (UIView *subviewCAMViewfinderView in subviewCAMCameraViewControllerContainerView.subviews)
{
if ([subviewCAMViewfinderView.class.description isEqualToString:#"CAMBottomBar"])
{
for (UIView *subviewCAMBottomBar in subviewCAMViewfinderView.subviews)
{
if ([subviewCAMBottomBar.class.description isEqualToString:#"CUShutterButton"] && [subviewCAMBottomBar.class isSubclassOfClass:[UIButton class]])
{
UIButton *shutterButton = (UIButton *)subviewCAMBottomBar;
[shutterButton addTarget:self action:#selector(touchUpInsideCMKShutterButton) forControlEvents:UIControlEventTouchUpInside];
}
else
{
nil;
}
}
}
}
}
else if ([subviewCAMCameraViewControllerContainerView.class.description isEqualToString:#"PLCropOverlay"])
{
for (UIView *subviewPLCropOverlay in subviewCAMCameraViewControllerContainerView.subviews)
{
if ([subviewPLCropOverlay.class.description isEqualToString:#"PLCropOverlayBottomBar"])
{
for (UIView *subviewPLCropOverlayBottomBar in subviewPLCropOverlay.subviews)
{
if ([subviewPLCropOverlayBottomBar.class.description isEqualToString:#"PLCropOverlayPreviewBottomBar"])
{
for (UIView *itemPLCropOverlayPreviewBottomBar in subviewPLCropOverlayBottomBar.subviews)
{
if ([itemPLCropOverlayPreviewBottomBar.class isSubclassOfClass:[UIButton class]])
{
UIButton *buttonPLCropOverlay = (UIButton *)itemPLCropOverlayPreviewBottomBar;
if ([buttonPLCropOverlay.titleLabel.text isEqualToString:#"Retake"])
{
UIButton *retakeButton = buttonPLCropOverlay;
[retakeButton addTarget:self action:#selector(touchUpInsideButtonRetake) forControlEvents:UIControlEventTouchUpInside];
}
else
{
nil;
}
}
else
{
nil;
}
}
}
else
{
nil;
}
}
}
else
{
nil;
}
}
}
else
{
nil;
}
}
}
else
{
nil;
}
}
}
else
{
nil;
}
}
}
else
{
nil;
}
}
Xcode 7.3, iOS9.3.1
I had to get this working, so I spent a lot of time figuring this out.
The gist of it is, I drill down the view hierarchy after the UIImagePickerController was presented, looking for CMKShutterButton and the retake button with a title of "Retake", then I attach a selector to the buttons' action, like so...
[shutterButton addTarget:self action:#selector(touchUpInsideCMKShutterButton) forControlEvents:UIControlEventTouchUpInside];
[retakeButton addTarget:self action:#selector(touchUpInsideButtonRetake) forControlEvents:UIControlEventTouchUpInside];
Drop the code below into the completion block that is called after your image picker is presented:
[self presentViewController:self.imagePickerController animated:true completion:^(void){
//Code goes here
}
Here is the complete code, that replaces "//Code goes here" above:
for (UIView *subviewImagePickerControllerView in self.imagePickerController.view.subviews)
{
if ([subviewImagePickerControllerView.class.description isEqualToString:#"UINavigationTransitionView"])
{
for (UIView *subviewUINavigationTransitionView in subviewImagePickerControllerView.subviews)
{
if ([subviewUINavigationTransitionView.class.description isEqualToString:#"UIViewControllerWrapperView"])
{
for (UIView *subviewUIViewControllerWrapperView in subviewUINavigationTransitionView.subviews)
{
if ([subviewUIViewControllerWrapperView.class.description isEqualToString:#"PLImagePickerCameraView"])
{
for (UIView *subviewPLImagePickerCameraView in subviewUIViewControllerWrapperView.subviews)
{
if ([subviewPLImagePickerCameraView.class.description isEqualToString:#"CMKBottomBar"])
{
for (UIView *itemCMKBottomBar in subviewPLImagePickerCameraView.subviews)
{
if ([itemCMKBottomBar.class.description isEqualToString:#"CMKShutterButton"] && [itemCMKBottomBar.class isSubclassOfClass:[UIButton class]])
{
UIButton *shutterButton = (UIButton *)itemCMKBottomBar;
[shutterButton addTarget:self action:#selector(touchUpInsideCMKShutterButton) forControlEvents:UIControlEventTouchUpInside];
}
else
{
nil;
}
}
}
else if ([subviewPLImagePickerCameraView.class.description isEqualToString:#"PLCropOverlay"])
{
for (UIView *subviewPLCropOverlay in subviewPLImagePickerCameraView.subviews)
{
if ([subviewPLCropOverlay.class.description isEqualToString:#"PLCropOverlayBottomBar"])
{
for (UIView *subviewPLCropOverlayBottomBar in subviewPLCropOverlay.subviews)
{
if ([subviewPLCropOverlayBottomBar.class.description isEqualToString:#"PLCropOverlayPreviewBottomBar"])
{
for (UIView *itemPLCropOverlayPreviewBottomBar in subviewPLCropOverlayBottomBar.subviews)
{
if ([itemPLCropOverlayPreviewBottomBar.class isSubclassOfClass:[UIButton class]])
{
UIButton *buttonPLCropOverlay = (UIButton *)itemPLCropOverlayPreviewBottomBar;
if ([buttonPLCropOverlay.titleLabel.text isEqualToString:#"Retake"])
{
UIButton *retakeButton = buttonPLCropOverlay;
[retakeButton addTarget:self action:#selector(touchUpInsideButtonRetake) forControlEvents:UIControlEventTouchUpInside];
}
else
{
nil;
}
}
else
{
nil;
}
}
}
else
{
nil;
}
}
}
else
{
nil;
}
}
}
else
{
nil;
}
}
}
else
{
nil;
}
}
}
else
{
nil;
}
}
}
else
{
nil;
}
}
And here is the method I am attaching, which goes in the view controller that is presenting the image picker controller:
- (void)touchUpInsideCMKShutterButton
{
NSLog(#"Take");
}
- (void)touchUpInsideButtonRetake
{
NSLog(#"Re-take");
}
Hope this helps someone! Thanks.

removeFromSuperview ios crashes

My app crashes, not always, at the following method
// overridden
- (void)dismiss
{
[super dismiss];
[containerView_ removeFromSuperview];
containerView_ = nil;
}
crash happens at removerFromSuperview.
There is a "show" method as well
// overridden
- (void)show
{
if (self.parentView == nil)
{
// No parentView, create transparent view as parent
CGSize frameSize = [UIApplication currentSize];
containerView_ = [[UIView alloc] initWithFrame:CGRectMake(0, 0, frameSize.height, frameSize.width)];
containerView_.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
containerView_.backgroundColor = [UIColor clearColor];
self.parentView = containerView_;
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone)
{
if(some condition )
[[UIApplication sharedApplication].keyWindow.subviews.lastObject addSubview:containerView_];
else
[[UIApplication sharedApplication].keyWindow addSubview:containerView_];
}
else
{
[[UIApplication sharedApplication].delegate.window.rootViewController.view addSubview:containerView_];
}
}
[super show];
// This is done to allow the Cancel button to be pressed but nothing else - do after [super show]!
self.superview.userInteractionEnabled = YES;
}
It is strange, that code used to work. I am trying to compile the app for arm64, but I don't understand how that modification impacted those methods.
My app is a non-ARC app, and I cannot go to ARC right now.
Any ideas?
Change your code to dismiss view like this.
// overridden
- (void)dismiss
{
if(containerView_)
[containerView_ removeFromSuperview];
containerView_ = nil;
[super dismiss];
}
Please check with below code -
- (void)dismiss
{
if (containerView_)
{
[containerView_ removeFromSuperview];
containerView_ = nil;
[super dismiss];
}
}
Simply check if container view have superview
- (void)dismiss
{
if ([containerView_ superview])
{
[containerView_ removeFromSuperview];
containerView_ = nil;
[super dismiss];
}
}

How to remove top bar of the keyboard in ios 7

In my program I use UIWebView with editable div for the Rich text editor. I need to remove top bar of the keyboard.
I used below code - it removes only next/previous buttons
I want to remove full top bar.
- (void)removeBar {
UIWindow *keyboardWindow = nil;
for (UIWindow *testWindow in [[UIApplication sharedApplication] windows]) {
if (![[testWindow class] isEqual:[UIWindow class]]) {
keyboardWindow = testWindow;
break;
}
}
for (UIView *possibleFormView in [keyboardWindow subviews]) {
// iOS 5 sticks the UIWebFormView inside a UIPeripheralHostView.
if ([[possibleFormView description] rangeOfString:#"UIPeripheralHostView"].location != NSNotFound) {
for (UIView *subviewWhichIsPossibleFormView in [possibleFormView subviews]) {
if ([[subviewWhichIsPossibleFormView description] rangeOfString:#"UIWebFormAccessory"].location != NSNotFound) {
[subviewWhichIsPossibleFormView removeFromSuperview];
}
}
}
}
}
I found the solution for iOS 8. You can check it here: [ iOS 8 - Remove Previous/Next/Done UIKeyboard Toolbar inside a UIWebView][1]
You may try and improve this. try call this function inside Your UIKeyboardDidShowNotification event handler.
Hope this helps...
This is the level of views in accessory:
(UIWebFormAccessory) -> (UIToolbar) -> (UIImageView,UIToolbarButton,UIToolbarButton)
-(void) removeKeyboard {
UIWindow *keyboardWindow = nil;
for (UIWindow *testWindow in [[UIApplication sharedApplication] windows]) {
if (![[testWindow class] isEqual : [UIWindow class]]) {
keyboardWindow = testWindow;
break;
}
}
// Locate UIWebFormView.
for (UIView *possibleFormView in [keyboardWindow subviews]) {
if ([[possibleFormView description] hasPrefix : #"<UIInputSetContainerView"]) {
for (UIView* peripheralView in possibleFormView.subviews) {
for (UIView* peripheralView_sub in peripheralView.subviews) {
// hides the backdrop (iOS 8)
if ([[peripheralView_sub description] hasPrefix : #"<UIKBInputBackdropView"] && peripheralView_sub.frame.size.height == 44) {
[[peripheralView_sub layer] setOpacity : 0.0];
}
// hides the accessory bar
if ([[peripheralView_sub description] hasPrefix : #"<UIWebFormAccessory"]) {
for (UIView* UIInputViewContent_sub in peripheralView_sub.subviews) {
CGRect frame1 = UIInputViewContent_sub.frame;
frame1.size.height = 0;
peripheralView_sub.frame = frame1;
UIInputViewContent_sub.frame = frame1;
[[peripheralView_sub layer] setOpacity : 0.0];
}
CGRect viewBounds = peripheralView_sub.frame;
viewBounds.size.height = 0;
peripheralView_sub.frame = viewBounds;
}
}
}
}
}
}
There is a solution for this here.
That answer includes a function called removeKeyboardTopBar which should be called on the UIKeyboardWillShowNotification.
Listen to the notification:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
On the notification, call the function after a delay. The delay is necessary to make sure that the objects exist before the function runs (since we are calling this on keyboard will show, not keyboard did show).
- (void)keyboardWillShow:(NSNotification*) notification {
[self performSelector:#selector(removeKeyboardTopBar) withObject:nil afterDelay:0];
}
From what I can tell, it looks like the keyboard has an added inputAccessoryView to the top of it. Otherwise, I'm not certain why it is appearing. Anyways, if that is the case then whatever you assign firstResponder to set their inputAccessoryView to nil:
someObjectWithFirstResponder.inputAccessoryView = nil;
EDIT: Looks like the UIWebView sets the inputAccessoryView itself, but if it is actually receiving firstResponder then you should be able to override the inputAccessoryView. If setting it to nil causing it to default back to the inputAccessoryView that you are trying to remove, then you might try setting it to an empty view:
someObjectWithFirstResponder.inputAccessoryView = [UIView alloc] initWithFrame:CGRectMake(0, 0, 0, 0)];
EDIT This method does not work in iOS 8.0 and greater.

Removing the border of uipopover controller in iOS

I would like to create a popover with white color border. I have done by assigning instance of subclass to popoverBackgroundViewClass. I am able to achieve this with white color (using white image at the background )but with border of the popover is not removed. A white color border Still appears. Is there any way to remove it?
Yes, there is one crazy solution ) After you presentPopover, you need call this method
-(void)removeInnerShadow {
UIWindow *window = [[[UIApplication sharedApplication] delegate] window];
for (UIView *windowSubView in window.subviews) {
if ([NSStringFromClass([windowSubView class]) isEqualToString:#"UIDimmingView"]) {
for (UIView *dimmingViewSubviews in windowSubView.subviews) {
for (UIView *popoverSubview in dimmingViewSubviews.subviews) {
if([NSStringFromClass([popoverSubview class]) isEqualToString:#"UIView"]) {
for (UIView *subviewA in popoverSubview.subviews) {
if ([NSStringFromClass([subviewA class]) isEqualToString:#"UILayoutContainerView"]) {
subviewA.layer.cornerRadius = 0;
}
for (UIView *subviewB in subviewA.subviews) {
if ([NSStringFromClass([subviewB class]) isEqualToString:#"UIImageView"] ) {
[subviewB removeFromSuperview];
}
if ([NSStringFromClass([subviewB class]) isEqualToString:#"UILayoutContainerView"] ) {
for (UIView *subviewC in subviewB.subviews) {
if ([NSStringFromClass([subviewC class]) isEqualToString:#"UIImageView"]) {
[subviewC removeFromSuperview];
}
}
}
}
}
}
}
}
}
}
}
You can try this library https://github.com/ddebin/DDPopoverBackgroundView
UIPopoverController *popOver = [[UIPopoverController alloc] initWithContentViewController:content];
[popOver setPopoverBackgroundViewClass:[DDPopoverBackgroundView class]];
just set
[popOver.popoverBackgroundViewClass setContentInset:0.0f];
thats it.
But remember this will only work on iOS 5+

Check if a subview is in a view

I'm making an app where I add a subview to a view using addSubview: on an IBAction. In the same way, when the button with that IBAction is touched again should call removeFromSuperview on that subview added on that IBAction:
PSEUDO CODE
-(IBAction)showPopup:(id)sender
{
System_monitorAppDelegate *delegate = (System_monitorAppDelegate *)[[UIApplication sharedApplication] delegate];
UIView *rootView = delegate.window.rootViewController.view;
if([self popoverView] is not on rootView)
{
[rootView addSubview:[self popoverView]];
}
else
{
[[self popoverView] removeFromSuperview];
}
}
You are probably looking for UIView's -(BOOL)isDescendantOfView:(UIView *)view; taken in UIView class reference.
Return Value
YES if the receiver is an immediate or distant
subview of view or if view is the receiver itself; otherwise NO.
You will end up with a code like :
Objective-C
- (IBAction)showPopup:(id)sender {
if(![self.myView isDescendantOfView:self.view]) {
[self.view addSubview:self.myView];
} else {
[self.myView removeFromSuperview];
}
}
Swift 3
#IBAction func showPopup(sender: AnyObject) {
if !self.myView.isDescendant(of: self.view) {
self.view.addSubview(self.myView)
} else {
self.myView.removeFromSuperview()
}
}
Try this:
-(IBAction)showPopup:(id)sender
{
if (!myView.superview)
[self.view addSubview:myView];
else
[myView removeFromSuperview];
}
UIView *subview = ...;
if([self.view.subviews containsObject:subview]) {
...
}
The Swift equivalent will look something like this:
if(!myView.isDescendantOfView(self.view)) {
self.view.addSubview(myView)
} else {
myView.removeFromSuperview()
}
Check the superview of the subview...
-(IBAction)showPopup:(id)sender {
if([[self myView] superview] == self.view) {
[[self myView] removeFromSuperview];
} else {
[self.view addSubview:[self myView]];
}
}
Your if condition should go like
if (!([rootView subviews] containsObject:[self popoverView])) {
[rootView addSubview:[self popoverView]];
} else {
[[self popoverView] removeFromSuperview];
}
Here we used two different views. Parent view is the view in which we are searching for descendant view and check wether added to parent view or not.
if parentView.subviews.contains(descendantView) {
// descendant view added to the parent view.
}else{
// descendant view not added to the parent view.
}

Resources