UILabel auto scroll like a marquee - ios

I am trying I make a UI label auto scroll the text that is inside it like a marquee. The below code works depending on what kind of text/content I throw at it. I can't tell what works and what does not. What happens is that the label does not show anything, then suddenly scrolls the text at an extremely high speed that you can't read it.
For some reason, this works perfectly on the iPhone but not on the iPad. I am guessing because the text I am putting at the iPhone is always way bigger than the Uilabel's size?
Here is the code:
self.currentTrack.textColor = [UIColor colorWithRed:15.0/255.0 green:176.0/255.0 blue:223.0/255.0 alpha:1];
self.currentTrack.labelSpacing = 35; // distance between start and end labels
self.currentTrack.pauseInterval = 1.7; // seconds of pause before scrolling starts again
self.currentTrack.scrollSpeed = 30; // pixels per second
self.currentTrack.textAlignment = NSTextAlignmentCenter; // centers text when no auto-scrolling is applied
self.currentTrack.fadeLength = 12.f;
self.currentTrack.scrollDirection = CBAutoScrollDirectionLeft;
[self.currentTrack observeApplicationNotifications];
}

Here is the code:
AutoScrollLabel, extended from UIView (code provided below) has an instance method to set text (setLabelText). The text provided will auto scroll only if the length of the text is bigger than the width of the AutoScrollLabel view.
Eg:
AutoScrollLabel *autoScrollLabel = [[AutoScrollLabel alloc] initWithFrame:CGRectMake(0, 0, 150, 25)];
[autoScrollLabel setLabelText:#"Some lengthy text to be scrolled"];
Note: You can make changes in setLabelText: Method implementation to support Attributed Text (use appropriate methods to find size of Attributed Text)
*** AutoScrollLabel.h
#interface AutoScrollLabel : UIView {
UILabel *textLabel;
NSTimer *timer;
}
- (void) setLabelText:(NSString*) text;
- (void) setLabelFont:(UIFont*)font;
- (void) setLabelTextColor:(UIColor*)color;
- (void) setLabelTextAlignment:(UITextAlignment)alignment;
#end
**** AutoScrollLabel.m
#import "AutoScrollLabel.h"
#import <QuartzCore/QuartzCore.h>
#implementation AutoScrollLabel
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
self.clipsToBounds = YES;
self.autoresizesSubviews = YES;
textLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, frame.size.width, frame.size.height)];
textLabel.backgroundColor = [UIColor clearColor];
textLabel.textColor = [UIColor blackColor];
textLabel.textAlignment = UITextAlignmentRight;
[self addSubview:textLabel];
}
return self;
}
-(void) setLabelText:(NSString*) text {
textLabel.text = text;
CGSize textSize = [text sizeWithFont:textLabel.font];
if(textSize.width > self.frame.size.width) {
textLabel.frame = CGRectMake(0, 0, textSize.width, self.frame.size.height);
}
else {
textLabel.frame = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height);
}
if(textLabel.frame.size.width > self.frame.size.width) {
[timer invalidate];
timer = nil;
CGRect frame = textLabel.frame;
frame.origin.x = self.frame.size.width-50;
textLabel.frame = frame;
timer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:#selector(moveText) userInfo:nil repeats:YES];
}
else {
[timer invalidate];
timer = nil;
}
}
-(void) moveText {
if(textLabel.frame.origin.x < textLabel.frame.size.width-2*textLabel.frame.size.width) {
CGRect frame = textLabel.frame;
frame.origin.x = self.frame.size.width;
textLabel.frame = frame;
}
[UIView beginAnimations:nil context:nil];
CGRect frame = textLabel.frame;
frame.origin.x -= 5;
textLabel.frame = frame;
[UIView commitAnimations];
}
- (void) setLabelFont:(UIFont*)font {
textLabel.font = font;
}
- (void) setLabelTextColor:(UIColor*)color {
textLabel.textColor = color;
}
- (void) setLabelTextAlignment:(UITextAlignment)alignment {
textLabel.textAlignment = alignment;
}

