How to make floating view? - ios

What I mean by floating view is custom view that is a subview (or appears to be a subview) of scrollview which scrolls along until it anchors on certain point. Similar behavior would be UITableView's section header. Attached image below
My content view (the view underneath the floating view) is not in tableview layout. Meaning if I use tableview only for the floating view, I have to put my content view inside 1 giant cell or break it to several cells with different layouts. The content view will have a lot of dynamic elements which is why I don't want to put it inside UITableViewCell unless I have to. Can I make floating view programmatically / using autolayout on scrollview?

Using the tableview section header is probably the best solution, you can always easily customise the number of cells or cells themselves to achieve a particular layout.
However if you definitely don’t want to deal with a tableview, this component seems really cool, it's actually is meant to be added to a tableview, but I tested it with the twitter example and you can actually add it to a scrollview, so you don’t need a table view and it will work, give props the guy who made it. GSKStretchyHeaderView
Hope this helps, comment if you have any questions, good luck.

Use KVO to update the floating view's frame.
Here is the sample code written in Objective-C:
// ScrollView.m
// ScrollView is a subclass of UIScrollView
#interface ScrollView ()
#property (nonatomic, strong) UIView *floatingView;
#property (nonatomic) CGRect originalBorderFrame;
#property (nonatomic) CGFloat anchorHeight;
#end
#implementation ScrollView
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
self.floatingView = [UIView new];
self.floatingView.backgroundColor = [UIColor colorWithRed:0.8211 green:0.5 blue:0.5 alpha:1.0];
self.floatingView.frame = CGRectMake(0, 150, frame.size.width, 20);
self.originalBorderFrame = self.floatingView.frame;
[self addSubview:self.floatingView];
self.anchorHeight = 44;
[self addObserver:self forKeyPath:#"contentOffset" options:NSKeyValueObservingOptionNew context:nil];
}
return self;
}
- (void)dealloc {
[self removeObserver:self forKeyPath:#"contentOffset"];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
if ([keyPath isEqualToString:#"contentOffset"]) {
if (self.contentOffset.y > self.originalBorderFrame.origin.y-self.anchorHeight) {
self.floatingView.frame = CGRectOffset(self.originalBorderFrame, 0, self.contentOffset.y - (self.originalBorderFrame.origin.y-self.anchorHeight));
}
}
}
#end
Here is the capture:

Related

UISearchBar modifying its frame/bounds when clicked

I'm trying to place a UISearchController within my apps UI. The layout is:
Yellow: a ViewController
Red: another ViewController
Black: a container within the YellowViewController
I want to put the UISearchView of the UISearchController within the black container.
My code is the following:
self.searchController = [[UISearchController alloc] initWithSearchResultsController:searchResultsViewController];
UISearchBar* searchBar = self.searchController.searchBar;
searchBar.frame =_searchBarContainer.bounds;
[_searchBarContainer addSubview:searchBar];
[_searchBarContainer layoutIfNeeded];
It places the UISearchBar in the correct place:
But when I select the search field it expands the bar over the container's bounds:
How can I solve that and avoid the size/appearance change when selected?
Note: Tried some options playing with the translatesAutoresizingMaskIntoConstraints and the clipToBounds options with no success. I'm not an expert of iOS UI so I would appreciate an accurate answer. Thanks
According to my research, at each time you select SearchBar, a UISearchController is presented. This UISearchController always try to make searchBar's width equals to UIViewController which is presenting UISearchController.
My solution is when UISearchController makes SearchBar has wrong frame, set SearchBar'frame again. You can try this code below.
#interface ViewController () <UISearchControllerDelegate>
#property (nonatomic, strong) UISearchController* searchController;
#property (weak, nonatomic) IBOutlet UIView *searchBarContainer;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.searchController = [[UISearchController alloc] initWithSearchResultsController:searchResultsViewController];
UISearchBar* searchBar = self.searchController.searchBar;
self.searchController.delegate = self;
searchBar.frame =_searchBarContainer.bounds;
[_searchBarContainer addSubview:searchBar];
[_searchBarContainer layoutIfNeeded];
}
- (void)willPresentSearchController:(UISearchController *)searchController {
[searchController.searchBar addObserver:self forKeyPath:#"frame" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
}
- (void)willDismissSearchController:(UISearchController *)searchController{
[searchController.searchBar removeObserver:self forKeyPath:#"frame"];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
if (object == self.searchController.searchBar) {
if (!CGSizeEqualToSize(self.searchController.searchBar.frame.size, _searchBarContainer.frame.size)) {
self.searchController.searchBar.superview.clipsToBounds = NO;
self.searchController.searchBar.frame = CGRectMake(0, 0, _searchBarContainer.frame.size.width, _searchBarContainer.frame.size.height);
}
}
}
#end
At least, it works :)
Or
You can create another UIViewController which contains SearchBar after that add it to _searchBarContainer if your case don't have any problem with this.
Use UISearchBar and UITableView instead of UISearchController. It's easier to handle.
I have found useful infos.
There are several methods that are invoked when you tap the UISearchBar.
When some of this method are invoked, the frame of the UISearchBar change his value.
One of these methods try to fill the width equal to UIViewController.
Try to set your frame value inside one of these methods:
searchBarTextDidBeginEditing
searchBarShouldBeginEditing
In this way you override the default value.
Bye

Redrawing UIViewController and its subviews

I have a UIViewController with many subviews like UILabels, UIImages and a UIWebview. With a defined action by the user, the subviews of the UIViewController animate to different sizes and different locations inside of the UIViewController's view. Is it possible that this can be undone with a different defined action by the user? I want to make all the subviews revert back to their previous locations and sizes that they were before the animation was run. I thought of two possible solutions:
Get the properties of the subviews with the view.subviews() method before the animation is run, and then set the subviews after the animation to the properties in this array, or,
Call a method on the UIViewController to tell it to redraw all the subviews according to the properties set in the storyboard file.
Are these the right way of accomplishing what I would like to do? And if so, how would I go about doing this? (I don't know how to programmatically implement either of my ideas.)
Any help is greatly appreciated. Thanks.
Here is the solution.
#interface ViewController ()
#property (strong, nonatomic) NSMutableArray *frames;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//Saving initial frames of all subviews
self.frames = [NSMutableArray new];
NSArray *allViews = [self allViewsOfView:self.view];
for (UIView *view in allViews) {
CGRect frame = view.frame;
NSValue *frameValue = [NSValue valueWithCGRect:frame];
[self.frames addObject:frameValue];
}
}
- (NSMutableArray *)allViewsOfView:(UIView *)view
{
NSMutableArray *result = [NSMutableArray new];
[result addObject:view];
for (UIView *subView in view.subviews) {
[result addObjectsFromArray:[self allViewsOfView:subView]];
}
return result;
}
- (void)resetFrames
{
NSArray *allViews = [self allViewsOfView:self.view];
for (UIView *view in allViews) {
NSValue *frameValue = [self.frames objectAtIndex:[allViews indexOfObject:view]];
CGRect frame = [frameValue CGRectValue];
view.frame = frame;
}
}
#end
Call [self resetFrame]; whenever you want to revert view's frames back to their initial values.
You could cache all your subview's frame before changing it and running the animation, in this way you can even cache more than one action. A stack structure will be perfect for this, but there is no way to achieve this in interface builder, you have to reference outlets from IB to code to get their frame.

Keyboard handling just like in Messages app in iOS 7

I am implementing a view that is in some way similar to what happens in Messages app, so there is a view with UITextView attached to the bottom of the screen and there is also UITableView showing the main content. When it is tapped it slides up with the keyboard and when keyboard is dismissed it slides back to the bottom of the screen.
That part I have and it is working perfectly - I just subscribed to keyboard notifications - will hide and wil show.
The problem is that I have set keyboard dismiss mode on UITableView to interactive and I cannot capture changes to keyboard when it is panning.
The second problem is that this bar with uitextview is covering some part of uitableview. How to fix this? I still want the uitableview to be "under" this bar just like in messages app.
I am using AutoLayout in all places.
Any help will be appreciated!
============
EDIT1:
Here is some code:
View Hierarchy is as follows:
View
- UITableView (this one will contain "messages")
- UIView (this one will slide)
UITableView is has constraints to top, left, right and bottom of parent view so it fills whole screen.
UIView has constraints to left, right and bottom of parent view so it is glued to the bottom - I moved it by adjusting constant on constraint.
In ViewWillAppear method:
NSNotificationCenter.DefaultCenter.AddObserver (UIKeyboard.DidShowNotification, OnKeyboardDidShowNotification);
NSNotificationCenter.DefaultCenter.AddObserver (UIKeyboard.WillChangeFrameNotification, OnKeyboardDidShowNotification);
NSNotificationCenter.DefaultCenter.AddObserver (UIKeyboard.WillHideNotification, OnKeyboardWillHideNotification);
And here are methods:
void OnKeyboardDidShowNotification (NSNotification notification)
{
AdjustViewToKeyboard (Ui.KeyboardHeightFromNotification (notification), notification);
}
void OnKeyboardWillHideNotification (NSNotification notification)
{
AdjustViewToKeyboard (0.0f, notification);
}
void AdjustViewToKeyboard (float offset, NSNotification notification = null)
{
commentEditViewBottomConstraint.Constant = -offset;
if (notification != null) {
UIView.BeginAnimations (null, IntPtr.Zero);
UIView.SetAnimationDuration (Ui.KeyboardAnimationDurationFromNotification (notification));
UIView.SetAnimationCurve ((UIViewAnimationCurve)Ui.KeyboardAnimationCurveFromNotification (notification));
UIView.SetAnimationBeginsFromCurrentState (true);
}
View.LayoutIfNeeded ();
commentEditView.LayoutIfNeeded ();
var insets = commentsListView.ContentInset;
insets.Bottom = offset;
commentsListView.ContentInset = insets;
if (notification != null) {
UIView.CommitAnimations ();
}
}
I'd recommend you to override -inputAccessoryView property of your view controller and have your editable UITextView as its subview.
Also, don't forget to override -canBecomeFirstResponder method to return YES.
- (BOOL)canBecomeFirstResponder
{
if (!RUNNING_ON_IOS7 && !RUNNING_ON_IPAD)
{
//Workaround for iOS6-specific bug
return !(self.viewDisappearing) && (!self.viewAppearing);
}
return !(self.viewDisappearing);
}
With this approach system manages everything.
There are also some workarounds you must know about: for UISplitViewController (UISplitViewController detail-only inputAccessoryView), for deallocation bugs (UIViewController with inputAccessoryView is not deallocated) and so on.
This solution is based on a lot of different answers on SO. It have a lot of benefits:
Compose bar stays on bottom when keyboard is hidden
Compose bas follows keyboard while interactive gesture on UITableView
UITableViewCells are going from bottom to top, like in Messages app
Keyboard do not prevent to see all UITableViewCells
Should work for iOS6, iOS7 and iOS8
This code just works:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = // . . .
// . . .
cell.contentView.transform = CGAffineTransformMakeScale(1,-1);
cell.accessoryView.transform = CGAffineTransformMakeScale(1,-1);
return cell;
}
- (UIView *)inputAccessoryView {
return self.composeBar;
}
- (BOOL)canBecomeFirstResponder {
return YES;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.tableView.transform = CGAffineTransformMakeScale(1,-1);
// This code prevent bottom inset animation while appearing view
UIEdgeInsets newEdgeInsets = self.tableView.contentInset;
newEdgeInsets.top = CGRectGetMaxY(self.navigationController.navigationBar.frame);
newEdgeInsets.bottom = self.view.bounds.size.height - self.composeBar.frame.origin.y;
self.tableView.contentInset = newEdgeInsets;
self.tableView.scrollIndicatorInsets = newEdgeInsets;
self.tableView.contentOffset = CGPointMake(0, -newEdgeInsets.bottom);
// This code need to be done if you added compose bar via IB
self.composeBar.delegate = self;
[self.composeBar removeFromSuperview];
[[NSNotificationCenter defaultCenter] addObserverForName:UIKeyboardWillChangeFrameNotification object:nil queue:nil usingBlock:^(NSNotification *note)
{
NSNumber *duration = note.userInfo[UIKeyboardAnimationDurationUserInfoKey];
NSNumber *options = note.userInfo[UIKeyboardAnimationCurveUserInfoKey];
CGRect beginFrame = [note.userInfo[UIKeyboardFrameBeginUserInfoKey] CGRectValue];
CGRect endFrame = [note.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
UIEdgeInsets newEdgeInsets = self.tableView.contentInset;
newEdgeInsets.bottom = self.view.bounds.size.height - endFrame.origin.y;
CGPoint newContentOffset = self.tableView.contentOffset;
newContentOffset.y += endFrame.origin.y - beginFrame.origin.y;
[UIView animateWithDuration:duration.doubleValue
delay:0.0
options:options.integerValue << 16
animations:^{
self.tableView.contentInset = newEdgeInsets;
self.tableView.scrollIndicatorInsets = newEdgeInsets;
self.tableView.contentOffset = newContentOffset;
} completion:^(BOOL finished) {
;
}];
}];
}
Use for example pod 'PHFComposeBarView' compose bar:
#property (nonatomic, strong) IBOutlet PHFComposeBarView *composeBar;
And use this class for your table view:
#interface InverseTableView : UITableView
#end
#implementation InverseTableView
void swapCGFLoat(CGFloat *a, CGFloat *b) {
CGFloat tmp = *a;
*a = *b;
*b = tmp;
}
- (UIEdgeInsets)contentInset {
UIEdgeInsets insets = [super contentInset];
swapCGFLoat(&insets.top, &insets.bottom);
return insets;
}
- (void)setContentInset:(UIEdgeInsets)contentInset {
swapCGFLoat(&contentInset.top, &contentInset.bottom);
[super setContentInset:contentInset];
}
#end
If you would like keyboard to disappear by tapping on message:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self.composeBar.textView resignFirstResponder];
}
Do not call this, this will hide composeBar at all:
[self resignFirstResponder];
UPDATE 2:
NEW SOLUTION for keyboard tracking works much better:
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
// Compose view height growing tracking
[self.composeBar addObserver:self forKeyPath:#"frame" options:0 context:nil];
// iOS 7 keyboard tracking
[self.composeBar.superview addObserver:self forKeyPath:#"center" options:0 context:nil];
// iOS 8 keyboard tracking
[self.composeBar.superview addObserver:self forKeyPath:#"frame" options:0 context:nil];
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
[self.composeBar removeObserver:self forKeyPath:#"frame"];
[self.composeBar.superview removeObserver:self forKeyPath:#"center"];
[self.composeBar.superview removeObserver:self forKeyPath:#"frame"];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if (object == self.composeBar.superview || object == self.composeBar)
{
// Get all values
CGPoint newContentOffset = self.tableView.contentOffset;
UIEdgeInsets newEdgeInsets = self.tableView.contentInset;
UIEdgeInsets newScrollIndicartorInsets = self.tableView.scrollIndicatorInsets;
// Update values
CGFloat bottomInset = self.view.bounds.size.height - [self.composeBar convertPoint:CGPointZero toView:self.view].y;
CGFloat diff = newEdgeInsets.bottom - (bottomInset + 7);
newContentOffset.y += diff;
newEdgeInsets.bottom = bottomInset + 7;
newScrollIndicartorInsets.bottom = bottomInset;
// Set all values
if (diff < 0 || diff > 40)
self.tableView.contentOffset = CGPointMake(0, newContentOffset.y);
self.tableView.contentInset = newEdgeInsets;
self.tableView.scrollIndicatorInsets = newEdgeInsets;
}
}
OK, the interactive keyboard dismissal will send a notification with name UIKeyboardDidChangeFrameNotification.
This can be used to move the text view while the keyboard is being dismissed interactively.
You are already using this but you are sending it to the OnKeyboardDidShow method.
You need a third method called something like keyboardFramedDidChange. This works for the hide and the show.
For the second problem, you should have your vertical constraints like this...
|[theTableView][theTextView (==44)]|
This will tie the bottom of the tableview to the top of the text view.
This doesn't change how any of the animation works it will just make sure that the table view will show all of its contents whether the keyboard is visible or not.
Don't update the content insets of the table view. Use the constraints to make sure the frames do not overlap.
P.S. sort out your naming conventions. Method names start with a lowercase letter.
P.P.S. use block based animations.
I'd try to use an empty, zero-height inputAccessoryView. The trick is to glue your text field's bottom to it when the keyboard appears, so that they'd move together. When the keyboard is gone, you can destroy that constraint and stick to the bottom of the screen once again.
I made an open source lib for exactly this purpose. It works on iOS 7 and 8 and is set up to work as a cocoapod as well.
https://github.com/oseparovic/MessageComposerView
Here's a sample of what it looks like:
You can use a very basic init function as shown below to create it with screen width and default height e.g.:
self.messageComposerView = [[MessageComposerView alloc] init];
self.messageComposerView.delegate = self;
[self.view addSubview:self.messageComposerView];
There are several other initializers that are also available to allow you to customize the frame, keyboard offset and textview max height as well as some delegates to hook into frame changes and button clicks. See readme for more!

Layout views below another programmatically created views

I have a screen, which contains multiple UIImages (their amount and size are known only at runtime, so i add them programmatically) and some fixed buttons below these UIImages.
How to make buttons display certainly under all Images?
I've tried
1.) Put Buttons and Images into 2 separate views, and then add constraint between them. No result, buttons are hidden behind images.
2.) Put buttons into separate view and set constraint in code, (tried both viewDidLoad and viewDidAppear). Constraint is set between container view and top of the screen, depending on size and amount of images.
Example of code:
-(void) viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
NSInteger totalImages = [self.object.fullphotos count];
self.labelsTopConstraint.constant = totalImages*(imageHeight + 20) + 10;
}
In case 2 buttons are positioned right, but don't respond to touches.
How should I layout everything correctly?
Thanks in advance!
Take a Tableview for those images and add buttons in a last cell.
The best way is creating a Object with a refresh method that can be called in viewDidAppear
MyObject.h
#interface MyObject : UIViewController
#property (nonatomic,strong) UIImageview *img;
#property (nonatomic,strong) UIButton *btn;
- (void) refresh;
in MyObject.m
- (void)viewDidLoad {
[self.btn addTarget:self action:#selector(myMethod:) forControlEvents:UIControlEventTouchUpInside];
}
- (void) refresh {
//make your settings here
}
-(void)myMethod {
//your button action here
}
Then in your controller if you have your objects in an NSArray:
-(void) viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
for (MyObject *myObj in objectsArray) {
#autoreleasePool {
[myObj refresh];
}
}
}

iOS 7 UITextView vertical alignment

How is that possible that my editable UITextView (placed inside a straightforward UIViewController inside a UISplitView that acts as delegate for the UITextView) is not showing text from the beginning but after something like 6-7 lines?
I didn't set any particular autolayout or something similar, trying to delete text doesn't help (so no hidden chars or something).
I'm using iOS 7 on iPad, in storyboard looks good...
The problem is the same on iOS simulator and real devices. I'm getting mad :P
Here's some code. This is the ViewController viewDidLoad()
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.itemTextField.delegate = self;
self.itemTextField.text = NSLocalizedString(#"NEWITEMPLACEHOLDER", nil);
self.itemTextField.textColor = [UIColor lightGrayColor]; //optional
}
And here are the overridden functions for the UITextView I'm using some code I've found on StackOverflow to simulate a placeholder for the view (the same stuff on iPhone version of the storyboard works fine)...
// UITextView placeholder
- (void)textViewDidBeginEditing:(UITextView *)textView
{
if ([textView.text isEqualToString:NSLocalizedString(#"NEWITEMPLACEHOLDER", nil)]) {
textView.text = #"";
textView.textColor = [UIColor blackColor]; //optional
}
[textView becomeFirstResponder];
}
- (void)textViewDidEndEditing:(UITextView *)textView
{
if ([textView.text isEqualToString:#""]) {
textView.text = NSLocalizedString(#"NEWITEMPLACEHOLDER", nil);
textView.textColor = [UIColor lightGrayColor]; //optional
}
[textView resignFirstResponder];
}
-(void)textViewDidChange:(UITextView *)textView
{
int len = textView.text.length;
charCount.text = [NSString stringWithFormat:#"%#: %i", NSLocalizedString(#"CHARCOUNT", nil),len];
}
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
return YES;
}
Try to call -sizeToFit after passing the text. This answer could be useful to Vertically align text within a UILabel.
[UPDATE]
I update this answer o make it more readable.
The issue is that from iOS7, container view controllers such as UINavigationController or UITabbarController can change the content insets of scroll views (or views that inherit from it), to avoid content overlapping. This happens only if the scrollview is the main view or the first subviews. To avoid that you should disable this behavior by setting automaticallyAdjustsScrollViewInsets to NO, or overriding this method to return NO.
I got through the same kind of issue.
Solved it by disabling the automatic scrollView insets adjustement :
if(SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"7.0")){
self.automaticallyAdjustsScrollViewInsets = NO; // Avoid the top UITextView space, iOS7 (~bug?)
}
This is a fairly common problem, so I would create a simple UITextView subclass, so that you can re-use it and use it in IB.
I would used the contentInset instead, making sure to gracefully handle the case where the contentSize is larger than the bounds of the textView
#interface BSVerticallyCenteredTextView : UITextView
#end
#implementation BSVerticallyCenteredTextView
- (id)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame])
{
[self addObserver:self forKeyPath:#"contentSize" options: (NSKeyValueObservingOptionNew) context:NULL];
}
return self;
}
- (id)initWithCoder:(NSCoder *)aDecoder
{
if (self = [super initWithCoder:aDecoder])
{
[self addObserver:self forKeyPath:#"contentSize" options: (NSKeyValueObservingOptionNew) context:NULL];
}
return self;
}
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if ([keyPath isEqualToString:#"contentSize"])
{
UITextView *tv = object;
CGFloat deadSpace = ([tv bounds].size.height - [tv contentSize].height);
CGFloat inset = MAX(0, deadSpace/2.0);
tv.contentInset = UIEdgeInsetsMake(inset, tv.contentInset.left, inset, tv.contentInset.right);
}
}
- (void)dealloc
{
[self removeObserver:self forKeyPath:#"contentSize"];
}
#end
use -observerForKeyPath with contentSize KeyPath
Look some code at My Blog (don't focus on Thai Language)
http://www.macbaszii.com/2012/10/ios-dev-uitextview-vertical-alignment.html
Inspired by Kiattisak, I've implemented vertical alignment as a category over UITextView so that you can control the vertical alignment of legacy UITextView.
You can find it as a gist here.
I had the same issue with iOS 8.1, and none of these suggestions worked.
What did work was to go into the Storyboard, and drag my UITableView or UITextView so that it was no longer the first subview of my screen's UIView.
http://www.codeproject.com/Tips/852308/Bug-in-XCode-Vertical-Gap-Above-UITableView
It seems to be linked to having a UIView embedded in a UINavigationController.
Bug ? Bug ? Did I say "bug" ...?
;-)
Swift version of Tanguy.G's answer:
if(UIDevice.currentDevice().systemVersion >= "7.0") {
self.automaticallyAdjustsScrollViewInsets = false; // Avoid the top UITextView space, iOS7 (~bug?)
}
Check top content inset of textView in -viewDidLoad:
NSLog(#"NSStringFromUIEdgeInsets(self.itemTextField.contentInset) = %#", NSStringFromUIEdgeInsets(self.itemTextField.contentInset));
Reset it in storyboard if it is not zero

Resources