Swift: remove layer, without removing UIView in UITableViewCell - ios

I have UITableViewCell with UIView in it.
I made some CABasicAnimation and attach it to new CAShapeLayer, then I add this layer to my super layer in my UITableViewCell:
self.layer.addSublayer(myLayer!)
All nice except that myLayer (and his animation) showing above my UIView.
I want that label be below UIView.
I achieve this by adding my UIView layer the same way:
self.layer.addSublayer(myViewLayer!)
In this case, my UIView layer be on the top of the CAShapeLayer with animation.
But I have a problem, I need to remove layer of UIView - myViewLayer because it violates width of the UIView when scroll.
When animation is done, and I need to remove layers, I can remove CAShapeLayer - myLayer without troubles.
myLayer?.removeFromSuperlayer()
But when I try to do the same with myViewLayer, my UIView removed too. But I don't want that, I need my UIView on screen and in my view hierarchy.
I don't understand why, if look to self.layer.sublayers I see this (before adding layers):
[<CALayer: 0x7fd1f0d4fe40>, <CALayer: 0x7fd1f0ddc950>]
And after animation done and myLayer is removed:
[<CALayer: 0x7fd1f0d4fe40>, <CALayer: 0x7fd1f0ddc950>, <CAGradientLayer: 0x7fd1f0de3660>]
As you can see CAGradientLayer is a layer of my UIView. So, I haven't it before I manually add it to sublayers array. How I can remove it, without removing my UIView?
OR how can I add myLayer below UIView?
EDIT
In few words I have this layer hierarchy before animation:
[<CALayer: 0x7fd1f0d4fe40> <- (I think this is UITableViewCell layer), <CALayer: 0x7fd1f0ddc950> <- (then, this is UITableViewCell content view layer)]
In the same time, I have this view hierarchy:
UITableViewCell -> Content View -> UIView
I need to add new layer with animation, below UIView (I want that UIView partially cover that new layer with animation). How I can do this?
I haven't my UIView layer in the UITableView layer hierarchy, so I can't just add layer with animation using addLayer:below: and so on.

I found the problem. I made a simple mistake. I used self.layer.sublayers, but I must use self.contentView.layer.sublayers this is my mistake.
When I found that, I was able to fix another issues and use addLayer:below:.
So, if you don't see a layer that must be in sublayer of your object, means that you're looking at the wrong place, think where it can be else and you'll find it, like in UITableView you need to work with contentView.

You can add myLayer below UIView.layer by setting
myLayer.zPosition = -1

The example below could have fixed your problem as well.
First solution:
self.avPlayerLayer.zPosition = 0 // or -1
self.view.layer.addSublayer(self.avPlayerLayer)
Or second solution
self.view.layer.insertSublayer(self.avPlayerLayer, below: self.button1.layer)

Related

How to detect a transform-only UIView?

UIStackView is a transform-only view. This means it is not possible to perform operations on the view's layer.
Is there a general-case way to detect if a UIView is a transform-only view?
Actually, transform-only view is view which has CATransformLayer layer.
So the question should be How to detect a UIView which has transform-only layer? and the answer is very simple, check class's type of view.layer.
For example, when you want to change cornerRadius on stackView.layer, it will through a warning like
changing property cornerRadius in transform-only layer, will have no effect
It's not because something which is called transform-only view, it's because you are changing cornerRadius on a CATransformLayer and cornerRadius property is ignored according to Apple document for CATransformLayer.
Only the sublayers of a transform layer are rendered. The CALayer properties that are rendered by a layer are ignored, including: backgroundColor, contents, border style properties, stroke style properties, etc.
Something you maybe wrong is It's possible to perform operations on the view's layer but not all of them.
How to detect if a UIView is a transform-only view? - Use below extension
extension UIView {
func isTransformOnlyView() -> Bool {
return self.layer.isKind(of: CATransformLayer.self)
}
}
Usage
stackView.isTransformOnlyView()

