I am trying to have dynamic font size for the textview.I have mad a custom class for the dynamic font size of text view.I have used following code for the custom class.
#import "CustomTextView.h"
#implementation CustomTextView
- (void)drawRect:(CGRect)rect
{
// Drawing code
int numLines = self.contentSize.height / self.font.lineHeight;
self.font = [UIFont fontWithName:self.font.fontName size:((self.frame.size.height / numLines) - 4)];
[super drawRect: rect];
}
#end
but this does not work.it shows a black color for the textview.please guide how to do it?
There must be something wrong while implementing "CustomTextView.h" in your ViewController.
Let us know how u have done the same.
Share your code in ViewController.
Have you added "CustomTextView" as subview in your view controller.
Related
I thought I'd try and reuse the font settings and size class variations in my own view. I have my drawing code within drawRect within a UILabel class. However the size of the font isn't that I've set with my sizing classes.
OK, I know I'm not using the label as intended, but shouldn't this work ?
H
=
IB_DESIGNABLE
#interface TitleBannerView : UILabel
M
=
#implementation TitleBannerView
- (void)drawRect:(CGRect)rect {
NSLog(#"self.font.pointSize=%f", self.font.pointSize);
UIFont* textFont = [UIFont fontWithName:APP_FONT size:self.font.pointSize];
//reuse the font in my drawing code here
//Don't add the label!
//[super drawRect: rect];
Maybe you should try preferredFontDescriptorWithTextStyle which respect the user's selected content size category as described here.
UIFontDescriptor *userFont = [UIFontDescriptor preferredFontDescriptorWithTextStyle:UIFontTextStyleBody];
float userFontSize = [userFont pointSize];
UIFont *font = [UIFont fontWithName:APP_FONT size:userFontSize];
You need to use the system font in IB with all your sizing classed and use this method.
#import <UIKit/UIKit.h>
#interface UILabelEx : UILabel
#end
#import "UILabelEx.h"
#import "Constants.h"
#implementation UILabelEx
- (void) traitCollectionDidChange: (UITraitCollection *) previousTraitCollection {
[super traitCollectionDidChange: previousTraitCollection];
self.font = [UIFont fontWithName:APP_FONT size:self.font.pointSize];
}
#end
i am trying to get constraints correct so that the font size scales depending on device. it seems that when the vertical size of the UILabel shrinks the scaling does not happen. the scaling only happens when the horizontal size changes. i have tried fixing the aspect ratio as well but then the text does not fit in the screen vertically in that case.
i would like all the text to be centered in the gray container and scale according to the width of the container.
this is what i am trying to accomplish:
here is the xcode file i am trying to modify - https://www.dropbox.com/sh/c1yx8gk2h8d1ycg/AACnSXUq2j3EiyCnsMHJIqxBa?dl=0
My suggestion:
Create your custom UILabel, UIButton, UITextField subclasses for your project.
In that classes, you can adjust font size on initialise.
Use your custom classes in storyboard/xib/code instead of standard.
For example something like this for UILabel
- (void)awakeFromNib {
[super awakeFromNib];
CGFloat fontSizeMultiplier = 1;
if (isPhone5) {
fontSizeMultiplier = 1.1;
} else if (isPhone6) {
fontSizeMultiplier = 1.2;
} else if (isPhone6Plus) {
fontSizeMultiplier = 1.35;
}
self.font = [UIFont fontWithName:self.font.fontName size:self.font.pointSize * fontSizeMultiplier];
}
Normally, you use:
label.adjustsFontSizeToFitWidth = YES;
to make a label reduce the size of its font whenever it is no longer possible to increase the size of its frame.
Is there any way to make it try an alternate font, like a condensed version of the same font family before it reduces font size?
There are a few good ways to handle this. In IB select your label:
Method 1:
If you click the plus button, you can add specific fonts for a given size class.
In code:
- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection
{
if(self.view.traitCollection.horizontalSizeClass == UIUserInterfaceSizeClassRegular && self.view.traitCollection.verticalSizeClass == UIUserInterfaceSizeClassRegular)
{
//iPad here
myLbl.Font = [UIFont fontWithName:#"Heyo" size:10];
}
}
The better way, in my opinion, is Method 2:
With this approach, you can either tell the font to shrink up to a certain size, or instead identify a scale factor. Toy with these values until you get the desired result. I also talk about this topic in this tutorial.
In code:
//Minimum font size
[myLbl setMinimumScaleFactor:MIN_FONT_SIZE/[UIFont labelFontSize]];
//Scale factor
[myLbl setMinimumScaleFactor:0.4];
This didn't work for me, but this did.
You also need to use the system font in IB
#import <UIKit/UIKit.h>
#interface UILabelEx : UILabel
#end
#import "UILabelEx.h"
#import "Constants.h"
#implementation UILabelEx
- (void) traitCollectionDidChange: (UITraitCollection *) previousTraitCollection {
[super traitCollectionDidChange: previousTraitCollection];
self.font = [UIFont fontWithName:APP_FONT size:self.font.pointSize];
}
#end
I want my app to be when you click the stepper it will resize the font in a UITextView. The problem is I'm getting errors.
- (IBAction)myStepper:(id)sender {
[myStepper setMinimumValue:14.0]
self.myStepper.maximumValue =20.0;
UIFont newSize = [myTextView fontWithSize:self.stepper.value];
self.myTextView.font = newSize;
}
This all of my code, am I missing something?
You are missing a self and a semicolon in the first line:
[self.myStepper setMinimumValue:14.0];
And an asterisk and self in this line, and stepper should be myStepper:
UIFont *newSize = [self.myTextView fontWithSize:self.myStepper.value];
I would clean your method a bit like this:
- (IBAction)myStepperValueChanged:(UIStepper *)sender {
[sender setMinimumValue:14.0];
[sender setMaximumValue:20.0];
UIFont * newSize = [UIFont fontWithName:myTextView.font.fontName size:sender.value];
[self.myTextView setFont:newSize];
}
but I'd put the first two lines into the -viewDidLoad method as part of the standard init procedure, if they are static values in runtime using the outlet's name (I assume it is myStepper in your class):
[myStepper setMinimumValue:14.0];
[myStepper setMaximumValue:20.0];
or I'd set these values in the Interface Builder, and you'd not need to deal with any outlet for your stepper at all.
NOTE: it is hard to tell which solution would fit better for you, you have not shared too much information which could help me to recommend a specific solution.
For easier code-reading, you shouldn't give your action method the same name of your UISteppert property. Change it to -(IBAction)stepperValueChanged:(id)sender for example.
You don't need to set the min and max value in this method, but in your initialization methods
- (void) viewDidLoad
{
[super viewDidLoad];
// Various implementation
self.myStepper.minimumValue = 14;
self.myStepper.maximumValue = 20.0;
}
- (IBAction) stepperValueChanged:(id)sender
{
self.myTextView.font = [UIFont fontWithSize:self.myStepper.value];
}
It looks like you are some issues understanting the differences between method and properties, you should read some documentation and tutorials if you're beginning development (and welcome to the development world ;) ).
EDIT :
The property myStepper doesn't exists in your class. If you use interface builder, you have to link your stepper to an UIStepper property : this apple tutorial will help you : https://developer.apple.com/library/ios/recipes/xcode_help-interface_builder/articles-connections_bindings/CreatingOutlet.html .
Otherwise, if you don't use Interface Builder, you must add an UIStepper property to your class and allocate it by yourself.
Summary:
In iOS 6, I centered text vertically in a UITextView by key-value-observing the text view's contentSize property (https://stackoverflow.com/a/12591299/1239263). When I upgraded to iOS 7, the latter technique worked inconsistently.
Rather than try to fix the KVO technique, I would rather use Text Kit to center text vertically in a UITextView.
I have designed a solution using Text Kit, but it breaks upon device rotation.
The UITextView is orange.
When the text view initially loads, the text is centered properly:
When the device rotates to landscape, the text is still centered properly:
However, when the device rotates back to portrait, the text is not centered properly. The text should be on one line, as it was in the first screenshot above.
For the latter screenshot, logging geometries to the console reveals that the text view's text-container width is too narrow.
Details:
#interface ViewController ()
// text view is created in storyboard; it's added to the root view and it's using auto layout
#property (weak, nonatomic) IBOutlet UITextView *textView;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
NSTextContainer *textContainer = self.textView.textContainer;
[textContainer setWidthTracksTextView:YES];
}
- (void)centerText
{
NSTextContainer *container = self.textView.textContainer;
NSLayoutManager *layoutManager = container.layoutManager;
CGRect textRect = [layoutManager usedRectForTextContainer:container];
UIEdgeInsets inset = UIEdgeInsetsZero;
inset.top = self.textView.bounds.size.height / 2 - textRect.size.height / 2;
inset.left = self.textView.bounds.size.width / 2 - textRect.size.width / 2;
self.textView.textContainerInset = inset;
}
- (void)viewDidLayoutSubviews
{
[self centerText];
}
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
[super willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration];
[self centerText];
}
What I have tried:
I tried to manually set the container size in the centerText method. Depending upon what value I set for the container size, setting the container size does actually work in some cases. Which cases? It depends upon the number of lines of text displayed.
// fixes problem if a single line of text; clips multi-line text
container.size = CGSizeZero;
// fixes problem if multi-line text, but not if a single line of text
container.size = CGSizeMake(self.textView.bounds.size.width, FLT_MAX);
Since I'm setting widthTracksTextView to YES, I don't understand why I would need to set the text container size at all. And if I do need to set the text container width, why does the correct value seem to depend upon the number of lines displayed?
I think I found both explanation and solution. The container itself has some problems with fragment of lines. This is what I saw in the package.
Returns the bounds of a line fragment rect inside the receiver for proposedRect. This is the intersection of proposedRect and the receiver's bounding rect defined by -size property. The regions defined by -exclusionPaths property are excluded from the return value. charIndex is the character location inside the text storage for the line fragment being processed. It is possible that proposedRect can be divided into multiple line fragments due to exclusion paths.
When you use rotation of screen, the exclusionPaths are excluded. So the text cannot save the orientation value you want. That is why when you define the CGRect, it solved the problem somehow.
So the method you should use is:
- (CGRect)lineFragmentRectForProposedRect:(CGRect)proposedRect atIndex:(NSUInteger)characterIndex writingDirection:(NSWritingDirection)baseWritingDirection remainingRect:(CGRect *)remainingRect;