Custom font in iOS - iphone

Ok,
using a custom font since 3.2 is pretty straightforward:
Load the font in resources bundle, specify it's name in plist and there you go, you can use is in a text field with [textField setFont...].
The thing is, i want to replace the font in every part of my app, say the navigation bar so it gets complicated, because it seems i have to replace every component with a custom one in order to set the font.
Is there any way to let the bloody thing know that i want the default font replaced with a custom one, in one step? Not in every bar item, and so...
Thanks!

Maybe a category on UIFont which redefines
+ (UIFont *)systemFontOfSize:(CGFloat)size {
return [self fontWithName:#"YourFontName" size:size];
}
+ (UIFont *)boldSystemFontOfSize:(CGFloat)size {
return [self fontWithName:#"YourBoldFontName" size:size];
}
to return your custom font.
As pointed by Jonathan in the comments, it may also change the status bar font (I can't verify at the moment). I don't know if Apple would accept this behavior (redefining methods is OK but modifying the default UI isn't IMHO).
Subclassing UIFont wouldn't be sufficient because labels and others would still use the UIFont class by default.

Related

How can I send characters to cursor position of UISearchBar?

I am trying to add a couple characters that are inconveniently located in the normal keyboard, and place them in a toolbar so that the user can use them just like normal keys.
Does anyone have a useable way to do this?
I found an article explaining how to do this by simulating a "Paste" operation, (remove pasteboard contents, replace with my character, paste into field, return original pasteboard contents) but my trouble is that I'm trying to do this with a UISearchBar, which seems to have no paste selector.
Update
I found a lead:
UIKIT_CLASS_AVAILABLE(2_0) #interface UISearchBar : UIView {
#private
UITextField *_searchField;
Since it is documented that there's a UITextField in a search bar, if I were to root through the searchbar's subviews and locate said text field, (assuming with 99% certainty that the text field has a delegate) would it make sense that I could "steal" the text field and make my class the delegate, then forward the messages to the original delegate once I'm done with them?
This is definitely tricky. UISearchBar doesn't give you inputAccessoryView and nor do you get selectedRange.
You can paste in a UISearchBar. If you want to get your tricky characters to the pasteboard, you could get a button to execute something such as:
[[UIPasteboard generalPasteboard] setString:#"[*]"];
and then get the user to use paste in the UISearchBar. Pretty awkward for the user though.
Rooting through the subviews to find the UITextField might work. If you do this, you'd need to grab the existing delegate and make yourself the delegate. Then your delegate would need to transmit messages on. The process is described in this stackoverflow question and answer. Potential challenges here: (a) the Apple implementation could change between iOS updates and even, though unlikely, change the delegate during the lifetime of the UISearchBar; (b) Apple might see this as using a private API and reject the app. (I don't have any hard evidence of (b), but it's something to consider.)
One approach might be to use the bookmark button. The UISearchBar delegate can detect this. You could use that to insert your special characters or offer up a menu of special character insertions. Of course, you won't know where the cursor is. But, depending on your use case, appending the special characters at the end might be OK. Perhaps this doesn't get you anything over a button on your interface that just appends something.
[[self searchBar] setText: [NSString stringWithFormat:#"%#[*]", [[self searchBar] text]]].)
Implementing your own search bar might be the best way to go as already suggested #hyperbole. I've done this successfully by adding a custom UITextField (with my own magnifying glass in the leftView slot etc.) and adding it as the titleView of my navigationBar. But, if I understand your question aright, that still won't be enough, as UITextField doesn't provide selectedRange and its delegate doesn't provide an equivalent of textViewDidChangeSelection:. You might have a go with a UITextView that is fixed to one line (with scrolling clamped down if required - it often seems to be).
Can't you simply set the text of the UISearchBar? Of course, the tricky part is to determine the cursor position. For that, you can register a UITapGestureRecognizer on the UISearchBar, determine the tap co-ordinates & calculate the cursor position using - (CGSize)sizeWithFont:(UIFont *)font forWidth:(CGFloat)width lineBreakMode:(UILineBreakMode)lineBreakMode or its variants.
You may also have to register a UIPanGestureRecognizer, as the user can change the cursor position by tapping, dragging & then releasing the finger.
HTH,
Akshay

Cocoa Touch UITextView setText: method useless

I have a UITextView which I create in Interface Builder for an iOS app. I checked (and double checked, and triple checked) that it is properly connected to the outlet in my code. I create a property and synthesize it, and when I run NSLog(#"%#", myTextView);, it returns the UITextView's properties, not null. However, when I try calling [myTextView setText:#"My Text."];, it doesn't change anything on the view. I have found many people with similar problems like this on Stackoverflow and other places on the internet, however none of the solutions there helped me. I am using Xcode 4.0.2 on Snow Leopard. I am attempting to do this in the -viewDidLoad method. What could be causing this issue?
If you need any more information about my code setup, post a comment and I will update this post.
Are you sure the whole text view is visible on screen, and that the font color is not the same as your background?
It is very likely that the view that is displayed on the screen is not the same view as myTextView points to. Check [myTextView superview] and make sure it's onscreen. Then look and see if you've accidentally covered it with something. Change other aspects like the backgroundColor. Also, check the frame and make sure it's not CGRectZero.

UINavigationItem#titleView alignment problems

I am finding little information about using UINavigationItem#titleView with a custom font.
When I have done so, the font is misaligned vertically in the navigation bar.
This entry is partly to document a hack, and also hoping someone has a succinct answer to this problem, as I feel I am missing something simple.
First the hack, using my own UILabel derived class:
#interface NavigationItemLabel : UILabel
- (void)setFrame:(CGRect)frame;
#end
#implementation NavigationItemLabel
- (void)setFrame:(CGRect)frame {
// Called by UINavigationBar layoutSubviews.
frame.origin.y -= self.font.descender;
}
#end
For some reason, frame.origin.y == -11, no matter what font I use.
Does anyone have any intuition as to why this is?
Adding my font's descender (custom font called Gabriola) seems to help. Without this hack, the text is aligned with the bottom of the descenders on the center of the navigation bar.
This doesn't work for all fonts.
Does anyone have a better solution?
Thanks.
If you are deploying to iOS 5+, you could check out the titleVerticalPositionAdjustmentForBarMetrics property the in the UINavigationBar documentation:
- (CGFloat)titleVerticalPositionAdjustmentForBarMetrics:(UIBarMetrics)barMetrics
Returns the title’s vertical position adjustment for given bar metrics.
Also, you should check out titleTextAttributes (also iOS5+), which you can use to set a custom font:
NSDictionary *attributes = #{
UITextAttributeFont: yourFont
};
[navBar setTitleTextAttributes:attributes];
If you're NOT on iOS5, I'd suggest wrapping the UILabel inside a UIView and setting your UIView as titleView instead (this allows you to further adjust the wrapped label's position by changing its frame).
If you have access to the WWDC 2012 videos (i.e. if you've got a developer account), I'd strongly recommend watching the talk on Advanced Appearance Customization on iOS (this stuff is included there).
Hope it helps somehow.
I had the same problem using Grotesque and there was a great SO solution shown by #kolyuchiy here. (It involves downloading the Apple Font Tool Suite command line utilities and adjusting the ascender attribute for your custom font).

What is the best way to create multi-theme application

I need to create an application that should have several themes. It means that for each theme we use different set of images. The theme should be changed without full reload of all view controllers (just change the images). The themes could be added via In app purchases so they should not be hardcoded.
I also want to use Interface Builder to create my views.
Question: what is the best way to do that?
On MyAppNotificationUIThemeChanged every controller has to retrieve and set images for every UIImageView in it's main view. I can think of 2 approaches for doing this:
1) Brute force. Something like this:
self.imageView1.image = [self currentThemeImage:#"someController_image1.png"];
self.imageView2.image = [self currentThemeImage:#"someController_image2.png"];
2) Automated approach.
NSArray *imageViews = [self fetchAllImageViews];
foreach (UIImageView *iv in imageViews) {
iv.image = [self currentThemeImageForTag:iv.tag];
}
where currentThemeImageForTag: is something like this:
- (UIImage*)currentUIThemeImageForTag:(NSUInteger)imageTag {
return [self currentUIThemeImage:[NSString stringWithFormat:#"%#_%u.png", NSStringFromClass([self class]), imageTag]];
}
I also suggest to use NSBundle to package theme images and other resources.
Update:
I chose NSBundle only because of it's cool methods like pathForResource:ofType: and such and also ability to support localization. You can create bundle with XCode (just look under Mac OS X -> Framework&Library section in new project dialog). Put your images in Resources, remove liks to any frameworks (there is no code anyway), build and that's it. In your app load bundle with [NSBundle bundleWithPath:pathToDownloadedBundle]. Beware though: I don't know if Apple allows to download bundles and use it's content in app. All I can guarantee is that it works on simulator.
I would suggest the approach that I detail in my answer here:
Is there a simple way to set a default font for the whole app?
You could have view controllers in your app ask a ThemeApplicator class to style them when necessary. It would do this by setting the correct background image, that sort of thing. You can still use IB to build your views; just don't set a background in IB (or set a default background). The key is that you programmatically update the background later.
Look at Three20 project, especially at Three20Style.

iPhone Checkboxes à la Mail

After reading the iPhone Human Interface Guidelines, I notice there's little mention of checkboxes in the style that one may encounter them on the desktop or web.
Checkboxes are generally handled by UISwitchs on the iPhone, but for an app I'm presently working on, they're really not the right control. Instead, the control you'll see in Mail is a much better fit:
Actual mail blanked out. Obviously.
How would I go about using these checkbox controls in my app? Are they standard, or will I need to imitate them with a custom control?
Cheers friends.
You'll need to create a custom control. It won't be difficult since UIControl already has 'selected', 'highlighted' and 'state' properties at your disposal. You'll just need to draw and toggle appropriately.
Don't subclass UIControl. What you want is a UIButton of "custom" type. Load it with your "unlit" image in IB (or programmatically in -viewDidLoad--you can set it appropriate to its data there too, if you came here with that property already "checked").
Point its touchUpInside event at a method called -(void)toggleCheckBox, and in that method, toggle whatever setting you're toggling (probably a BOOL property of the objects you're listing), and toggle the "lit/unlit" status of the button image by using its -setImage: forState: method. Use the control state UIControlStateNormal.
I do something similar where I let people poke a button to toggle the "favorite" status of the thing ("thisEvent"--a member of an array of local cultural/arts events) they're looking at:
- (IBAction)toggleFavorite {
if (self.thisEvent.isFavorite == YES) {
self.thisEvent.isFavorite = NO;
[self.favoriteButton setImage:[UIImage imageNamed:#"notFavorite.png"] forState:UIControlStateNormal];
}
else {
self.thisEvent.isFavorite = YES;
[self.favoriteButton setImage:[UIImage imageNamed:#"isFavorite.png"] forState:UIControlStateNormal];
}
}
I'm pretty certain there is no standard way to do this. However it's fairly simple to achieve, all you need is two images, one for each state. I would probably do something simple like subclass UIImageView and add a setState:(BOOL)theState method, which would then simply select the relevant image.
I'd rather subclass UITableViewCell then UIImageView. UITableViewCell allready comes with selected/unselected states and handlers for editmodes etc.
As said before, you'll need to subclass UIControl. The actual process was discussed here w little while ago.
I also found a description of another way to do this using the same image/method that the Mail app uses:
http://networkpx.blogspot.com/2009/07/multiple-row-selection-with-uitableview.html
but as this implements undocumented features of the iOS SDK, it may not be best for apps intended for the official App Store.