Why adding sublayer overlaps subviews?

For example I have a view with UILabel as subview. If at some time I add sublayer with some background color to this view's layer, then this label will disappear. Can someone explain this behavior?
When you add your UILabel as a subview of your view it is adding your UILabel's layer as a sublayer of your view's layer. So when you add another sublayer to your view's layer it will be on top of your UILabel's layer.
You can either add your background layer before you add the UILabel or do:
Swift
view.layer.insertSublayer(backgroundLayer, below: yourLabel.layer)
Objective C
[view.layer insertSublayer:backgroundLayer below:yourLabel.layer]
and it should put the background behind the label.
What worked for me was to insert the layer at a specific index like this:
view.layer.insertSublayer(backgroundLayer, at: 0)

UIView not resizing within UITableViewCell

I have a custom UITableViewCell that has two elements. A UIView and a UILabel. The cell is used for voting so I want to be able change the dimensions fo the UIView based on the vote. I currently am setting the frame of the UIView in the cellForIndexAtPath method. The frame of the UIView is being changed correcting (as I am checking in 3 places to make sure using NSLogs) but is not being reflected on the cell after they are displayed on the screen. Does anyone know why the UIView's frame would say it has changed but when displayed it would stay at the cell's frame size?
EDIT
NSLog(#"before: %#",NSStringFromCGRect(cell.voting_scale.frame));
[cell.voting_scale setFrame:CGRectMake(0.0, 0.0, width, row_dim.height+10.0)];
[cell.voting_scale setBounds:CGRectMake(0.0, 0.0, width, row_dim.height+10.0)];
[cell.voting_scale setClipsToBounds:true];
NSLog(#"after: %#",NSStringFromCGRect(cell.voting_scale.frame));
Hope this helps more
I don't have a thorough understanding of the behind-the-scenes processes of UITableView but I have found that when my UITableViewCell subclasses don't seem to be working as intended, that moving as much of the code as I can to the layoutSubviews method of the subclass instead of calling it in cellForRowAtIndexPath of the UITableViewController helps.

Autorotation issue with UITableViewCell and CALayer

I have a UITableViewCell subclass with backgroundView set to my own UIView object. This UIView object contains three CALayer layers. I implemented - (void)layoutSubviews where I update all my CALayer layers. The problem is autorotation.
When I rotate from landscape to portrait mode there's this cosmetic issue:
During the animation, all my CALayer layers are as narrow as in portrait mode.
It seems that this guy is right:
When layoutSubviews gets called during an orientation change, the view's bounds are already set to what they will be at the conclusion of the rotation.
Source: How to achieve smooth animation when using single-step rotation / How do I get the new frame size at the start of rotation?
So, where should I update my layers to achieve proper autorotation? The view is already rotating them, so I suppose there's no need to do any custom animations, just adjust the size. Right?
Figured it out:
subclass CALayer + add sublayers into it
implement resizing of sublayers in CALayer's - (void)layoutSublayers method
subclass UIView + override + (Class)layerClass in it:
+ (Class)layerClass {
return [SubclassedCALayer class];
}
set the subclassed UIView as backgroundView of UITableViewCell

What is the CALayer equivalent to UIView's sizeToFit-method?

I'm searching for a way to let a CALayer resize itself whenever its sublayers change (which means either when the bounds of any sublayer change or when the sublayer array itself changes).
When i worked with views before, i managed that through implementing sizeThatFits in my custom UIView subclass, which was called automatically by sizeToFit whenever the view's subviews changed.
Since CALayer has the sizeThatFits-equivalent-method preferredSize, i was surprised not to find a sizeToFit-equivalent.
I think you need to implement(override) the - (void)layoutSublayers
...
*Subclasses can override this to
* provide their own layout algorithm, which should set the frame of
* each sublayer
- (void)layoutSublayers
{
// self.frame = aNewSubLayer.bounds
// basically do algorithm for setting frame and bounds for this(self) layer and subLayers here
}

Resources