UIViews, subviews and alpha - iphone

I have three views on top of each other inside a superview.
superview
- subview 1 (CD Case)
- subview 2 (Artwork)
- subview 3 (Shine)
when I animate the alpha property of the superview it seams to affect the alpha of all subviews i.e. while the animation is running subview 1 the CD Case shines through the artwork.
While blending all three into one UIImage solves this problem, but for performance reasons this not really an option. (The views are display in a grid view and loaded on demand.)
Is there any other way to avoid this behaviour?

You can either reverse the fade, as suggested by #debleek63. Or you can change the shouldRasterize flag on the superviews layer.
myView.layer.shouldRasterize = YES
This will make it use 'group opacity' and everything should composite as you'd expect. The first way is probably more performant, but not as 'correct'.

Related

Setting alpha a group of elements in a view in SWIFT

I've created a layout using the Xcode's Autolayout. I have a number of views with label and imageView inside. Is there any way to change the alpha for labels and imageView without creating outlets for all of them in ViewController in code?
Could I change the alpha for all the elements inside the view in code, not changing it for the view?
You can enumerate through a views subviews and set the alpha that way.
for v in view.subviews {
let view = v as! UIView
view.alpha = 0
}
Another approach is to use an IBOutletCollection which you can create in interface builder
Sure, there's lots of ways to handle this.
You could set up an IBOutletCollection of views who's alpha you want to change. An IBOutletCollection is really just an array of view objects that the runtime sets up for you. Beware that the order of the objects in the collection view is not guaranteed.
You could set a numeric range of tags on your views (starting with a non-zero value) and then use a for loop and the UIView method viewWithTag.
You could loop through all of a view's subviews in code and manipulate the view's alpha directly.

Increase UIView's frame size at the left edge

I have an UIView that can grow dynamically in width. The view also have subviews located inside it's bounds.
Default behavior seems to be that when the view's frame grows along the x axis, increasing frame.size.width, it always grows at the right edge, keeping the subviews fixed as if there were a fix left margin. However, when I want to expand the view on the left edge this doesn't work because of this behavior. In this case I want it to behave in a mirrored way, as if there were a fix right margin. I could of course "manually" move all subviews so it looks like that is the case, but that seems really awkward since there could be plenty of them.
So I guess the question really is if there is a way to shift a views bounds relative to it's subviews? Is maybe autoresizingMask the way to do this?
Thanks.
Maybe you should take a look at the AutoresizingMask property of a UIView subclass :-)
For example, if you have a UILabel called labelVideoTitle, you could set a mask like this :
[ labelVideoTitle setAutoresizingMask:UIViewAutoresizingFlexibleWidth ];
You can by the way add 2 mask at once like :
[ labelVideoTitle setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight ];
Good Luck !
Edit : To increase the parent view frame size at the left edge, you could change too its X position to the left to give the impression wanted ^^ For example if you add 10 pt to the width, try modifying the X origin -10 pt :-)
In interface builder, you can graphically indicate in the CMD-3 (little ruler icon) Size Inspector what each element in your view should do when the parent view is resized: you can indicate which borders (top, left, right, bottom), the given element should "stick to" when the parent view is resized. You can also indicate whether the given element should itself resize (in either width or height) or stay the same size. Underneath the hood, this sets the autoresize mask for the UIView element you're editing, but especially for making an element stick to a particular border, Interface Builder is the way to go.
IB Size Inspector also has a neat little animation that shows you the effect on a hypothetical element (little red square) during a resize, given your settings to the left.

Objective-C Auto Adjust Subviews

