In Storyboard I applied Multiplier for height and width to UIImageView then I just want to rounded border so I used below code its not work for all iPhones.
_profileImgView.clipsToBounds = YES;
_profileImgView.layer.backgroundColor = color.CGColor;
_profileImgView.layer.cornerRadius =_profileImgView.frame.size.width/2;
_profileImgView.layer.borderColor = [UIColor colorWithRed:253.0/255.0 green:182.0/255.0 blue:43.0/255.0 alpha:100].CGColor;
_profileImgView.layer.borderWidth = 5.0f;
Since your corner radius depends on your frame size, you need to update it whenever the frame size changes. If you are using storyboards for your design, you will get the frame size that is in the design when viewDidLoad is called. If the frame size differs for different devices, you will get the final size at a later point in time in the views layoutSubviews or possibly the view controller's viewDidLayoutSubviews.
My suggested solution is to sub-class UIImageView and put the specifics for the image view in awakeFromNib and layoutSubviews, then use this class instead of UIImageView where appropriate.
// CircularImageView.h
#import <UIKit/UIKit.h>
#interface CircularImageView : UIImageView
#end
// CircularImageView.m
#implementation CircularImageView
- (void)awakeFromNib {
[super awakeFromNib];
self.clipsToBounds = YES;
self.layer.borderColor = [UIColor colorWithRed:253.0/255.0 green:182.0/255.0 blue:43.0/255.0 alpha:100].CGColor;
self.layer.borderWidth = 5.0f;
}
- (void)layoutSubviews {
[super layoutSubviews];
self.layer.cornerRadius = self.frame.size.width / 2;
}
#end
implement this code in same Viewcontroller class it is work for me
-(void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
_profileImgView.clipsToBounds = YES;
_profileImgView.layer.backgroundColor = color.CGColor;
_profileImgView.layer.cornerRadius =_profileImgView.frame.size.width/2;
_profileImgView.layer.borderColor = [UIColor colorWithRed:253.0/255.0 green:182.0/255.0 blue:43.0/255.0 alpha:100].CGColor;
_profileImgView.layer.borderWidth = 5.0f;
}
I'm initializing a loader subview to match the height, width and position of the UITabBar I'm using to wrap my app:
// In UITabBarController implementation
LoaderView *loaderView = [[LoaderView alloc] initWithFrame:[self tabBar].viewForBaselineLayout.frame];
[[self view] addSubview:loaderView];
//
// LoaderView.h
#import <UIKit/UIKit.h>
#interface LoaderView : UIView
#property (nonatomic, strong) UILabel *messageLabel;
#property (nonatomic, strong) NSString *message;
#property (nonatomic) CGRect frame;
- (void)createLabel;
- (void)drawLoader;
- (void)setText:(NSString *)newMessage;
- (void)show:(NSNotification *)notification;
#end
//
// LoaderView.m
#import "LoaderView.h"
#implementation LoaderView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self drawLoader];
}
return self;
}
- (void)drawLoader
{
UIColor *semiOpaqueGray = [[UIColor alloc] initWithRed:0.0f green:0.0f blue:0.0f alpha:0.8f];
[self setBackgroundColor:semiOpaqueGray];
[self createLabel];
}
- (void)createLabel
{
_messageLabel = [[UILabel alloc] initWithFrame: CGRectMake(15,9,([self frame].size.width - 10), 30)];
_messageLabel.textColor = [[UIColor alloc] initWithWhite:1.0 alpha:1];
_messageLabel.backgroundColor = [[UIColor alloc] initWithWhite:1.0 alpha:0.0];
[self addSubview:_messageLabel];
}
#end
The frame struct represents this incoming frame data:
2013-09-16 07:48:35.552 ---[97825:a0b] {{0, 519}, {320, 49}}
// Ostensibly 0,519 origin point and 320,49 w/h
The result is this. The mostly opaque dark box can be spotted in the top left corner. It looks like it's being positioned by its center point of the loader to the top left most point of the screen:
I can make the size of the box change, but I can't seem to move it from that top left position. Further, I set an animation on it, and that animation adjusts the frame (sliding it up an down from the tab bar area). That seems to have no effect either.
Thanks in advance for your help.
You can gently add your loadingView your application window. After set the frame of loaderView.
[loadView setFrame:CGRectMake(0,0,self.frame.size.width.,self.frame.size.height)];
[self.window addSubview:loaderView];
Then after loading finished.
[self.window removeSubview:loaderView];
Your superview is the problem. If you're adding it to your UINavigationController then the y-axis likely won't respond nicely. Try using the primary view of your controller
loaderView.frame = CGRectMake(x, 514, 40, 320); // made up numbers
[self.mapView addSubview:loaderView];
Also you're accessing your tabBar. Try using UIDevice window for getting your width and inherit the height from your labels on the bottom (or nest the labels within your LoaderView)
Also look into actually using UITabBar for handling this.
I'm trying to create a function to change the size of something like a UILabel or UIButton without having to type the three lines out every time. This is what I have.
-(void)setObject:(UIControl*)object SizeWidth:(NSInteger)width Height:(NSInteger)height
{
CGRect labelFrame = object.frame;
labelFrame.size = CGSizeMake(width, height);
object.frame = labelFrame;
}
However, when I give (UIControl*)object a UILabel, it says "incompatible pointer types". How can I fix this to work for anything I can put on a UIView?
UILabel is not a subclass of UIControl, it inherits from UIView.
Try changing UIControl to UIView:
-(void)setObject:(UIView*)object SizeWidth:(NSInteger)width Height:(NSInteger)height
{
CGRect labelFrame = object.frame;
labelFrame.size = CGSizeMake(width, height);
object.frame = labelFrame;
}
(UIControl inherits from UIView anyway, and frame is a UIView property)
Label is not a subclass of UIControl. You can use UIView in place of UIControl.
Here is the hierarchy for UILabel
UILabel: UIView : UIResponder : NSObject
-(void)setObject:(UIView*)object SizeWidth:(NSInteger)width Height:(NSInteger)height
{
CGRect labelFrame = object.frame;
labelFrame.size = CGSizeMake(width, height);
object.frame = labelFrame;
}
One suggestion for you is, the method name seems kind of odd to me. You can write a simple category to update the size for UIView. With the following category you can simply call
[myLabel setWidth:20 andHeight:20];
In UIView + MyCategory.h
#import <UIKit/UIKit.h>
#interface UIView (MyCategory)
- (void)setWidth:(NSInteger)aWidth andHeight:(NSInteger)aHeight;
#end
In UIView + MyCategory.m
#import "UIView + MyCategory.h"
#implementation UIView (MyCategory)
- (void)setWidth:(NSInteger)aWidth andHeight:(NSInteger)aHeight;
{
CGRect frameToUpdate = self.frame;
frameToUpdate.size = CGSizeMake(aWidth, aHeight);
self.frame = frameToUpdate;
}
#end
And to address the actual problem you're trying to solve, I highly recommend using this set of helpers https://github.com/kreeger/BDKGeometry
Following Obj-C style conventions (as selecting the right tools for the job) make it more efficient for others to read and comprehend our code. The Objective-C style here needs a bit of cleanup. See my notes after the source if you're interested. On to a more concise way to do this:
You can go the class method route (perhaps in a view manipulation class)
#implementation CCViewGeometry
+ (void)adjustView:(UIView *)view toSize:(CGSize)size
{
CGRect frame = view.frame;
frame.size = size;
view.frame = frame;
}
#end
or the UIView category route
#implementation UIView (CCGeometry)
- (void)resize:(CGSize)size
{
CGRect frame = self.frame;
frame.size = size;
self.frame = frame;
}
#end
Style notes pertinent to code found on this page:
All method params should begin with a lower-case char.
setFoo: is used in #property synthesis & by convention your method name indicates setting a property named object to the value of object. You're setting the size, not the object itself.
Be explicit. Why have a method called setObject: when you know the general type of object being passed?
Width & height in UIKit are represented (rightly) by CGFloat, not NSInteger. Why pass width + height instead of CGSize anyway?
Try using class methods when state is not required. + is your friend. Don't fire up instances for every little thing (most singleton methods I see in ObjC code should be refactored as class methods).
The programmers that don't care about the little things end up with unmaintainable code—code that will slow them and those that come after them down. Convention and style matter a lot on any decent-sized project.
I have a NSSplitView as my "Superview". In this SplitView is a Custom View with a NSTableView. I'm try to load my Custom View from a Controller class and then adjust the size of the custom view and the Table. But the table and or the custom view don't get resized. What i'm doing wrong?
Here is my controller class method where i load and set the size of the custom view:
// Header File
#property (weak) IBOutlet NSView *navigationView;
#property (strong) AppsNavigationViewController *navigationViewController;
// Implementation
- (void) initNavigationView :(id)viewControllerClass :(NSString*) viewNibName {
_navigationViewController = [[viewControllerClass alloc]
initWithNibName:viewNibName bundle:nil];
// add the current custom view to the parent view
[_navigationView addSubview:[_navigationViewController view]];
[[_navigationViewController view] setAutoresizingMask:
NSViewHeightSizable|NSViewWidthSizable];
// set the bounds of the custom view to the size of the parent view
[[_navigationViewController view] setBounds:[_navigationView bounds]];
[_navigationViewController setDelegate:self]; // not relevant
[_splitView adjustSubviews]; // checked. contains the _navigationView
}
And here is how it looks:
EDIT
I subclassed some views and draw different backgrounds. And it's definitely the custom view which don't get the size!
It seems maybe your table's frame is not at the origin of its super view. First, try setting the frame instead of the bounds and you could call this after you do that.
[[_navigationViewController view] setFrameOrigin:NSMakePoint(0,0)];
Normally though I usually set the frame/bounds like this because your superview's bounds may not be at {0,0} of its superview...
NSRect newFrame;
newFrame.origin.x = 0;
newFrame.origin.y = 0;
newFrame.size.width = [[someView superview] frame].size.width;
newFrame.size.height = [[someView superview] frame].size.height;
[someView setFrame:newFrame];
I have 6 UITextFields on my UIScrollView. Now, I can scroll by user request. But when the keyboard appear, some textfields are hidden.
That is not user-friendly.
How scroll programmatically the view so I get sure the keyboard not hide the textfield?
Here's what worked for me. Having an instance variable that holds the value of the UIScrollView's offset before the view is adjusted for the keyboard so you can restore the previous state after the UITextField returns:
//header
#interface TheViewController : UIViewController <UITextFieldDelegate> {
CGPoint svos;
}
//implementation
- (void)textFieldDidBeginEditing:(UITextField *)textField {
svos = scrollView.contentOffset;
CGPoint pt;
CGRect rc = [textField bounds];
rc = [textField convertRect:rc toView:scrollView];
pt = rc.origin;
pt.x = 0;
pt.y -= 60;
[scrollView setContentOffset:pt animated:YES];
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[scrollView setContentOffset:svos animated:YES];
[textField resignFirstResponder];
return YES;
}
Finally, a simple fix:
UIScrollView* v = (UIScrollView*) self.view ;
CGRect rc = [textField bounds];
rc = [textField convertRect:rc toView:v];
rc.origin.x = 0 ;
rc.origin.y -= 60 ;
rc.size.height = 400;
[self.scroll scrollRectToVisible:rc animated:YES];
Now I think is only combine this with the link above and is set!
I've put together a universal, drop-in UIScrollView and UITableView subclass that takes care of moving all text fields within it out of the way of the keyboard.
When the keyboard is about to appear, the subclass will find the subview that's about to be edited, and adjust its frame and content offset to make sure that view is visible, with an animation to match the keyboard pop-up. When the keyboard disappears, it restores its prior size.
It should work with basically any setup, either a UITableView-based interface, or one consisting of views placed manually.
Here it is.
(For google: TPKeyboardAvoiding, TPKeyboardAvoidingScrollView, TPKeyboardAvoidingCollectionView.)
Editor's note: TPKeyboardAvoiding seems to be continually updated and fresh, as of 2014.
If you set the delegate of your text fields to a controller object in your program, you can have that object implement the textFieldDidBeginEditing: and textFieldShouldReturn: methods. The first method can then be used to scroll to your text field and the second method can be used to scroll back.
You can find code I have used for this in my blog: Sliding UITextViews around to avoid the keyboard. I didn't test this code for text views in a UIScrollView but it should work.
simple and best
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
// self.scrlViewUI.contentOffset = CGPointMake(0, textField.frame.origin.y);
[_scrlViewUI setContentOffset:CGPointMake(0,textField.center.y-90) animated:YES];
tes=YES;
[self viewDidLayoutSubviews];
}
The answers posted so far didn't work for me as I've a quite deep nested structure of UIViews. Also, the I had the problem that some of those answers were working only on certain device orientations.
Here's my solution, which will hopefully make you waste some less time on this.
My UIViewTextView derives from UIView, is a UITextView delegate and adds a UITextView after having read some parameters from an XML file for that UITextView (that XML part is left out here for clarity).
Here's the private interface definition:
#import "UIViewTextView.h"
#import <CoreGraphics/CoreGraphics.h>
#import <CoreGraphics/CGColor.h>
#interface UIViewTextView (/**/) {
#private
UITextView *tf;
/*
* Current content scroll view
* position and frame
*/
CGFloat currentScrollViewPosition;
CGFloat currentScrollViewHeight;
CGFloat kbHeight;
CGFloat kbTop;
/*
* contentScrollView is the UIScrollView
* that contains ourselves.
*/
UIScrollView contentScrollView;
}
#end
In the init method I have to register the event handlers:
#implementation UIViewTextView
- (id) initWithScrollView:(UIScrollView*)scrollView {
self = [super init];
if (self) {
contentScrollView = scrollView;
// ...
tf = [[UITextView alloc] initWithFrame:CGRectMake(0, 0, 241, 31)];
// ... configure tf and fetch data for it ...
tf.delegate = self;
// ...
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self selector:#selector(keyboardWasShown:) name: UIKeyboardWillShowNotification object:nil];
[nc addObserver:self selector:#selector(keyboardWasHidden:) name: UIKeyboardWillHideNotification object:nil];
[self addSubview:tf];
}
return(self);
}
Once that's done, we need to handle the keyboard show event. This gets called before the textViewBeginEditing is called, so we can use it to find out some properties of the keyboard. In essence, we want to know the height of the keyboard. This, unfortunately, needs to be taken from its width property in landscape mode:
-(void)keyboardWasShown:(NSNotification*)aNotification {
NSDictionary* info = [aNotification userInfo];
CGRect kbRect = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue];
CGSize kbSize = kbRect.size;
CGRect screenRect = [[UIScreen mainScreen] bounds];
CGFloat sWidth = screenRect.size.width;
CGFloat sHeight = screenRect.size.height;
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
if ((orientation == UIDeviceOrientationPortrait)
||(orientation == UIDeviceOrientationPortraitUpsideDown)) {
kbHeight = kbSize.height;
kbTop = sHeight - kbHeight;
} else {
//Note that the keyboard size is not oriented
//so use width property instead
kbHeight = kbSize.width;
kbTop = sWidth - kbHeight;
}
Next, we need to actually scroll around when we start editing. We do this here:
- (void) textViewDidBeginEditing:(UITextView *)textView {
/*
* Memorize the current scroll position
*/
currentScrollViewPosition = contentScrollView.contentOffset.y;
/*
* Memorize the current scroll view height
*/
currentScrollViewHeight = contentScrollView.frame.size.height;
// My top position
CGFloat myTop = [self convertPoint:self.bounds.origin toView:[UIApplication sharedApplication].keyWindow.rootViewController.view].y;
// My height
CGFloat myHeight = self.frame.size.height;
// My bottom
CGFloat myBottom = myTop + myHeight;
// Eventual overlap
CGFloat overlap = myBottom - kbTop;
/*
* If there's no overlap, there's nothing to do.
*/
if (overlap < 0) {
return;
}
/*
* Calculate the new height
*/
CGRect crect = contentScrollView.frame;
CGRect nrect = CGRectMake(crect.origin.x, crect.origin.y, crect.size.width, currentScrollViewHeight + overlap);
/*
* Set the new height
*/
[contentScrollView setFrame:nrect];
/*
* Set the new scroll position
*/
CGPoint npos;
npos.x = contentScrollView.contentOffset.x;
npos.y = contentScrollView.contentOffset.y + overlap;
[contentScrollView setContentOffset:npos animated:NO];
}
When we end editing, we do this to reset the scroll position:
- (void) textViewDidEndEditing:(UITextView *)textView {
/*
* Reset the scroll view position
*/
CGRect crect = contentScrollView.frame;
CGRect nrect = CGRectMake(crect.origin.x, crect.origin.y, crect.size.width, currentScrollViewHeight);
[contentScrollView setFrame:nrect];
/*
* Reset the scroll view height
*/
CGPoint npos;
npos.x = contentScrollView.contentOffset.x;
npos.y = currentScrollViewPosition;
[contentScrollView setContentOffset:npos animated:YES];
[tf resignFirstResponder];
// ... do something with your data ...
}
There's nothing left to do in the keyboard was hidden event handler; we leave it in anyway:
-(void)keyboardWasHidden:(NSNotification*)aNotification {
}
And that's it.
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
}
*/
#end
I know this is old, but still none of the solutions above had all the fancy positioning stuff required for that "perfect" bug-free, backwards compatible and flicker-free animation.
Let me share my solution (assuming you have set up UIKeyboardWill(Show|Hide)Notification):
// Called when UIKeyboardWillShowNotification is sent
- (void)keyboardWillShow:(NSNotification*)notification
{
// if we have no view or are not visible in any window, we don't care
if (!self.isViewLoaded || !self.view.window) {
return;
}
NSDictionary *userInfo = [notification userInfo];
CGRect keyboardFrameInWindow;
[[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardFrameInWindow];
// the keyboard frame is specified in window-level coordinates. this calculates the frame as if it were a subview of our view, making it a sibling of the scroll view
CGRect keyboardFrameInView = [self.view convertRect:keyboardFrameInWindow fromView:nil];
CGRect scrollViewKeyboardIntersection = CGRectIntersection(_scrollView.frame, keyboardFrameInView);
UIEdgeInsets newContentInsets = UIEdgeInsetsMake(0, 0, scrollViewKeyboardIntersection.size.height, 0);
// this is an old animation method, but the only one that retains compaitiblity between parameters (duration, curve) and the values contained in the userInfo-Dictionary.
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
[UIView setAnimationCurve:[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
_scrollView.contentInset = newContentInsets;
_scrollView.scrollIndicatorInsets = newContentInsets;
/*
* Depending on visual layout, _focusedControl should either be the input field (UITextField,..) or another element
* that should be visible, e.g. a purchase button below an amount text field
* it makes sense to set _focusedControl in delegates like -textFieldShouldBeginEditing: if you have multiple input fields
*/
if (_focusedControl) {
CGRect controlFrameInScrollView = [_scrollView convertRect:_focusedControl.bounds fromView:_focusedControl]; // if the control is a deep in the hierarchy below the scroll view, this will calculate the frame as if it were a direct subview
controlFrameInScrollView = CGRectInset(controlFrameInScrollView, 0, -10); // replace 10 with any nice visual offset between control and keyboard or control and top of the scroll view.
CGFloat controlVisualOffsetToTopOfScrollview = controlFrameInScrollView.origin.y - _scrollView.contentOffset.y;
CGFloat controlVisualBottom = controlVisualOffsetToTopOfScrollview + controlFrameInScrollView.size.height;
// this is the visible part of the scroll view that is not hidden by the keyboard
CGFloat scrollViewVisibleHeight = _scrollView.frame.size.height - scrollViewKeyboardIntersection.size.height;
if (controlVisualBottom > scrollViewVisibleHeight) { // check if the keyboard will hide the control in question
// scroll up until the control is in place
CGPoint newContentOffset = _scrollView.contentOffset;
newContentOffset.y += (controlVisualBottom - scrollViewVisibleHeight);
// make sure we don't set an impossible offset caused by the "nice visual offset"
// if a control is at the bottom of the scroll view, it will end up just above the keyboard to eliminate scrolling inconsistencies
newContentOffset.y = MIN(newContentOffset.y, _scrollView.contentSize.height - scrollViewVisibleHeight);
[_scrollView setContentOffset:newContentOffset animated:NO]; // animated:NO because we have created our own animation context around this code
} else if (controlFrameInScrollView.origin.y < _scrollView.contentOffset.y) {
// if the control is not fully visible, make it so (useful if the user taps on a partially visible input field
CGPoint newContentOffset = _scrollView.contentOffset;
newContentOffset.y = controlFrameInScrollView.origin.y;
[_scrollView setContentOffset:newContentOffset animated:NO]; // animated:NO because we have created our own animation context around this code
}
}
[UIView commitAnimations];
}
// Called when the UIKeyboardWillHideNotification is sent
- (void)keyboardWillHide:(NSNotification*)notification
{
// if we have no view or are not visible in any window, we don't care
if (!self.isViewLoaded || !self.view.window) {
return;
}
NSDictionary *userInfo = notification.userInfo;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:[[userInfo valueForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
[UIView setAnimationCurve:[[userInfo valueForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
// undo all that keyboardWillShow-magic
// the scroll view will adjust its contentOffset apropriately
_scrollView.contentInset = UIEdgeInsetsZero;
_scrollView.scrollIndicatorInsets = UIEdgeInsetsZero;
[UIView commitAnimations];
}
You may check it out: https://github.com/michaeltyson/TPKeyboardAvoiding (I used that sample for my apps). It is working so well. I hope that helps you.
Actually, here's a full tutorial on using TPKeyboardAvoiding, which may help someone
(1) download the zip file from the github link. add these four files to your Xcode project:
(2) build your beautiful form in IB. add a UIScrollView. sit the form items INSIDE the scroll view. (Note - extremely useful tip regarding interface builder: https://stackoverflow.com/a/16952902/294884)
(3) click on the scroll view. then at the top right, third button, you'll see the word "UIScrollView". using copy and paste, change it to "TPKeyboardAvoidingScrollView"
(4) that's it. put the app in the app store, and bill your client.
(Also, just click on the Inspector tab of the scroll view. You may prefer to turn on or off bouncing and the scroll bars - your preference.)
Personal comment - I strongly recommend using scroll view (or collection view) for input forms, in almost all cases. do not use a table view. it's problematic for many reasons. and quite simply, it's incredibly easier to use a scroll view. just lay it out any way you want. it is 100% wysiwyg in interface builder. hope it helps
This is my code, hope it will help you. It work ok in case you have many textfield
CGPoint contentOffset;
bool isScroll;
- (void)textFieldDidBeginEditing:(UITextField *)textField {
contentOffset = self.myScroll.contentOffset;
CGPoint newOffset;
newOffset.x = contentOffset.x;
newOffset.y = contentOffset.y;
//check push return in keyboar
if(!isScroll){
//180 is height of keyboar
newOffset.y += 180;
isScroll=YES;
}
[self.myScroll setContentOffset:newOffset animated:YES];
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField{
//reset offset of content
isScroll = NO;
[self.myScroll setContentOffset:contentOffset animated:YES];
[textField endEditing:true];
return true;
}
we have a point contentOffset to save contentoffset of scrollview before keyboar show. Then we will scroll content for y about 180 (height of keyboar). when you touch return in keyboar, we will scroll content to old point(it is contentOffset). If you have many textfield, you don't touch return in keyboar but you touch another textfield, it will +180 . So we have check touch return
Use any of these,
CGPoint bottomOffset = CGPointMake(0, self.MainScrollView.contentSize.height - self.MainScrollView.bounds.size.height);
[self.MainScrollView setContentOffset:bottomOffset animated:YES];
or
[self.MainScrollView scrollRectToVisible:CGRectMake(0, self.MainScrollView.contentSize.height - self.MainScrollView.bounds.size.height-30, MainScrollView.frame.size.width, MainScrollView.frame.size.height) animated:YES];
I think it's better use keyboard notifications because you don't know if the first responder (the control with focus on) is a textField or a textView (or whatever). So juste create a category to find the first responder :
#import "UIResponder+FirstResponder.h"
static __weak id currentFirstResponder;
#implementation UIResponder (FirstResponder)
+(id)currentFirstResponder {
currentFirstResponder = nil;
[[UIApplication sharedApplication] sendAction:#selector(findFirstResponder:) to:nil from:nil forEvent:nil];
return currentFirstResponder;
}
-(void)findFirstResponder:(id)sender {
currentFirstResponder = self;
}
#end
then
-(void)keyboardWillShowNotification:(NSNotification*)aNotification{
contentScrollView.delegate=nil;
contentScrollView.scrollEnabled=NO;
contentScrollViewOriginalOffset = contentScrollView.contentOffset;
UIResponder *lc_firstResponder = [UIResponder currentFirstResponder];
if([lc_firstResponder isKindOfClass:[UIView class]]){
UIView *lc_view = (UIView *)lc_firstResponder;
CGRect lc_frame = [lc_view convertRect:lc_view.bounds toView:contentScrollView];
CGPoint lc_point = CGPointMake(0, lc_frame.origin.y-lc_frame.size.height);
[contentScrollView setContentOffset:lc_point animated:YES];
}
}
Eventually disable the scroll and set the delegate to nil then restore it to avoid some actions during the edition of the first responder. Like james_womack said, keep the original offset to restore it in a keyboardWillHideNotification method.
-(void)keyboardWillHideNotification:(NSNotification*)aNotification{
contentScrollView.delegate=self;
contentScrollView.scrollEnabled=YES;
[contentScrollView setContentOffset:contentScrollViewOriginalOffset animated:YES];
}
In Swift 1.2+ do something like this:
class YourViewController: UIViewController, UITextFieldDelegate {
override func viewDidLoad() {
super.viewDidLoad()
_yourTextField.delegate = self //make sure you have the delegate set to this view controller for each of your textFields so textFieldDidBeginEditing can be called for each one
...
}
func textFieldDidBeginEditing(textField: UITextField) {
var point = textField.convertPoint(textField.frame.origin, toView: _yourScrollView)
point.x = 0.0 //if your textField does not have an origin at 0 for x and you don't want your scrollView to shift left and right but rather just up and down
_yourScrollView.setContentOffset(point, animated: true)
}
func textFieldDidEndEditing(textField: UITextField) {
//Reset scrollview once done editing
scrollView.setContentOffset(CGPoint.zero, animated: true)
}
}