For Swift5
set top of your UILabel equal to superview bottom, and then use this code:
func createAnimationLbl() -> CAAnimation {
let animation = CABasicAnimation(keyPath: "transform.translation.y")
animation.fromValue = 0
animation.toValue = -(self.view.frame.height )
animation.duration = 15
animation.repeatCount = Float.infinity //times of scrolling, infinity for unlimited times.
animation.timingFunction = CAMediaTimingFunction.init(name: CAMediaTimingFunctionName.linear)
animation.fillMode = CAMediaTimingFillMode.forwards
animation.isRemovedOnCompletion = false
return animation
}
then in your viewWillAppear call it as below:
self.aboutLbl.layer.add(createAnimationLbl(), forKey: nil)

Related

How do I add both shadow and rounded corners to a UIVisualEffectView?

I'm using a container for elements which I'd like for it to be blurred. In order to add rounded corners I modified the layer while for the shadow I created a second view named containerShadow and placed it below it.
It works, but not flawlessly. The shadow darkens the effect of the blur. Is there a way to perfect it?
.h
#property (strong) UIVisualEffectView *containerView;
#property (strong) UIView *containerShadowView;
.m
- (instancetype)init {
if (self = [super init]) {
self.containerShadowView = [[UIView alloc] init];
self.containerShadowView.layer.masksToBounds = NO;
self.containerShadowView.layer.shadowRadius = 80.0;
self.containerShadowView.layer.shadowColor = [[UIColor blackColor] CGColor];
self.containerShadowView.layer.shadowOffset = CGSizeZero;
self.containerShadowView.layer.shadowOpacity = 0.25;
[self addSubview:self.containerShadowView];
self.containerView = [[UIVisualEffectView alloc] initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleExtraLight]];
self.containerView.clipsToBounds = YES;
self.containerView.layer.cornerRadius = 20.0;
[self addSubview:self.containerView];
}
return self;
}
- (void)setFrame:(CGRect)frame {
[super setFrame:frame];
// Random container frame for testing...
self.containerView.frame =
CGRectMake(20.0,
200.0,
380,
480);
self.containerShadowView.frame = self.containerView.frame;
self.containerShadowView.layer.shadowPath =
[[UIBezierPath bezierPathWithRoundedRect:self.containerShadowView.bounds cornerRadius:self.containerView.layer.cornerRadius] CGPath];
}
You can do this by masking your containerShadowView with a "cutout" that matches the containerView effect view.
So, this is how it looks - I centered the 380x480 view, and used 0.9 for the .shadowOpacity to emphasize the differences.
Your original on the left, masked version on the right:
Kinda difficult to tell what's really going on, since that could be an opaque layer, we'll add a label behind it:
and, to clarify what we're doing, let's look at it with the containerView effect view hidden:
Here's the source code I used for that - each tap anywhere will cycle through the 8 different layouts:
#import <UIKit/UIKit.h>
#interface OrigShadowView : UIView
#property (strong) UIVisualEffectView *containerView;
#property (strong) UIView *containerShadowView;
#end
#implementation OrigShadowView
- (instancetype)init {
if (self = [super init]) {
self.containerShadowView = [[UIView alloc] init];
self.containerShadowView.layer.masksToBounds = NO;
self.containerShadowView.layer.shadowRadius = 80.0;
self.containerShadowView.layer.shadowColor = [[UIColor blackColor] CGColor];
self.containerShadowView.layer.shadowOffset = CGSizeZero;
self.containerShadowView.layer.shadowOpacity = 0.9;
[self addSubview:self.containerShadowView];
self.containerView = [[UIVisualEffectView alloc] initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleExtraLight]];
self.containerView.clipsToBounds = YES;
self.containerView.layer.cornerRadius = 20.0;
[self addSubview:self.containerView];
}
return self;
}
- (void)setFrame:(CGRect)frame {
[super setFrame:frame];
// let's center a 380 x 480 rectangle in self
CGFloat w = 380.0;
CGFloat h = 480.0;
CGRect vRect = CGRectMake((frame.size.width - w) * 0.5, (frame.size.height - h) * 0.5, w, h);
self.containerView.frame = vRect;
self.containerShadowView.frame = self.containerView.frame;
// change origin to 0,0 because the following will be relative to the subviews
vRect.origin = CGPointZero;
self.containerShadowView.layer.shadowPath =
[[UIBezierPath bezierPathWithRoundedRect:vRect cornerRadius:self.containerView.layer.cornerRadius] CGPath];
}
#end
#interface MaskShadowView : UIView
#property (strong) UIVisualEffectView *containerView;
#property (strong) UIView *containerShadowView;
#end
#implementation MaskShadowView
- (instancetype)init {
if (self = [super init]) {
self.containerShadowView = [[UIView alloc] init];
self.containerShadowView.layer.masksToBounds = NO;
self.containerShadowView.layer.shadowRadius = 80.0;
self.containerShadowView.layer.shadowColor = [[UIColor blackColor] CGColor];
self.containerShadowView.layer.shadowOffset = CGSizeZero;
self.containerShadowView.layer.shadowOpacity = 0.9;
[self addSubview:self.containerShadowView];
self.containerView = [[UIVisualEffectView alloc] initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleExtraLight]];
self.containerView.clipsToBounds = YES;
self.containerView.layer.cornerRadius = 20.0;
[self addSubview:self.containerView];
}
return self;
}
- (void)setFrame:(CGRect)frame {
[super setFrame:frame];
// let's center a 380 x 480 rectangle in self
CGFloat w = 380.0;
CGFloat h = 480.0;
CGRect vRect = CGRectMake((frame.size.width - w) * 0.5, (frame.size.height - h) * 0.5, w, h);
self.containerView.frame = vRect;
self.containerShadowView.frame = self.containerView.frame;
// change origin to 0,0 because the following will be relative to the subviews
vRect.origin = CGPointZero;
self.containerShadowView.layer.shadowPath =
[[UIBezierPath bezierPathWithRoundedRect:vRect cornerRadius:self.containerView.layer.cornerRadius] CGPath];
UIBezierPath *bigBez;
UIBezierPath *clipBez;
// we need a rectangle that will encompass the shadow radius
// double the shadowRadius is probably sufficient, but since it won't be seen
// and won't affect anything else, we'll make it 4x
CGRect expandedRect = CGRectInset(vRect, -self.containerShadowView.layer.shadowRadius * 4.0, -self.containerShadowView.layer.shadowRadius * 4.0);
bigBez = [UIBezierPath bezierPathWithRect:expandedRect];
// we want to "clip out" a rounded rect in the center
// which will be the same size as the visual effect view
clipBez = [UIBezierPath bezierPathWithRoundedRect:vRect cornerRadius:self.containerView.layer.cornerRadius];
[bigBez appendPath:clipBez];
bigBez.usesEvenOddFillRule = YES;
CAShapeLayer *maskLayer = [CAShapeLayer new];
maskLayer.fillRule = kCAFillRuleEvenOdd;
maskLayer.fillColor = UIColor.whiteColor.CGColor;
maskLayer.path = bigBez.CGPath;
self.containerShadowView.layer.mask = maskLayer;
}
#end
#interface BlurTestViewController : UIViewController
{
OrigShadowView *origView;
MaskShadowView *newView;
UILabel *bkgLabel;
// so we can step through on taps to see the results
NSInteger step;
UILabel *infoLabel;
}
#end
#implementation BlurTestViewController
- (void)viewDidLoad {
[super viewDidLoad];
bkgLabel = [UILabel new];
bkgLabel.textColor = UIColor.blueColor;
bkgLabel.font = [UIFont systemFontOfSize:48.0 weight:UIFontWeightBlack];
bkgLabel.textAlignment = NSTextAlignmentCenter;
bkgLabel.numberOfLines = 0;
bkgLabel.text = #"A label can contain an arbitrary amount of text, but UILabel may shrink, wrap, or truncate the text, depending on the size of the bounding rectangle and properties you set. You can control the font, text color, alignment, highlighting, and shadowing of the text in the label.";
bkgLabel.text = #"I'm using a container for elements which I'd like for it to be blurred. In order to add rounded corners I modified the layer while for the shadow I created a second view named containerShadow and placed it below it.";
origView = [OrigShadowView new];
newView = [MaskShadowView new];
[self.view addSubview:bkgLabel];
[self.view addSubview:origView];
[self.view addSubview:newView];
infoLabel = [UILabel new];
infoLabel.font = [UIFont systemFontOfSize:20.0 weight:UIFontWeightBold];
infoLabel.textAlignment = NSTextAlignmentCenter;
[self.view addSubview:infoLabel];
step = 0;
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
// let's inset the "shadow blur" views 40-points
CGRect r = CGRectInset(self.view.frame, 40.0, 40.0);
origView.frame = r;
newView.frame = r;
// let's put the background label midway down the screen
r.origin.y += r.size.height * 0.5;
r.size.height *= 0.5;
bkgLabel.frame = r;
// put the info label near the top
infoLabel.frame = CGRectMake(40.0, 80.0, r.size.width, 40.0);
[self nextStep];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[self nextStep];
}
- (void)nextStep {
bkgLabel.hidden = YES;
origView.hidden = YES;
newView.hidden = YES;
origView.containerView.hidden = NO;
newView.containerView.hidden = NO;
step++;
switch (step) {
case 1:
origView.hidden = NO;
infoLabel.text = #"1: Original View";
break;
case 2:
newView.hidden = NO;
infoLabel.text = #"2: Masked View";
break;
case 3:
bkgLabel.hidden = NO;
origView.hidden = NO;
infoLabel.text = #"3: Original View";
break;
case 4:
bkgLabel.hidden = NO;
newView.hidden = NO;
infoLabel.text = #"4: Masked View";
break;
case 5:
origView.hidden = NO;
origView.containerView.hidden = YES;
infoLabel.text = #"5: Original View - effect view hidden";
break;
case 6:
newView.hidden = NO;
newView.containerView.hidden = YES;
infoLabel.text = #"6: Masked View - effect view hidden";
break;
case 7:
bkgLabel.hidden = NO;
origView.hidden = NO;
origView.containerView.hidden = YES;
infoLabel.text = #"7: Original View - effect view hidden";
break;
default:
bkgLabel.hidden = NO;
newView.hidden = NO;
newView.containerView.hidden = YES;
infoLabel.text = #"8: Masked View - effect view hidden";
step = 0;
break;
}
}
#end

