UIWebView Keyboard - Getting rid of the "Previous/Next/Done" bar - iphone

I want to get rid of the bar on top of the keyboard that appears when you focus a text field in a webview. We have some other ways of handling this and it's redundant and unnecessary.
webview keyboard bar http://beautifulpixel.com/assets/iPhone_Simulator-20100120-152330.png
If you hit this problem, make sure to head over to https://bugreport.apple.com and duplicate rdar://9844216

- (void)viewDidLoad {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
}
- (void)keyboardWillShow:(NSNotification *)notification {
[self performSelector:#selector(removeBar) withObject:nil afterDelay:0];
}
- (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];
}
}
}
}
}
This works well.
url: http://ios-blog.co.uk/iphone-development-tutorials/rich-text-editor-inserting-images-part-6/

This is an addition to Yun's answer. On iOS6 (6.0.1) there might be a horizontal grey border or shadow line on top of the row where the accessory (previous / next / done) used to be before it was removed. This fix works for me, and I'd like to share. Curious to hear if it works for you as well.
To remove the border, I added this code to the inner loop of removeBar():
if ([[subviewWhichIsPossibleFormView description] rangeOfString:#"UIImageView"].location != NSNotFound) {
[[subviewWhichIsPossibleFormView layer] setOpacity: 0.0];
}
We need to add the QuartzCore framework to the head of the .m file, so we can set the opacity of the layer involved.
So, we get:
...
#import <QuartzCore/QuartzCore.h>
...
- (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];
}
// iOS 6 leaves a grey border / shadow above the hidden accessory row
if ([[subviewWhichIsPossibleFormView description] rangeOfString:#"UIImageView"].location != NSNotFound) {
// we need to add the QuartzCore framework for the next line
[[subviewWhichIsPossibleFormView layer] setOpacity: 0.0];
}
}
}
}
}

It looks like there is a very simple way, but I'm pretty sure it will not pass the App Store review. Maybe someone has a clever idea? ;)
#interface UIWebBrowserView : UIView
#end
#interface UIWebBrowserView (UIWebBrowserView_Additions)
#end
#implementation UIWebBrowserView (UIWebBrowserView_Additions)
- (id)inputAccessoryView {
return nil;
}
#end

There are no public APIs for doing this. You could remove it by examining the view hierarchy and removing the view as some have suggested, but this would be very risky.
Here's why it's a bad idea:
If Apple doesn't have an official API for removing the bar, they may have good reasons for doing so, and their own code may rely on it being there. You might not ever encounter a problem because you do all your testing (for example) on an English keyboard. But what if the view you are removing is required for entry in another language, or for accessibility purposes? Or what if in a future version of iOS their own implementation changes such that it assumes the view is always there? Your code will crash, and you'll be stuck scrambling to get an update out while frustrated users wait for weeks.
Interestingly, Remco's appended answer proves this point. On iOS 6.0.1, a change was made that required a fix to the hack. Anyone who had implemented the hack for ios 5 would have been forced to do an update as a result. Fortunately it was only an aesthetic change, but it could have been much worse.

I was thinking of intercepting the UIKeyboardWillAppear notification, and giving it to a hidden text field instead, and forwarding the events through javascript to the real one in the webview. But it seems hairy. Things cursor movement and selection would then suck.

check out this one. https://gist.github.com/2048571.
It works in iOS 5 and later, doesnt work for earlier versions.

