Positioning NSTextField correctly with setFrame: - objective-c

I am having problems positioning my NSTextFields inside my views so I hope you guys can help me. I have this NSView *theView with [theView setFrame:NSMakeRect(10, 10, 64, 64)]; which positions the view exactly where I want it.
But now I am trying to add a NSTextField as a subView to theView but something isn't right. Now the image above is how it should be.
Here's my code and what it looks like:
primaryDigit = [[NSTextField alloc] init];
[primaryDigit setFrame:NSMakeRect(4, 6, 60, 58)];
[primaryDigit setFont:[NSFont fontWithName:#"Helvetica Neue" size:55]];
[primaryDigit setBezeled:NO];
[primaryDigit setEditable:NO];
[primaryDigit setSelectable:NO];
[primaryDigit setDrawsBackground:NO];
[primaryDigit setTextColor:[NSColor whiteColor]];
[primaryDigit setStringValue:#"2"];
[self addSubview:primaryDigit];
And when I do [primaryDigit setFrame:NSMakeRect(0, 0, 64, 64)]; the digit doesn't end up in the left lower corner but it does this:
Is there something fundamental that I don't understand about positioning these views? I'm quite the noobie but I still thought that I understand this. (Btw, the font is different in these images but that shouldn't cause a problem, I think?)
Update: as 'dasdom' asked me to, here's the text field with a background colour

Okay I found out what the problem is.
The text in NSTextFields need "space" around them. So when they have text they don't appear in the bottom left corner of the view but are position a bit away from it.
That also means that if NSTextFields don't have a frame that is large enough then the text may appear cut off.
An example here:
All the red space above the "2" has to be there otherwise the digit will move off the frame and gets cut off at the bottom.

Related

How do you customise UISearchBar colors in iOS7?

I have searched quite a bit but cannot find a good answer to this.
I want to change the backgroundColor of the inner rounded view.
Like in Tweetbot on the search tap where it changes from gray to blue.
I understand that I probably need to iterate over the subviews but I don't know how to get the right object. (for the backgroundColor it's not the _searchLabel)
The default contrast of this element is so bad it's not even funny :(
Ok, this works. But note that you can't set a UIBarStyle beforehand or it will override everything.
https://stackoverflow.com/a/19836215/1252720
If you're still looking for a better answer, I just stumbled across this thread and found a great solution: UISearchBar text color change in iOS 7
If you look at the answer given by Sandeep-Systematix (not the accepted answer, but the answer right below), he mentions a really clean way to modify subviews in any class with this method:
[[UITextField appearanceWhenContainedIn:[UISearchBar class], nil] setTextColor:[UIColor blueColor]];
You can read more about this in Apple's documentation: https://developer.apple.com/library/ios/documentation/uikit/reference/UIAppearance_Protocol/Reference/Reference.html
That said, here's what you'll need to change the white, rounded background of the UITextField inside the UISearchBar:
[[UITextField appearanceWhenContainedIn:[UISearchBar class], nil] setBackgroundColor:[UIColor redColor]];
Now if you needed to create different UISearchBars with different styles, you would simply create a subclass of UISearchBar and you'd end up with something like this:
[[UITextField appearanceWhenContainedIn:[MyCustomSearchBar class], nil] setBackgroundColor:[UIColor redColor]];
Use this code.
_searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0.0f, 0.0f, self.contentView.bounds.size.width, 44.0f)];
_searchBar.autoresizingMask = UIViewAutoresizingFlexibleWidth;
_searchBar.delegate = self;
[self.view addSubView:_searchBar];
UITextField *txfSearchField = [_searchBar valueForKey:#"_searchField"];
txfSearchField.backgroundColor = [UIColor redColor];

NSTextView inherits parents view background on update

I have a NSTextView that I am using to display a timer. This timer updates every second counting down to 00:00. When the timer updates the string for the NSTextView, the NSTextView acts as if it redraws but uses its parents views background for its own background.
My NSTextView has a clear background color and has been set not to draw its background. Its parent view draws a 3 part image for its own background. Below is the code for the NSTextView.
_timerLabel = [[NSTextView alloc] init];
[self.timerLabel setSelectable:NO];
[self.timerLabel setEditable:NO];
self.timerLabel.font = fontLoaded ? [NSFont fontWithName:#"DS-Digital" size:26.0f] : [NSFont fontWithName:#"Lucida Grande" size:26.0f];
self.timerLabel.textColor = [NSColor colorWithCalibratedRed:(50.0f/255.0f) green:(50.0f/255.0f) blue:(50.0f/255.0f) alpha:1.0f];
self.timerLabel.backgroundColor = [NSColor clearColor];
[self.timerLabel setDrawsBackground:NO];
[self.timerLabel setAllowsDocumentBackgroundColorChange:NO];
[self.timerLabel setAlignment:NSCenterTextAlignment];
self.timerLabel.string = #"5:11";
[self addSubview:self.timerLabel];
Any ides why this would be happening? I have tried everything I could think of or find in the apple documents and nothing has solved my issue. Any help would be greatly appreciated.
Before updating the text in the NSTextView
https://www.dropbox.com/s/za3twd8hb7r1apr/Screen%20Shot%202013-04-10%20at%205.37.10%20PM.png
After updating the text in the NSTextView
https://www.dropbox.com/s/p0bsk63o8yweyqs/Screen%20Shot%202013-04-10%20at%205.37.28%20PM.png
I figured out what was happening and thought I share in case anyone else gets stuck with the same issue.
When updating the text for the NSTextView (can be an NSTextField too), the drawRect function gets called with the rect for the NSTextView that was updated.
In my case, my draw rect was drawing a 3 part image for the background of my NSView to the supplied rect in the drawRect function. Since the rect was the rect of the NSTextView after and updated to its string, this would redraw my background image for the size of the NSTextView.
Currently the only solution I have been able to come up with is to always draw my 3 part image for the bounds of my NSView.
Hope that makes since.

Mac OS X: How to force a Field Editor to scroll instead of wrap text?

I have a Cocoa, Document-based Mac OS X application.
One feature that I have in my app is a list of text items which can be double-clicked to edit. When the user double-clicks one of the text items, I place the current window's fieldEditor text field over the clicked text item to allow editing.
Everything is working fine except for one problem. I cannot figure out how to make the fieldEditor text field clip + scroll rather than wrap its text. Here's what it currently looks like:
See how the text is wrapping to a second line? I don't want that. I'd like it to remain one line which scrolls (and appears clipped).
Here's an example of it working correctly on a list item which has less text:
Here's what I'm trying in my view controller:
NSWindow *win = [listItemView window];
NSText *fieldEditor = [win fieldEditor:YES forObject:listItemView];
[fieldEditor setFont:[TDListItemView titleFont]];
[fieldEditor setAlignment:NSLeftTextAlignment];
[fieldEditor setDrawsBackground:YES];
[fieldEditor setBackgroundColor:[NSColor whiteColor]];
[fieldEditor setString:str];
[fieldEditor setDelegate:self];
[fieldEditor selectAll:nil];
if ([fieldEditor isKindOfClass:[NSTextView class]]) {
NSTextView *tv = (NSTextView *)fieldEditor;
NSMutableParagraphStyle *style = [[[tv defaultParagraphStyle] mutableCopy] autorelease];
[style setLineBreakMode:NSLineBreakByClipping];
[tv setDefaultParagraphStyle:style];
}
CGRect r = [self fieldEditorRectForBounds:[listItemView bounds] index:idx]; // height here is 10.0
[fieldEditor setFrame:r];
[fieldEditor setNeedsDisplay:YES];
[[self view] addSubview:fieldEditor];
[win makeFirstResponder:fieldEditor];
Notice that part in the middle: I check to see if this fieldEditor is an instance of NSTextView in order to call the setDefaultParagraphStyle: method on it. This is my attempt to get the fieldEditor to clip its text -- via the NSLineBreakByClipping value. It's not having any effect. And I'm not even sure this is what I should be doing to get the fieldEditor to scroll on one line.
Also note that the height of the rect which I compute in my -fieldEditorRectForBounds:index: method is correct, and is providing a rect which is correctly sized for a single line of text (14.0 pixels in this case).
What am I missing to make the fieldEditor display a single line of scrolled/clipped text?
I've also tried adding these lines in the middle section:
[[tv textContainer] setHeightTracksTextView:YES];
[[tv textContainer] setWidthTracksTextView:YES];
This has the desired effect of resizing the visible portion of the fieldEditor which is good. But the bad news is that it doesn't change the fact that the text is still wrapped, rather than clipped + scrolled. :(
This seems related to this constant:
NSStringDrawingUsesLineFragmentOrigin
which can be used in the options: argument of:
-[NSAttributedString drawWithRect:options:attributes:]
but in my case, I'm working from a NSText field editor, not an NSAttributedString. I can't figure out how to do this sort of thing with an NSText field editor.
Hmmm ... NSTextView relies on an NSScrollView entirely for its scrolling behavior. I'm not sure if there's more to this that I'm not seeing, but it looks like the "historic" solution to your problem is either to:
Use A Different Control
You can use an editable NSTextField in its standard IB label configuration with editing enabled and scrolling selected as the behavior. It does all the heavy lifting for you already when configured properly - no need to mess around with the field editor directly.
...or to...
Cheat
Slap the field editor into an appropriately-sized and configured NSScrollView (allow only horizontal scroll; don't show the scrollers) dynamically, then remove the scroll view when finished editing.
NSMutableParagraphStyle* style = [[NSMutableParagraphStyle alloc] init];
[style setLineBreakMode:NSLineBreakByTruncatingHead];
NSMutableDictionary* attributes = [[NSMutableDictionary alloc] init];
[attributes setObject:style forKey:NSParagraphStyleAttributeName];
NSTextView* textView = [[NSTextView alloc] init];
[textView setTypingAttributes:attributes];
If you use NSTextView, please try below codes ....
[self.textView setMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)];
[self.textView setHorizontallyResizable:YES];
[[self.textView textContainer] setWidthTracksTextView:NO];
[[self.textView textContainer] setContainerSize:NSMakeSize(FLT_MAX, FLT_MAX)];

How To Draw A Line Dividing The Cell's Accessory View

I just wanted to know how I could draw a line dividing the cell's accessory view from the rest of the cell.
You could simply add a thin UIView (or UIImageView if you wanted a fancier divider) like so.
UIView *divider = [[UIView alloc] initWithFrame:CGRectMake(290, 3, 1, 38)];
[divider setBackgroundColor:[UIColor blackColor]];
[cell.contentView addSubview:divider];
[divider release];
If you're using one of UITableView's default accessory views, your content view will be squashed to make room for the accessory, so you your x-coordinate may have to change to sit at the very edge of the content view.

Resize UITableViewCell content when delete button shows up

Is there any way to use autoresizing masks to move my content so that the delete button doesn't cover it up? Googling has told me that I need to set an autoresizing mask of UIViewAutoresizingFlexibleRightMargin on my subview. It seems to me like UIViewAutoresizingFlexibleWidth would actually make more sense; though I've tried them both and neither works.
The view that I am trying to shrink is just a label that is a subview of the cell's contentView. I am unsure if the contentView itself automatically resizes when the delete button shows up; but it seems like it isn't; otherwise my autoresizing mask should have worked.
If the presence of the delete button doesn't cause any views to be resized; is there anyway that I can do this manually?
You should use UIViewAutoresizingFlexibleLeftMargin.
Here's why. You want your contents to move to the left, basically making it seem like the delete button is pushing the contents to the left, out of it's way. flexibleLeftMargin basically means your UILabel will stay fixed to the right side of your contentView. The reason you want this, is because the delete button actually causes your contentView to shrink it's width.
The autoresizingmask of your UILabel refers to how it behaves inside the contentView, not the cell.
Give it a try, it should work.
This question is really old but I feel I should answer this anyway since I just found the solution myself.
Only the cell's ContentView gets resized with the confirmation button is shown. If you don't add your views (labels, imageviews, etc...) to the cell.contentView instead of adding them to the cell directly then they won't be resized when the contentView is resized. In my case, I was adding it to the cell directly.
So, instead of doing something like:
UILabel *nameLabel = [[UILabel alloc] initWithFrame:CGRectMake(5, 5, width-10, 20)];
[nameLabel setFont:[UIFont boldSystemFontOfSize:16]];
[nameLabel setHighlightedTextColor:[UIColor whiteColor]];
[nameLabel setAutoresizingMask:UIViewAutoresizingFlexibleWidth];
[nameLabel setTag:101];
[cell addSubview:nameLabel];
[nameLabel release];
you should do:
UILabel *nameLabel = [[UILabel alloc] initWithFrame:CGRectMake(5, 5, width-10, 20)];
[nameLabel setFont:[UIFont boldSystemFontOfSize:16]];
[nameLabel setHighlightedTextColor:[UIColor whiteColor]];
[nameLabel setAutoresizingMask:UIViewAutoresizingFlexibleWidth];
[nameLabel setTag:101];
[[cell contentView] addSubview:nameLabel]; // <<--- note the change in this line!
[nameLabel release];
Hope this helps others who stumble upon this issue.
I am using iOS 7, I got the same issue. I am using a separate xib for the UITableViewCell with auto layout enabled, so just added one more constraint to the label so that it will have a fixed gap on its right side.