Just want to add a darken layer or make the UIImageView darken by Swift - ios

As people already know that this seems simple but Stackoverflow has no answers for me. Basically I want to make an image darker like the bg image of Beijing ancient building below:
to make it darker so that the tags on it can be more contrasting obvious.
I tried adding a layer which is one of the answers from Stackoverflow or adding tintColor but none of them worked, is there any method that can really work? Thank you, guys.
I'm under iOS 13 and swift 5.1

Add this UIView extension to your project
extension UIView {
func addoverlay(color: UIColor = .black,alpha : CGFloat = 0.6) {
let overlay = UIView()
overlay.autoresizingMask = [.flexibleWidth, .flexibleHeight]
overlay.frame = bounds
overlay.backgroundColor = color
overlay.alpha = alpha
addSubview(overlay)
}
//This function will add a layer on any `UIView` to make that `UIView` look darkened
}
then use it like on any UIView(In your Case yourImageView)
yourImageView.addoverlay()
Or you can specify your own overlay color and alpha value
yourImageView.addoverlay(color: .blue, alpha: 0.5)

Related

Add shadow to image in UIKit

I have this screen with an UIImageView (the image is a SF Symbol)
The user can see this icon clearly, white on black. But - if the background is different:
It may be hard to see it.
I want to add a black shadow to the image so the user can see it better.
I tried looking online but all I saw is how to add shadow to the image view box, and that is not what I need. I need the shadow around the icon itself and not around the box of the image.
Any ideas? thanks in advance
Try this:
imageView.layer.shadowColor = UIColor.black.cgColor
imageView.layer.shadowRadius = 3.0
imageView.layer.shadowOpacity = 1.0
imageView.layer.shadowOffset = CGSize(width: 4, height: 4)
imageView.layer.masksToBounds = false

What do I need for masking a UIImageView and how do I do it in Swift 3?

I was wondering what I would need if I wanted to use a mask image to get my UIImageView in a specific shape. From what I understand, to create a mask, I need to have an image with the shape of the mask all black on top of a white background. Something like this, for example:
First of all, is this sufficient to shape an image view, and if so, how do I do it in Swift 3? I can only find masking code that is either outdated or written in Objective-C. I've tried simply assigning the image above to an UIImageView and then assign the image view to the mask property of the UIImageView I want to shape, like so:
self.defaultImageView.mask = self.maskImageView
This didn't do anything. It just made self.maskImageView disappear (both image view's added through the storyboard and connected using IBOutlet properties). I'm sure I'm forgetting to do something. It can't be this simple. I would appreciate it if someone could help me out. Like I said, I put both image views on the exact same spot, on top of each other, in the storyboard.
UPDATE:
My first attempt to set the mask programmatically after deleting it from my storyboard.
let layer:CALayer = CALayer()
let mask:UIImage = UIImage(named: "Black-Star-Photographic-Agency")!
layer.contents = mask
layer.frame = CGRect(x: 0, y: 0, width: ((self.defaultImageView.image?.size.width)!), height: (self.defaultImageView.image?.size.height)!)
self.defaultImageView.layer.mask = layer
self.defaultImageView.layer.masksToBounds = true
The result was that the image view had completely disappeared and wasn't visible anymore. Am I doing something, am I forgetting something or both?
You should use a png image, which supports transparency, unlike jpg.
In Photoshop your image should look similar to this:
It doesn't matter if your shape is black or white. What matters is transparency of each pixel. Opaque area (black in this case) will be visible and transparent area will get trimmed.
Edit:
You should not create mask view from storyboard if you do so. It is not going to be a part of your view hierarchy. Just add it programmatically like this:
let maskView = UIImageView()
override func viewDidLoad() {
super.viewDidLoad()
maskView.image = UIImage(named: "mask")
imageView.mask = maskView
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
maskView.frame = imageView.bounds
}
Output:
Here is a test project to show how it's working.
Also if you're using a custom frame/image and run into the mask not showing properly, try setting the content mode of the mask:
maskView.contentMode = .scaleAspectFit

Fix UIVisualEffectView extra light blur being gray on white background

