View based NSTableView text field loses focus - objective-c

After selecting a row, pressing TAB will normally move focus to the next editable text field(s), or in my case, column. However, I have noticed that only sometimes after pressing TAB, the row will turn gray and focus is lost. I must then click on the text field to continue. After days of observations, I still cannot detect a repeatable pattern, and internet searches have not given me enough information. I wonder if my delegate might be the culprit. Some questions come to mind.
Can anyone shed light on why or how focus might be lost? (indirectly answered by Willeke's comment to remove some code)
Is there a proper or deliberate way to force focus on the next text field? (now irrelevant)
The unpredictable behavior prompting the first two questions seemed to be interference between two methods. Resolving one has at least led to predictable behavior and this related question. I included more code below with another method. One column contains a pop-up button. Ordinarily, choosing a value does not select the row (ie, highlighted). I would like the row to be selected and focused (ie, highlighted blue) so that I can immediately TAB to the next field and begin editing. In editPopUps:, selectRowIndexes: will select the row, but the row is gray instead of blue and hence TAB has no effect. How do I select and focus the row?
Update: Here are some pertinent methods. I setup each view based on column because only some columns are editable.
- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
NSString *column = tableColumn.identifier;
NSTableCellView *value = [tableView makeViewWithIdentifier:column owner:self];
Foo *foo = self.foos[row];
[self setupView:value column:column foo:foo];
[self populateCellView:value column:column foo:foo object:[foo valueForKey:column]];
return value;
}
- (void)setupCellView:(NSTableCellView *)view column:(NSString *)column foo:(Foo *)foo {
view.textField.alignment = NSRightTextAlignment;
BOOL editable = YES;
if ([attribute isEqualToString:column] || ![foo.x isEqualToNumber:bar.x]) {
editable = NO;
} else {
view.textField.target = self;
view.textField.action = #selector(editTextField:);
}
[view.textField setEditable:editable];
}
- (void)editTextField:(NSTextField *)sender {
if ([self.fooTableView numberOfSelectedRows]) {
NSTableCellView *cellView = (NSTableCellView *)[sender superview];
NSString *column = cellView.identifier;
NSInteger row = [self.fooTableView rowForView:cellView];
Foo *foo = self.foos[row];
NSNumber *amountNumber = [NSNumber numberWithShort:[sender intValue]];
if ([attribute isEqualToString:column]) {
foo.y = amountNumber;
} else {
foo.z = amountNumber;
}
[self.fooTableView reloadDataForRowIndexes:[NSIndexSet indexSetWithIndex:row] columnIndexes:[NSIndexSet indexSetWithIndex:[self.fooTableView columnWithIdentifier:column]]];
[self refreshSelection];
}
}
- (void)editPopUps:(NSPopUpButton *)sender {
GlorpView *glorpView = (GlorpView *)[sender superview];
NSString *column = pokeCellView.identifier;
NSInteger row = [self.fooTableView rowForView:glorpView];
Foo *foo = self.foos[row];
NSNumber *indexValue = [NSNumber numberWithShort:[sender indexOfSelectedItem]];
NSMutableIndexSet *columnIndexes = [NSMutableIndexSet indexSetWithIndex:[self.fooTableView columnWithIdentifier:column]];
if ([attribute isEqualToString:column]) {
foo.Z = indexValue;
}
[self.fooTableView selectRowIndexes:[NSIndexSet indexSetWithIndex:row] byExtendingSelection:NO];
[self refreshSelection];
}

Related

Extend selection in NSCollectionView with Shift key

