i am calling setFrames multiple times for the same view.
for example after setting ltr views frames, i check if the layout should be rtl and change the views frames again.
-(void)setViewsFrames:(BOOL)RTL{
view1.frame = CGRECMAKE();
view2.frame = CGRECMAKE();
view3.frame = CGRECMAKE();
.
.
.
if(RTL){
[view1 setRtlFrame];
[view2 setRtlFrame];
[view3 setRtlFrame];
.
.
.
}
}
-(void)setRtlFrame{
CGRect RTLFrame = self.frame;
RTLFrame.origin.x = [self superview].frame.size.width - self.frame.origin.x - self.frame.size.width;
[self setFrame:RTLFrame];
}
does calling setFrames multiple time force the system to draw the view multiple times ? and may that effect performance.
I am using that also in UICollectionViewCell, so the system calls setViewsFrames: every time she want to draw the cell.
EDIT:
i've did a small test. i check when drawRect is called and here is the result:
it's called just one time, no matter how much times setFrame was called.
in UICollectionCellView it called just when the cell created or at reload.
setting the frame calls 'setNeedsLayout' and then on the next runloop iteration, IOS knows to layout & redraw the view.
there'd be no point in layouting / redrawing stuff the user doesn't see so iOS coalesces the calls for you -- if you let it by using the setNeedsXY methods
so the overhead of setting the frame is normally minimal
(except if you deal with custom (badly implemented) views [which you don't ;)])
Related
I know that it works if I change the view's frame via the changing of a layer's transform (in this case it simply takes a view with all the subviews and works with it as if it is a single image). It is not good enough for me to use it because:
It is too hard to calculate the appropriate position;
I use HMLauncherView which has some logic based on frames not
transforms.
I tried a lot of ways described here but it seems they are all for autolayout because none of them works. Depending on the type of the autoresizing mask some elements jump to their destination position and some of them are not affected at all or affected via strange ways.
How to solve such issue? Are there ways to solve this via an autoresizing mask?
EDITED
Animation code (the same result is for setting of center/bounds):
[UIView animateWithDuration:0.3 animations:^{
lastLauncherIcon.layer.transform = CATransform3DIdentity;
CGRect r = self.bounds;
r.origin.y = MAX(0, MIN(self.scrollView.contentOffset.y, self.scrollView.contentSize.height - self.bounds.size.height));
launcherIcon.frame = r;
} completion:^(BOOL finished) {
...
}];
The code of layoutSubviews seems to be extra because I have already tried to subclass UILabel which always jumps to the animation destination position. The investigation showed that the frame of this label is set when I set the view's frame/bounds only. In other cases label's setCenter, setFrame and setBounds are called when you call them directly.
This question is very similar but the suggested solution doesn't work for my case. I also found out I had broken something so the view with transformation doesn't appear on iOS 7.1 (maybe 7.x) but works on 8.3.
I have an UIScrollView with UIViews being added by lazy-loading algorithm. The UIViews contain previews of previous and next image, so at some point the actual views have to be used more than once (e.g. preview of the 2nd picture is NEXT now, but after 2 page scrolls it is PREVIOUS).
All the UIViews are stored in NSMutableArray and are added dynamically. I have the code, which checks, whether particular UIView is already added to the UIScrollView. If not, the code checks, is there needed UIView in NSMutableArray and if not, creates a new one...
The problem occurs when I try to get an UIView from NSMutableArray, change it's position on the screen and add to UIScrollView again. It just changes it's position and I see white squares where some UIViews have to be.
Is it possible to have 2 UIViews with pointer referred to one memory location or UIImage but with only one different parameter (position)? Is it good idea to copy already created UIView to NSMutable array twice to use with different position? (Win: creation process takes place only once, loss: amount of memory required is doubled).
From my point of view, I havent fount the good solution, but this worked for me - I just implemented copy method in UIView subclass, something like this:
- (ExhibitPreview *)copy {
ExhibitPreview *exhibitPreview =[[ExhibitPreview alloc] initWithImage:self.image];
exhibitPreview.number.text = self.number.text;
exhibitPreview.author.text = self.author.text;
exhibitPreview.title.text = self.title.text;
exhibitPreview.contentMode = UIViewContentModeScaleAspectFill;
exhibitPreview.clipsToBounds = YES;
CGRect screenRect = [[UIScreen mainScreen] bounds];
CGFloat screenWidth = screenRect.size.width;
CGRect frame = CGRectMake(0.0f, 0.0f, screenWidth/2, PREVIEW_HEIGHT);
exhibitPreview.frame = frame;
return exhibitPreview;
}
The first view is view itself and the second I create is a copy.
I'm quitely new for the iOS, so I don't know much of it.
I know how to make UIView (and its childviews) but I don't know about drawRect
I make a class which inherits from UIView and make subviews in initWithFrame method.
I want to draw a NSString using CGContext after adding subViews and move it outside of view after 5 seconds.
Could anyone explain when drawRect is called and how to move it?
This code helps you to draw a NSString which was stored before in _content:
- (void)drawRect:(CGRect)rect{
CGContextRef context = UIGraphicsGetCurrentContext();
[_content drawInRect:rectForFrame
withFont:[UIFont fontWithName:kFontMedium size:15.0f]
lineBreakMode:NSLineBreakByWordWrapping
alignment:NSTextAlignmentCenter];
}
To let the element slide out, you would have to call a NSTimer after your UIView was shown (Maybe with a delay using performSelector:withObject:afterDelay:) and change the attributes of the CGRect you want to write the NSString inside. You can just setup a method which will be called by your NSTimer in a specific interval which also updates the UIView.
- (void)updateView{
//create a rect
rectForFrame = CGRectMake....;
[self setNeedsDisplay];
}
One way to do it would be to draw the string and then start an NSTimer. Start a 5 second timer, and when it fires, then you can move it.
As for when -drawRect: is called - it's called whenever your view needs to be updated. It will be called when your view is first displayed by the OS. After that, it will usually be called when it changes size or shape, or when your code calls [myView setNeedsDisplay:YES], which tells the OS to update it.
I have to draw a custom border for a UIView.
I already have code to do that but it was written before we started using autolayout.
The code basically adds a sublayer of width/height=1.0f
-(void)BordeIzquierdo:(UIColor *)pcColor cfloatTamanio:(CGFloat )pcfloatTamanio
{
CALayer* clElemento = [self layer];
CALayer *clDerecho = [CALayer layer];
clDerecho.borderColor = [UIColor darkGrayColor].CGColor;
clDerecho.borderWidth = pcfloatTamanio;
clDerecho.frame = CGRectMake(0, 1, pcfloatTamanio, self.frame.size.height);
[clDerecho setBorderColor:pcColor.CGColor];
[clElemento addSublayer:clDerecho];
}
Now the problem is that with autolayout, this happens before layoutSubViews. So UIView.layer.frame is (0,0;0,0) and so the sublayer added is not shown because it has width/height=0.0f
Now how can I make this code without transferring this custom drawing to another method executed after viewDidLoad such as didLayoutSubviews.
I would like this styling to be correctly applied before viewDidLoad is called.
Is there anything like autolayout constraints that I can use with CALayers?
Any other ideas?
There is no CALayer autoresizing or constraints in iOS. (There is on Mac OS X, but no in iOS.)
Your requirements here are unreasonable. You say that you refuse to move the call to BordeIzquierdo:. But you can't give clDerecho a correct size until you know the size of self (and therefore self.layer). Half the art of Cocoa touch programming is putting your code in the right place. You must find the right place to put the call to BordeIzquierdo: so that the values you need have meaning at the moment it is called.
What I would do is put it in layoutSubviews along with a BOOL flag so that you only do it once.
One concern over a universal app I currently developing.
I just finishing with functionality development and need to add eye candy (animations).
Now wondering in a single iPhone or iPad app I would just play and set frame, bounds, to move a View, layer etc with hardcoded values.
Now how would you handled the different device frame and bounds?
Meaning you want to move a UIImageView from outside the parent View bounds and make it come to a position. Handling differently while testing what device we running at?
Thank you.
You could add a method in your AppDelegate,
- (BOOL) ISIPAD {
return (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad);
}
And refer to that each time you are making animations. If you then have some variables in your class with the width of the screen and so, you only need to check for this in either the viewDidLoad, or your init method. Then you could use the dynamic variables to do your animations. To place a button in the middle of the screen, you could do:
[UIView animateWithDuration:1.0 animations:^{
UIButton *yourButton;
yourButton.frame = (CGRect){.origin = CGPointMake(screenwidth/2.0f-yourButton.frame.size.width/2.0f, screenheight/2.0f - yourButton.frame.size.height/2.0f), .size = yourButton.frame.size};
}];
Considering the screenvariables are set in your init or viewDidLoad method, this will put your button in the middle of your screen.