updating custom uiview's frame after adding subviews to it

I am having a big mental block figuring out something I think easy. Please see this very short video: http://screencast.com/t/eaW7rbECv4Ne.
I would like to draw a rectangle in my layoutSubviews method around the whole area that covers the subviews. I currently draw yellow rect around each term as you can see in the video.
I have a StatementView. In each key tap I am creating new objectView and adding it to my StatementView like below. I add the objectViews to a containerView and try to get the origin and size of the containerView in order to draw the stroke around it. However, it always gives me 0.
How should I update containerViews bounds values after I add the subviews to it?
// Created by ilteris on 1/31/15.
// Copyright (c) 2015 ilteris. All rights reserved.
#implementation QWZStatementView
-(id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
self.userInteractionEnabled = NO;
self.textField = [[MyUITextField alloc] initWithFrame:CGRectMake(0, 0, 0, 0)];
self.textField.inputView = [LNNumberpad defaultLNNumberpad];
self.textField.delegate = self;
self.isNumerator = NO;
self.isDenominator = NO;
[self addSubview:self.textField];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(statementOneTextFieldChanged:) name:UITextFieldTextDidChangeNotification object:nil];
self.containerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 0, 0)];
[self addSubview:self.containerView];
self.autoresizesSubviews = YES;
self.objectsArray = [NSMutableArray arrayWithCapacity:1];
self.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin;
}
return self;
}
-(void)statementOneTextFieldChanged:(NSNotification *)notification {
NSLog(#"statementOneTextFieldChanged");
QWZObjectView *objectView = [[QWZObjectView alloc] initWithFrame:self.bounds];
[self.containerView addSubview:objectView];
QWZTerm* term = [QWZQuestionDetailViewController createAndReturnCoreDataTermForJSONDict:objectData];
[objectView createTerm:term];
[self.objectsArray addObject:objectView];
[self setNeedsLayout];
}
- (void)layoutSubviews {
NSLog(#"layoutSubviews StatementView");
[super layoutSubviews];
CGSize totalSize = CGSizeMake(0, 0);
for (QWZObjectView* objectView in self.objectsArray) {
CGSize textSize = objectView.bounds.size;
objectView.frame = CGRectMake(totalSize.width , totalSize.height, textSize.width , textSize.height);
totalSize.width = textSize.width + totalSize.width;
}
CGRect bounds = self.containerView.bounds;
/*
NSLog(#"self.containerView.bounds is %#", NSStringFromCGRect(self.containerView.bounds)); //always 0.
bounds.origin = CGPointMake(totalSize.width/2, self.containerView.bounds.origin.y); //adding this code didn't help at all.
CGFloat borderWidth = 2.0f;
self.bounds = CGRectInset(self.bounds, -borderWidth, -borderWidth);
self.layer.borderColor = [UIColor redColor].CGColor;
self.layer.borderWidth = borderWidth;
*/
bounds.origin = CGPointMake(totalSize.width/2, self.containerView.bounds.origin.y);
self.containerView.bounds = bounds;
}
#end

iOS UITextView putting character onto next line

In this picture with a UITextView saying "Coordinate Geometry", the "e" gets put onto the next line. There is no line space there. I have also tried this with a UILabel (I switched to UITextView to try and fix the problem but there was no difference).
Here is my code for my subclass of UITextView
- (instancetype)initWithFrame:(CGRect)frame text:(NSString *)text circular:(BOOL)isCircular {
self = [super initWithFrame:frame];
if (self) {
self.backgroundColor = [UIColor lightGrayColor];//[UIColor clearColor];
self.alpha = 0.5;
self.textColor = [Styles mainTextColour];
[self setFont:[Styles heading2Font]];
[self setTextAlignment:NSTextAlignmentCenter];
self.text = text;
self.editable = NO;
self.contentInset = UIEdgeInsetsMake(-8, 0, -8, 0);
[self resizeFontToFix];
}
return self;
}
- (instancetype)initWithFrame:(CGRect)frame {
NSAssert(NO, #"Don't use BubbleText -initWithFrame:, use -initWithFrame: andText: instead");
return nil;
}
- (void)resizeFontToFix {
//Resize to fix
CGFloat fontSize = self.font.pointSize;
CGFloat minSize = 6.0 * [Styles sizeModifier];
while (fontSize > minSize && [self sizeThatFits:(CGSizeMake(self.frame.size.width, FLT_MAX))].height >= self.frame.size.height) {
fontSize -= 1.0;
self.font = [self.font fontWithSize:fontSize];
}
//this below resizes to fit and centres the resulting view
// [self resizeFrameAndCentre];
}
- (void)resizeFrameAndCentre {
CGRect originalFrame = self.frame;
[self sizeToFit];
CGPoint centre = self.center;
centre.x = originalFrame.origin.x + (originalFrame.size.width / 2);
centre.y = originalFrame.origin.y + (originalFrame.size.height / 2);
self.center = centre;
}

IOS RoundView make child ImageView to be rounded

I've created this custom UIView named RoundView:
#import <QuartzCore/QuartzCore.h>
#implementation RoundedView
+(UIColor *)grayUIColor {
return [UIColor colorWithRed:161.0/255.0 green:157.0/255.0 blue:164.0/255.0 alpha:1.0];
}
+(UIColor *)darkBlueUIColor {
return [UIColor colorWithRed:86.0/255.0 green:88.0/255.0 blue:87.0/255.0 alpha:1];
}
+(UIColor *)greenUIColor {
return [UIColor colorWithRed:51.0/255.0 green:141.0/255.0 blue:130.0/255.0 alpha:1];
}
- (id)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self)
{
//add pico icon as default image
_defaultImage = [UIImage imageNamed:#"actionBar_pico_icon"];
_isCreated = NO;
}
return self;
}
-(UIView*)createRoundViewWithBorder:(UIColor*)borderColor andPaddingColor:(UIColor*)paddingColor{
_borderColor = borderColor;
_paddingBackgroundColor = paddingColor;
[self setViewAppearance];
[self addImageToView];
_isCreated = YES;
return self;
}
/**
Set the current view appearance
*/
-(void) setViewAppearance {
self.layer.borderWidth = 1.5;
self.layer.borderColor = [_borderColor CGColor];
self.backgroundColor = _paddingBackgroundColor;
}
-(void) addImageToView {
CGRect frame = CGRectMake(0, 0, self.frame.size.width - 5, self.frame.size.height - 5);
_imageView = [[UIImageView alloc] initWithFrame:frame];
//calculate center x
float x = (self.frame.size.width - _imageView.frame.size.width) / 2;
//calculate center y
float y = (self.frame.size.height - _imageView.frame.size.height) / 2;
//create new frame
frame = CGRectMake(x, y, _imageView.frame.size.width, _imageView.frame.size.height);
_imageView.image = _defaultImage;
_imageView.frame = frame;
_imageView.contentMode = UIViewContentModeScaleAspectFit;
[self addSubview:_imageView];
[self makeViewRounded:_imageView];
[self makeViewRounded:self];
}
-(UIView*) makeViewRounded:(UIView*)view {
//set the look of the image
view.layer.cornerRadius= self.frame.size.height /2;
view.layer.opaque = NO;
view.layer.masksToBounds = YES;
return view;
}
-(void)updateImage:(UIImage *)image {
_image = image;
_imageView.image = image;
}
-(void)reset {
[self updateImage:_defaultImage];
}
#end
an example for the output will be :
If you look closely you will notice that the border is a circle, but the image view has edges.
How can i make the Image smooth as well ?
self.imgViewbg.layer.cornerRadius = self.imgViewbg.frame.size.width / 2;
self.imgViewbg.clipsToBounds = YES;
u Can Try This Code. And Implement in your Project..
It Will Definetly Work.. for u
I think the problem seems to be here:
view.layer.cornerRadius= self.frame.size.height /2;
Try giving it a constant small number and see the change. May be the height/2 is not making a perfect circle. You can give a smaller value than height/2 and see the change. It a wild guess by watching your image.

How to always rotate half with facebook POP?

I'm new in iOS.
I want to always rotate half when user clicked a button.
Following is the code, it only rotate once and never rotate again when I clicked it.
#property UIButton *button;
- (void)viewDidLoad {
[super viewDidLoad];
CGFloat buttonSize = 220;
self.button = [UIButton buttonWithType:UIButtonTypeCustom];
self.button.backgroundColor = [UIColor colorFromHexString:#"#B084C7"];
self.button.frame = CGRectMake(0, 0, buttonSize, buttonSize);
[self.button addTarget:self
action:#selector(didTap:)
forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:self.button];
}
- (void)didTap:(id)sender {
POPSpringAnimation *anim = [self.button.layer pop_animationForKey:#"rotate"];
if (anim) {
anim.toValue = #(M_PI * 0.5);
} else {
anim = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerRotation];
anim.toValue = #(M_PI * 0.5);
anim.springSpeed = 3;
anim.springBounciness = 1;
}
[self.button.layer pop_addAnimation:anim forKey:#"rotate"];
}
You are always rotating to the same value #(M_PI * 0.5) this is an absolute rotation that is applied to the layer. If you want to increment the angle then you need to do something like this:
anim.toValue = #(anim.fromValue.floatValue + (M_PI * 0.5));

Resources