I'd like to apply layer on top of ImageView that slightly blurrs it.
I put a view on top of imageView, subclass it as follows:
class BlurredView: UIView {
override func draw(_ rect: CGRect) {
self.backgroundColor = UIColor.clear
let blurEffect = UIBlurEffect(style: UIBlurEffectStyle.extraLight)
let blurEffectView = UIVisualEffectView(effect: blurEffect)
blurEffectView.backgroundColor = UIColor.clear
blurEffectView.frame = self.bounds
blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
self.addSubview(blurEffectView)
}
}
The result is quite different from what I expected.
How to customize it to make this blur much lighter, so the picture still shows some details?
As https://stackoverflow.com/users/1387306/chrstpsln mentioned in the comment, this can be achieved by changing the alpha of the UIVisualEffectView.
As a bonus, you can add a fade animation to make the transition feel smoother.
Heres an example of how you can add this effect to any viewController through an extension:
extension UIViewController {
func addBlurEffect() {
let blurEffect = UIBlurEffect(style: .light)
let blurVisualEffectView = UIVisualEffectView(effect: blurEffect)
blurVisualEffectView.frame = UIScreen.main.bounds
blurVisualEffectView.alpha = 0.1
// Bonus animation - Or just set the alpha higher
UIView.animate(withDuration: 0.3) {
blurVisualEffectView.alpha = 0.90
}
view.addSubview(blurVisualEffectView)
}
}
Usage:
let viewController = UIViewController()
viewController.addBlurEffect()
You can't change the blur amount, the only thing you can do is to change the blur effect style:
UIBlurEffectStyle.light
UIBlurEffectStyle.extraLight
UIBlurEffectStyle.dark
Try to change the blur effect alpha. Also, since your image is light, you should use the light style and not the extra light in order to not lose details.
let blurEffect = UIBlurEffect(style: UIBlurEffectStyle.light)
blurEffect.alpha = 0.95
I`ve a App like the iOS 10 Maps-App or maybe like the Home-Screen with Control Center. For example take a look at the Picture. If you open the Control Center the shadow of the background changes to black & transparent. How can i access this layer or subview and change the color from this shadow to another in my App. Maybe to red or white?
EDIT:
Maybe directly with the Framework.
https://github.com/iosphere/ISHPullUp
You can use UIVisualEffectView like this:
Obj-C:
UIBlurEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark];//SELECT STYLE OF YOUR CHOICE
UIVisualEffectView *blurEffectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];
blurEffectView.frame = self.view.bounds;//view Will be YOUR_VIEW
blurEffectView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self.view addSubview:blurEffectView];//This add Blur view to your view
Swift:
let blurEffect = UIBlurEffect(style: UIBlurEffectStyle.dark)
let blurEffectView = UIVisualEffectView(effect: blurEffect)
blurEffectView.frame = self.view.bounds
blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
self.view.addSubview(blurEffectView)
Sometimes open your eyes and you will find what you want. 😕 If you using the same Framework there is one variable you can change. In the sample of the Framework you can got to the "BottomVC" and add the following line to your viewDidLoad().
weak var pullUpController: ISHPullUpViewController!
override func viewDidLoad() {
super.viewDidLoad()
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTapGesture))
topView.addGestureRecognizer(tapGesture)
handleView.arrowSize = CGSize(width: 1 , height: 2)
//This line change the default 40% black to a 70% white.
pullUpController.dimmingColor = UIColor.white().withAlphaComponent(0.7)
}
The "Shadow" is just a normal View. Here you can see how the author has implemented this.
Followed this question to get real time blur effect in Navigation Bar:
func addBlurEffect() {
var bounds = self.navigationController?.navigationBar.bounds as CGRect!
var visualEffectView = UIVisualEffectView(effect: UIBlurEffect(style: .Light)) as UIVisualEffectView
visualEffectView.frame = bounds
visualEffectView.autoresizingMask = .FlexibleHeight | .FlexibleWidth
self.navigationController?.navigationBar.addSubview(visualEffectView)
}
But the status bar remains translucent:
How to fix it?
Debugging:
print(self.navigationController?.navigationBar.bounds)
// Returns (0.0, 0.0, 320.0, 44.0)
print(UIApplication.sharedApplication().statusBarFrame)
// Returns (0.0, 0.0, 320.0, 20.0)
It's partly because you set the visual effect view's frame to the navigation bar's bounds. What you see in the screen shot are the navigation bar's bounds. So, you might be able to compensate by giving your visual effect view a different frame, i.e. move its origin up 20 points and increase its height.
It's a little unclear to me, though, why you don't just make the navigation bar translucent. Navigation bar translucency is the blur effect, and it is supported. What you're doing — adding a subview to the navigation bar — is not.
Managed to get it working adding this:
bounds.offsetInPlace(dx: 0.0, dy: -20.0)
bounds.size.height = bounds.height + 20.0
As for this problem, I have modified Kampai's earlier answer, which the original was posted here.
The code below would blur the status bar as well as navigation bar.
Swift 4:
func navigationBarBlur() {
let bounds = CGRect(x: 0.0, y: -20.0, width: UserDefaults.screenWidth, height: (self.navigationController?.navigationBar.bounds.size.height)! + 20.0)
let visualEffectView = UIVisualEffectView(effect: UIBlurEffect(style: .dark))
self.visualEffectView = visualEffectView
visualEffectView.frame = bounds
visualEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
self.navigationController?.navigationBar.addSubview(visualEffectView)
}
I have a UIScrollView which covers one of my views entirely. I have added a background image to this same view which scrolls at a slightly different rate to the actual UIScrollView. This works absolutely fine unless I use the back swipe gesture or tap the 'Back' button. What happens is the image covers the view for about 0.5 seconds before disappearing, and it looks pretty bad.
This is what I mean:
As you can see, that is mid way through the gesture, and rather than being able to see the previous view, you just see the part of the image that is off to the left. It doesn't happen on the first page of the UIScrollView so I guess it's because the image is overlapping the previous view.
Here is my code:
override func viewDidLoad() {
let pagesScrollViewSize = scrollView.frame.size
scrollView.contentSize = CGSize(width: pagesScrollViewSize.width * CGFloat(images.count), height: pagesScrollViewSize.height)
backgroundImageView.frame = CGRect(x: 0, y: 0, width: 2484, height: 736)
backgroundImageView.image = UIImage(named: "SF.png")
var visualEffectView = UIVisualEffectView(effect: UIBlurEffect(style: .Light)) as UIVisualEffectView
visualEffectView.frame = backgroundImageView.bounds
backgroundImageView.addSubview(visualEffectView)
view.addSubview(backgroundImageView)
view.sendSubviewToBack(backgroundImageView)
scrollView.backgroundColor = UIColor.clearColor()
}
func scrollViewDidScroll(scrollView: UIScrollView) {
loadVisiblePages()
var factor = scrollView.contentOffset.x / (scrollView.contentSize.width - 414);
if factor < 0 {
factor = 0
}
if factor > 1 {
factor = 1
}
var frame: CGRect = backgroundImageView.frame
frame.origin.x = factor * (414 - backgroundImageView.frame.size.width)
backgroundImageView.frame = frame
}
Anyone have any suggestions?
You have to add the following in your viewDidLoad function:
self.view.clipsToBounds = true or scrollView.clipsToBounds = true if you just want to clip the subviews in your UIScrollView.
Setting this value to true causes subviews to be clipped to the bounds of the receiver. If set to false, subviews whose frames extend beyond the visible bounds of the receiver are not clipped. The default value is false.
From Apple' doc : https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIView_Class/index.html#//apple_ref/occ/instp/UIView/clipsToBounds
I'm using an image view to display an image in my nav bar. The problem is that I can't set it to the center correctly because of the back button. I checked the related questions and had almost the same problem earlier that I solved, but this time I have no idea.
Earlier I solved this problem with fake bar buttons, so I tried to add a fake bar button to the right (and left) side, but it doesn't helped.
- (void) searchButtonNavBar {
CGRect imageSizeDummy = CGRectMake(0, 0, 25,25);
UIButton *dummy = [[UIButton alloc] initWithFrame:imageSizeDummy];
UIBarButtonItem
*searchBarButtonDummy =[[UIBarButtonItem alloc] initWithCustomView:dummy];
self.navigationItem.rightBarButtonItem = searchBarButtonDummy;
}
- (void)setNavBarLogo {
[self setNeedsStatusBarAppearanceUpdate];
CGRect myImageS = CGRectMake(0, 0, 44, 44);
UIImageView *logo = [[UIImageView alloc] initWithFrame:myImageS];
[logo setImage:[UIImage imageNamed:#"color.png"]];
logo.contentMode = UIViewContentModeScaleAspectFit;
self.navigationItem.titleView = logo;
[[UIBarButtonItem appearance] setTitlePositionAdjustment:UIOffsetMake(0.0f, 0.0f) forBarMetrics:UIBarMetricsDefault];
}
I think it should be workin fine because in this case the titleView has bar buttons on the same side. Is there any explanation why it worked with bar buttons that was created programmatically but doesn't works with the common back button?
UINavigationBar automatically centers its titleView as long as there is enough room. If the title isn't centered that means that the title view is too wide to be centered, and if you set the backgroundColor if your UIImageView you'll see that's exactly what is happening.
The title view is too wide because that navigation bar will automatically resize the title to hold its content, using -sizeThatFits:. This means that your title view will always be resized to the size of your image.
Two possible fixes:
The image you're using is way too big. Use a properly sized 44x44 pt image with 2x and 3x versions.
Wrap UIImageView inside of a regular UIView to avoid resizing.
Example:
UIImageView* imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"test.jpeg"]];
imageView.contentMode = UIViewContentModeScaleAspectFit;
UIView* titleView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 44, 44)];
imageView.frame = titleView.bounds;
[titleView addSubview:imageView];
self.navigationItem.titleView = titleView;
An example in Swift 3 version of Darren's second way:
let imageView = UIImageView(image: UIImage(named: "test"))
imageView.contentMode = UIViewContentMode.scaleAspectFit
let titleView = UIView(frame: CGRect(x: 0, y: 0, width: 44, height: 44))
imageView.frame = titleView.bounds
titleView.addSubview(imageView)
self.navigationItem.titleView = titleView
I suggest you Override the function - (void)setFrame:(CGRect)fram
like this:
- (void)setFrame:(CGRect)frame {
[super setFrame:frame]; //systom function
self.center = CGPointMake(self.superview.center.x, self.center.y); //rewrite function
}
so that the titleView.center always the right location
Don't use titleView.
Just add your image to navigationController.navigationBar
CGRect myImageS = CGRectMake(0, 0, 44, 44);
UIImageView *logo = [[UIImageView alloc] initWithFrame:myImageS];
[logo setImage:[UIImage imageNamed:#"color.png"]];
logo.contentMode = UIViewContentModeScaleAspectFit;
logo.center = CGPointMake(self.navigationController.navigationBar.width / 2.0, self.navigationController.navigationBar.height / 2.0);
logo.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin;
[self.navigationController.navigationBar addSubview:logo];
Qun Li's worked perfectly for me. Here's the swift 2.3 code:
override var frame: CGRect {
set(newValue) {
super.frame = newValue
if let superview = self.superview {
self.center = CGPoint(x: superview.center.x, y: self.center.y)
}
}
get {
return super.frame
}
}
If you're using a custom view from a nib, be sure to disable auto-layout on the nib file.
I created a custom UINavigationController that after dropping in, the only thing you have to do is call showNavBarTitle(title:font:) when you want to show and removeNavBarTitle() when you want to hide:
class NavigationController: UINavigationController {
private static var mTitleFont = UIFont(name: <your desired font (String)> , size: <your desired font size -- however, font size will automatically adjust so the text fits in the label>)!
private static var mNavBarLabel: UILabel = {
let x: CGFloat = 60
let y: CGFloat = 7
let label = UILabel(frame: CGRect(x: x, y: y, width: UIScreen.main.bounds.size.width - 2 * x, height: 44 - 2 * y))
label.adjustsFontSizeToFitWidth = true
label.minimumScaleFactor = 0.5
label.font = NavigationController.mTitleFont
label.numberOfLines = 0
label.textAlignment = .center
return label
}()
func showNavBarLabel(title: String, font: UIFont = mTitleFont) {
NavigationController.mNavBarLabel.text = title
NavigationController.mNavBarLabel.font = font
navigationBar.addSubview(NavigationController.mNavBarLabel)
}
func removeNavBarLabel() {
NavigationController.mNavBarLabel.removeFromSuperview()
}
}
I find the best place to call showNavBarTitle(title:font:) and removeNavBarTitle() are in the view controller's viewWillAppear() and viewWillDisappear() methods, respectively:
class YourViewController: UIViewController {
func viewWillAppear() {
(navigationController as! NavigationController).showNavBarLabel(title: "Your Title")
}
func viewWillDisappear() {
(navigationController as! NavigationController).removeNavBarLabel()
}
}
1) You can try setting your image as UINavigationBar's background image by calling
[self.navigationController.navigationBar setBackgroundImage:[UIImage imageNamed:#"color.png"] forBarMetrics:UIBarMetricsDefault];
inside the viewDidLoad method.
That way it will be always centered, but if you have back button with long title as left navigation item, it can appear on top of your logo. And you should probably at first create another image with the same size as the navigation bar, then draw your image at its center, and after that set it as the background image.
2) Or instead of setting your image view as titleView, you can try simply adding at as a subview, so it won't have the constraints related to right and left bar button items.
In Swift, this is what worked for me however it´s not the best solution (basically, add it up to navigationBar):
let titleIV = UIImageView(image: UIImage(named:"some"))
titleIV.contentMode = .scaleAspectFit
titleIV.translatesAutoresizingMaskIntoConstraints = false
if let navigationController = self.navigationController{
navigationController.navigationBar.addSubview(titleIV)
titleIV.centerXAnchor.constraint(equalTo:
navigationController.navigationBar.centerXAnchor).isActive = true
titleIV.centerYAnchor.constraint(equalTo: navigationController.navigationBar.centerYAnchor).isActive = true
}
else{
view.addSubview(titleIV)
titleIV.topAnchor.constraint(equalTo: view.topAnchor, constant: UIApplication.shared.statusBarFrame.height).isActive = true
titleIV.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
}
Extending Darren's answer, a fix for me was to return a sizeThatFits with the UILabel size. It turns out that this is called after layoutSubViews so the label has a size.
override func sizeThatFits(_ size: CGSize) -> CGSize {
return CGSize(width: titleLabel.frame.width + titleInset*2, height: titleLabel.frame.height)
}
Also note that I have + titleInset*2 because Im setting the horizontal constraints like so:
titleLabel.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: titleInset),
titleLabel.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -titleInset)