I recently reviewed one of my Applications that I released a year ago.
And I see that nowadays the NSCollectionView inside it has lost the selection functioning such as SHIFT + Select now it behaving as CMD + Select.
(Secondary issue: I am also not getting a selection rectangle when dragging with the mouse.)
Obviously I want this feature back, where using shift would expand the selection from the previously clicked cell to the shift-clicked cell.
What have I done:
//NSCollectionView * _picturesGridView; //is my iVar
//In initialization I have set my _picturesGridView as follows
//Initializations etc are omitted -- (only the selection related code is here)
[_picturesGridView setSelectable:YES];
[_picturesGridView setAllowsMultipleSelection:YES];
Question: Is there an easy way to get back this functionality? I don't see anything related in documentation and I couldn't find any solution on the internet.
Sub Question: If there is no easy way to achieve that -> Should I go ahead and create my own FancyPrefix##CollectionViewClass and to reimplement this feature as I wish -- Or is it better to go over the existing NSCollectionView and force it to behave as I wish?
Sub Note: Well if I will find myself reimplementing it it will be light weight class that will just comply to my own needs -- I mean I will not mimic the entire NSCollectionView class.
P.S.
I am able to select an item by clicking on it I am able to select multiple items only with CMD+Click or SHIFT+Click but the latter behaves exactly as CMD+Click which I don't want as well.
As for the mouse Selection Rectangle - I didn't override any Mouse events. It is not clear why I don't have this functionality.
Per Apple's documentation, shouldSelectItemsAtIndexPaths: is the event that only gets invoked when the user interacts with the view, but not when the selection is modified by one's own code. Therefore, this approach avoids side effects that may occur when using didSelectItemsAt:.
It works as follows:
It needs to remember the previously clicked-on item. This code assumes that the NSCollectionView is actually a subclass called CustomCollectionView that has a property #property (strong) NSIndexPath * _Nullable lastClickedIndexPath;
It only remembers the last clicked-on item when it was a simple selection click, but not, for instance, a drag-selection with more than one selected item.
If it detects a second single-selection click with the Shift key down, it selects all the items in the range from the last click to the current click.
If an item gets deselected, we clear the last clicked-on item in order to simulate better the intended behavior.
- (NSSet<NSIndexPath *> *)collectionView:(CustomCollectionView *)collectionView shouldDeselectItemsAtIndexPaths:(NSSet<NSIndexPath*> *)indexPaths
{
collectionView.lastClickedIndexPath = nil;
return indexPaths;
}
- (NSSet<NSIndexPath *> *)collectionView:(CustomCollectionView *)collectionView shouldSelectItemsAtIndexPaths:(NSSet<NSIndexPath*> *)indexPaths
{
if (indexPaths.count != 1) {
// If it's not a single cell selection, then we also don't want to remember the last click position
collectionView.lastClickedIndexPath = nil;
return indexPaths;
}
NSIndexPath *clickedIndexPath = indexPaths.anyObject; // now there is only one selected item
NSIndexPath *prevIndexPath = collectionView.lastClickedIndexPath;
collectionView.lastClickedIndexPath = clickedIndexPath; // remember last click
BOOL shiftKeyDown = (NSEvent.modifierFlags & NSEventModifierFlagShift) != 0;
if (NOT shiftKeyDown || prevIndexPath == nil) {
// not an extension click
return indexPaths;
}
NSMutableSet<NSIndexPath*> *newIndexPaths = [NSMutableSet set];
NSInteger startIndex = [prevIndexPath indexAtPosition:1];
NSInteger endIndex = [clickedIndexPath indexAtPosition:1];
if (startIndex > endIndex) {
// swap start and end position so that we can always count upwards
NSInteger tmp = endIndex;
endIndex = startIndex;
startIndex = tmp;
}
for (NSInteger index = startIndex; index <= endIndex; ++index) {
NSUInteger path[2] = {0, index};
[newIndexPaths addObject:[NSIndexPath indexPathWithIndexes:path length:2]];
}
return newIndexPaths;
}
This answer has been made "Community wiki" so that anyone may improve this code. Please do so if you find a bug or can make it behave better.
I hacked together a sample of doing this, starting with the sample code git#github.com:appcoda/PhotosApp.git, all my changes are in ViewController.swift.
I kept track of whether the shift was up or down by adding
var shiftDown = false
override func flagsChanged(with event: NSEvent) {
shiftDown = ((event.modifierFlags.rawValue >> 17) & 1) != 0
}
I added this instance variable to remember the last selection
var lastIdx: IndexPath.Element?
Then, to the already defined collectionView(_:didSelectItemsAt), I added
let thisIdx = indexPaths.first?[1]
if shiftDown, let thisIdx = thisIdx, let lastIdx = lastIdx {
let minItem = min(thisIdx, lastIdx)
let maxItem = max(thisIdx, lastIdx)
var additionalPaths = Set<IndexPath>()
for i in minItem...maxItem {
additionalPaths.insert(IndexPath(item: i, section: 0))
}
collectionView.selectItems(at: additionalPaths, scrollPosition: [])
}
lastIdx = thisIdx
This is just a start. There's probably bugs, especially around the saving of the lastIdx.
None of the answers appear to support sections or shift selecting across section boundaries. Here is my approach:
- (NSSet<NSIndexPath *> *)collectionView:(NSCollectionView *)collectionView shouldSelectItemsAtIndexPaths:(NSSet<NSIndexPath *> *)indexPaths
{
if ([shotCollectionView shiftIsDown])
{
// find the earliest and latest index path and make a set containing all inclusive indices
NSMutableSet* inclusiveSet = [NSMutableSet new];
__block NSIndexPath* earliestSelection = [NSIndexPath indexPathForItem:NSUIntegerMax inSection:NSUIntegerMax];
__block NSIndexPath* latestSelection = [NSIndexPath indexPathForItem:0 inSection:0];
[indexPaths enumerateObjectsUsingBlock:^(NSIndexPath * _Nonnull obj, BOOL * _Nonnull stop) {
NSComparisonResult earlyCompare = [obj compare:earliestSelection];
NSComparisonResult latestCompare = [obj compare:latestSelection];
if (earlyCompare == NSOrderedAscending)
{
earliestSelection = obj;
}
if (latestCompare == NSOrderedDescending)
{
latestSelection = obj;
}
}];
NSSet<NSIndexPath *>* currentSelectionPaths = [shotCollectionView selectionIndexPaths];
[currentSelectionPaths enumerateObjectsUsingBlock:^(NSIndexPath * _Nonnull obj, BOOL * _Nonnull stop) {
NSComparisonResult earlyCompare = [obj compare:earliestSelection];
NSComparisonResult latestCompare = [obj compare:latestSelection];
if (earlyCompare == NSOrderedAscending)
{
earliestSelection = obj;
}
if (latestCompare == NSOrderedDescending)
{
latestSelection = obj;
}
}];
NSUInteger earliestSection = [earliestSelection section];
NSUInteger earliestItem = [earliestSelection item];
NSUInteger latestSection = [latestSelection section];
NSUInteger latestItem = [latestSelection item];
for (NSUInteger section = earliestSection; section <= latestSection; section++)
{
NSUInteger sectionMin = (section == earliestSection) ? earliestItem : 0;
NSUInteger sectionMax = (section == latestSection) ? latestItem : [self collectionView:collectionView numberOfItemsInSection:section];
for (NSUInteger item = sectionMin; item <= sectionMax; item++)
{
NSIndexPath* path = [NSIndexPath indexPathForItem:item inSection:section];
[inclusiveSet addObject:path];
}
}
return inclusiveSet;
}
// Otherwise just pass through
return indexPaths;
}

