I am taking a square cropped photo with GPUImageStillCamera and allowing the user to zoom the camera. When the user clicks to take a picture the camera jumps forward for a split second (as if the camera zoomed in even further past the area the user zoomed to and then immediately returns to the correct crop once the image is returned to screen). This only happens when the user has zoomed the camera. If they have not zoomed the camera the flicker/jump does not happen. (The image return has the correct crop whether or not the user has zoomed).
Thoughts?
Creating camera and adding square crop
//Add in filters
stillCamera = [[GPUImageStillCamera alloc] initWithSessionPreset:AVCaptureSessionPreset1280x720 cameraPosition:AVCaptureDevicePositionBack];
stillCamera.outputImageOrientation = UIInterfaceOrientationPortrait;
//Creating a square crop filter
cropFilter = [[GPUImageCropFilter alloc] initWithCropRegion:CGRectMake(0.f, (720.0f/1280.0f)/2.0f, 1.f, (720.0f/1280.0f))];
Image zoom method
-(void)imagePinch:(UIPinchGestureRecognizer *)recognizer{ //Controlling the zoom scale as the user pinches the live preview
if (recognizer.state == UIGestureRecognizerStateBegan) {
zoomOutAdder = 0.0f;
if (currentScale > 2) {
zoomOutAdder = currentScale;
}
}
float addition = (recognizer.scale - lastScale);
if (addition > 0) {
addition = addition *1.7;
}
if (addition < 0) {
addition = addition *(1.7+zoomOutAdder);
}
currentScale = currentScale +addition;
lastScale = recognizer.scale;
if (currentScale < 1) {
currentScale = 1;
}
if (currentScale > 4) {
currentScale =4;
}
if (currentScale == 1) {
zoomOutAdder = 0.0f;
}
cameraImagePreview.transform = CGAffineTransformMakeScale(currentScale, currentScale);
if (recognizer.state == UIGestureRecognizerStateEnded) {
lastScale = 1.0f;
}
Take a photo method
//Adjust crop based on zoom scale of the user
CGFloat zoomReciprocal = 1.0f / currentScale;
CGPoint offset = CGPointMake(((1.0f - zoomReciprocal) / 2.0f), (((1.0f- zoomReciprocal)*(720.0f/1280.0f)) / 2.0f) + ((720.0f/1280.0f)/2)) ;
CGRect newCrop = cropFilter.cropRegion;
newCrop.origin.x = offset.x;
newCrop.origin.y = offset.y;
newCrop.size.width = cropFilter.cropRegion.size.width * zoomReciprocal;
newCrop.size.height = cropFilter.cropRegion.size.height *zoomReciprocal;
cropFilter.cropRegion = newCrop;
*/
//Place photo inside an image preview view for the user to decide if they want to keep it.
[stillCamera capturePhotoAsImageProcessedUpToFilter:cropFilter withOrientation:imageOrientation withCompletionHandler:^(UIImage *processedImage, NSError *error) {
//Pause the current camera
[stillCamera pauseCameraCapture];
//Rest of method
ADDED METHODS
- (void) flipCamera {
if (stillCamera.cameraPosition != AVCaptureDevicePositionFront) {
[UIView animateWithDuration:.65 animations:^{
flipCamera.transform = CGAffineTransformMakeScale(-1, 1);
}];
} else {
[UIView animateWithDuration:.65 animations:^{
flipCamera.transform = CGAffineTransformMakeScale(1, 1);
}];
}
[self performSelector:#selector(rotateCamera) withObject:0 afterDelay:.2];
}
- (void) rotateCamera {
[stillCamera rotateCamera];
//Adjust flash settings as needed
[stillCamera.inputCamera lockForConfiguration:nil];
if (stillCamera.cameraPosition != AVCaptureDevicePositionFront) {
[stillCamera.inputCamera setFlashMode:AVCaptureFlashModeOff];
}
NSAttributedString *attributedFlash =
[[NSAttributedString alloc]
initWithString:#"off"
attributes:
#{
NSFontAttributeName : [UIFont fontWithName:#"Roboto-Regular" size:13.0f],
NSForegroundColorAttributeName : [UIColor colorWithWhite:1 alpha:.55],
NSKernAttributeName : #(.25f)
}];
flashLabel.attributedText = attributedFlash;
[UIView animateWithDuration:.2 animations:^{
[flash setTintColor:[UIColor colorWithWhite:1 alpha:.55]];
}];
[stillCamera.inputCamera unlockForConfiguration];
}
- (void) changeFlash {
if (stillCamera.cameraPosition == AVCaptureDevicePositionFront) {//no flash available on front of camera
return;
}
[stillCamera.inputCamera lockForConfiguration:nil];
if (stillCamera.inputCamera.flashMode == AVCaptureFlashModeOff) {
[stillCamera.inputCamera setFlashMode:AVCaptureFlashModeOn];
[self animateFlashWithTintColor:[UIColor colorWithWhite:1 alpha:1] andString:#"on"];
} else if (stillCamera.inputCamera.flashMode == AVCaptureFlashModeOn) {
[stillCamera.inputCamera setFlashMode:AVCaptureFlashModeOff];
[self animateFlashWithTintColor:[UIColor colorWithWhite:1 alpha:.55] andString:#"off"];
}
[stillCamera.inputCamera unlockForConfiguration];
}
- (void) animateFlashWithTintColor:(UIColor *)color andString:(NSString *)text {
//Set new text
NSAttributedString *attributedFlash =
[[NSAttributedString alloc]
initWithString:text
attributes:
#{
NSFontAttributeName : [UIFont fontWithName:#"Roboto-Regular" size:13.0f],
NSForegroundColorAttributeName : [UIColor colorWithWhite:1 alpha:.55],
NSKernAttributeName : #(.25f)
}];
flashLabel.attributedText = attributedFlash;
float duration = .7;
[UIView animateKeyframesWithDuration:duration delay:0 options:0 animations:^{
[UIView addKeyframeWithRelativeStartTime:0 relativeDuration:duration animations:^{
[flash setTintColor:color];
}];
[UIView addKeyframeWithRelativeStartTime:0 relativeDuration:.7/duration animations:^{
flash.transform = CGAffineTransformMakeRotation(M_PI);
}];
}completion:^(BOOL finished){
flash.transform = CGAffineTransformIdentity;
}];
}
-(void) usePhoto {
if ([ALAssetsLibrary authorizationStatus] != ALAuthorizationStatusAuthorized){
NSLog(#"Do Not Have Right To Save to Photo Library");
}
//Save Image to Phone Album & save image
UIImageWriteToSavedPhotosAlbum(takenPhoto.image, nil, nil, nil);
//Save Image to Delegate
[self.delegate saveImageToDatabase:takenPhoto.image];
[self performSelector:#selector(dismissCamera) withObject:0 afterDelay:.4];
}
Some additional code showing the creation of the the various camera elements used to capture a photo.
centerPoint = CGPointMake(self.view.frame.size.width/2, (cameraHolder.frame.size.height+50+self.view.frame.size.height)/2);
cameraImagePreview = [[GPUImageView alloc] initWithFrame:CGRectMake(0, 0, cameraHolder.frame.size.width, cameraHolder.frame.size.width)];
[cameraHolder addSubview:cameraImagePreview];
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(imageTouch:)];
[cameraImagePreview addGestureRecognizer:tapGesture];
UIPinchGestureRecognizer *pinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:#selector(imagePinch:)];
[cameraImagePreview addGestureRecognizer:pinchGesture];
float scaleForView = self.view.frame.size.width/720.0;
fullCameraFocusPoint = [[UIView alloc]initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 1280*scaleForView)];
fullCameraFocusPoint.center = CGPointMake(cameraHolder.frame.size.width/2, (cameraHolder.frame.size.width/2)+50);
[self.view insertSubview:fullCameraFocusPoint atIndex:0];
takenPhoto = [[UIImageView alloc]initWithFrame:cameraHolder.frame];
takenPhoto.alpha = 0;
[self.view addSubview:takenPhoto];
//Add in filters
stillCamera = [[GPUImageStillCamera alloc] initWithSessionPreset:AVCaptureSessionPreset1280x720 cameraPosition:AVCaptureDevicePositionBack];
stillCamera.outputImageOrientation = UIInterfaceOrientationPortrait;
//Creating a square crop filter
cropFilter = [[GPUImageCropFilter alloc] initWithCropRegion:CGRectMake(0.f, (720.0f/1280.0f)/2.0f, 1.f, (720.0f/1280.0f))];
//Create standard vignette filter
vignetteFilter = [[GPUImageVignetteFilter alloc] init]; //1
vignetteFilter.vignetteCenter = CGPointMake(.5, .5);
vignetteFilter.vignetteStart = 0.4f;
vignetteFilter.vignetteEnd = 1.08f;
//Add filters to photo
[cropFilter addTarget:vignetteFilter];
[stillCamera addTarget:cropFilter];
[vignetteFilter addTarget:cameraImagePreview];
[stillCamera startCameraCapture];
I am creating a view with UINavigationBar and UITabBar. I have added a button on tab bar, on button click, i am hiding tab bar and show tool bar at the bottom. My code is written for current as well as previous iOS versions. I am using this code self.edgesForExtendedLayout = UIRectEdgeNone; for iOS7 this is my code :
- (void)hideTabBar {
UITabBar *tabBar = self.tabBarController.tabBar;
UIView *parent = tabBar.superview; // UILayoutContainerView
UIView *content = [parent.subviews objectAtIndex:0]; // UITransitionView
UIView *window = parent.superview;enter code here
[UIView animateWithDuration:0.5
animations:^{
CGRect tabFrame = tabBar.frame;
tabFrame.origin.y = CGRectGetMaxY(window.bounds);
tabBar.frame = tabFrame;
// CGRect contentFrame = content.frame;
// contentFrame.size.height -= tabFrame.size.height;
content.frame = window.bounds;
}];
if ([[[UIDevice currentDevice] systemVersion] intValue] < 7.0)
{
CGRect frame = tbl_AllFiles.frame;
frame.size.height -=tabBar.frame.size.height;
tbl_AllFiles.frame = frame;
}
}
- (void)showTabBar {
UITabBar *tabBar = self.tabBarController.tabBar;
UIView *parent = tabBar.superview; // UILayoutContainerView
UIView *content = [parent.subviews objectAtIndex:0]; // UITransitionView
UIView *window = parent.superview;
if ([[[UIDevice currentDevice] systemVersion] intValue] < 7.0)
{
CGRect frame = tbl_AllFiles.frame;
frame.size.height +=tabBar.frame.size.height;
tbl_AllFiles.frame = frame;
}
[UIView animateWithDuration:0.5
animations:^{
CGRect tabFrame = tabBar.frame;
tabFrame.origin.y = CGRectGetMaxY(window.bounds) - CGRectGetHeight(tabBar.frame);
tabBar.frame = tabFrame;
CGRect contentFrame = content.frame;
contentFrame.size.height -= tabFrame.size.height;
content.frame = contentFrame;
}];
}
- (void)loadToolBar {
toolbar = [UIToolbar new];
toolbar.barStyle = UIBarStyleBlackTranslucent;
moveButton = [UIButton buttonWithType:UIButtonTypeCustom];
[moveButton setFrame:CGRectMake(10, 10, 120, 25)];
[moveButton setBackgroundColor:[UIColor redColor]];
[moveButton setTitle:#"Move" forState:UIControlStateNormal];
[moveButton addTarget:self action:#selector(moveFile_Folder:) forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem *moveItem = [[[UIBarButtonItem alloc] initWithCustomView:moveButton] autorelease];
moveItem.style = UIBarButtonItemStyleBordered;
NSArray *items = [NSArray arrayWithObjects:moveItem, nil];
toolbar.items = items;
[toolbar sizeToFit];
CGFloat toolbarHeight = [toolbar frame].size.height;
CGRect mainViewBounds = self.view.bounds;
if ([[[UIDevice currentDevice] systemVersion] intValue] < 7.0)
{
[toolbar setFrame:CGRectMake(CGRectGetMinX(mainViewBounds),
CGRectGetMinY(mainViewBounds) + CGRectGetHeight(mainViewBounds) - (toolbarHeight),
CGRectGetWidth(mainViewBounds),
toolbarHeight)];
}
else
{
[toolbar setFrame:CGRectMake(CGRectGetMinX(mainViewBounds),
CGRectGetMinY(mainViewBounds) + CGRectGetHeight(mainViewBounds),
CGRectGetWidth(mainViewBounds),
toolbarHeight)];
}
[self.view addSubview:toolbar];
[toolbar bringSubviewToFront:self.view];
}
My issue is on button clicked hideTabBar and loadToolBar methods are called. Everything is working fine, except my button is un-clickable now on toolbar.
Please help me.
i had a similar issue if your viewcontroller is not the root view controller iOS doesn't get the view frame.
Add this line to your viewcontroller in viewdidload,
self.view.frame = [UIScreen mainScreen].bounds;
hope it helps
I have two View Controllers with views. The first one is a login screen and the second one fetches stuff from the web (irrelevant).
I used a custom segue animation and had to do some weird stuff with the superview to get the sourceViewController.view to be "on top" (visually) of the destinationViewController.view
I can only assume this is why when i try to call IBAction methods from the second view they won't call.
Here is the segue class implementation:
- (void) perform {
UIViewController *sourceViewController = (UIViewController *) self.sourceViewController;
UIViewController *destinationViewController = (UIViewController *) self.destinationViewController;
UIView *parent = sourceViewController.view.superview;
[sourceViewController.view removeFromSuperview];
[parent addSubview: destinationViewController.view];
[parent addSubview:sourceViewController.view];
sourceViewController.view.layer.masksToBounds = NO;
sourceViewController.view.layer.cornerRadius = 8; // if you like rounded corners
sourceViewController.view.layer.shadowOffset = CGSizeMake(0,0);
sourceViewController.view.layer.shadowRadius = 10;
sourceViewController.view.layer.shadowOpacity = 1;
destinationViewController.view.frame = CGRectMake(0, 20, destinationViewController.view.frame.size.width, destinationViewController.view.frame.size.height);
sourceViewController.view.frame = CGRectMake(0, 20, sourceViewController.view.frame.size.width, sourceViewController.view.frame.size.height);
[UIView animateWithDuration:.6
delay:0.0
options:UIViewAnimationCurveEaseInOut
animations:^{
sourceViewController.view.frame = CGRectMake(-sourceViewController.view.frame.size.width-10, 20, sourceViewController.view.frame.size.width, sourceViewController.view.frame.size.height);
}
completion:^(BOOL finished){
//[destinationViewController.view removeFromSuperview];
[sourceViewController.navigationController pushViewController:destinationViewController animated:NO];
}];
}
My question is, can removing the source view from its superview and playing around with that ruin the way that IBActions are called on the second view?
The IBAction methods just crash the app, on a button push for example.
I fixed my issue by changing my code to this:
UIViewController *sourceViewController = (UIViewController *) self.sourceViewController;
UIViewController *destinationViewController = (UIViewController *) self.destinationViewController;
UIView *parent = sourceViewController.view.superview;
[parent addSubview:destinationViewController.view];
[parent sendSubviewToBack: destinationViewController.view];
sourceViewController.view.layer.masksToBounds = NO;
sourceViewController.view.layer.cornerRadius = 8; // if you like rounded corners
sourceViewController.view.layer.shadowOffset = CGSizeMake(0,0);
sourceViewController.view.layer.shadowRadius = 10;
sourceViewController.view.layer.shadowOpacity = 1;
destinationViewController.view.frame = CGRectMake(0, 20, destinationViewController.view.frame.size.width, destinationViewController.view.frame.size.height);
sourceViewController.view.frame = CGRectMake(0, 20, sourceViewController.view.frame.size.width, sourceViewController.view.frame.size.height);
[UIView animateWithDuration:.6
delay:0.0
options:UIViewAnimationCurveEaseInOut
animations:^{
sourceViewController.view.frame = CGRectMake(-sourceViewController.view.frame.size.width-10, 20, sourceViewController.view.frame.size.width, sourceViewController.view.frame.size.height);
}
completion:^(BOOL finished){
[sourceViewController presentViewController:destinationViewController animated:NO completion:NULL];
}];
A few things changed, but notably, i used
[sourceViewController presentViewController:destinationViewController animated:NO completion:NULL];
to initialise the controller properly.
Hope this helps someone else out in the future.
I am trying to create a page turn application in xcode. The page turn works fine for landscape right but for landscape left, the page curl happens from the left. I added a container view and then the page curl on landscape left started happening from the bottom but not from right.
I found some suggestions here (http://stackoverflow.com/questions/4780488/i-want-to-use-animation-to-imageview-using-uianimationtransitioncurl-right-or-lef) and here (http://stackoverflow.com/questions/4780488/i-want-to-use-animation-to-imageview-using-uianimationtransitioncurl-right-or-lef)
but these both suggestions were with old style of page transition code and not with the block code. I tried to modify these with new block style code but it is not working for me.
I am attaching my code here:
- (void)viewDidLoad
{
UIImage *img = [UIImage imageNamed:#"s1p1.png"];
currentView.image = img;
img = [UIImage imageNamed:#"s1p2.png"];
swapView.image = img;
UISwipeGestureRecognizer *nextPage;
nextPage = [[[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(turnPage)] autorelease];
if ([[UIDevice currentDevice] orientation] == UIInterfaceOrientationLandscapeLeft) {
[nextPage setDirection:UISwipeGestureRecognizerDirectionRight];
}
else {
[nextPage setDirection:UISwipeGestureRecognizerDirectionLeft];
}
[self.view addGestureRecognizer:nextPage];
[super viewDidLoad];
}
-(void) turnPage
{
if ([[UIDevice currentDevice] orientation] == UIInterfaceOrientationLandscapeLeft)
{
NSLog(#"landscapeleft");
mainView.transform = CGAffineTransformMakeRotation(M_PI);
currentView.transform = CGAffineTransformMakeRotation(-M_PI);
swapView.transform = CGAffineTransformMakeRotation(-M_PI);
[UIView transitionWithView:mainView
duration:1
options:UIViewAnimationOptionTransitionCurlUp
animations:^{
currentView.hidden = YES;
swapView.hidden = NO;
}
completion:^(BOOL finished){
UIImage *temp = [currentView.image retain];
currentView.image = swapView.image;
swapView.image = temp;
[temp release];
currentView.hidden = NO;
swapView.hidden = YES;
}];
}
else
{
NSLog(#"landscaperight");
[UIView transitionWithView:self.view
duration:1
options:UIViewAnimationOptionTransitionCurlUp
animations:^{
currentView.hidden = YES;
swapView.hidden = NO;
}
completion:^(BOOL finished){
UIImage *temp = [currentView.image retain];
currentView.image = swapView.image;
swapView.image = temp;
[temp release];
currentView.hidden = NO;
swapView.hidden = YES;
}];
}
}
where I have two views: the self.view is the primary view from the window and then the mainView is my container view. currentView and SwapView are imageviews.
Any thoughts on this? Many thanks for reviewing this.
I have a UITextField in a table view on a UIViewController (not a UITableViewController).
If the table view is on a UITableViewController, the table will automatically scroll to the textField being edited to prevent it from being hidden by the keyboard. But on a UIViewController it does not.
I have tried for a couple of days reading through multiple ways to try to accomplish this and I cannot get it to work. The closest thing that actually scrolls is:
-(void) textFieldDidBeginEditing:(UITextField *)textField {
// SUPPOSEDLY Scroll to the current text field
CGRect textFieldRect = [textField frame];
[self.wordsTableView scrollRectToVisible:textFieldRect animated:YES];
}
However this only scrolls the table to the topmost row.
What seems like an easy task has been a couple of days of frustration.
I am using the following to construct the tableView cells:
- (UITableViewCell *)tableView:(UITableView *)aTableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *identifier = [NSString stringWithFormat: #"%d:%d", [indexPath indexAtPosition: 0], [indexPath indexAtPosition:1]];
UITableViewCell *cell = [aTableView dequeueReusableCellWithIdentifier:identifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:identifier] autorelease];
cell.accessoryType = UITableViewCellAccessoryNone;
UITextField *theTextField = [[UITextField alloc] initWithFrame:CGRectMake(180, 10, 130, 25)];
theTextField.adjustsFontSizeToFitWidth = YES;
theTextField.textColor = [UIColor redColor];
theTextField.text = [textFieldArray objectAtIndex:indexPath.row];
theTextField.keyboardType = UIKeyboardTypeDefault;
theTextField.returnKeyType = UIReturnKeyDone;
theTextField.font = [UIFont boldSystemFontOfSize:14];
theTextField.backgroundColor = [UIColor whiteColor];
theTextField.autocorrectionType = UITextAutocorrectionTypeNo;
theTextField.autocapitalizationType = UITextAutocapitalizationTypeNone;
theTextField.clearsOnBeginEditing = NO;
theTextField.textAlignment = UITextAlignmentLeft;
//theTextField.tag = 0;
theTextField.tag=indexPath.row;
theTextField.delegate = self;
theTextField.clearButtonMode = UITextFieldViewModeWhileEditing;
[theTextField setEnabled: YES];
[cell addSubview:theTextField];
[theTextField release];
}
return cell;
}
I suspect I can get the tableView to scroll properly if I can somehow pass the indexPath.row in the textFieldDidBeginEditing method?
Any help is appreciated.
In my app, I have successfully used a combination of contentInset and scrollToRowAtIndexPath like this:
When you want to display the keyboard, just add a contentInset at the bottom with your table with desired height:
tableView.contentInset = UIEdgeInsetsMake(0, 0, height, 0);
Then, you can safely use
[tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:cell_index inSection:cell_section] animated:YES];
By adding the contentInset, even if you are focusing on the last cell the tableView will still be able to scroll. Just make sure that when you are dismissing the keyboard, you reset the contentInset.
EDIT:
If you have only one section (you can replace cell_section with 0) and the use the textView tag to inform the cell row.
Swift
#objc private func keyboardWillShow(_ notification: Notification) {
guard let userinfo = notification.userInfo else {
return
}
guard
let duration = (userinfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue,
let endFrame = (userinfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue,
let curveOption = userinfo[UIResponder.keyboardAnimationCurveUserInfoKey] as? UInt else {
return
}
UIView.animate(withDuration: duration, delay: 0, options: [.beginFromCurrentState, .init(rawValue: curveOption)], animations: {
let edgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: endFrame.height, right: 0)
self.scrollView.contentInset = edgeInsets
self.scrollView.scrollIndicatorInsets = edgeInsets
})
}
#objc private func keyboardWillHide(_ notification: Notification) {
guard let userinfo = notification.userInfo else {
return
}
guard
let duration = (userinfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue,
let curveOption = userinfo[UIResponder.keyboardAnimationCurveUserInfoKey] as? UInt else {
return
}
UIView.animate(withDuration: duration, delay: 0, options: [.beginFromCurrentState, .init(rawValue: curveOption)], animations: {
let edgeInsets = UIEdgeInsets.zero
self.scrollView.contentInset = edgeInsets
self.scrollView.scrollIndicatorInsets = edgeInsets
})
}
override func viewDidLoad() {
super.viewDidLoad()
// ...
subscribeToKeyboardNotifications()
}
deinit {
unsubscribeFromKeyboardNotifications()
}
private func subscribeToKeyboardNotifications() {
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIWindow.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIWindow.keyboardWillHideNotification, object: nil)
}
private func unsubscribeFromKeyboardNotifications() {
NotificationCenter.default.removeObserver(self, name: UIWindow.keyboardWillShowNotification, object: nil)
NotificationCenter.default.removeObserver(self, name: UIWindow.keyboardWillHideNotification, object: nil)
}
Objective C
- (void)keyboardWillShow:(NSNotification *)sender
{
CGFloat height = [[sender.userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size.height;
NSTimeInterval duration = [[sender.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
UIViewAnimationOptions curveOption = [[sender.userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] unsignedIntegerValue] << 16;
[UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionBeginFromCurrentState|curveOption animations:^{
UIEdgeInsets edgeInsets = UIEdgeInsetsMake(0, 0, height, 0);
tableView.contentInset = edgeInsets;
tableView.scrollIndicatorInsets = edgeInsets;
} completion:nil];
}
- (void)keyboardWillHide:(NSNotification *)sender
{
NSTimeInterval duration = [[sender.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
UIViewAnimationOptions curveOption = [[sender.userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] unsignedIntegerValue] << 16;
[UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionBeginFromCurrentState|curveOption animations:^{
UIEdgeInsets edgeInsets = UIEdgeInsetsZero;
tableView.contentInset = edgeInsets;
tableView.scrollIndicatorInsets = edgeInsets;
} completion:nil];
}
And in - (void)viewDidLoad
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
Then
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
This is a tweak to FunkyKat's answer (big thank you FunkyKat!). It would probably be beneficial to not hardcode UIEdgeInsetsZero for future iOS compatibility.
Instead, I ask for the current inset value and tweak the bottom value as needed.
- (void)keyboardWillShow:(NSNotification *)sender {
CGSize kbSize = [[[sender userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
NSTimeInterval duration = [[[sender userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
CGFloat height = UIDeviceOrientationIsPortrait([[UIDevice currentDevice] orientation]) ? kbSize.height : kbSize.width;
if (isIOS8()) height = kbSize.height;
[UIView animateWithDuration:duration animations:^{
UIEdgeInsets edgeInsets = [[self tableView] contentInset];
edgeInsets.bottom = height;
[[self tableView] setContentInset:edgeInsets];
edgeInsets = [[self tableView] scrollIndicatorInsets];
edgeInsets.bottom = height;
[[self tableView] setScrollIndicatorInsets:edgeInsets];
}];
}
- (void)keyboardWillHide:(NSNotification *)sender {
NSTimeInterval duration = [[[sender userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
[UIView animateWithDuration:duration animations:^{
UIEdgeInsets edgeInsets = [[self tableView] contentInset];
edgeInsets.bottom = 0;
[[self tableView] setContentInset:edgeInsets];
edgeInsets = [[self tableView] scrollIndicatorInsets];
edgeInsets.bottom = 0;
[[self tableView] setScrollIndicatorInsets:edgeInsets];
}];
}
For the sake of anyone else running into this issue, I'm posting the necessary methods here:
- (UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *identifier = [NSString stringWithFormat: #"%d:%d", [indexPath indexAtPosition: 0], [indexPath indexAtPosition:1]];
UITableViewCell *cell = [aTableView dequeueReusableCellWithIdentifier:identifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier] autorelease];
UITextField *theTextField = [[UITextField alloc] initWithFrame:CGRectMake(180, 10, 130, 25)];
theTextField.keyboardType = UIKeyboardTypeDefault;
theTextField.returnKeyType = UIReturnKeyDone;
theTextField.clearsOnBeginEditing = NO;
theTextField.textAlignment = UITextAlignmentLeft;
// (The tag by indexPath.row is the critical part to identifying the appropriate
// row in textFieldDidBeginEditing and textFieldShouldEndEditing below:)
theTextField.tag=indexPath.row;
theTextField.delegate = self;
theTextField.clearButtonMode = UITextFieldViewModeWhileEditing;
[theTextField setEnabled: YES];
[cell addSubview:theTextField];
[theTextField release];
}
return cell;
}
-(void) textFieldDidBeginEditing:(UITextField *)textField {
int z = textField.tag;
if (z > 4) {
// Only deal with the table row if the row index is 5
// or greater since the first five rows are already
// visible above the keyboard
// resize the UITableView to fit above the keyboard
self.wordsTableView.frame = CGRectMake(0.0,44.0,320.0,200.0);
// adjust the contentInset
wordsTableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 10);
// Scroll to the current text field
[wordsTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:z inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:YES];
}
}
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField {
// Determine which row is being edited
int z = textField.tag;
if (z > 4) {
// resize the UITableView to the original size
self.wordsTableView.frame = CGRectMake(0.0,44.0,320.0,416.0);
// Undo the contentInset
wordsTableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0);
}
return YES;
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
// Dismisses the keyboard when the "Done" button is clicked
[textField resignFirstResponder];
return YES;
}
I needed a simple solution so for me helped:
func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
let pointInTable = textField.superview!.convert(textField.frame.origin, to: tableView)
var tableVContentOffset = tableView.contentOffset
tableVContentOffset.y = pointInTable.y
if let accessoryView = textField.inputAccessoryView {
tableVContentOffset.y -= accessoryView.frame.size.height
}
tableView.setContentOffset(tableVContentOffset, animated: true)
return true;
}
Try my coding, this will help for ypu
tabelview.contentInset = UIEdgeInsetsMake(0, 0, 210, 0);
[tableview scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:your_indexnumber inSection:Your_section]
atScrollPosition:UITableViewScrollPositionMiddle animated:NO];
Apple has an official post explaining how to do this naturally as they do in the UITableViewController. My Stackoverflow answer has this explained along with a swift version.
https://stackoverflow.com/a/31869898/1032179
You need to resize the tableView itself so that it does not go under the keyboard.
-(void) textFieldDidBeginEditing:(UITextField *)textField {
// SUPPOSEDLY Scroll to the current text field
self.worldsTableView.frame = CGRectMake(//make the tableView smaller; to only be in the area above the keyboard);
CGRect textFieldRect = [textField frame];
[self.wordsTableView scrollRectToVisible:textFieldRect animated:YES];
}
Alternatively, you can use a keyboard notification; this works slightly better because you have more information, and is more consistent in terms of knowing when the keyboard is coming up:
//ViewDidLoad
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
And then implement:
- (void)keyboardWillShow:(NSNotification *)notification {
}
- (void)keyboardWillHide:(NSNotification *)notification {
}
My code. Maybe someone will be useful:
Custom textField cell in tableView
.m
#property (nonatomic, strong) UITextField *currentCellTextField;
CustomCell * cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier2];
if (cell == nil) {
NSArray * nib = [[NSBundle mainBundle] loadNibNamed:#"CustomCell" owner:self options:nil];
cell = (CustomCell *)[nib objectAtIndex:0];
cell.textfield.delegate = self;
}
- (void) textFieldDidBeginEditing:(UITextField *)textField
{
self.currentCellTextField = textField;
CGPoint pnt = [self.organisationTableView convertPoint:textField.bounds.origin fromView:textField];
NSIndexPath* path = [self.organisationTableView indexPathForRowAtPoint:pnt];
if (path.section >= 2) {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.3];
self.organisationTableView.contentInset = UIEdgeInsetsMake(0, 0, kOFFSET_FOR_KEYBOARD, 0);
CGPoint siize = self.organisationTableView.contentOffset;
siize.y =(pnt.y-170);
self.organisationTableView.contentOffset = CGPointMake(0, siize.y);
[UIView commitAnimations];
}
}
-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
CGPoint pnt = [self.organisationTableView convertPoint:textField.bounds.origin fromView:textField];
NSIndexPath* path = [self.organisationTableView indexPathForRowAtPoint:pnt];
if (path.section >= 2) {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.3];
self.organisationTableView.contentInset = UIEdgeInsetsZero;
self.organisationTableView.contentOffset = CGPointMake(0, self.organisationTableView.contentOffset.y);
[UIView commitAnimations];
}
return YES;
}
In my case my UITableview was inside another UIView and that UIvie was in the main UIScrollview. So I used more general solution for those kind of problems.
I simply found the Y coordinate of my cell in the specific UIScrollView and then scrolled to correct point:
-(void)textFieldDidBeginEditing:(UITextField *)textField{
float kbHeight = 216;//Hard Coded and will not support lanscape mode
UITableViewCell *cell = (UITableViewCell *)[textField superview];
float scrollToHeight = [self FindCordinate:cell];
[(UIScrollView *)self.view setContentOffset:CGPointMake(0, scrollToHeight - kbHeight + cell.frame.size.height) animated:YES];
}
-(float)FindCordinate:(UIView *)cell{
float Ycordinate = 0.0;
while ([cell superview] != self.view) {
Ycordinate += cell.frame.origin.y;
cell = [cell superview];
}
Ycordinate += cell.frame.origin.y;
return Ycordinate;
}
Another simple solution is adding an additional space for the footer of the last table section:
- (float)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
if (section == lastSection) {
return keyboard height;
}
return 0;
}
We can add our icon into this area as well. :)
You can try adding a UITableViewController to the UIViewController instead of just a table view. This way you can call UITableViewController's viewWillAppear and everything will appear to work.
Example:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[tableViewController viewWillAppear:animated];
}
I have add a little feature to #FunkyKat and #bmauter answers (great answer by the way, it should be the one accepted)
The regular Table View edge insets is preserved, before/after the keyboard apparition.
- (void)keyboardWillShow:(NSNotification *)sender
{
CGSize kbSize = [[[sender userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
NSTimeInterval duration = [[[sender userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
CGFloat height = UIDeviceOrientationIsPortrait([[UIDevice currentDevice] orientation]) ? kbSize.width : kbSize.height;
[UIView animateWithDuration:duration animations:^{
UIEdgeInsets edgeInsets = self.tableView.contentInset;
edgeInsets.bottom += height;
self.tableView.contentInset = edgeInsets;
edgeInsets = self.tableView.scrollIndicatorInsets;
edgeInsets.bottom += height;
self.tableView.scrollIndicatorInsets = edgeInsets;
}];
}
- (void)keyboardWillHide:(NSNotification *)sender
{
CGSize kbSize = [[[sender userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
NSTimeInterval duration = [[[sender userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
CGFloat height = UIDeviceOrientationIsPortrait([[UIDevice currentDevice] orientation]) ? kbSize.width : kbSize.height;
[UIView animateWithDuration:duration animations:^{
UIEdgeInsets edgeInsets = self.tableView.contentInset;
edgeInsets.bottom -= height;
self.tableView.contentInset = edgeInsets;
edgeInsets = self.tableView.scrollIndicatorInsets;
edgeInsets.bottom -= height;
self.tableView.scrollIndicatorInsets = edgeInsets;
}];
}