I know it may sound a little bit of a drag to ask this question but I am curious if anything like this is available.
I am building a app in which the background image (covers full view with a blur effect) of each view controller changes dynamically. This background image will be in all the view controllers, each one having a different set of UIControls (Labels, Buttons, Table Views, Collection Views, containers, tabs, etc).
Sometimes when the background image is very light, the foreground texts (labels, buttons) with white text colour are not visible at all. Also the vice versa is a problem too.
So I would like to know if there is any way to change the foreground text colour dynamically based on its background.
Recently I faced the same problem, And I think what you looking for is either image is bright or dark so that you can set property accordingly Hope this will help.
Create observer, everytime image change it will check if its a dark image or bright and based on that will call the function UIForDarkImage and UIForBrightImage
//ImageView observer to observe the image change and perform the UI action based on the image colour
//Your imageView you are using to set image
var imageView: UIImageView {
didSet {
if imageView.isDark(image.bounds) { //dont pass the full image bounds pass the rect where your buttons or label places it will save your hell lot of time
setUIForDarkImage() // here you set buttons and labels color to white or whatever changes you want to perform based dark image
}
else {
setUIForBrightImage() // here you set buttons and labels color to black or whatever changes you want to perform based bright image
}
}
}
UIImageViewExtension for checking if Image is a dark image or bright Image.
What happening is, It will go through image pixel-by-pixel and check if the pixel is bright or dark and if we get dark pixels more than the threshold we have set, we will assuming that its a dark image else it's a bright image.
PS: For better efficiency not checking the whole image (for a high-resolution image it will slow down if we will check all pixels) so only checking the part of the image in which we need our button or label, you can set rect based on your requirement. And also scaling by 0.45 to check few pixels in that rect(you can increase or decrease for more/less accuracy).
extension UIImageView {
func isDark(_ rect:CGRect)->Bool {
let s=image?.cgImage?.cropping(to: rect);
let data=s?.dataProvider?.data;
if data == nil {return false;}
guard let ptr = CFDataGetBytePtr(data) else {return false;}
let threshold = Int(Double(rect.width * rect.height) * 0.45);
var dark = 0,len=CFDataGetLength(data);
for i in stride(from: 0, to: len, by: 4) {
let r = ptr[i], g = ptr[i+1], b = ptr[i+2];
if (0.299 * Double(r) + 0.587 * Double(g) + 0.114 * Double(b)) < 100 {dark += 1;}
if dark > threshold {return true;}
}
return false;
}
}
PS: If you also like to know what I am doing in setUIForBrightImage() and setUIForDarkImage do let me know
Here's what I would do: Create a struct that contains the name of the image view and a tint color to use for your labels, buttons, etc.
Add a property to your view controllers using this new struct. Let's call it backgroundImageSettings.
Add a didSet method to the property that calls another method useBackgroundImageSettings() that installs the image into the background of the view controller's content view, sets the tint color for the view controller's content view, and calls setNeedsDisplay() on the content view.. Also call useBackgroundImageSettings() in your viewDidLoad so that setting your backgroundImageSettings still works even if you view controller's view hasn't been loaded yet.
I like Duncan's answer! An additional step you can take is to set a slight overlay onto your background image.
For example, if you have a background image with really dark colors and you can't see your black text very well, then you can add a layer with a background color of white and an opacity less than 1. That way there's a bit of white to make your text more readable, and you can still see the background image.
let overlay = UIView(frame: yourSuperView.bounds)
overlay.backgroundColor = UIColor.white
overlay.layer.opacity = 0.5
yourSuperView.addSubview(overlay)
Related
I am trying to make an overlaying view which just makes the screen turn red. However, even if I set the background color to any color, it just shows as gray. I can still maneuver it around the screen, I just can't change the color for some reason.
Here's what I put into my didMove to view function:
let pulseView = SKView(frame: self.view!.frame)
pulseView.backgroundColor = SKColor.red
pulseView.alpha = 1
self.view?.addSubview(pulseView)
Is there any way to obtain a flash screen effect like the one produced when a screenshot is taken, on demand, for a certain NSView? My question is not a duplicate of flashing screen programatically with Swift (on 'screenshot taken') , since I need a solution for osx, not ios and the methods are different.
Something like this might work
func showScreenshotEffect() {
let snapshotView = UIView()
snapshotView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(snapshotView)
// Activate full screen constraints
let constraints:[NSLayoutConstraint] = [
snapshotView.topAnchor.constraint(equalTo: view.topAnchor),
snapshotView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
snapshotView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
snapshotView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor)
]
NSLayoutConstraint.activate(constraints)
// White because it's the brightest color
snapshotView.backgroundColor = UIColor.white
// Animate the alpha to 0 to simulate flash
UIView.animate(withDuration: 0.2, animations: {
snapshotView.alpha = 0
}) { _ in
// Once animation completed, remove it from view.
snapshotView.removeFromSuperview()
}
}
The way to achieve this is to create a new UIView that is the same size of the screen, and black in color, add it a subview of your view then animate the alpha to zero( play around with the duration to achieve the desired effect) after completion remove the view from superview.
I have used this technique in many of my projects and it works like a charm. You can play around with the background color of the view to customize the look of the flash.
I'm again struggling with setting NSViews background colors to transparent. I have a NSCollectionView as part of NSClipView which is part of a NSScrollview. My MainViewController has an outlet to the collectionView. With adding the two lines of code and after compiling the background is sometimes transparent but most of the times not:
view.wantsLayer = true
collectionView.layer?.backgroundColor = NSColor.clear.cgColor
I also tried to select/de-select the "Draw Background" property of the NSScrollView in the IB without any effects.
What do I miss here.
I struggled a bit attempting to get my NSCollectionView background "transparent" #JFS solution pointed me in the right direction: and I finally achieved it by setting both the parent scrollView and the collectionView backgrounds:
cvScrollView.backgroundColor = NSColor.clear
collectionView.backgroundColors = [NSColor.clear]
Ok, after a long evil trial and error phase I found a solution at least for myself. There are two background colors to set in order to have the proper behavior:
the background color of the NSScrollView:
the NSCollectionView primary color:
Both have to be set appropriately. At the point I set both to the same color I got the background I want. With setting only the ScrollView background color there was still the white background when scrolling the items in the CollectionView.
To make clear background for NSScrollView, the best option in Swift 4.2 is "Not draw a background". Let's get to view a programmatically example:
let scrollView = NSScrollView()
scrollView.drawsBackground = false
scrollView.contentView.drawsBackground = false
NSCollectionView has background for sections, so you need to specify colors for sections
let collectionView = NSCollectionView()
collectionView.backgroundColors = [.clear]
If you set backgroundColors to nil or to empty array, the background color is set by default to white.
If you set a background view for NSCollectionView, this array is ignored
You could try to put a NSView with frame zero as a backgroundView for NSCollectionView
I am wanting to make a round UIButton but with a light blur effect with vibrancy as it's background
So far I've got a rounded UIButton, but the code I have found online (I'm new to iOS development so don't really understand how the blur etc works) to add a blur just puts it as the entire button's frame, essentially making the button appear square again.
I've also tried adding a view, then the UIButton and then the blur effect and applied the cornerRadius code to that view but it also didn't work.
Here is what I've tried:
shortcutButton.layer.cornerRadius = 0.5 * shortcutButton.bounds.size.width // add the round corners in proportion to the button size
let blur = UIVisualEffectView(effect: UIBlurEffect(style:
UIBlurEffectStyle.Light))
blur.frame = shortcutButton.bounds
blur.userInteractionEnabled = false //This allows touches to forward to the button.
shortcutButton.insertSubview(blur, atIndex: 0)
Add the following two lines of code to your project, before you add the subview:
blur.layer.cornerRadius = 0.5 * shortcutButton.bounds.size.width
blur.clipsToBounds = true
Enjoy! :)
I set my window's appearance to NSAppearanceNameVibrantDark in order to have some kind of "dark" theme, which works wonderfully. Not being a fan of pure black though, I want to lighten the UI elements a little bit.
I set the window's background color to pure white, that made the toolbar look grey, which is perfect:
But in my window, I have a NSTableView that was not affected by this change:
As you see, everything is really dark and the alternating colors for the rows are barely visible. I want to lighten up this so I tried setting the NSTableView background color to white, it didn't help. I tried setting the enclosing NSView CALayer's background color to white and this didn't help either (I specified that this view needed to have a layer with the wantsLayer property).
My most fortunate attempt was to implement tableView(_: didAddRowView: forRow:) and manually set the colors of the row views:
if row % 2 == 1 {
rowView.backgroundColor = NSColor(white: 0.4, alpha: 1)
} else {
rowView.backgroundColor = NSColor(white: 0.2, alpha: 1)
}
BUT, this doesn't affect empty rows below my data, they remain very dark. I would like the empty rows to be the same color as the populated ones.
Thanks !
NOTE: I don't care about the header row background color, it can stay the current shade of grey.