Add insets/margin to Blurred ModalView? - ios

I am trying to open a ModalView with blurred background (but with some space around)
Why does this code ignore the inset/frame command? I can see the blurred image. But it's fullscreen.
PS: This VC is assigned via Storyboard
class InfoViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.setupView()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func setupView() {
// Add some space around the view
self.view.clipsToBounds = true
self.view.frame = UIEdgeInsetsInsetRect(self.view.frame, UIEdgeInsetsMake(20, 10, 10, 10)) // <-- not working?
// Take screenshot from parent VC
let parentVC : UIViewController = self.presentingViewController
UIGraphicsBeginImageContext(parentVC.view.bounds.size)
parentVC.view.drawViewHierarchyInRect(parentVC.view.bounds, afterScreenUpdates:true)
var image:UIImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
// Blur screnshot
image = image.applyBlurWithRadius(20, tintColor: UIColor(white: 1.0, alpha: 0.2), saturationDeltaFactor: 1.3, maskImage: nil)
// Add screenshot to view
let backgroundImageView : UIImageView = UIImageView(image:image)
self.view.addSubview(backgroundImageView)
}
}

Related

Managing Custom UITabBar View

Following this repo, I created a custom "tabBar" via a separate uiview that sits behind the native uitabbarcontroller tabBar. The custom tabBar has rounded corners and a shadow.
Everything works great except in the instances I push/pop a new uiviewcontroller onto/from the embedded uinavigationcontroller stack, where I hide the tabBar.
My issue is smoothly toggling the custom tabBar to hide/show during these instances.
I've set .isHidden = true/false for the custom tabBar when a uiviewcontroller is pushed/popped, and either the custom tabBar disappears too early or appears too late relative to the native uitabbarcontroller tabBar.
Any guidance would be appreciated.
class TabBarViewController: UITabBarController {
let customTabBarView: UIView = {
let view = UIView(frame: .zero)
view.backgroundColor = Constants.style.offWhite
view.layer.cornerRadius = 20
view.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
view.clipsToBounds = true
view.layer.masksToBounds = false
view.layer.shadowColor = UIColor.black.cgColor
view.layer.shadowOffset = CGSize(width: 0, height: -8.0)
view.layer.shadowOpacity = 0.12
view.layer.shadowRadius = 10.0
return view
}()
override func viewDidLoad() {
super.viewDidLoad()
self.tabBar.isHidden = true
self.tabBar.backgroundColor = .clear
self.tabBar.barStyle = .default
self.tabBar.isTranslucent = true
addCustomTabBarView()
hideTabBarBorder()
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
customTabBarView.frame = tabBar.frame
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
var newSafeArea = UIEdgeInsets()
newSafeArea.bottom += customTabBarView.bounds.size.height
self.children.forEach({$0.additionalSafeAreaInsets = newSafeArea})
}
//Function invoked when pushing/popping viewControllers onto/from the embedded navigation stack
func toggleCustomTabBarView(shouldHide: Bool) {
self.customTabBarView.isHidden = shouldHide
DispatchQueue.main.async {
UIView.transition(with: self.view, duration: TimeInterval(UINavigationController.hideShowBarDuration), options: .transitionCrossDissolve, animations: {
})
}
}
func addCustomTabBarView() {
customTabBarView.frame = tabBar.frame
view.addSubview(customTabBarView)
view.bringSubviewToFront(self.tabBar)
}
func hideTabBarBorder() {
let tabBar = self.tabBar
tabBar.backgroundImage = UIImage.from(color: .clear)
tabBar.shadowImage = UIImage()
tabBar.clipsToBounds = true
}
}
extension UIImage {
static func from(color: UIColor) -> UIImage {
let rect = CGRect(x: 0, y: 0, width: 1, height: 1)
UIGraphicsBeginImageContext(rect.size)
let context = UIGraphicsGetCurrentContext()
context!.setFillColor(color.cgColor)
context!.fill(rect)
let img = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return img!
}
}
https://stackoverflow.com/a/65285566/9466631
Couldn't find anything as a solve for the dummy view behind the tabBar, but this new solution worked for me that avoids using the dummy view altogether and adds a CAShapeLayer instead.

The nav bar doesn't clip to the top of iphone x