Apple provides this live blurring view class UIVisualEffectView and you use it with a UIBlurEffect which takes one of three available UIBlurEffectStyles:
enum UIBlurEffectStyle : Int {
case ExtraLight
case Light
case Dark
}
Now for demo purposes I set up two effect views with the styles Light and ExtraLight:
let lightBlur = UIBlurEffect(style: UIBlurEffectStyle.Light)
let extraLightBlur = UIBlurEffect(style: UIBlurEffectStyle.ExtraLight)
let lightView = UIVisualEffectView(effect: lightBlur)
lightView.frame = CGRectMake(10, 30, 150, 150)
self.view.addSubview(lightView)
let extraLightView = UIVisualEffectView(effect: extraLightBlur)
extraLightView.frame = CGRectMake(160, 30, 150, 150)
self.view.addSubview(extraLightView)
So far so good, everything works as expected, they blur images:
and kind of work on colors, too:
but when it comes to a white background this happens:
The Light effect on the left works as expected, but the ExtraLight effect on the right leaves some kind of gray square behind.
Now the question: Is there any kind of trick or method that would enable me to use an extra light blur effect on white background (with live blurring support) AND remove that ugly gray shadow?
As far as I know the additional tint is a built-in feature of the UIVisualEffectView class. If you examine the view hierarchy with Xcode, you can see that there are two default subviews in the visual effect view instance: UIVisualEffectBackdropView and UIVisualEffectSubview. (I assume that these are private classes.) If you inspect UIVisualEffectSubview you can see that it has a background color which causes the unwanted tint that you've noticed.
I am not sure if there's an officially supported way to remove it, but you can modify this background color by filtering to the name of the private subview:
if let vfxSubView = visualEffectView.subviews.first(where: {
String(describing: type(of: $0)) == "_UIVisualEffectSubview"
}) {
vfxSubView.backgroundColor = UIColor.white.withAlphaComponent(0.7)
}
(Swift 5 compatible)
The default tint is around 70% opacity, so the easiest is to use the target background color with 0.7 alpha component.
I've also noticed that this might reset to the default value if the visual effect contains a custom subview. If I add this same snippet to the viewDidLayoutSubviews function of the view's controller, then it will keep the custom background color even after the built-in subview is updated.
Here's an example with a dark blur effect style. The top part shows the default tint and the bottom version has a custom black background color with 70% opacity.
If you just want the blur and your blurred view is gonna be stationary, you could use the UIImageEffects class and change the tintColor to a "full" white:
- (UIImage *)applyExtraLightEffect
{
UIColor *tintColor = [UIColor colorWithWhite:0.97 alpha:0.82];
return [self applyBlurWithRadius:20 tintColor:tintColor saturationDeltaFactor:1.8 maskImage:nil];
}
As far as I know you can't change it in the UIVisualEffectView.
You can try :
var visualEffectView = UIVisualEffectView(effect: UIBlurEffect(style: .Light))
visualEffectView.frame = imageView.bounds
imageView.addSubview(visualEffectView)
Simple Solution
I could find a simple solution inspired by Shannon Hughes' Blog Post. Just add a white background color with transparency to the effect view. I don't know if it is exactly like extraLight but for me it is close enough.
let visualEffectView = UIVisualEffectView(effect: UIBlurEffect(style: .light))
visualEffectView.frame = sectionHeaderView.bounds
visualEffectView.backgroundColor = UIColor(white: 1.0, alpha: 0.9)
sectionHeaderView.addSubview(visualEffectView)
The following code should do the trick to give it a the desired tint:
let visualEffectView = UIVisualEffectView(effect: UIBlurEffect(style: .regular))
visualEffectView.subviews.forEach { subview in
subview.backgroundColor = UIColor.blue.withAlphaComponent(0.2)
}
Important Note:
I wouldn't recommend adding a check for "_UIVisualEffectSubview" since this class can change on subsequent iOS updates.
Also, there is a possibility of app getting rejected because of this.
iOS 15 has the nice
.background(.ultraThinMaterial)
but it still suffers from the nasty grey tint. Wish there was an option to blur background views without any tint.
I tried a simple color-correct hack which worked for my background color but only in light mode! For dark mode I just made the background solid black (no translucent blur)
.background(
// negate the slight grey tint of ultrathinmaterial
Color("materialTintColorCorrect")
.background(.ultraThinMaterial)
)
My "materialTintColorCorrect" color asset was #F0F8FF 27% opacity for light mode and #000000 100% opacity for dark.
let vc = UIViewController()
vc.view.frame = self.view!.frame
let efv = UIVisualEffectView(effect: UIBlurEffect(style: UIBlurEffectStyle.light))
efv.frame = vc.view.frame
vc.view.addSubview(efv)
self.addChildViewController(vc)
self.view.addSubview(vc.view)
// below method has a bug
// self.present(vc, animated: true, completion:nil)
I would recommend adding your extraLightView to a view of UIColor(white: 1.0, alpha: 0.x), where x can be modified based on the scroll view's contentOffset. When there's nothing behind the view, your extraLightView will be white when x is 1. When you scroll and modify x, you won't be modifying the UIVisualEffectView (which is highly discouraged), but rather its parent view, which is perfectly safe.
Works with Swift 5
My way of making the visual effect view completely white when the background view is white.
let blurView = UIVisualEffectView(effect: UIBlurEffect(style: .light))
blurView.backgroundColor = UIColor.white.withAlphaComponent(0.7)

Adding a layer of color over a UIImage