I'm looking to write a method for an iPhone app that will auto adjust a UIViews's subviews Y values depending on the available space within that view. I'll try my best to explain without getting too confusing.
I have a Container view that is housing up to 3 Subviews. With in each subview is a button that removes the sub view from the container view, when the subview is removed i would like to adjust the remaining subviews to take up whatever space that has been opened by the removed subview.
Thanks in advance for any help!
One way is to make your wrapper view a custom UIView subclass. In that subclass, maintain a separate NSMutableArray of your subviews wherein each subview's array index corresponds to its position on the screen.
With this in place, you have a couple of options. One is to overide didAddSubview:. Based on the frame of the subview being added, you can determine the subview's position and insert reference to the subview at the appropriate index in your array.
A cleaner option is to implement your own custom method like this:
- (void)insertSubview:(UIView *)subview atPosition:(NSInteger)position;
where position is an index identifying which "slot" the subview should fill. You can set the frame for the subview explicitly within this method, along with any other subviews that are impacted by the insertion. Then insert the subview into your array at the corresponding index.
Finally, override willRemoveSubview:. In it you can use indexOfObject: on your array to find the position of the subview being removed. Then simply adjust the frames of all the subviews that follow it, and remove the subview from your array.
(One other alternative is to skip the array and just use the tag property to indicate the position of each subview. I don't like this option though. Using the tag property for anything always feels like a terrible hack to me.)
Well the first thing you need to do is signal your container that a subview has been removed.
Then you can take the height value of the view that was removed, divide it by the number of remaining subviews, and then expand the height of those remaining subviews.
Then you set your first remaining subview to Y coordinate 0, and the second (if there is one), to a Y coordinate of the first subviews height value

UILabel inside custom UITableViewCell not drawing at the correct size

I have a custom table cell which contains a number of UILabels. At runtime, I am adjusting the height of the labels to fit their contents using sizeWithFont:constrainedToSize:lineBreakMode: and repositioning them accordingly. The last label in the cell contains a large amount of text, causing it to wrap, and I'm having a very odd problem. Although the sizeWithFont call returns the correct size, and I'm setting the UILabel's frame to that height, it draws a couple of lines short. This screenshot illustrates what I'm talking about:
In this example, the height of the full block of text should be 90 (as checked in Interface Builder), and that's what returns from sizeWithFont. It's also the height that the UILabel's frame is set to, which I have verified by logging and also by stopping execution and inspecting the value. However, as you can see, it's clearly not drawing the full 90 pixels high, although it's correctly allocating the space for it (the thin black line above 'Edited' is the table cell border). I'm completely perplexed. If anyone can offer some insight as to why it's behaving this way, I would be very grateful.
At last, a solution!
Turns out that the cell does layout twice -- once during heightForRowAtIndexPath, which is where I tweak all the heights of the subviews and the cell, and later during some untraceable transaction originating in __CFRunLoopDoObservers. How did I trace this? I added a layoutSubviews override to my custom table view cell class so I could breakpoint it.
During the second pass, the last UILabel subview was getting set to a shorter height than I set it to, probably in accordance with some arcane autoresizing rules. (Yes, I tried tweaking all of those settings first, with no success.) As it turns out, merely doing nothing in layoutSubviews disabled this framework behavior, allowing me to completely control how my views draw.
With iOS 8 it doesn't work anymore like this. Implementing layoutSubviews alone doesn't do the trick, because the layout of subviews have already changed when the method is called.
I have found 2 solutions:
adding NSLayoutConstraint to layout the subviews programmatically
implementing subview's layoutSubviews and change the frame
An example für solution 2:
- (void)layoutSubviews
{
[super layoutSubviews];
CGRect frame = self.frame;
frame.size.height = 39.f;
self.frame = frame;
}
I've fought with similar problems. It was to do with other properties being set in previous incarnations of the cell. To find it / prove it I changed the reuseidentifer for the offending cell to make sure it was a unique cell.

Is there a way of setting some kind of z-index for z-position of UIImageView objects?

I'm building up a grid of images, and I start at the top, creating UIImageView objects all over the place. Now I want that they overlap a little bit, but the last ones I draw are the ones most on top. I'd like to set the z-position programmatically, so that the first ones I draw will be the ones most on top.
instead of using insertSubiew you can try:
- (void)bringSubviewToFront:(UIView *)view
- (void)sendSubviewToBack:(UIView *)view
You said you used UIImageView. Drawing an image with UIImageView means initializing it and then adding it to a container view.
Can't you just use this code in your loop?
[containerView insertSubview:image atIndex:[[containerView subviews] count]]
The result would be that the view added first is on the top of the view stack (I haven't been able to test this yet though :) )
https://stackoverflow.com/a/4631895/2482283
You can use the zPosition property of the view's layer (it's a CALayer object) to change the z-index of the view.
theView.layer.zPosition = 1;
As Viktor Nordling added, "big values are on top. You can use any values you want, including negative values." The default value is 0.
You need to import the QuartzCore framework to access the layer. Just add this line of code at the top of your implementation file.
#import "QuartzCore/QuartzCore.h"
another way(https://stackoverflow.com/a/4663526/2482283), you can also utilize uiviews method:
#property(nonatomic,readonly) UIView *superview;
#property(nonatomic,readonly,copy) NSArray *subviews;
- (void)removeFromSuperview;
- (void)insertSubview:(UIView *)view atIndex:(NSInteger)index;
- (void)exchangeSubviewAtIndex:(NSInteger)index1 withSubviewAtIndex:(NSInteger)index2;
- (void)addSubview:(UIView *)view;
- (void)insertSubview:(UIView *)view belowSubview:(UIView *)siblingSubview;
- (void)insertSubview:(UIView *)view aboveSubview:(UIView *)siblingSubview;
- (void)bringSubviewToFront:(UIView *)view;
- (void)sendSubviewToBack:(UIView *)view;
Not directly.
One solution would be giving the UIViews a z-index property; an integer defining your depth level. Then you could itterate through an NSArray (myArray) containing the UIViews adding them as subviews in order of depth.
I had the same problem. I needed the subview element with the highest and lowest z-index. From my testing I found out, that UIKit arranges the elements in the subviews-property according to their z-position. If you take
[self.scrollview subviews]
for example. The first array element is the subview which is at the very back. The array element with the highest index is the subview at the very front. If you use
- (void)bringSubviewToFront:(UIView *)view
- (void)sendSubviewToBack:(UIView *)view`
the subviews array will be reordered accordingly.
If you have the ref to the view below/above you need to add the sub view you can use the following
[self.view insertSubview:<#(UIView *)#> belowSubview:<#(UIView *)#>];
[self.view insertSubview:<#(UIView *)#> aboveSubview:<#(UIView *)#>];
Actually, as far as I know, there is no z-index position property for that. Drawing in the view uses a simple drawing model.
You can either put your logic in the drawing loop (i.e draw the things you want on top last) or you can use Cocoa Animation, since unlike UIImageView, CALayers do have depth (they are a 2D projection of a 3D space). See here for a reference.
imageView.layer.zPosition = 100;
You really might want to consider using CALayer's instead of lots of UIImageView Objects. UIImageView objects are great but for intense drawing CALayer's are lighter weight and more efficient (though if you need to have a user interact with the images, a view object is better). It really depends on what you are doing. CALayers do have a zPosition property. This is what UIKit uses when it arranges the UIView's position in the view stack.