iOS - Issue adding my CATextLayer frame to a UIScrollView - ios

I am trying to add my CATextLayer frame to a UIScrollView in order to get some scrolling. I have been trying to use the technique mentioned here (How can i make my CATextLayer object Scrollable like UITextView?) with no success.
Actually due to the (suggested) 3 lines I've added to my code my CATextLayer does not display anymore.
I have attached my code below and noted these 3 lines. Perhaps someone can help me troubleshoot this or even propose a better way to approach this :-)
// Create the scrool view (FIRST LINE ADDED)
UIScrollView* scrollLayer = [[UIScrollView alloc] initWithFrame:CGRectMake(0.0, 0.0, 500.0, 500.0)];
// Create the new layer object
boxLayer = [[CATextLayer alloc] init];
// Give it a size
[boxLayer setBounds:CGRectMake(0.0, 0.0, 500.0, 500.0)];
// Give it a location
[boxLayer setPosition:CGPointMake(300.0, 350.0)];
// Make half-transparent red the background color for the layer
UIColor *reddish = [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.1];
// Get CGColor object with the same color values
CGColorRef cgReddish = [reddish CGColor];
[boxLayer setBackgroundColor:cgReddish];
// Make it a sublayer on the view's layer
[self.view.layer addSublayer:boxLayer];
// Create string
NSString *text2 = #"The article was about employment.\nHe leafed through it in an instant.\nHis feeling of anxiety resurfaced and he closed the magazine.\n\n-Hm…, he breathed.\n\n-Have you been looking for work long?, asked the stranger at his side.\nThe article was about employment.\nHe leafed through it in an instant.\nHis feeling of anxiety resurfaced and he closed the magazine.\n\n-Hm…, he breathed.\n\n-Have you been looking for work long?, asked the stranger at his side.\nThe article was about employment.\nHe leafed through it in an instant.\nHis feeling of anxiety resurfaced and he closed the magazine.\n\n-Hm…, he breathed.\n\n-Have you been looking for work long?, asked the stranger at his side.";
// Set font type
[boxLayer setFont:#"MarkerFelt-Thin"];
// Set font size
[boxLayer setFontSize:20.0];
// Text is left justified
[boxLayer setAlignmentMode:kCAAlignmentLeft];
// Text is wrapped
boxLayer.wrapped = YES;
// Assign string to layer
[boxLayer setString:text2];
// Define the text size (SECOND LINE ADDED)
scrollLayer.contentSize = CGSizeMake(500, 1000);
// Set the text layer as a sub layer of the scroll view (THIRD LINE ADDED)
[scrollLayer.layer addSublayer:boxLayer];

Pursuant to our discussion on another discussion, I wonder if you should even be adding CATextLayer objects at all. You can add UILabel objects, for example. For example, let's add a series of UILabel objects to our scroll view:
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
if (!self.addedLabels)
{
[self addLabelsToScrollView:self.scrollView];
self.addedLabels = YES;
}
}
- (void)addLabelsToScrollView:(UIScrollView *)scrollView
{
NSArray *gettysburgAddress = #[
#"Four score and seven years ago our fathers brought forth on this continent a new nation, conceived in liberty, and dedicated to the proposition that all men are created equal.",
#"Now we are engaged in a great civil war, testing whether that nation, or any nation, so conceived and so dedicated, can long endure. We are met on a great battle-field of that war. We have come to dedicate a portion of that field, as a final resting place for those who here gave their lives that that nation might live. It is altogether fitting and proper that we should do this.",
#"But, in a larger sense, we can not dedicate, we can not consecrate, we can not hallow this ground. The brave men, living and dead, who struggled here, have consecrated it, far above our poor power to add or detract. The world will little note, nor long remember what we say here, but it can never forget what they did here. It is for us the living, rather, to be dedicated here to the unfinished work which they who fought here have thus far so nobly advanced. It is rather for us to be here dedicated to the great task remaining before us—that from these honored dead we take increased devotion to that cause for which they gave the last full measure of devotion—that we here highly resolve that these dead shall not have died in vain—that this nation, under God, shall have a new birth of freedom—and that government of the people, by the people, for the people, shall not perish from the earth."
];
CGFloat y = 0.0;
UIFont *font = [UIFont fontWithName:#"MarkerFelt-Thin" size:20.0];
CGSize maxSize = CGSizeMake(scrollView.frame.size.width, 10000.0);
for (NSString *line in gettysburgAddress)
{
CGSize labelSize = [line sizeWithFont:font constrainedToSize:maxSize lineBreakMode:NSLineBreakByWordWrapping];
CGRect labelFrame = CGRectMake(0.0, y, labelSize.width, labelSize.height);
UILabel *label = [[UILabel alloc] initWithFrame:labelFrame];
label.font = font;
label.text = line;
label.numberOfLines = 0;
[scrollView addSubview:label];
y += labelSize.height + 16.0;
}
scrollView.contentSize = CGSizeMake(scrollView.contentSize.width, y);
}
Or even easier, rather than adding UILabel objects to a UIScrollView, you could just use a UITextView:
- (void)updateTextView
{
NSArray *gettysburgAddress = #[
#"Four score and seven years ago our fathers brought forth on this continent a new nation, conceived in liberty, and dedicated to the proposition that all men are created equal.",
#"Now we are engaged in a great civil war, testing whether that nation, or any nation, so conceived and so dedicated, can long endure. We are met on a great battle-field of that war. We have come to dedicate a portion of that field, as a final resting place for those who here gave their lives that that nation might live. It is altogether fitting and proper that we should do this.",
#"But, in a larger sense, we can not dedicate, we can not consecrate, we can not hallow this ground. The brave men, living and dead, who struggled here, have consecrated it, far above our poor power to add or detract. The world will little note, nor long remember what we say here, but it can never forget what they did here. It is for us the living, rather, to be dedicated here to the unfinished work which they who fought here have thus far so nobly advanced. It is rather for us to be here dedicated to the great task remaining before us—that from these honored dead we take increased devotion to that cause for which they gave the last full measure of devotion—that we here highly resolve that these dead shall not have died in vain—that this nation, under God, shall have a new birth of freedom—and that government of the people, by the people, for the people, shall not perish from the earth."
];
NSString *text = [gettysburgAddress componentsJoinedByString:#"\n\n"];
self.textView.text = text;
self.textView.font = [UIFont fontWithName:#"MarkerFelt-Thin" size:20.0];
self.textView.editable = NO;
}
It all comes down to whether you really need to use a CATextLayer.

Related

Updating UILabel text too often

I need to show a tilt of the device in my app. The algorithm is pretty simple, I'm using CMMotionManager's attitude for calculating tilt, and I'm updating a label which shows degrees like so:
- (void)tiltUpdated:(float)tilt
{
_degreesLabel.text = [NSString stringWithFormat:#"%.1f°", tilt];
}
My problem is next - CMMotionManager calls gyroscope updates approximately 10 times per second. And every time I'm calculating new tilt and calling tiltUpdated method each time. And when I do that, my app starts to incredibly lag. Few things I need to clarify:
Cause of lags is in updating the label. I defined it pretty easily
by commenting on it. So it's not the tilt calculations (that is why I
didn't provide a code for that here)
Applications also show camera output all the time. I turned off
camera and things got a little better but still, the application is lagging.
Is there any way to optimize updating UILabel text? Thanks in advance!
Ok, ending up answering my own question, but I hope that'll come in handy for somebody :).
I didn't find any valuable and detailed information about UILabel performance (which is too bad because I'm interested to learn something about that), but I found an alternative, which is CATextLayer.
I'm creating CATextLayer:
_textLayer = [CATextLayer new];
_textLayer.frame = CGRectMake(0.0f, _degreesLabelView.frame.size.height*0.5f - textHeight*0.5f, _degreesLabelView.frame.size.width, textHeight);
_textLayer.backgroundColor = [UIColor clearColor].CGColor;
_textLayer.foregroundColor = [UIColor whiteColor].CGColor;
_textLayer.alignmentMode = kCAAlignmentCenter;
_textLayer.contentsScale = UIScreen.mainScreen.scale;
_textLayer.fontSize = 17.0;
_textLayer.string = #"0°";
[_degreesLabelView.layer addSublayer:_textLayer];
And here I'm updating text:
- (void)tiltUpdated:(float)tilt
{
_textLayer.string = [NSString stringWithFormat:#"%.1f°", tilt];
}
Also CATextLayer is kind of "animating" text changes with slight "fadeIn/fadeOut" and I like it :)

Set CALayer as SCNMaterial's diffuse contents

I've been searching all over the internet over the past couple of days to no avail. Unfortunately, the apple documentation about this specific issue is vague and no sample code is available (at least thats what I found out). What seems to be the issue you may ask...
I'm trying to set a uiview's layer as the contents of the material that is used to render an iPhone model's screen (Yep, trippy :P ). The iPhone's screen's UV mapping is set from 0 to 1 so that no issue persists in mapping the texture/layer onto the texels.
So, instead of getting this layer to appear rendered on the iPhone, same as left image, Instead, I get this rendered onto the iPhone like right image
Correct Render                                        Incorrect Render
Also note, that when I set a breakpoint and debug the actual iPhone node and view it in Xcode, a completely different render is shown and the layer gets half-fixed when I continue execution:
Now then... HOW do I fix this issue??? I've tried playing with the diffuse's contents transform matrix but nothing gets fixed. I've also tried resizing the UIView to 256x256 (since the UV seems to be 256x256 as shown in blender - the 3d modelling package), but that doesn't fix anything.
Here is the code for the layer:
UIView *screen = [[UIView alloc] initWithFrame:self.view.bounds];
screen.backgroundColor = [UIColor redColor];
UIView *temp = [[UIView alloc] initWithFrame:CGRectMake(0, 0, screen.bounds.size.width, 60)];
temp.backgroundColor = [UIColor colorWithRed:0 green:(112.f/255.f) blue:(235.f/255.f) alpha:1];
UILabel *label = [[UILabel alloc] initWithFrame:CGRectInset(temp.bounds, 40, 0)];
label.frame = CGRectOffset(label.frame, 40, 0);
label.textColor = [UIColor colorWithRed:0 green:(48.f/255.f) blue:(84.f/255.f) alpha:1];
label.text = #"Select Track";
label.font = [UIFont fontWithName:#"HelveticaNeue-Light" size:30];
label.minimumScaleFactor = 0.001;
label.adjustsFontSizeToFitWidth = YES;
label.lineBreakMode = NSLineBreakByClipping;
[temp addSubview:label];
UIView *separator = [[UIView alloc] initWithFrame:CGRectMake(0, temp.bounds.size.height - 2, temp.bounds.size.width, 2)];
separator.backgroundColor = [UIColor colorWithRed:0 green:(48.f/255.f) blue:(84.f/255.f) alpha:1];
[temp addSubview:separator];
[screen addSubview:temp];
screen.layer.contentsGravity = kCAGravityCenter;
Edit
What's even weirder is that if I capture a UIImage of the view using:
- (UIImage *) imageWithView:(UIView *)view
{
UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.opaque, 0.0);
[view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage * img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return img;
}
and use that as the diffuse's content... everything works out perfectly fine?! It's really weird and frustrating since the image's size is exactly the same as the uiview's...
Edit 2
I ended up just using an image of the view as the texture, which makes things much more static than I needed. I won't set this as the answer because I'll still be waiting for a correct fix to this issue even if it in a long time. So, if you have an answer and this topic has been opened for a long time, please bump it if you can. The documentation on this section is just so poor.
New post on an old thread, but this day-in-age, it's possible to set the UIView itself as SCNMaterialProperty (diffuse) contents. Intention to support this feature is communicated directly from SceneKit engineering at Apple, though the documentation has not yet been updated to reflect it.
To tied back to the original post, do not set a UIView.layer as material property contents; instead set contents to the UIView itself.
[Update: according to Lance's comment below, support for views may be getting worse rather than getting better.]
The SceneKit docs pretty strongly suggest that, while there are cases where you can use animated CALayers as material content, that doesn't include UIView layers:
SceneKit cannot use a layer that is already being displayed elsewhere (for example, the backing layer of a UIView object).
That suggests that if you want to make animated content for your material, you're better off with either Core Animation used entirely on its own or SpriteKit.

How to make sharp look of views in Scroll view on zooming

I am working on application where I have a bunch of views (UILabel, UITextField, UIButton and etc). I enabled zooming and every thing working fine, but only one thing which is not good when user zoom in and want to look any view its gets pixelated and looking quite blurry. One thing which may be the reason I am using quite low font size as you may in below code, and I am not able to use high font because I am bound to use many views because to add many view in iphone litter size.
UITextField *textField = [[UITextField alloc]init];
rect.origin.x = rect.origin.x + 3;
textField.frame = rect;
textField.backgroundColor = [UIColor whiteColor];
[textField setFont:[UIFont systemFontOfSize:5.0]];
textField.tag = fieldsYValue;
textField.adjustsFontSizeToFitWidth = NO; // this is default value
[scrollView addSubview:textField];
Looking for any help who worked on this kind of projects.
Maybe this could help.
This lets the user zoom in by a factor of 3 -- but when they do so, they're really just zooming up to full resolution, at which 1 pixel in the UIScrollView's content buffer is 1 pixel on screen. (And of course, within our content view, we draw everything three times bigger to compensate.) No need to implement any of the delegate methods except the standard viewForZoomingInScrollView; no redrawing at different scales depending on the zoom.
scrollView.contentSize = myContentView.bounds.size;
scrollView.maximumZoomScale = 1.0;
scrollView.minimumZoomScale = 0.33;
scrollView.zoomScale = 0.33;

Switch from animating frames to animating constraints

I had what seemed a perfectly good animation scheme (animating frame attributes using UIView animateWithDuration) until an upgrade to Xcode 6 or iOS 8 (or both) changed everything. I suspect that part of the problem is that I paid scant attention to AutoLayout because the app only supports portrait view.
A picture is worth a thousand words, and a video is worth a million, so a screen capture example of this change in animation can be seen in the following youtube uploads:
The first example (iOS 7) graphically shows what I'm trying to achieve, and the second shows what happened after I switched to Xcode 6 / iOS 8. Please view if you want to respond:
Here's my current (simplified) code, which is inside a fast enumeration loop iterating over the fetchedResults of a FRC:
[UIView animateWithDuration:.8
delay:0.0
options: UIViewAnimationOptionCurveEaseInOut
animations:^
{
// Starting state *************************************
thisBar.frame = CGRectMake(20, self.scroller.contentSize.height, 130, 0);
thisBar.backgroundColor = [UIColor blackColor];
thisInfoLabel.frame = CGRectMake(20, self.scroller.contentSize.height, thisBar.frame.size.width, 30);
thisTimeLabel.frame = CGRectMake((thisBar.frame.origin.x) + (thisBar.frame.size.width + 35), self.scroller.contentSize.height, 150, 15);
thisTimeLabel.textColor = [UIColor blueColor];
arrowView.frame = CGRectMake(thisTimeLabel.frame.origin.x - 20, thisTimeLabel.frame.origin.y, 16, 16);
thisInfoLabel.textColor = [UIColor clearColor];
// End state *************************************
thisBar.frame = CGRectMake(20, barY, 130, - barHeight);
thisBar.backgroundColor = thisBar.endColor;
thisBar.layer.shadowColor = [[UIColor blackColor] CGColor];
thisBar.layer.frame = CGRectInset(thisBar.layer.frame, 0.0, 3.0);
thisBar.layer.shadowOpacity = 0.7;
thisBar.layer.shadowRadius = 4.0;
thisBar.layer.shadowOffset = CGSizeMake(5.0f, 5.0f);
...
}
I've read various possible reasons for this change, but the detail appears to be moot, and apparently the only proper way to fix the problem is to switch from animating the frame attributes of my views and start animating constraints instead.
OK, I accept it. However, as I've looked at quite a few SO posts on the subject for guidance, most seem to be geared toward IB-generated views. My views are code generated, of any number, and of any height, both of which are determined on the fly in code. For added drama, these views are inside a UIScrollView.
At this point, it seems my strategy should be (per view):
1) Create the view
2) Set up constraints for each view
3) Animate the constraints for each view, sequentially
Anybody have any suggestions or pointers to helpful tutorials? A simple example relating several code-generated views to each other, particularly inside a UIScrollView would be a godsend.
Many thanks!

Label with fixed x & y inside tableView.cell

I'm trying to make a label for comment for each cell in tableView .. the problem is the label everytime change the "y" position if I change the text string.
I use CGSize to calculate the text string size for width & height .. so if the comment is too long the y will be more bottom .. if the comment is too short also the y changed.
How could I fix x & y for every size of text string. here is my code:
static CGFloat messageTextSize = 14.0;
+(CGFloat)maxTextWidth {
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
return 220.0f;
} else {
return 400.0f;
}
}
+(CGSize)messageSize:(NSString*)message {
return [message sizeWithFont:[UIFont systemFontOfSize:messageTextSize] constrainedToSize:CGSizeMake([FirstViewController maxTextWidth], CGFLOAT_MAX) lineBreakMode:NSLineBreakByWordWrapping];
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *text = #"After a power struggle with the board of directors in 1985, Jobs left Apple and founded NeXT, a computer platform development company specializing in the higher-education and business markets. In 1986, he acquired the computer graphics division of Lucasfilm, which was spun off as Pixar.[13] He was credited in Toy Story (1995) as an executive producer. He served as CEO and majority shareholder until Disney's purchase of Pixar in 2006.[14] In 1996, after Apple had failed to deliver its operating system, Copland, Gil Amelio turned to NeXT Computer, and the NeXTSTEP platform became the foundation for the Mac OS X.[15] Jobs returned to Apple as an advisor, and took control of the company as an interim CEO. Jobs brought Apple from near bankruptcy to profitability by 1998";
CGSize textSize = [FirstViewController messageSize:text];
// NSLog(#"%f",textSize.width);
return 460 + (textSize.height - 100);
}
And this the label:
NSString *comment = #"After a power struggle with the board of directors in 1985, Jobs left Apple and founded NeXT, a computer platform development company specializing in the higher-education and business markets. In 1986, he acquired the computer graphics division of Lucasfilm, which was spun off as Pixar.[13] He was credited in Toy Story (1995) as an executive producer. He served as CEO and majority shareholder until Disney's purchase of Pixar in 2006.[14] In 1996, after Apple had failed to deliver its operating system, Copland, Gil Amelio turned to NeXT Computer, and the NeXTSTEP platform became the foundation for the Mac OS X.[15] Jobs returned to Apple as an advisor, and took control of the company as an interim CEO. Jobs brought Apple from near bankruptcy to profitability by 1998";
CGSize textSize = [FirstViewController messageSize:comment];
UILabel *label6 = [[UILabel alloc] initWithFrame:CGRectMake(20, 330, cell.frame.size.width - 30, textSize.height)];
label6.textColor = [UIColor colorWithRed:61.0/255.0 green:113.0/255.0 blue:154.0/255.0 alpha:1.0];
label6.backgroundColor = [UIColor clearColor];
label6.font = [UIFont fontWithName:#"Helvetica-Bold" size:11];
label6.numberOfLines = 0;
label6.lineBreakMode = UILineBreakModeCharacterWrap;
label6.text = [NSString stringWithFormat:#"%#: %#",username,comment];
[cell addSubview:label6];
Here you can see screenshot to get the point.. I want to fix the comment under likes label or lets say the starting position is customized
http://d.pr/i/RBid
Try using a UITextView and not UILabel, as labels are thought to be one-liners.
Make sure you use the same string, font, font-size and wrapping in the size calculation and your TextView.

Resources