I was hoping to make my UIImage "highlight" briefly upon being tapped. Not sure of the color yet, but let's say blue for arguments sake. So you tap the image, it briefly looks blue and then it navigates you to a details page to edit something on another screen.
From some initial reading it seems the right course of action is to use the Quartz framework and do this:
imageView.layer.backgroundColor = UIColor.blueColor()
imageView.layer.opacity = 0.7
I guess the idea would be you change the background of the layer behind the image, and then by setting the opacity of the image, the blue "bleeds through" a little bit, giving you a slightly blue image?
When I try the above, however, a blue border goes around the image itself, and based upon the opacity, the blue is either dark or light. The actual image does not become any more blue, but it does react to the opacity (meaning if I set it to something like .1, the image is very faded and barely visible). Why does the image react correctly, but not show blue?
Thanks so much!
As far as I know changing the opacity will change the opacity for the WHOLE view, meaning not just the UIImage that the UIImageView holds. So instead of fading to reveal the UIImageView's background color, instead the opacity of the whole view is just decreased as you're seeing.
Another way you could do it though would be to add an initially transparent UIView on top of your UIImageView and change its opacity instead:
UIView *blueCover = [[UIView alloc] initWithFrame: myImageView.frame];
blueCover.backgroundColor = [UIColor blueColor];
blueCover.layer.opacity = 0.0f;
[self.view addSubview: blueCover];
[UIView animateWithDuration:0.2f animations^{
blueCover.layer.opacity = 0.5f
}];
Here's how I use tint and tint opacities in IOS 9 with Swift -
//apply a color to an image
//ref - http://stackoverflow.com/questions/28427935/how-can-i-change-image-tintcolor
//ref - https://www.captechconsulting.com/blogs/ios-7-tutorial-series-tint-color-and-easy-app-theming
func getTintedImage() -> UIImageView {
var image : UIImage
var imageView : UIImageView
image = UIImage(named: "someAsset")!
let size : CGSize = image.size
let frame : CGRect = CGRectMake((UIScreen.mainScreen().bounds.width-86)/2, 600, size.width, size.height)
let redCover : UIView = UIView(frame: frame)
redCover.backgroundColor = UIColor.redColor()
redCover.layer.opacity = 0.75
imageView = UIImageView()
imageView.image = image.imageWithRenderingMode(UIImageRenderingMode.Automatic)
imageView.addSubview(redCover)
return imageView
}
Is this tap highlight perhaps something you could do with a UIButton? UIButton has all these states off the bat and might be a bit easier to work with, specially if there's something that actually needs to happen after you tap it. Worst case scenario is you have a UIButton that does not trigger any method when tapped.
You can try changing the tint color instead:
UIImage *image = [UIImage imageNamed:#"yourImageAsset"];
image = [image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
imageView.tintColor = [UIColor blueColor];
imageView.image = image;

How to mask UIViews in iOS

I've seen similar questions, but haven't found workable answers.
I want to mask a UIView using a grey image (need to convert to alpha scale for masking). The UIView has background. It should be easy to mask an image, but I want to mask any UIView.
Any clues will be appreciated.
I've been working on this problem for a couple of hours and have a solution that I think will do what you want. First, create your masking image using whatever means you see fit. Note that we only need the alpha values here, all other colours will be ignored, so make certain that the method you use supports alpha values. In this example I'm loading from a .png file, but don't try it with .jpg files as they don't have alpha values.
Next, create a new layer, assign your mask to its contents and set this new layer to your UIView's own layer, like so: you should find that this masks the UIView and all its attached subviews:
UIImage *_maskingImage = [UIImage imageNamed:#"mask"];
CALayer *_maskingLayer = [CALayer layer];
_maskingLayer.frame = theView.bounds;
[_maskingLayer setContents:(id)[_maskingImage CGImage]];
[theView.layer setMask:_maskingLayer];
With this done, you can set the UIView's background colour to whatever you like and the mask will be used to create a coloured filter.
EDIT: As of iOS8 you can now mask a view simply by assigning another view to its maskView property. The general rules stay the same in that the maskView's alpha layer is used to determine the opacity of the view it is applied to.
For apps targeting iOS 8.0+ this worked well (in this case, using a gradient as the mask) It avoids any need to resize or position the mask.
// Add gradient mask to view
func addGradientMask(targetView: UIView)
{
let gradientMask = CAGradientLayer()
gradientMask.frame = targetView.bounds
gradientMask.colors = [UIColor.blackColor().CGColor, UIColor.clearColor().CGColor]
gradientMask.locations = [0.8, 1.0]
let maskView: UIView = UIView()
maskView.layer.addSublayer(gradientMask)
targetView.maskView = maskView
}
In my case, I want to remove the mask once the user starts scrolling. This is done with:
func scrollViewWillBeginDragging(scrollView: UIScrollView) {
exerDetailsTableView.maskView = nil
}
where the view is defined as an #IBOutlet:
#IBOutlet weak var exerDetailsTableView: UITableView!
Result:
I don't know the exact code off the top of my head but the basic idea is to have two UIViews. One UIView would have it's image property set to be the grey scale image and the other UIView would be set as usual the only difference is that you would position the initial UIView directly on top of the UIView containing the "normal" image.
I hope that is enough to push your idea a step further.

Resources