I'm using drawRect to create a line. Based on the "4inch screen" my line is the correct place. When ran on a "3.5 inch screen" the line is lower down and in the wrong place.
- (void)drawRect:(CGRect)rect
{
CGContextRef firstLine = UIGraphicsGetCurrentContext();
CGContextMoveToPoint(firstLine, 15, 389);
CGContextAddLineToPoint(firstLine, 320, 389);
CGContextStrokePath(firstLine);
CGContextSetLineWidth(firstLine, 1.1);
}
I know I need to do something with self.frame.heigh to make it dynamic to screen size but don't know where to put it.
Get the height of the view bounds each time you draw it and you are good to go.
- (void)drawRect:(CGRect)rect
{
/* Get the height of the view */
float height = CGRectGetHeight(self.bounds);
/* the amount to inset the line by */
float lineInset = 20;
/* y-position after insetting the line */
float yPosition = height - lineInset;
CGContextRef firstLine = UIGraphicsGetCurrentContext();
CGContextMoveToPoint(firstLine, 15, yPosition);
CGContextAddLineToPoint(firstLine, 320, yPosition);
CGContextSetLineWidth(firstLine, 1.1);
CGContextStrokePath(firstLine);
}
Related
Hi i am trying to magnify the view with same place finger touch (Y value). I wrote below code but, it gives half of magnified view remains blur.
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
NSLog(#"%#", context);
CGContextTranslateCTM(context, self.frame.size.width / 2, self.frame.size.height / 2);
CGContextScaleCTM(context, scale, scale);
CGContextTranslateCTM(context, - touchPoint.x, - touchPoint.y + (self.scaleAtTouchPoint? 0 : self.bounds.size.height/2));
[self.viewToMagnify.layer renderInContext:context];
}
here frame width and height is 80. Scale is 1.5. if i give scale = 1 gives correct result.
but the result will be like this.
You should use the method setNeedsDisplay to redraw just like this
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
// some code here
//redraw
[magnify setNeedsDisplay];
}
I have a subclass of a UITextView (Custom Control DALinedTextView) where i draw lined text. It works perfect on iOS5 and iOS6 but on iOS7 it fails (text does not match lines).
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 1.0f);
if (self.horizontalLineColor)
{
CGContextBeginPath(context);
CGContextSetStrokeColorWithColor(context, self.horizontalLineColor.CGColor);
// Create un-mutated floats outside of the for loop.
// Reduces memory access.
CGFloat baseOffset = 7.0f + self.font.descender;
CGFloat screenScale = [UIScreen mainScreen].scale;
CGFloat boundsX = self.bounds.origin.x;
CGFloat boundsWidth = self.bounds.size.width;
// Only draw lines that are visible on the screen.
// (As opposed to throughout the entire view's contents)
NSInteger firstVisibleLine = MAX(1, (self.contentOffset.y / self.font.lineHeight));
NSInteger lastVisibleLine = ceilf((self.contentOffset.y + self.bounds.size.height) / self.font.lineHeight);
for (NSInteger line = firstVisibleLine; line <= lastVisibleLine; ++line)
{
CGFloat linePointY = (baseOffset + (self.font.lineHeight * line));
// Rounding the point to the nearest pixel.
// Greatly reduces drawing time.
CGFloat roundedLinePointY = roundf(linePointY * screenScale) / screenScale;
CGContextMoveToPoint(context, boundsX, roundedLinePointY);
CGContextAddLineToPoint(context, boundsWidth, roundedLinePointY);
}
CGContextClosePath(context);
CGContextStrokePath(context);
}
if (self.verticalLineColor)
{
CGContextBeginPath(context);
CGContextSetStrokeColorWithColor(context, self.verticalLineColor.CGColor);
CGContextMoveToPoint(context, -1.0f, self.contentOffset.y);
CGContextAddLineToPoint(context, -1.0f, self.contentOffset.y + self.bounds.size.height);
CGContextClosePath(context);
CGContextStrokePath(context);
}
}
I know it's someting related to UIFont metrics..perphaps someone can help me out? I've change contentSize to intrinsicContentSize but it dos not work.
If i use systemFontOfSize it works perfectly, but with fontWithName it fails.
I've been struggling with this weird issue for quite a while, but finally stumbled upon a legit solution:
textView.layoutManager.usesFontLeading = NO;
This makes UITextView render text (almost) identically to UILabel.
Yes , i think you are using Custom Control DALinedTextView.
I am also facing a problem like you said in iOS7.
Even you can't scroll that control correctly in iOS7.
First i used that control and now i leaved it and using built-in UITextView. :D
Perhaps , you need to change the font size and text margin or text padding of your textView.
check this link.
It uses NSLayoutManagerDelegate, that is used in ios7.
For iOS 7, the styleString approach no longer works.
You have to use NSLayoutManagerDelegate, it is easy to use.
txtViewNote.layoutManager.delegate = self;
txtViewNote.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"textView_bg_lines"]];
- (CGFloat)layoutManager:(NSLayoutManager *)layoutManager lineSpacingAfterGlyphAtIndex:(NSUInteger)glyphIndex withProposedLineFragmentRect:(CGRect)rect
{
return 20.5; // For really wide spacing
}
I am drawing a bar chart, it works fine except it dosent have animation. Ex: fill colore 0-50%.
I am using simple DrawRect method to draw here is my code:
- (void)drawRect:(CGRect)rect
{
CGFloat height = self.bounds.size.height;
CGContextRef context = UIGraphicsGetCurrentContext();
// CGContextClearRect(context, rect);
CGContextSetFillColorWithColor(context, [self colorWithR:149 G:21 B:29 A:1].CGColor);
CGFloat barWidth = 52;
int count = 0;
NSNumber *num = [NSNumber numberWithFloat:graphValue];
CGFloat x = count * (barWidth + 10);
CGRect barRect = CGRectMake(x, height - ([num floatValue] * height), barWidth, [num floatValue] * height);
CGContextAddRect(context, barRect);
count++;
CGContextFillPath(context);
}
Please help me know the simple way to add animation.
I believe you want to animate the heights of the bars in the bargraph.
I suggest you implement each bar as a separate UIview, a simple rectangle. You can also put all of them in one view with a custom drawRect. Then you need to scale these views or change their frame inside the animation block of either of the following methods:
+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion
OR
+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations
For a great tutorial see this.
This is an example if you don't have a lot of time.
[UIView animateWithDuration:1//Amount of time the animation takes.
delay:0//Amount of time after which animation starts.
options: UIViewAnimationCurveEaseOut//How the animation will behave.
animations:^{
//here you can either set a CGAffineTransform, or change your view's frame.
//Both will work just fine.
yourBarView.transform = CGAffineTransformMakeScale (
scaleForX,//say 1, you dont want it to change.
scaleForY//say 20, you want to make it 20 times larger in the y
//direction.
//Note* to animate from a zero height to a finite height change the
//view's frame.
//yourBarView.frame = CGRectMake(0,0,20,100);
);
}
completion:^(BOOL finished){//This block is called when the animation completes.
NSLog(#"Done!");
}];
I have a view in which I want to draw a text with Text Core (on the iPad). When text grown up I'd like to increase a height of the view, but I don't know how to calculate needed height of frame.
I use it to draw a text in drawRect method:
CGContextSetTextMatrix(context, CGAffineTransformIdentity);
CGContextTranslateCTM(context, 0, self.bounds.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)currentTexts);
CGMutablePathRef textPath = CGPathCreateMutable();
CGRect textRect = CGRectMake(PADDING, PADDING, self.frame.size.width - 2 * PADDING, self.frame.size.height - 2 * PADDING);
CGPathAddRect(textPath, NULL, textRect);
CTFrameRef textFrame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), textPath, NULL);
CTFrameDraw(textFrame, context);
CFRelease(textFrame);
CGPathRelease(textPath);
CFRelease(framesetter);
I tried to get a height of text using sizeWithFont and also that:
- (CGSize) measureFrame: (CTFrameRef) frame
{
CGPathRef framePath = CTFrameGetPath(frame);
CGRect frameRect = CGPathGetBoundingBox(framePath);
CFArrayRef lines = CTFrameGetLines(frame);
CFIndex numLines = CFArrayGetCount(lines);
CGFloat maxWidth = 0;
CGFloat textHeight = 0;
// Now run through each line determining the maximum width of all the lines.
// We special case the last line of text. While we've got it's descent handy,
// we'll use it to calculate the typographic height of the text as well.
CFIndex lastLineIndex = numLines - 1;
for(CFIndex index = 0; index < numLines; index++)
{
CGFloat ascent, descent, leading, width;
CTLineRef line = (CTLineRef) CFArrayGetValueAtIndex(lines, index);
width = CTLineGetTypographicBounds(line, &ascent, &descent, &leading);
if(width > maxWidth)
{
maxWidth = width;
}
if(index == lastLineIndex)
{
// Get the origin of the last line. We add the descent to this
// (below) to get the bottom edge of the last line of text.
CGPoint lastLineOrigin;
CTFrameGetLineOrigins(frame, CFRangeMake(lastLineIndex, 1), &lastLineOrigin);
// The height needed to draw the text is from the bottom of the last line
// to the top of the frame.
textHeight = CGRectGetMaxY(frameRect) - lastLineOrigin.y + descent;
}
}
// For some text the exact typographic bounds is a fraction of a point too
// small to fit the text when it is put into a context. We go ahead and round
// the returned drawing area up to the nearest point. This takes care of the
// discrepencies.
return CGSizeMake(ceil(maxWidth), ceil(textHeight));
}
I use that to create an attrubuted string:
CTParagraphStyleSetting setting[1] = {
{kCTParagraphStyleSpecifierMinimumLineSpacing, sizeof(CGFloat), &minimumLineSpacing}
};
CTParagraphStyleRef paragraphStyle = CTParagraphStyleCreate(setting, 1);
NSDictionary *attr = [NSDictionary dictionaryWithObjectsAndKeys:
(id)textColor.CGColor, kCTForegroundColorAttributeName,
(id)currentFont, kCTFontAttributeName,
(id)paragraphStyle, kCTParagraphStyleAttributeName,
nil];
When I use sizeWithFont, at the begin everything is ok, but when text has more lines, the frame is bigger and bigger than a text and I want it to fit exactly the text. How can I make it?
To calculate the height of the text, have you tried using CTFramesetterSuggestFrameSizeWithConstraints ?
http://foobarpig.com/iphone/using-ctframesettersuggestframesizewithconstraints-and-sizewithfont-to-calculate-text-height.html
I'm using this code to resize an image on the iPhone:
CGRect screenRect = CGRectMake(0, 0, 320.0, 480.0);
UIGraphicsBeginImageContext(screenRect.size);
[value drawInRect:screenRect blendMode:kCGBlendModePlusDarker alpha:1];
UIImage *tmpValue = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
Which is working great, as long as the aspect ratio of the image matches that of the new resized image. I'd like to modify this so that it keeps the correct aspect ratio and just puts a black background anywhere the image doesn't show up. So I would still end up with a 320x480 image but with black on the top and bottom or sides, depending on the original image size.
Is there an easy way to do this similar to what I'm doing? Thanks!
After you set your screen rect, do something like the following to decide what rect to draw the image in:
float hfactor = value.bounds.size.width / screenRect.size.width;
float vfactor = value.bounds.size.height / screenRect.size.height;
float factor = fmax(hfactor, vfactor);
// Divide the size by the greater of the vertical or horizontal shrinkage factor
float newWidth = value.bounds.size.width / factor;
float newHeight = value.bounds.size.height / factor;
// Then figure out if you need to offset it to center vertically or horizontally
float leftOffset = (screenRect.size.width - newWidth) / 2;
float topOffset = (screenRect.size.height - newHeight) / 2;
CGRect newRect = CGRectMake(leftOffset, topOffset, newWidth, newHeight);
If you don't want to enlarge images smaller than the screenRect, make sure factor is greater than or equal to one (e.g. factor = fmax(factor, 1)).
To get the black background, you would probably just want to set the context color to black and call fillRect before drawing the image.
I know this is very old, but thanks for that post -- it redirected me from attempting to use scale to drawing the image. In case it is of benefit to anyone, I made an extension class I'll throw in here. It allows you to resize an image like this:
UIImage imgNew = img.Fit(40.0f, 40.0f);
I don't need a fit option, but it could easily be extended to support Fill as well.
using CoreGraphics;
using System;
using UIKit;
namespace SomeApp.iOS.Extensions
{
public static class UIImageExtensions
{
public static CGSize Fit(this CGSize sizeImage,
CGSize sizeTarget)
{
CGSize ret;
float fw;
float fh;
float f;
fw = (float) (sizeTarget.Width / sizeImage.Width);
fh = (float) (sizeTarget.Height / sizeImage.Height);
f = Math.Min(fw, fh);
ret = new CGSize
{
Width = sizeImage.Width * f,
Height = sizeImage.Height * f
};
return ret;
}
public static UIImage Fit(this UIImage image,
float width,
float height,
bool opaque = false,
float scale = 1.0f)
{
UIImage ret;
ret = image.Fit(new CGSize(width, height),
opaque,
scale);
return ret;
}
public static UIImage Fit(this UIImage image,
CGSize sizeTarget,
bool opaque = false,
float scale = 1.0f)
{
CGSize sizeNewImage;
CGSize size;
UIImage ret;
size = image.Size;
sizeNewImage = size.Fit(sizeTarget);
UIGraphics.BeginImageContextWithOptions(sizeNewImage,
opaque,
1.0f);
using (CGContext context = UIGraphics.GetCurrentContext())
{
context.ScaleCTM(1, -1);
context.TranslateCTM(0, -sizeNewImage.Height);
context.DrawImage(new CGRect(CGPoint.Empty, sizeNewImage),
image.CGImage);
ret = UIGraphics.GetImageFromCurrentImageContext();
}
UIGraphics.EndImageContext();
return ret;
}
}
}
As per the post above, it starts a new context for an image, then for that image it figures out aspect and then paints into the image. If you haven't done any Swift xcode dev time, UIGraphics is a bit backwards to most systems I work with but not bad. One issue is that bitmaps by default paint bottom to top. To get around that,
context.ScaleCTM(1, -1);
context.TranslateCTM(0, -sizeNewImage.Height);
Changes the orientation of drawing to the more common top-left to bottom-right... but then you need to move the origin as well hence the TranslateCTM.
Hopefully, it saves someone some time.
Cheers