NSCollectionViewItem's custom view flickers onReloadData - swift

I have a NSCollectionViewItem with a custom view, in that view I am adding custom CALayer to some items. On button action, I am calling NSCollectionView's reloadData() method to reload the different data. This causes the custom CALayer to flicker as the item changes. Any idea how to fix it?
Adding CALayer to item's view based on some condition
circleLayer = CALayer();
let dimension = floor(min(bounds.width, bounds.height) - 10);
circleLayer.frame = NSMakeRect(4.5, 4, dimension, dimension);
circleLayer.cornerRadius = dimension / 2;
backgroundLayer.backgroundColor = NSColor(red: 84/255, green: 84/255, blue: 87/255, alpha: 1.0).cgColor;
circleLayer.masksToBounds = false;
circleLayer.isHidden = false;
layer?.addSublayer(circleLayer);
Function called on button click
//loading different data
collectionView.reloadData();
So as the button is clicked the background color of some other item changes, but the background color of previous item flickers. I guess this probably due to reuse of NSCOllectionViewItem. How can I avoid this? Any idea?

Related

Animating a mask alongside an expanding CollectionViewCell

I am working on a transition during which a collectionView cell expands to reveal new elements.
In order to prevent the new elements from animating with the cell, I removed them from the animated view.
Here is an image of the view hierarchy
After I remove the elements from the animated view, they are also not being clipped by the cell anymore, revealing them before the cell has expanded.
Right now I can decide between the elements animating with the cell or the elements appearing before they should.
Here is a video of the current state of the animation
You can see the new elements appearing on the cell to the left of the selected one.
Below is the code for my animated transitioning:
let destination = transitionContext.viewController(forKey: .to)
let containerView = transitionContext.containerView
containerView.addSubview(destination.view)
// Initial state
let widthConstraint = destination.header.widthAnchor.constraint(equalToConstant: 500)
let heightConstraint = destination.header.heightAnchor.constraint(equalToConstant: 601)
NSLayoutConstraint.activate([widthConstraint, heightConstraint])
let transform = CATransform3DMakeTranslation(cellFrame.origin.x, cellFrame.origin.y, 0.0)
destination.topView.layer.transform = transform
destination.view.layer.zPosition = 999
containerView.layoutIfNeeded()
let animator = UIViewPropertyAnimator(duration: 4, dampingRatio: 10) {
// Final state
NSLayoutConstraint.deactivate([widthConstraint, heightConstraint])
destination.topView.layer.transform = CATransform3DIdentity
destination.view.layoutIfNeeded()
}
I was thinking about masking the new elements based on the frame of the expanding cell but am not sure how I could make that work.
An alternative solution you could do is to transition the labelingView to show only when it should be present. For example, only show your labelingView once you finish your animation transition.
Some psuedo code..
labelingView.alpha = 0
UIView.animate(withDuration: 1, animations: {
// perform transitions
}) { _ in
labelingView.alpha = 1
}
I solved it an it turned out to be easier than expected.
I simply created a mask based on the initial collectionViewCell and animated it to fullscreen alongside the expanding cell.
let mask = UIView()
mask.frame.origin = CGPoint(x: cellFrame.origin.x, y: cellFrame.origin.y)
mask.frame.size = CGSize(width: 500, height: 601)
mask.backgroundColor = .white
mask.alpha = 1
destination.labelingView.mask = mask
// Final mask state
mask.frame.origin = CGPoint(x: 0.0, y: 0.0)
mask.frame.size = CGSize(width: 1366, height: 1024)

Add UIView (from xib) with transparency to SceneKit

I'm trying to load a UIView into SceneKit with a translucent background, but currently, it just fades to white as I decrease the opacity.
I have a very simple UIView layout in a .xib file that I want to load into SceneKit.
So far I can display the UIView in the SCNMaterial, change any text fields, images, etc inside the view without a problem. However, I cannot let it have transparency. If I change the alpha of the view it just fades to white.
most of the code is the below:
if let cardView = Bundle.main.loadNibNamed("OverlayCard", owner: self, options: nil)?.first as? OverlayCard {
cardView.backgroundColor = UIColor(displayP3Red: 1.0, green: 0.4, blue: 0.9, alpha: 0.2)
let newplane = SCNPlane()
let newMaterial = SCNMaterial()
cardView.alpha = 0.2
cardView.isOpaque = false
newMaterial.diffuse.contents = cardView
newMaterial.blendMode = .add
newplane.materials = [newMaterial]
let viewNode = SCNNode(geometry: newplane)
self.addChildNode(viewNode)
}
I've left in various things like assigning the blendMode, backgroundColor with 0.2 opacity as well as the entire view because these are all things I've tried but still get a white background with some of the view's elements on top of the white very faded out. Have also tried blendMode = .alpha to find no difference.
'self' here is a subclass of SCNNode.
Does anyone know how I can make this view's background fade to transparent, rather than fade to white? Or, another way to load a view into SceneKit.
Try setting the layer of the view as diffuse.contents instead of the view itself.
newMaterial.diffuse.contents = cardView.layer