string not populating with array data, even though arrays are not really empty

I am trying to create a non-Document-based application for Mac OS X that randomizes cards for the game of Dominion.
From many of the ones I have tried, the only thing I cannot seem to do is limit the number of sets picked from a selection made by the user, and things worked pretty well in my program, but I am having issues.
I am trying to get the results to print in a custom view, but every time I look at the print preview, nothing shows, except header text, as specified in an NSMutableString.
This piece of code is what is being used to print and is found in MasterViewController:
- (IBAction)print:(id)sender
{
NSMutableString *content = [[NSMutableString alloc] initWithString:#"Cards\r\n\r\n"];
for (int i = 0; i < [supply.game count]; i++)
{
[content appendFormat:#"Card: %# Set: %# Cost: %d\r\n", [supply.game[i] name], [supply.game[i] collection], [supply.game[i] cost]];
}
[content appendFormat:#"\r\n\r\nRequired\r\n\r\n"];
for (int i = 0; i < [[setup supply] count]; i++)
{
NSDictionary* current = [setup supply][i];
NSString* key = [current allKeys][0]; // get the key of the current dictionary must be 0, as there is only one key
int value = [[current valueForKey:key] integerValue]; // variable to hold key value
if (value > 0) {
[content appendFormat:#"%#: %#", key, #"Yes"];
}
else
{
[content appendFormat:#"%#: %#", key, #"No"];
}
}
printView.content = [NSMutableString stringWithString:content];
[printView print:sender];
}
the data initially gets filled into some tableviews, which displays the correct content, and the supply.game array is the exact array that contains cards used for games.
setup is a property that refers to a view controller that populates a table with kinds of cards that may be required for games (e.g. shelters, colonies, ruins, spoils, and potions) and the supply method is supposed to return the array that view controller creates, which is itself not empty, as that table populates properly.
printView is a property that is assigned to a custom view found in MainMenu.xib and is the real view being used to print from.
the printView class looks like this:
header:
#import <Cocoa/Cocoa.h>
#interface PrintView : NSView
{
NSMutableString* content;
}
#property NSMutableString* content;
- (void)drawStringInRect:(NSRect)rect; // method to draw string to page
- (void)print:(id)sender; // method to print
#end
implementation:
#import "PrintView.h"
#implementation PrintView
#synthesize content;
- (BOOL)acceptsFirstResponder
{
return YES;
}
- (void)print:(id)sender
{
[[NSPrintOperation printOperationWithView:self] runOperation];
}
- (void)drawRect:(NSRect)dirtyRect {
NSGraphicsContext *context = [NSGraphicsContext currentContext];
if ([context isDrawingToScreen])
{
}
else
{
[[NSColor whiteColor] set];
NSRect bounds = [self bounds];
if (content == nil || [content length] == 0)
{
NSRectFill(bounds);
}
else
{
[self drawStringInRect:bounds];
}
}
}
- (void)drawStringInRect:(NSRect)rect
{
NSSize strSize; // variable to hold string size
NSPoint strOrigin; // variable used to position text
NSMutableDictionary *attributes = [[NSMutableDictionary alloc] init];
[attributes setObject:[NSFont fontWithName:#"Helvetica" size:12] forKey:NSFontAttributeName];
[attributes setObject:[NSColor blackColor] forKey:NSForegroundColorAttributeName];
strSize = [content sizeWithAttributes:attributes];
strOrigin.x = rect.origin.x + (rect.size.width - strSize.width)/2;
strOrigin.y = rect.origin.y + (rect.size.height - strSize.height)/2;
[content drawAtPoint:strOrigin withAttributes:attributes];
}
#end
When I check the array sizes for printing operation, the size of the arrays is reported as zero, thus resulting in my current problem
If you need more code, here is code from Github, but I do not have the experimental branch up there, which is where the above code came from, though it should not be too different.
The MasterViewController will show how the supply.game array is made and SetupViewController houses the code that is used to determine what is needed in the game, as well as show how the supply array from [setup supply] is being produced.
MasterViewController has also been added as an object to MainMenu.xib, so I do not know if that affects anything.
Any idea of what I need to do?
Edit: Added in info that might be relevant

disabling rows on condition on xlform

I have a section set up using xlform where there is a bool field and then a text field under it. I want to disable the text field if the bool is chosen. I tried with the following, but it did not work
if ([[self.form valueForKey:#"pay"] isEqualToValue:#(1)]){
row.disabled = YES;
} else {
row.required = YES;
}
[section addFormRow:row];
Any suggestions? Here is the documentation, spent a bunch of time search without being able to find the answer.
Edit: I'm starting to think that the values of the dictionary don't get updated dynamically. Which is odd because the dictionary can be accessed in other parts of the view controller at any time.
Edit
- (void)formRowDescriptorValueHasChangedTwo:(XLFormRowDescriptor *)formRow value:(id)value
{
[value isEqual:[self.formValues valueForKey:#"pay"]];
if([formRow.tag isEqualToString:#"pay"] && [value isEqual:[NSNumber numberWithBool:YES]])
{
self.price.disabled = NO;
self.price.required = YES;
[self.tableView reloadRowsAtIndexPaths:#[[self.form indexPathOfFormRow:self.price]]
withRowAnimation:UITableViewRowAnimationNone];
}
}
I got it working, but I have a new problem.
Here is the code
- (void)formRowDescriptorValueHasChanged:(XLFormRowDescriptor *)formRow oldValue:(id)oldValue newValue:(id)newValue
{
if([formRow.tag isEqualToString:#"now"] && [newValue isEqual:[NSNumber numberWithBool:YES]])
{
self.time.disabled = YES;
[self.tableView reloadRowsAtIndexPaths:#[[self.form indexPathOfFormRow:self.time]]
withRowAnimation:UITableViewRowAnimationAutomatic];
}
if([formRow.tag isEqualToString:#"pay"] && [newValue isEqual:[NSNumber numberWithBool:YES]])
{
self.price.disabled = NO;
self.price.required = YES;
[self.tableView reloadRowsAtIndexPaths:#[[self.form indexPathOfFormRow:self.price]]
withRowAnimation:UITableViewRowAnimationAutomatic];
}
}
When I click on the first row (now), it disables the corresponding row fine, but when I click on the second row (pay), it makes the row that now disables reappear AND it makes the row that I want to appear under pay to disappear.
Edit Got it to work by changing the animation to UITableViewRowAnimationNone
Here's how you can do it using XLFormDescriptorDelegate. This will change the state as the field is toggled on the form.
#interface SomeClass() <XLFormDescriptorDelegate>
#end
#implementation SomeClass
- (void)formRowDescriptorValueHasChanged:(XLFormRowDescriptor *)formRow oldValue:(id)oldValue newValue:(id)newValue
{
if([formRow.tag isEqualToString:#"boolFieldTag"] && [newValue boolValue])
{
self.otherRow.disabled = YES;
[self.tableView reloadRowsAtIndexPaths:#[[self.form indexPathOfFormRow:self.otherRow]]
withRowAnimation:UITableViewRowAnimationNone];
}
}
#end
In this example I set the row as a property when I originally added it to the form. Alternatively you can just use: [self.form formRowWithTag:#"someTag"]

NSInternalInconsistencyException with UITableViewController and a Storyboard-Pop

I integrated GrabKit in my iPhone-App, which is a Library to Grab Photos from social Networks. Now I have the following situation/problem:
I have a UITableViewController - AlbumListViewController.
Then there's a UITableViewCell - AlbumCellViewController.
When you tap on one of these cells - albums with photos
There's a UITableViewController - PhotoListViewController
and a UITableViewCell - PhotoCellViewController.
Everything here works just finde, I can browse albums, choose one, browse the photos in it and then when I choose one of the single photos, there is a PushViewController to my SetPhotoViewController, which displays the selected image in Fullscreen.
Now when I want to use the back-Button of my navigation bar in the SetPhotoViewController, the crashes with the following message:
*** Assertion failure in -[UISectionRowData refreshWithSection:tableView:tableViewRowData:], /SourceCache/UIKit_Sim/UIKit-2372/UITableViewRowData.m:400
2012-10-22 22:49:32.814 Amis[1820:c07] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Failed to allocate data stores for 1073741821 rows in section 1. Consider using fewer rows'
*** First throw call stack:
(0x23de012 0x1b63e7e 0x23dde78 0x15f9f35 0xc8f83b 0xc923c4 0xb56fa2 0xb5692c 0x1690f 0x1cd653f 0x1ce8014 0x1cd87d5 0x2384af5 0x2383f44 0x2383e1b 0x2a9a7e3 0x2a9a668 0xaab65c 0x42fd 0x2b75)
libc++abi.dylib: terminate called throwing an exception
DataSource and Delegate of my two UITableViewControllers are both set to File's Owner.
When I debug trough the code, I can't find any special things, all photos can be loaded, all the arrays are filled with data, there's nothing strange.
Here are the two functions of the PhotoListViewController which get called, as soon as I press the back button on my NavigationController:
(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = nil;
NSLog(#"%i", indexPath.row);
NSLog(#"%ii", indexPath.section);
// Extra Cell
if ( indexPath.section > _lastLoadedPageIndex ){
static NSString *extraCellIdentifier = #"ExtraCell";
cell = [tableView dequeueReusableCellWithIdentifier:extraCellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:extraCellIdentifier];
}
cell.textLabel.text = #"load more";
cell.textLabel.font = [UIFont fontWithName:#"System" size:8];
} else {
static NSString *photoCellIdentifier = #"photoCell";
cell = [tableView dequeueReusableCellWithIdentifier:photoCellIdentifier];
if (cell == nil) {
cell = [[[NSBundle mainBundle] loadNibNamed:#"PhotoRowViewController" owner:self options:nil] objectAtIndex:0];
}
}
// setting of the cell is done in method [tableView:willDisplayCell:forRowAtIndexPath:]
return cell;
}
and..
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
// extra cell
if ( [cell.reuseIdentifier isEqualToString:#"ExtraCell"] ){
if ( state == GRKDemoPhotosListStateAllPhotosGrabbed ) {
cell.textLabel.text = [NSString stringWithFormat:#" %d photos", [[_album photos] count] ];
}else {
cell.textLabel.text = [NSString stringWithFormat:#"Loading page %d", _lastLoadedPageIndex+1];
[self fillAlbumWithMorePhotos];
}
} else // Photo cell
{
NSArray * photosAtIndexPath = [self photosForCellAtIndexPath:indexPath];
[(PhotoRowViewController*)cell setPhotos:photosAtIndexPath];
}
}
What am I missing?
Edit: The code of the numberOfRowsInSection-Method:
If I debug it, the first time res is equal 0, the second time the method gets called, res is equal 322121535.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
NSUInteger res = 0;
if ( state == GRKDemoPhotosListStateAllPhotosGrabbed && section == _lastLoadedPageIndex ) {
NSUInteger photosCount = [_album count];
// Number of cells with kNumberOfPhotosPerCell photos
NSUInteger numberOfCompleteCell = (photosCount - section*kNumberOfRowsPerSection*kNumberOfPhotosPerCell) / kNumberOfPhotosPerCell;
// The last cell can contain less than kNumberOfPhotosPerCell photos
NSUInteger thereIsALastCellWithLessThenFourPhotos = (photosCount % kNumberOfPhotosPerCell)?1:0;
// always add an extra cell
res = numberOfCompleteCell + thereIsALastCellWithLessThenFourPhotos +1 ;
} else if ( section > _lastLoadedPageIndex) {
// extra cell
res = 1;
} else res = kNumberOfRowsPerSection;
return res;
}
I'm the developer of GrabKit. Thanks for using it :)
Actually, the controllers in GrabKit are there for demonstration purpose only, they are not designed to be used "as is" in a project, and more specifically : The GRKDemoPhotosList controller was not made to have another controller pushed in the controllers hierarchy.
So what you need is just a little fix to make grabKit demo's controllers fit to your project :)
I guess the problem is the following :
_ in [GRKDemoPhotosList viewWillAppear], the method fillAlbumWithMorePhotos is called.
_ when you pop back from your controller to GRKDemoPhotosList, this method is called one more time, and it generates this bug.
Try to add a flag in the viewWillAppear method, to avoid calling fillAlbumWithMorePhotos twice, I guess it'll work fine.
Feel free to contact me by mail ( pierre.olivier.simonard at gmail.com ) or on twitter ( #pierrotsmnrd ) if you need more informations or help :)

UISegmentedControl writing text labels problem

Goodday,
I got the following problem with this code:
-(void)textpopup:(UISegmentedControl *)sender {
int nummer = sender.tag;
if (sender.tag) {
if(sender.selectedSegmentIndex == 0 || sender.selectedSegmentIndex == 1){
beoordeling = [[UITextField alloc] init];
beoordeling.frame = CGRectMake(50 , nummer * 117 + 275 , scrollView.frame.size.width - 100 , 35);
beoordeling.autoresizingMask = (UIViewAutoresizingFlexibleWidth);
beoordeling.borderStyle = UITextBorderStyleLine;
beoordeling.tag = nummer;
[scrollView addSubview:beoordeling];
}
if(sender.selectedSegmentIndex == 2 || sender.selectedSegmentIndex == 3){
if (beoordeling.tag == sender.tag) {
[beoordeling removeFromSuperview];
}
}
}
}
i shall explain the scenario. I got some dynamic UISegmentedControls. At the moment there are 12 of them. At the first 2 segments chosen, a textfield needs to popup. This goes well. But after choosing the first 2 segments for a while and when i go to segments 2 and 3, sometimes the textfields won't remove.
I expected that the textfields which are written when i push segment 0 and 1 are removed when segment 2 and 3 are pushed.
Am i missing something?
EDIT:
At first i want to say, that i never know in advance how many UITextFields i got. When segments 0 and 1 are chosen, a UITextField needs to popup to that corresponding UISegmentedControl. And when segments 2 and 3 are chosen, the UITextField needs to stay away. But i got that fixed now in the following way.
-(void)textpopup:(UISegmentedControl *)sender {
int nummer = sender.tag;
if(sender.selectedSegmentIndex == 0 || sender.selectedSegmentIndex == 1){
// Before i add a new UITextField, the old one has to be removed.
UITextField *text = (UITextField *)[beoordeling viewWithTag:sender.tag];
[text removeFromSuperView];
beoordeling = [[UITextField alloc] init];
beoordeling.frame = CGRectMake(50 , nummer * 117 + 275 , scrollView.frame.size.width - 100 , 35);
beoordeling.autoresizingMask = (UIViewAutoresizingFlexibleWidth);
beoordeling.borderStyle = UITextBorderStyleLine;
beoordeling.tag = nummer;
[scrollView addSubview:beoordeling];
}
else if(sender.selectedSegmentIndex == 2 || sender.selectedSegmentIndex == 3) {
UITextField *tf = (UITextField *)[beoordeling viewWithTag:sender.tag];
tf.text = nil;
[tf removeFromSuperview];
}
}
The second if should be an else if, because it should execute only if the first one doesn't (the selected index can't be both 0 and 2).
What you're trying to do depends on how you've defined beoordeling. I suggest having it as an instance variable, possibly even an IBOutlet. Release in your class's dealloc. Then, in the first if clause, write
if (!beoordeling) {
beoordeling = [[UITextField alloc] init];
// Other setup
}
[scrollView addSubview:beoordeling];
I don't quite understand why you're checking for the tag, but to remove in the second if, just call removeFromSubview.
Do all your segmented controls invoke the same behavior? If you have only one beorrdeling that you're setting the tag on, then you don't need to bother checking for the tag. Just add/remove it, using removeFromSubview. If you have as many of text fields as segmented controls, maybe KVC would be what you want. If your segmented controls' tags go from 0–11, you might have beoordeling0, beoordeling1, beoordeling2, and so on. Then, to get the one you want, use something like this:
beoordeling = (UITextField *)[self valueForKey:[NSString stringWithFormat:#"beoordeling%d", sender.tag]];
Not really sure what you are trying to achieve here, but you do need to release your UITextField object beoordeling or you will leak. AddSubview adds one to the retain count, so should be safe to release straight away:
[scrollView addSubview:beoordeling];
[beoordeling release];