The Nav bar doesnt go to the top of the screen when rounding the edges on iphone x or up. Is there any way to fix this?
IMAGE(WHAT IT LOOKS LIKE NOW)
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.navigationBar.layer.cornerRadius = 20
self.navigationController?.navigationBar.clipsToBounds = true
self.navigationController?.navigationBar.layer.maskedCorners = [.layerMinXMaxYCorner, .layerMaxXMaxYCorner]
}
}
A default navigation bar has a background view which will be not generated when you apply custom operations on a layer.
Solution
Create a view with a given color, radius corner and dimension
Convert the view to an image
Set the image view to a navigation bar background property
override func viewDidLoad() {
super.viewDidLoad()
let v = UIView(frame: CGRect(x: 0, y: -UIApplication.shared.statusBarFrame.height, width: view.frame.width, height: UIApplication.shared.statusBarFrame.height + (navigationController?.navigationBar.frame.height ?? 0)))
v.backgroundColor = .red
v.layer.cornerRadius = 20
v.layer.maskedCorners = [.layerMinXMaxYCorner, .layerMaxXMaxYCorner]
v.clipsToBounds = true
let i = image(with: v)!
navigationController?.navigationBar.setBackgroundImage(i, for: .default)
}
func image(with view: UIView) -> UIImage? {
UIGraphicsBeginImageContextWithOptions(view.bounds.size, false, 0.0)
defer { UIGraphicsEndImageContext() }
if let context = UIGraphicsGetCurrentContext() {
view.layer.render(in: context)
let image = UIGraphicsGetImageFromCurrentImageContext()
return image
}
return nil
}
You can use xib for add navigation bar for proper navigation bar design. Which is compatible for all devices.
var customNavView: Your_xib_File?
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
navigationViewStup()
}
func navigationViewStup(){
customNavView = Bundle.main.loadNibNamed("NavBar", owner: self, options: nil)?[0] as? NavBarView
customNavView?.frame = (self.navigationController?.navigationBar.bounds)!
customNavView?.tag = 1111
customNavView?.btnVoice.addTarget(self, action: #selector(btnVoicePressed), for: .touchUpInside)
self.navigationController?.navigationBar.addSubview(customNavView!)
}
Or try this,
func position(for bar: UIBarPositioning) -> UIBarPosition {
return .topAttached
}
navigationBar.isTranslucent = false

How do I screenshot a uiview without adding it to the subview?

I have multiple subviews on a parent view, and I need to convert the uiview to a uiimage but of only certain subviews. So I added a tag to the views I needed to take a screenshot of and added it to its own view, but when I try to screenshot that I get a black screen. However, when I use the regular parent view I get a photo with all the subviews.
let viewPic = UIView()
for subview in self.view.subviews {
if(subview.tag == 6) {
viewPic.addSubview(subview)
}
if(subview.tag == 8) {
viewPic.addSubview(subview)
}
}
let picImage = viewPic.getSnapshotImage() //This is a black screen
getSnapshotImage
extension UIView {
public func getSnapshotImage() -> UIImage {
UIGraphicsBeginImageContextWithOptions(self.bounds.size, self.isOpaque, 0)
self.drawHierarchy(in: self.bounds, afterScreenUpdates: false)
let snapshotItem: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return snapshotItem
}
}
First of all, your viewPic doesn't set the frame size so the default will be zero frame which may cause the issue.
Secondly, I tried to use your getSanpshotImage() on my sample project, but I always get the blank image.
Have a look at the demo code, I can get what you want (see the screenshot):
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let viewPic = UIView()
viewPic.frame = self.view.frame
let view1 = UIView()
view1.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
view1.backgroundColor = UIColor.red
viewPic.addSubview(view1)
let view2 = UIView()
view2.frame = CGRect(x: 0, y: 200, width: 100, height: 100)
view2.backgroundColor = UIColor.blue
viewPic.addSubview(view2)
let picImage = viewPic.convertToImage() //This is a black screen
print(picImage)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
extension UIView {
func convertToImage() -> UIImage {
let renderer = UIGraphicsImageRenderer(bounds: bounds)
return renderer.image { rendererContext in
layer.render(in: rendererContext.cgContext)
}
}
}

Spawning UIView every second at random CGPoint in Swift

I am trying to "spawn" a UIView with a random UIColor as its background at a random CGPoint. I am using the code below which compiles fine with no bugs or anything but when it runs in the simulator I click start(the button on the first ViewController) but then go to ViewTwo but nothing happens(no "enemies" are spawned). Thank you for any help.
import UIKit
var randomPoint: CGPoint = CGPoint(x: Int(arc4random()%1000), y: Int(arc4random()%1000))
class ViewController: UIViewController {
#IBOutlet weak var startGameButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
class ViewTwo : UIViewController {
var timer = NSTimer()
func randomColor() -> UIColor {
let red = CGFloat(drand48())
let green = CGFloat(drand48())
let blue = CGFloat(drand48())
return UIColor(red: red, green: green, blue: blue, alpha: 1.0)
}
func spawnEnemy() {
let enemy: UIView = UIView(frame: CGRect(x: 0, y: 0, width: 50, height: 50))
enemy.backgroundColor = randomColor()
enemy.center = randomPoint
self.view.addSubview(enemy)
}
override func viewDidLoad() {
super.viewDidLoad()
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("spawnEnemy"), userInfo: nil, repeats: true)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
Your randomPoint needs to be recalculated in spawnEnemy, and is generating a random x y from 0 to 1000 (and should also be a float) It will likely be off the screen.

flipping view in swift : issues with whole screen flipping + tap gesture only works twice

I would like to create a simple flip effect, but I don't understand the problems I have here :
the whole screen is flipping, not only the view, is there a way to flip the 100,100 square only?
I can only flip twice, then the tap does not work anymore, would you know why?
import UIKit
class ViewController: UIViewController {
var fromOneToTwo : Bool = true
var view1 : UIImageView!
var view2 : UIImageView!
var tap : UITapGestureRecognizer!
func handleTap(tap: UITapGestureRecognizer){
println("1/fromOneToTwo \(fromOneToTwo)")
var v1 = (fromOneToTwo ? self.view1 : self.view2)
var v2 = (fromOneToTwo ? self.view2 : self.view1)
UIView.transitionFromView(v1, toView: v2, duration: 0.5, options: (UIViewAnimationOptions.TransitionFlipFromLeft | UIViewAnimationOptions.CurveEaseInOut) ) { finished in
self.fromOneToTwo = !self.fromOneToTwo
println("2/fromOneToTwo \(self.fromOneToTwo) ")
}
}
func createView( str:String)->UIImageView!{
var img = UIImage(named: str)!
var imgView = UIImageView(frame: CGRectMake(0,0, 200, 200))
imgView.image = img
imgView.sizeToFit()
imgView.userInteractionEnabled = true
imgView.addGestureRecognizer(tap)
return imgView
}
required init(coder aDecoder:NSCoder){
super.init(coder:aDecoder)
tap = UITapGestureRecognizer(target: self, action: "handleTap:")
view1 = createView("imageOnee.png")
view2 = createView("imageTwo.png")
}
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(view1)
view.addSubview(view2)
view.backgroundColor = UIColor.redColor()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
Also, when I try to add the whole code in a custom UIView, and add the custom instance myViewto the ViewController, the tap does not work at all.
I made this work creating a container view for view1 and view2. The tap recognizer is then added to this container view.
class ViewController: UIViewController {
var fromOneToTwo : Bool = true
var view1 : UIImageView!
var view2 : UIImageView!
var container : UIView!
var tap : UITapGestureRecognizer!
func handleTap(tap: UITapGestureRecognizer){
println("1/fromOneToTwo \(fromOneToTwo)")
var v1 = (fromOneToTwo ? self.view1 : self.view2)
var v2 = (fromOneToTwo ? self.view2 : self.view1)
UIView.transitionFromView(v1, toView: v2, duration: 0.5, options: .TransitionFlipFromLeft | .CurveEaseInOut ) { finished in
self.fromOneToTwo = !self.fromOneToTwo
println("2/fromOneToTwo \(self.fromOneToTwo) ")
}
}
func createView( str:String)->UIImageView!{
var img = UIImage(named: str)!
var imgView = UIImageView(frame: CGRectMake(0, 0, 200, 200))
imgView.image = img
imgView.sizeToFit()
return imgView
}
required init(coder aDecoder:NSCoder){
super.init(coder:aDecoder)
tap = UITapGestureRecognizer(target: self, action: "handleTap:")
view1 = createView("imageOnee.png")
container = UIView(frame: CGRectMake(0, 0, view1.bounds.width, view1.bounds.height))
container.userInteractionEnabled = true
container.addGestureRecognizer(tap)
container.addSubview(view1)
view2 = createView("imageTwo.png")
container.addSubview(view2)
}
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(container)
view.backgroundColor = UIColor.redColor()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}

Resources