shadow not behind text

I've made a function that is called in drawRect() inside a seperate made class for a Label. However, this draws only behind the text, and not behind the background of the label. I want to have a shadow behind the background of the label, not the text. How can I fix this? The same happens in a seperate made class for a View.
let COLOR_SHADOW_COLOR: CGColor = UIColor.gray.cgColor
let COLOR_SHADOW_OFFSET = CGSize(width: 2, height: -2)
let COLOR_SHADOW_RADIUS: CGFloat = 5
let COLOR_SHADOW_OPACITY: Float = 1.0
func setShadow(on object: UIView) {
object.layer.shadowColor = COLOR_SHADOW_COLOR
object.layer.shadowOpacity = COLOR_SHADOW_OPACITY
object.layer.shadowOffset = COLOR_SHADOW_OFFSET
object.layer.shadowRadius = COLOR_SHADOW_RADIUS
}
Fixed my own problem. The background was the same color as the text, but with a lower opacity. Xcode thinks that it should draw around text then. After using the pipet on the same color, it did made the shadow behind the label and view

Animation text does not appear in my UIView object

I am using a UIObject to display an animation using Lottie framework which is a submit button, and when this UIView object is tapped, the animation is played.
However the text within this animation does not appear, and the dimensions are also wrong. My UIView object has dimensions of 193*33 and the animation also does. Here is my code;
let SubmitButton = LOTAnimationView(name: "submit_195_33")
self.SubmitViewName.addSubview(SubmitButton)
SubmitButton.frame = CGRect(x: 0, y: 0, width: 195, height: 33)
SubmitButton.contentMode = .scaleAspectFill
SubmitButton.play()
My UIView object is larger then the animation even if I use this code, and the animation is super small like this:
Maybe you can try setting constraints to the button, for example:
submitButton.translatesAutoresizingMaskIntoConstraints = false
submitButton.widthAnchor.constraint(equalToConstant: 195).isActive = true
submitButton.heightAnchor.constraint(equalToConstant: 33).isActive = true

changing background color for the headers in NSTableView

Im trying to change the background color of a header row in a view-based NSTableView but not having any luck
tried this:
tableView.headerView?.layer?.backgroundColor = CGColor.black
and this (as was suggested in an earlier Obj-C post from a while ago):
for column in tableView.tableColumns {
column.headerCell.backgroundColor = NSColor(red: 0/255, green: 108/255, blue: 178/255, alpha: 1)
column.headerCell.textColor = NSColor.blue
}
Creating a custom NSTableHeaderCell subclass and setting NSTableColumn's headerCell property allows you to customize the appearance of your table's header row.
Apple's documentation recommends overriding the drawInterior:withFrame method when customizing a header cell, but this will not fill the background color for the whole cell - overriding draw:withFrame is needed. Calling drawInterior will draw the header's label and other elements. If you want to keep the header's content centered vertically in the cell, adjusting the interior frame is necessary.
override func draw(withFrame cellFrame: NSRect, in controlView: NSView) {
NSColor.gray.setFill()
NSBezierPath.fill(cellFrame)
let interiorFrame = CGRect(x: cellFrame.origin.x, y: cellFrame.origin.y + 4.0, width: cellFrame.size.width, height: 14.0)
drawInterior(withFrame: interiorFrame, in: controlView)
}
One thing to note - the column separator lines will need to be drawn as well if you want them.
I also have same problem. I found out that the headercell is inherit from NSTextFieldCell. Which have background Color properties. you can access to that and set it to new color. remember to set draw background to YES.
*when you create new column*
[[newCol headerCell] setDrawsBackground:YES];
- (void)tableView:(NSTableView *)tableView didClickTableColumn:(NSTableColumn *)tableColumn{
[[tableColumn headerCell] setBackgroundColor:<color you want to change to>];
}
Adding a colored subview is probably the cleanest way to achieve this. It goes between the default background and the cells that draw the header text and controls
NSRect rect = tableview.headerView.frame;
rect.size.width = 10000; /// just pick something wide enough here
MyColoredView * coverView = [[MyColoredView alloc] initWithFrame:rect];
coverView.autoresizingMask = tableview.headerView.autoresizingMask;
[tableview.headerView.superview addSubview:aView positioned:NSWindowBelow relativeTo:tableview.headerView];