this code definetly works for me... hope this also works for you.
- (void)viewDidLoad{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
}
-(void)viewWillAppear:(BOOL)animated{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
}
- (void)keyboardWillShow:(NSNotification *)notification {
[self performSelector:#selector(removeBar) withObject:nil afterDelay:0];
}
- (void)removeBar {
// Locate non-UIWindow.
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:#"<UIPeripheralHostView"]) {
for (UIView* peripheralView in [possibleFormView subviews]) {
// hides the backdrop (iOS 7)
if ([[peripheralView description] hasPrefix:#"<UIKBInputBackdropView"]) {
//skip the keyboard background....hide only the toolbar background
if ([peripheralView frame].origin.y == 0){
[[peripheralView layer] setOpacity:0.0];
}
}
// hides the accessory bar
if ([[peripheralView description] hasPrefix:#"<UIWebFormAccessory"]) {
// remove the extra scroll space for the form accessory bar
UIScrollView *webScroll;
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 5.0) {
webScroll = [[self webviewpot] scrollView];
} else {
webScroll = [[[self webviewpot] subviews] lastObject];
}
CGRect newFrame = webScroll.frame;
newFrame.size.height += peripheralView.frame.size.height;
webScroll.frame = newFrame;
// remove the form accessory bar
[peripheralView removeFromSuperview];
}
// hides the thin grey line used to adorn the bar (iOS 6)
if ([[peripheralView description] hasPrefix:#"<UIImageView"]) {
[[peripheralView layer] setOpacity:0.0];
}
}
}
}
}

Not easily. You could try to go poking around the subviews in the web view but it would be taboo with Apple.
How about not putting the text field in the web page on the web side, and adding your textfield/textview to the webview explicitly so it doesn't show the nav bar at all, and you can add your own from scratch?

[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWasShown:)
name:UIKeyboardDidShowNotification object:nil];
-(void)keyboardWasShown:(NSNotification*)aNotification
{
UIWindow* tempWindow;
//Because we cant get access to the UIKeyboard throught the SDK we will just use UIView.
//UIKeyboard is a subclass of UIView anyways
UIView* keyboard;
//Check each window in our application
for(int c = 0; c < [[[UIApplication sharedApplication] windows] count]; c ++)
{
//Get a reference of the current window
tempWindow = [[[UIApplication sharedApplication] windows] objectAtIndex:c];
//Get a reference of the current view
for(int i = 0; i < [tempWindow.subviews count]; i++)
{
keyboard = [tempWindow.subviews objectAtIndex:i];
if([[keyboard description] hasPrefix:#"<UIPeripheralHostView"] == YES)
{
keyboard.hidden = YES;
UIView* keyboardLayer;
for(int n = 0; n < [keyboard.subviews count]; n++)
{
keyboardLayer = [keyboard.subviews objectAtIndex:n];
NSLog(#" keyboardLayer ::: %# " ,keyboardLayer);
if([[keyboardLayer description] hasPrefix:#"<UIWebFormAccessory"] == YES)
{
[keyboardLayer removeFromSuperview ];
}
}
keyboard.hidden = NO;
}
}
}
NSLog(#"keyboardWasShown" );
}
check this as well: http://pastebin.com/s3Fkxvsk

Related

How to remove keyboard bar with buttons Previous and Next and Done on UIWebView? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
how to remove prev next button from virtual keyboard IOS
I am opening keyboard in my UIWebView but as per the default structure of UIWebView I am getting Bar with Previous, Next and Done button on the top of keyboard.
It consumes much space in my app so, I want to remove that bar.
How can I remove that bar?
Register for notification on keyboard showing:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
Then:
- (void)removeBar
{
// Locate non-UIWindow.
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])
{
// 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];
}
}
}
else if ([[possibleFormView description] rangeOfString:#"UIImageView"].location != NSNotFound)
{
[possibleFormView removeFromSuperview]; //remove shadow above bar. If it doesn't remove shadow then set possibleFormView's frame as CGRectZero
}
}
}

UISearchBar Keyboard Return Key

I am using a UISearchBar to match text input against entries in a database and display the matched results to the user in a UITableView, as they type.
All is well, however, I cannot find a way to alter the return key type of the search bar's keyboard. By default it replaces the standard return key with a Search button. Because I am doing a live search as the user types, I do not need this button and having it there and inactive has raised some usability issues.
Attempted solutions
I can set a keyboard with the setKeyboard:UIKeyboardType method, however this doesn't seem to override the default setting of replacing the return key (on the standard keyboard) with a Search key and it does not allow access to change this return key.
I have thought about using a UITextField, giving me access to the returnKeyType property through the UITextInputTraits protocol. My problem with this however is that I am implementing the UISearchBarDelegate method searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText, which I would lose with the UITextField.
Is there a way that I can keep the functionality of the search bar's delegate methods, whilst having legitimate access to the keyboard's return key?
In fact, almost the exact screen I am implementing is found in Apple's Clock application
Screenshot:
So any help on a clean solution would be much appreciated. Note the return key on the bottom right instead of the default Search button'.
Slightly different in iOS 7 compared to the answer of #sudip.
for (UIView *subview in self.searchBar.subviews)
{
for (UIView *subSubview in subview.subviews)
{
if ([subSubview conformsToProtocol:#protocol(UITextInputTraits)])
{
UITextField *textField = (UITextField *)subSubview;
[textField setKeyboardAppearance: UIKeyboardAppearanceAlert];
textField.returnKeyType = UIReturnKeyDone;
break;
}
}
}
I tried all of these solutions without luck until I realized that in IOS8, you can just set searchBar.returnKey = .Done or whatever UIReturnKeyType you like. Sigh.
Try this:
for(UIView *subView in searchBar.subviews) {
if([subView conformsToProtocol:#protocol(UITextInputTraits)]) {
[(UITextField *)subView setKeyboardAppearance: UIKeyboardAppearanceAlert];
}
}
If you want to dismiss the return key (i.e., make it do nothing), set the "returnKeyType" property on the UITextField subview to "UIReturnKeyDone" along with "keyboardAppearence".
I had to add some lines to Neo's answer. Here is my code to add a "Done" button for UISearchbar :
for(UIView *subView in sb_manSearch.subviews) {
if([subView conformsToProtocol:#protocol(UITextInputTraits)]) {
UITextField *t = (UITextField *)subView;
[t setKeyboardAppearance: UIKeyboardAppearanceAlert];
t.returnKeyType = UIReturnKeyDone;
t.delegate = self;
break;
}
}
To change Search into Done text.
Use below code.
youtSearchBar.returnKeyType = .done
you can do it by :
- (void)viewDidLoad
{
// Adding observer that will tell you keyboard is appeared.
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardDidShow:)
name:UIKeyboardDidShowNotification object:nil];
[super viewDidLoad];
}
- (void)keyboardDidShow:(NSNotification *)note
{
keyboardTest = [self getKeyboard];
[keyboardTest setReturnKeyEnabled: YES];
}
- (id) getKeyboard // Method that returns appeared keyboard's reference
{
id keyboardView;
// locate keyboard view
UIWindow* tempWindow = [[[UIApplication sharedApplication] windows] objectAtIndex:1];
UIView* keyboard;
for(int i=0; i<[tempWindow.subviews count]; i++)
{
keyboard = [tempWindow.subviews objectAtIndex:i];
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 3.2)
{
if([[keyboard description] hasPrefix:#"<UIPeripheralHost"] == YES)
{
keyboard = [[keyboard subviews] objectAtIndex:0];
keyboardView = keyboard ;
}
}
else
{
if([[keyboard description] hasPrefix:#"<UIKeyboard"] == YES)
keyboardView = keyboard ;
}
}
return keyboardView ;
}
UPDATE : From iOS 7 onwards, the accepted answer will not work, below version will the work on iOS 7 onwards.
UIView *subViews = [[_searchBar subviews] firstObject];
for(UIView *subView in [subViews subviews]) {
if([subView conformsToProtocol:#protocol(UITextInputTraits)]) {
[(UITextField *)subView setEnablesReturnKeyAutomatically:NO];
}
}
for (UIView *subView in view.subviews) {
if ([subView isKindOfClass:[UITextField class]])
{
UITextField *txt = (UITextField *)subView;
#try {
[txt setReturnKeyType:UIReturnKeyDone];
[txt setKeyboardAppearance:UIKeyboardAppearanceAlert];
}
#catch (NSException * e) {
// ignore exception
}
}
}
I just found the simplest wait to hack this, just put a blank when beginning editing search field
-(void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar{
//Add a blank character to hack search button enable
searchBar.text = #" ";}

IOS rotate device without rotation animation

What would be the correct way to achieve an effect similar to the one in the standard iPod app of the iPhone - when the device is rotated to landscape mode, the view changes to cover flow, but the type of transition is fade and not the rotating screen?
This is how I am loading the modal view:
- (void) willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
if (UIInterfaceOrientationIsLandscape(toInterfaceOrientation)) {
carouselView.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentModalViewController:carouselView animated:YES];
}
}
Thanks!
Andrius
I later found that it is more stable to use this solution:
In the parent view controller (in my case it is tab view controller) viewdidload method add this:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(didRotate:) name:#"UIDeviceOrientationDidChangeNotification" object:nil];
and then add this method:
- (void) didRotate:(NSNotification *)notification {
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
if (UIInterfaceOrientationIsLandscape(orientation) && !self.modalViewController) {
[self presentModalViewController:carouselView animated:YES];
[Globals sharedGlobals].startedAtLandscape = YES;
}
if (UIInterfaceOrientationIsPortrait(orientation) && self.modalViewController) {
[self dismissModalViewControllerAnimated:YES];
[Globals sharedGlobals].startedAtLandscape = NO;
}
}
And finally if you want to prevent the rotation animation, modify this method like this:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if(UIInterfaceOrientationIsLandscape(interfaceOrientation)) {
return NO;
}
return YES;
}

how to add done button in keypad

i need to add button done on keypad.
Apple does n't provide such felicity but some of application i found that done ,next,previous buttons.
like this.
how can i add these and how can i give click event to them.
can any one please help me.
1.Define the done button (= return key):
textField.returnKeyType = UIReturnKeyDone;
2.Add the action-listener:
[textField addTarget:self action:#selector(textFieldDoneEditing:) forControlEvents:UIControlEventEditingDidEndOnExit];
3.Define the action-event:
- (IBAction)textFieldDoneEditing:(id)sender {
[sender resignFirstResponder];
}
Have fun!
EDIT:
Here you can find detailed instructions how to add a Toolbar with Next & Previous above UITextField Keyboard:
http://www.randomsequence.com/articles/adding-a-toolbar-with-next-previous-above-uitextfield-keyboard-iphone/
EDIT2:
Now, I have a really great example for you: "This view extends UITextView adding on top of the keyboard associated with this UITextView a toolbar with a « Done » Button"
I check the code and it is a lot of easier than the first example:
http://blog.demay-fr.net/2009/07/cocoa-how-to-add-a-toolbar-with-button-on-top-of-a-uitextview-in-order-to-add-a-dismiss-button/
EDIT3:
Hmmm, no, I doesn't test to code. But I will test it now!
1.Problem: the right initialization. If I add the UITextView in IB, initWithCoder gets called:
- (id)init {
NSLog(#"init");
if (self = [super init]) {
//register a specific method on keyboard appearence
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
}
return self;
}
- (id)initWithCoder:(NSCoder *)decoder {
NSLog(#"initWithCoder");
if (self = [super initWithCoder:decoder]) {
//register a specific method on keyboard appearence
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
}
return self;
}
- (id)initWithFrame:(CGRect)frame {
NSLog(#"initWithFrame");
if (self = [super initWithFrame:frame]) {
//register a specific method on keyboard appearence
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
}
return self;
}
2.Problem: There's no view with the the Prefix "UIKeyboard":
for (UIWindow *keyboardWindow in [[UIApplication sharedApplication] windows]) {
NSLog(#"keyboardWindow = %#", keyboardWindow);
for (UIView *keyboard in [keyboardWindow subviews]) {
NSLog(#"keyboard = %#", keyboard);
if([[keyboard description] hasPrefix:#"<UIKeyboard"] == YES) {
// THERE'S NO VIEW 'UIKeyboard'!!!
}
}
}
The code doesn't work, I'm sorry... I don't know why there's no view "UIKeyboard"... Maybe the first example will help you at this point and you can build your own solution.

Hide/Show iPhone Camera Iris/Shutter animation

I am not able to Hide the iphone Camera shutter opening animation for my app.
I am using UIImagePickerController to access iphone camera and using my own overlay controllers.
Is there a way to remove the initial shutter(also known as Iris) animation as the camera starts.
Thank You
[EDIT]
For those who wants to know the way to change the camera iris animation.
The below function is called before the camera iris animation starts.
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
// Here is were I make the camera preview fit the entire screen.
// This might violate the "don't change the view hierarchy"-rule.
// So I am not sure if it is valid for App Store commitment.
// However, the NSLogs are used to
// figure out which subview is the actual Camera Preview which turns out
// to be the PLPreviewView. (uncomment to se the printouts).
// Change it's size to fit the entire screen (and scale it accordingly
// to avoid distorted image
NSLog(#"WillShowViewController called...");
NSLog(#"VC:view:subviews\n %#\n\n", [[viewController view] subviews]);
NSLog(#"VC:view:PLCameraView:subviews\n %#\n\n", [[[[viewController view] subviews] objectAtIndex: 0] subviews]);
NSLog(#"VC:view:PLCameraView:PLPreviewView:subviews\n %#\n\n", [[[[[[viewController view] subviews] objectAtIndex: 0] subviews] objectAtIndex: 0] subviews]);
NSLog(#"VC:view:PLCameraView:PLCropOverLay:subviews\n %#\n\n", [[[[[[viewController view] subviews] objectAtIndex: 0] subviews] objectAtIndex: 1] subviews]);
NSLog(#"VC:view:PLCameraView:UIImageView:subviews\n %#\n\n", [[[[[[viewController view] subviews] objectAtIndex: 0] subviews] objectAtIndex: 2] subviews]);
}
In the above function you can go through each layer by using the normal NSMuatableArray syntax like objectAtIndex
hope this might help you.
Regards,
Ankur
Using this answer as a starting point, I've finally solved this problem:
NOTE: This is obviously not 3.3.1-compliant.
Listen for the UINavigationControllerDidShowViewControllerNotification on your UIImagePickerController, and the PLCameraViewIrisAnimationDidEndNotification globally.
Traverse the view hierarchy (starting at the main UIWindow) looking for the PLCameraView. Save the index of the view against the main UIWindow, as you'll need it later.
Remove the PLCameraView from its superView. If desired, insert your own view at global index 0.
When the iris animation is finished, remove your view and re-add the PLCameraView at its original index.
Came across a similar: I wanted to have the shutter appear when I take the picture triggered by a button in a self.cameraOverlayView of a UIImagePickerController. Arrived to this page, did some extra research and came to this solution.
Synopsis:
#interface MyController : UIImagePickerController
...
- (id) init {
...
self.cameraOverlayView = _my_overlay_;
self.showsCameraControls = NO;
...
}
...
- (void) onMyShutterButton {
[self takePicture];
// You want the shutter animation to happen now.
// .. but it does not.
}
Solution:
// Some constants for the iris view and selector
NSString* kIrisViewClassName = #"PLCameraIrisAnimationView";
SEL kIrisSelector = NSSelectorFromString(#"animateIrisOpen");
#implementation MyController {
...
UIView* iris_;
}
- (void) viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
// Find the iris view in the siblings of your overlay view
for (UIView* view in self.cameraOverlayView.superview.subviews) {
if ([kIrisViewClassName isEqualToString:[[view class] description]]) {
// It will be hidden by 'self.showsCameraControls = NO'.
view.hidden = false;
// Extra precautions - as this is undocumented.
if ([view respondsToSelector:kIrisSelector]) {
iris_ = view;
}
break;
}
}
}
- (void) animateIrisOpen {
if (iris_) {
[iris_ performSelector:kIrisSelector];
}
}
...
- (void) onMyShutterButton {
[self takePicture];
[self animateIrisOpen]; // Voila - the shutter happens
}
I've messed around with this a bit, but sending various combinations of the view lifecycle methods to the image picker. (viewWillAppear, viewDidAppear, etc.) But I don't remember which ones ended up working.
Sorry for replying getting back so late. I found out the solution for that well I played around with the view hierarchy of the cameraView and added my own layer at the top of everything. The animation took place there and once the shutter was open the top most layer was removed. If someone need any further help with the code please let me know, I will provide with the exact steps and syntax.
-Ankur
joshwa's answer completely hides the entire camera view for the duration of the iris animation. For my purposes, I needed the camera view visible, just without the iris animation. I was able to accomplish this with a little tweaking of his method. As others have noted, this may or may not be allowed on the app store since we're messing with the view hierarchy as well as listening for undocumented notifications.
3 ivars are needed:
UIImagePickerController *imagePickerController;
UIView *plCameraIrisAnimationView; // view that animates the opening/closing of the iris
UIImageView *cameraIrisImageView; // static image of the closed iris
Hide the closed iris image and remove the animation view. I tried simply hiding the animation view as well, but the animation was still visible:
- (void)receivedNavigationControllerDidShowViewControllerNotification:(NSNotification *)notification {
UIView *view = imagePickerController.view;
[plCameraIrisAnimationView release];
plCameraIrisAnimationView = nil;
cameraIrisImageView = nil;
while (view.subviews.count && (view = [view.subviews objectAtIndex:0])) {
if ([[[view class] description] isEqualToString:#"PLCameraView"]) {
for (UIView *subview in view.subviews) {
if ([subview isKindOfClass:[UIImageView class]]) {
cameraIrisImageView = (UIImageView *)subview;
}
else if ([[[subview class] description] isEqualToString:#"PLCropOverlay"]) {
for (UIView *subsubview in subview.subviews) {
if ([[[subsubview class] description] isEqualToString:#"PLCameraIrisAnimationView"]) {
plCameraIrisAnimationView = [subsubview retain];
}
}
}
}
}
}
cameraIrisImageView.hidden = YES;
[plCameraIrisAnimationView removeFromSuperview];
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"UINavigationControllerDidShowViewControllerNotification" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(receivedPLCameraViewIrisAnimationDidEndNotification:) name:#"PLCameraViewIrisAnimationDidEndNotification" object:nil];
}
When the animation is over, unhide the iris image and re-add the animation view:
- (void)receivedPLCameraViewIrisAnimationDidEndNotification:(NSNotification *)notification {
cameraIrisImageView.hidden = NO;
UIView *view = imagePickerController.view;
while (view.subviews.count && (view = [view.subviews objectAtIndex:0])) {
if ([[[view class] description] isEqualToString:#"PLCameraView"]) {
for (UIView *subview in view.subviews) {
if ([[[subview class] description] isEqualToString:#"PLCropOverlay"]) {
[subview insertSubview:plCameraIrisAnimationView atIndex:1];
[plCameraIrisAnimationView release];
plCameraIrisAnimationView = nil;
break;
}
}
}
}
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"PLCameraViewIrisAnimationDidEndNotification" object:nil];
}
The below function is called before the camera iris animation starts.
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
// Here is were I make the camera preview fit the entire screen.
// This might violate the "don't change the view hierarchy"-rule.
// So I am not sure if it is valid for App Store commitment.
// However, the NSLogs are used to
// figure out which subview is the actual Camera Preview which turns out
// to be the PLPreviewView. (uncomment to se the printouts).
// Change it's size to fit the entire screen (and scale it accordingly
// to avoid distorted image
NSLog(#"WillShowViewController called...");
NSLog(#"VC:view:subviews\n %#\n\n", [[viewController view] subviews]);
NSLog(#"VC:view:PLCameraView:subviews\n %#\n\n", [[[[viewController view] subviews] objectAtIndex: 0] subviews]);
NSLog(#"VC:view:PLCameraView:PLPreviewView:subviews\n %#\n\n", [[[[[[viewController view] subviews] objectAtIndex: 0] subviews] objectAtIndex: 0] subviews]);
NSLog(#"VC:view:PLCameraView:PLCropOverLay:subviews\n %#\n\n", [[[[[[viewController view] subviews] objectAtIndex: 0] subviews] objectAtIndex: 1] subviews]);
NSLog(#"VC:view:PLCameraView:UIImageView:subviews\n %#\n\n", [[[[[[viewController view] subviews] objectAtIndex: 0] subviews] objectAtIndex: 2] subviews]);
}
In the above function you can go through each layer by using the normal NSMuatableArray syntax like objectAtIndex
hope this might help you.
Regards,
Ankur
To expound on Catalin's answer, (which was great btw), I found if you change the method "animateIrisOpen" slightly, the presentation is a fraction better... but noticeable.
- (void) animateIrisOpen {
if (iris_) {
iris_.hidden = NO;
[iris_ performSelector:kIrisSelector];
}
}