Dynamic textView resize broken after update to iOS 7.1 - dynamic

I have a tableview that requires a subview that's used to add content. The subview contains a UITextView that's used to enter text. Prior to 7.1 The following would happen:
The subview is glued to the bottom of the tableview via scrollViewDidScroll
When activated, the keyboard would show, the view animates up with the keyboard
When text is typed in, the textView would expand upwards if required, with the bottom of the textView remaining in place.
NOW after 7.1, the following behavior takes place:
The subview animates upwards with the keyboard fine
If the text forces a new line, instead of expanding, textViewDidEndEditing get's triggered and the keyboard dismisses.
No further editing is allowed in the textview, any edits makes the keyboard immediately dismiss.
Any suggestions on what changed with 7.1 that would make existing, working code break? Here is all the relevant code. I'll be happy to provide any additional details. I've been at this a while now and it's driving me mental.
tableViewController.m - The code that adds in the subview. The subview has it's own xib. The xib was created in IB. I stripped out the parts that pertain to other components.
- (void)viewDidLoad {
//Setup contentBar
if (self.contentBar == nil) {
//Add subView to View
NSArray *subviewArray = [[NSArray alloc] init];
subviewArray = [[NSBundle mainBundle] loadNibNamed:contentIdentifier owner:self options:nil];
self.contentBar = [subviewArray objectAtIndex:0];
[self.view addSubview:self.contentBar];
//Setup textView
UITextView *addContentTextView = (UITextView *)[self.contentBar viewWithTag:2];
addContentTextView.text = [NSString stringWithFormat:#"text (optional)"];
addContentTextView.delegate = self;
}
}
My textView delegates
#pragma mark - TextView Delegate
- (void)textViewDidEndEditing:(UITextView *)textView{
NSLog(#"textViewDidEndEditing:");
if ([textView.text isEqualToString:#""]) {
textView.text = #"text (optional)";
textView.textColor = [UIColor lightGrayColor]; //optional
}
[textView resignFirstResponder];
}
- (void)textViewDidBeginEditing:(UITextView *)textView {
NSLog(#"textViewDidBeginEditing:");
if ([textView.text isEqualToString:#"text (optional)"]) {
textView.text = #"";
textView.textColor = [UIColor blackColor]; //optional
}
[textView becomeFirstResponder];
}
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
NSString *newText = [textView.text stringByReplacingCharactersInRange:range withString:text];
if ([newText length] > 0 || _image) {
_addContentButton.enabled = YES;
} else {
_addContentButton.enabled = NO;
}
if([text isEqualToString:[text stringByTrimmingCharactersInSet:[NSCharacterSet newlineCharacterSet]]]) {
return YES;
} else {
NSLog(#"return pressed");
[textView resignFirstResponder];
[self addedContent:nil];
}
return YES;
}
- (void)textViewDidChange:(UITextView *)textView
{
NSLog(#"textViewDidChange");
[self sizeTextView];
}
- (void)sizeTextView
{
NSLog(#"sizeTextView");
UIImageView *barImage = (UIImageView *)[self.contentBar viewWithTag:87];
UITextView *textView = (UITextView *)[self.contentBar viewWithTag:2];
CGSize sizeThatShouldFitTheContent = [textView sizeThatFits:textView.frame.size];
CGRect newTextViewFrame = textView.frame;
newTextViewFrame.size.height = sizeThatShouldFitTheContent.height;
CGFloat adjustment = sizeThatShouldFitTheContent.height - textView.frame.size.height;
newTextViewFrame.origin.y = textView.frame.origin.y - adjustment;
textView.frame = newTextViewFrame;
CGRect newImageViewFrame = barImage.frame;
newImageViewFrame.size.height = barImage.frame.size.height + adjustment;
newImageViewFrame.origin.y = barImage.frame.origin.y - adjustment;
barImage.frame = newImageViewFrame;
}
If you want to see anything else, I'll be glad to post it.

I have solved this issue by implementing the following:
Rewrote my tableview controller as a standard ViewController, not a TableViewController
Added a tableview to the ViewController and a separate "contentWrapper" view.
The content wrapper consists of the example shown here: https://github.com/datwelk/RDRStickyKeyboardView
I'm still not sure what in iOS 7.1 caused this issue, but using the RDRStickyKeyboardView works great and solved all of my issues.
I've read that tableviews shouldn't be parents of other views, so this solution also works well for good coding practice.

Related

NSCollectionView header display

I have an NSCollectionView that has 3 sections which contains colors from a color palette. I want each section to have a header view with the name of the section. At first glance, it appears to work. On launch, it looks like this:
However, as soon as I resize the window, the header text ends up drawing outside the headers (and also inside it, somehow!):
In order to have headers in the collection view, I have a header view class named CollectionHeaderView. I register this class as a supplemental view:
[_collection registerClass:[CollectionHeaderView class]
forSupplementaryViewOfKind:#"UICollectionElementKindSectionHeader"
withIdentifier:kSupplementalView];
In the collection view's delegate, I implement the method to return the view for the supplemental element:
- (NSView *)collectionView:(NSCollectionView *)collectionView
viewForSupplementaryElementOfKind:(NSCollectionViewSupplementaryElementKind)kind
atIndexPath:(NSIndexPath *)indexPath {
NSView* result = [collectionView makeSupplementaryViewOfKind:kind
withIdentifier:kSupplementalView
forIndexPath:indexPath];
if ([kind isEqualToString:#"UICollectionElementKindSectionHeader"]) {
NSTextField* textView = ((CollectionHeaderView*)result).textField;
switch (indexPath.section) {
case 0:
[textView setStringValue:#"Bright Colors"];
break;
case 1:
[textView setStringValue:#"Pastel Colors"];
break;
case 2:
[textView setStringValue:#"Designer Colors"];
break;
}
return textView;
}
return nil;
}
Furthermore, if I resize the window, the header views do not move. The collection elements seem to flow around the headers, leaving things listed under the wrong section. And, as you can see in the second picture above, widening the window ends up leaving a gap between the right edge of the header and the right edge of the collection view.
The CollectionHeaderView class is very simple. It just creates a text field and draws the background and the text field:
#implementation CollectionHeaderView
- (instancetype)initWithFrame:(NSRect)frameRect {
self = [super initWithFrame:frameRect];
if (self != nil) {
NSRect textFrame = frameRect;
_textField = [[NSTextField alloc] initWithFrame:textFrame];
_textField.editable = NO;
_textField.bordered = NO;
_textField.font = [NSFont fontWithName:#"Helvetica-Bold" size:14.0];
_textField.backgroundColor = [NSColor colorWithSRGBRed:0.0 green:0.0 blue:0.0 alpha:0.0];
[self addSubview:_textField];
self.identifier = kSupplementalView;
}
return self;
}
- (void)drawRect:(NSRect)dirtyRect {
[super drawRect:dirtyRect];
// Drawing code here.
NSBezierPath* fillPath = [NSBezierPath bezierPath];
[fillPath appendBezierPathWithRect:dirtyRect];
[[NSColor lightGrayColor] setFill];
[fillPath fill];
[_textField drawRect:dirtyRect];
}
#end
Have I implemented any of the above methods incorrectly? Is there any method I need to implement that I haven't?
The return value of collectionView:viewForSupplementaryElementOfKind:atIndexPath: is the supplementary view result.
- (NSView *)collectionView:(NSCollectionView *)collectionView
viewForSupplementaryElementOfKind:(NSCollectionViewSupplementaryElementKind)kind
atIndexPath:(NSIndexPath *)indexPath {
NSView* result = [collectionView makeSupplementaryViewOfKind:kind
withIdentifier:kSupplementalView
forIndexPath:indexPath];
if ([kind isEqual:NSCollectionElementKindSectionHeader]) {
NSTextField* textView = ((CollectionHeaderView*)result).textField;
switch (indexPath.section) {
case 0:
[textView setStringValue:#"Bright Colors"];
break;
case 1:
[textView setStringValue:#"Pastel Colors"];
break;
case 2:
[textView setStringValue:#"Designer Colors"];
break;
}
return result;
}
return nil;
}

How to use UIPopOver to input text in to UITextField?

I would like to learn how would I make a UITextField get text from a UIPopover view. Let's say I have buttons with numbers on my popover and I want these numbers to be input into the textfield.
Some people sugested to us BOOL like this:
- (BOOL)textFieldShouldBeginEditing:(UITextField *) textField {
[self.myPopover presentPopoverFromRect:textField.frame
inView:self.view
permittedArrowDirections:UIPopoverArrowDirectionAny
animated:YES];
return NO;
}
And one more:
- (BOOL)textViewShouldBeginEditing:(UITextView *)textView {
if(popoverController == nil){ //make sure popover isn't displayed more than once in the view
popoverController = [[UIPopoverController alloc] initWithContentViewController:popoverDetailContent];
}
[popoverController presentPopoverFromRect:textView.frame
inView:self.view
permittedArrowDirections:UIPopoverArrowDirectionAny
animated:YES];
popoverController.delegate = self;
return NO; // tells the textfield not to start its own editing process (ie show the keyboard)
}
Both are not making much change, my textField still calls the default iPad keyboard instead of my popover.
Second example uses delegate popoverController and my controller is flipsidePopoverController.
Could I use an IBAction like this?
- (IBAction)togglePopover:(id)sender {
if (self.flipsidePopoverController) {
[self.flipsidePopoverController dismissPopoverAnimated:YES];
self.flipsidePopoverController = nil;
} else {
[self performSegueWithIdentifier:#"showAlternate" sender:sender];
}
}

Paging a TableView, but DataSource/Delegates not executing

I am having problems with getting the datasource or delegate methods to execute.
I am using a Paging View in my MainViewController and it pages just fine, but when it comes to the tableview is blank and when I put a breakpoint where the datasource methods are, it never gets called.
MainViewController to Load the View
if ((NSNull *)controller2 == [NSNull null])
{
if(page == 2)
{
controller2 = [[requestDetailThreeViewController alloc] initWithRequestNumber:[request objectForKey:#"RequestID"]];
[viewControllers replaceObjectAtIndex:page withObject:controller2];
CGRect frame = scrollView.frame;
frame.origin.x = frame.size.width * 2;
frame.origin.y = 0;
controller2.view.frame = frame;
[scrollView addSubview:controller2.view];
}
}
The TableViewController (requestDetailThreeViewController)
- (void)viewDidLoad
{
[super viewDidLoad];
[History fullHistoryWithBlock:^(NSArray *netMessages, NSError *error) {
if (error) {
[[[UIAlertView alloc] initWithTitle:NSLocalizedString(#"Error", nil) message: [error localizedDescription] delegate:nil cancelButtonTitle:nil otherButtonTitles:NSLocalizedString(#"OK", nil), nil] show];
} else {
NSLog(#"Number of Historical Entries: %d", [netMessages count]);
self.historyFromNet = [NSMutableArray arrayWithArray:netMessages];
}
} forID:requestNum];
}
- (id) initWithRequestNumber:(NSString *)requestID
{
if (self = [super initWithNibName:#"View" bundle:nil])
{
self.requestNum = requestID;
}
return self;
}
(Apologize for the spacing on the 2nd block of code, hard time getting it into code mode.
It executes these two methods, but it doesn't execute the datasource methods I also have in the class.
In the XIB file I have the owner of the xib set to the requestDetailThreeViewController
The tableView is set to datasource/delegate and view
If I set the tableview to hidden in the ViewDidLoad, it does disappear.
I just can't get it to execute the methods to populate the table.
Update:
Some more information-
The View XIB only has a TableView in it, no controllers.
Thanks!
Alan
You are adding a child view controller so you will need to use the UIViewController containment methods.
Something like:
controller2 = [[requestDetailThreeViewController alloc] initWithRequestNumber:[request objectForKey:#"RequestID"]];
[viewControllers replaceObjectAtIndex:page withObject:controller2];
[self addChildViewController:controller2];
CGRect frame = scrollView.frame;
frame.origin.x = frame.size.width * 2;
frame.origin.y = 0;
controller2.view.frame = frame;
[scrollView addSubview:controller2.view];
[controller didMoveToParentViewController:self];
}
Also consider using a UIPageViewController for a paging view rather than doing it manually via a scroll view
You can try to set self.tableView.delegate = self in -(void)viewDidLoad
that is
- (void)viewDidLoad
{
[super viewDidLoad];
self.tableView.delegate = self;
}

UIPickerView inside UIScrollView hitTest to disable Scrollview?

I am currently building an application which has a resized UIPickerView on a scrollview the problem I am facing is that when you try to scroll the picker the scrollview is moving instead.
For the past few hours I have tried to fix this by disabling the scrollview when the picker is selected by creating a UIScrollView sub class which performs the following hitTest:
- (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
UIView* result = [super hitTest:point withEvent:event];
if ([result.superview isKindOfClass:[UIPickerView class]])
{
NSLog(#"Cancel touch");
self.canCancelContentTouches = NO;
self.delaysContentTouches = NO;
self.scrollEnabled = NO;
}
else
{
self.canCancelContentTouches = YES;
self.delaysContentTouches = YES;
self.scrollEnabled = YES;
}
return result;
}
With this above code I find that when I click and hold certain sections of the UIPickerView it cancels the touch and disables the UIScrollview OK and I can move the UIPicker to select a new value, however when I certain areas on the PickerView and do an NSLog on the reported class like below
NSLog(#"%#", [result.superview class]);
It outputs UIPickerTableViewWrapperCell to the console and the isKindOfClass[UIPickerView class] never gets entered.
I have also tried isMemberOfClass which also does not work.
Any help would be appreciated.
Thanks Aaron
I think I have figured this out, by searching the class description to see if it contains #"UIPicker*"
- (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
UIView* result = [super hitTest:point withEvent:event];
NSString *viewDescription = [result.superview class].description;
NSRange range = [viewDescription rangeOfString : #"UIPicker"];
if (range.location != NSNotFound)
{
NSLog(#"Cancel touch on ScrollView");
self.canCancelContentTouches = NO;
self.delaysContentTouches = NO;
self.scrollEnabled = NO;
}
else
{
self.canCancelContentTouches = YES;
self.delaysContentTouches = YES;
self.scrollEnabled = YES;
}
return result;
}
Now when I drag the UIPicker it works perfectly and the scrollview does not move at all, unless I am clicking on that and dragging it.
Aaron

UITableView losing height when i search

Im getting a little trouble here. I have a UISearchBar that searchs for me some content, that are included on UITableView. Perfect.
When my view loads, i set a 110 height to my table view row. Nice. When my view appears, it comes with 110 px. of height. Nice.
But when i click on UISearchBar, my rows loses the height setted.
I dont know what can be.
Any help, thanks!
- (void)viewDidLoad {
[super viewDidLoad];
theTableView.rowHeight = 110;
theTableView.backgroundColor = [UIColor clearColor];
}
And the search code:
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar {
[searchBar setShowsCancelButton:YES animated:YES];
self.theTableView.allowsSelection = NO;
self.theTableView.scrollEnabled = NO;
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
searchBar.text=#"";
[searchBar setShowsCancelButton:NO animated:YES];
[searchBar resignFirstResponder];
self.theTableView.allowsSelection = YES;
self.theTableView.scrollEnabled = YES;
}
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
// All the actions goes here, like parsing xml.
[self.tableData removeAllObjects];
[theTableView reloadData];
}
Thanks!