UIViews in swift - uiview

All,
I have an image and then I display it on the screen and then I go to a function to blur the image. Then I run another function to add a box to it. but it doesn't show the blur and the box and this is because of the addSubView and the insertSubView - I presume. Basically I cannot put both the blur and the box on the view. If i uncomment out the addBox it doesn't show the blur. Can anyone help with my understanding of addSubView and InsertSubView (array).
Here is my code :
class ViewController: UIViewController {
var Box : UIView?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let bananaImage : UIImage = UIImage(named: "edify-backgound.png")
var imageV : UIImageView = UIImageView(image: bananaImage)
imageV.frame = CGRectMake(0, 0, bananaImage.size.width, bananaImage.size.height)
imageV.center = self.view.center
self.view.addSubview(imageV)
blur()
//addBox(CGRectMake(200, 300, 30, 30))
}
func addBox(location: CGRect)
{
let newBox = UIView(frame: location)
newBox.backgroundColor = UIColor.clearColor()
self.view.insertSubview(newBox, atIndex: 1)
Box = newBox
}
func blur()
{
var blur = UIVisualEffectView(effect: UIBlurEffect(style: .Light)) as UIVisualEffectView
blur.frame = self.view.frame
self.view.addSubview(blur)
}

Part of the problem is that you have no way of knowing whether addBox is doing anything or not. Here is your code:
let newBox = UIView(frame: location)
newBox.backgroundColor = UIColor.clearColor()
self.view.insertSubview(newBox, atIndex: 1)
A view that consists of nothing but a clear background color is completely invisible. So you see nothing - which, as Sherlock Holmes says, is exactly what you may expect to see.

Related

How create transparent view with with blur effect?

I learn how to create UI and in www find peace of design which I want to repeat it by myself. I can create main view and then add subView with all element like as example below, but I can't create subView with blurred effect like as on example, I am trying to create subview then add other peace of view and add blur but I can create copy like as an example.
What is the correct way to create this view? I can't understand which manipulation I need to do with view for this effect, it is a tricks with alpha of view and blur effect or something else?
I found an excellent tutorial that might help you to create a smooth transparent view with blur effect: https://www.raywenderlich.com/167-uivisualeffectview-tutorial-getting-started
I am solved this task using next approach:
First: Was created gradient layer for subview.
Second: Was added UIVisualEffectView with VibrancyEffect.
How create gradient was used information from this website ( https://www.appcoda.com/cagradientlayer/ )
And for vibrancy effect was used source code from this project ( https://github.com/ide/UIVisualEffects )
My source code:
func createGradientLayer() {
gradientLayer = CAGradientLayer()
gradientLayer.cornerRadius = 10
gradientLayer.frame = self.placeholder.bounds
gradientLayer.locations = [0.0, 0.35]
gradientLayer.colors = [UIColor.blue.cgColor, UIColor.white.cgColor]
self.placeholder.layer.addSublayer(gradientLayer)
}
override func viewDidLoad() {
super.viewDidLoad()
createGradientLayer()
let lightBlur = UIBlurEffect(style: .light)
let lightBlurView = UIVisualEffectView(effect: lightBlur)
lightBlurView.layer.cornerRadius = 10
lightBlurView.layer.masksToBounds = true
placeholder.addSubview(lightBlurView)
lightBlurView.frame.size.height = placeholder.frame.size.height
lightBlurView.frame.size.width = placeholder.frame.size.width
let lightVibrancyView = vibrancyEffectView(forBlurEffectView: lightBlurView)
lightBlurView.contentView.addSubview(lightVibrancyView)
}
fileprivate func vibrancyEffectView(forBlurEffectView blurEffectView:UIVisualEffectView) -> UIVisualEffectView {
let vibrancy = UIVibrancyEffect(blurEffect: blurEffectView.effect as! UIBlurEffect)
let vibrancyView = UIVisualEffectView(effect: vibrancy)
vibrancyView.frame = blurEffectView.bounds
vibrancyView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
return vibrancyView
}
Final example:

Draw a progress that grows

In the following code, I want to draw a progress bar that grows. what should I call at the line marked
// what goes here?
Assume the code is run on the main thread.
class View: UIView {
func updateProgressBar(){
var boxFrame = CGRect(x:10, y:10: width:100, height: 100)
for _ in 0...<10 {
let box = UIView(frame: boxFrame)
box.backgroundColor = .blue
addSubview(box)
// What goes here?
Thread.sleep(forTimeInterval: 2)
boxFrame.origin.x = boxFrame.width
}
}
}
What will be the answer from the following option and why?
setNeedsDisplay()
layer.draw(in: UIGraphicsGetCurrentConntext()!)
draw(bounds)
This approach is incorrect. It should be implemented in another way. such as with DispatchQueue.asyncAfter()

"removeFromSuperview" NEVER work on UIApplication?

How to remove subviews?
I am trying to integrate GIF by creating UIView and UIImageView programmatically.
It works fine to show GIF but when the function of hiding if is called, there is no response.
Here are the codes of both functions.
class CustomLoader: UIView {
static let instance = CustomLoader()
var viewColor: UIColor = .black
var setAlpha: CGFloat = 0.5
var gifName: String = ""
lazy var transparentView: UIView = {
let transparentView = UIView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height))
transparentView.backgroundColor = viewColor.withAlphaComponent(setAlpha)
transparentView.isUserInteractionEnabled = false
return transparentView
}()
lazy var gifImage: UIImageView = {
var gifImage = UIImageView(frame: CGRect(x: 0, y: 0, width: 200, height: 60))
gifImage.contentMode = .scaleAspectFit
gifImage.center = transparentView.center
gifImage.isUserInteractionEnabled = false
gifImage.loadGif(name: gifName)
return gifImage
}()
func showLoaderView() {
self.addSubview(self.transparentView)
self.transparentView.addSubview(self.gifImage)
self.transparentView.bringSubview(toFront: self.gifImage)
UIApplication.shared.keyWindow?.addSubview(transparentView)
}
func hideLoaderView() {
self.transparentView.removeFromSuperview()
}
}
A couple of thoughts:
I’d suggest you add a breakpoint or a logging statement in hideLoaderView and make sure you’re getting to that line.
You should make the init method to this class private to make sure you’re not calling hideLoaderView on some separate instance. When dealing with singletons, you want to make sure you can’t accidentally create another instance.
But I tested your code, and it works fine. Your problem probably rests with where and how you call this (and making init private, you might find where you might be using it inappropriately).
In the comments below, you said:
I simply call the function "CustomLoader().hideLoaderView()" Both are being called technically. What do you mean by "where I using it inappropriately?"
That is the root of the problem.
The CustomLoader() of CustomLoader().hideLoaderView() will create a new instance of CustomLoader with its own transparencyView, etc., which is precisely what the problem is. You’re not hiding the old view that was presented earlier, but trying to hide another one that you just created and was never displayed.
If you instead use that static, e.g. CustomLoader.instance.showLoaderView() and CustomLoader.instance.hideLoaderView(), then the problem will go away. Then you will be hiding the same view that your previously showed.
By the way, a few other unrelated observations:
If this is a singleton or shared instance, the convention would be to call that static property shared, not instance.
By the way, you aren’t using this CustomLoader as a UIView, so I’d not make it a UIView subclass. Don’t make it a subclass of anything.
You would obviously eliminate that self.addSubview(transparentView) line, too.
The bringSubview(toFront:) call is unnecessary.
You should avoid referencing UIScreen.main.bounds. You don’t know if your app might be in multitasking mode (maybe this isn’t an issue right now, but it’s the sort of unnecessary assumption that will cause problems at some later date). Just refer to the bounds of the UIWindow to which you’re adding this. You should also update this frame when you show this view, not when you create it (in case you changed orientation in the intervening time, or whatever).
By the way, using keyWindow is discouraged in iOS 13 and later, so you might eventually want to remove that, too.
When adding the gifImage (which I’d suggest renaming to gifImageView because it’s an image view, not an image), you should not reference the center of its superview. That’s the coordinate of the transparent view in its super view’s coordinate system, which could be completely different than the transparent view’s own coordinate system. In this case, it just happens to work, but it suggests a fundamental misunderstanding of view coordinate systems. Reference the bounds of the transparentView, not its center.
If you’re going to expose viewColor and setAlpha, you should pull the setting of the transparentView’s color out of the lazy initializer and into showLoaderView, at the very least. Right now, if you show the loader once, and then change the color, and try to show it again, you won’t see the new color.
The same issue applies with the gif image. So, I’d move that to the didSet observer.
Thus, pulling this all together:
class CustomLoader{
static let shared = CustomLoader()
private init() { }
var dimmingColor: UIColor = .black
var dimmingAlpha: CGFloat = 0.5
var gifName: String = "" { didSet { gifImage.loadGif(name: gifName) } }
lazy var transparentView: UIView = {
let transparentView = UIView()
transparentView.isUserInteractionEnabled = false
return transparentView
}()
lazy var gifImageView: UIImageView = {
var gifImage = UIImageView(frame: CGRect(x: 0, y: 0, width: 200, height: 60))
gifImage.contentMode = .scaleAspectFit
gifImage.isUserInteractionEnabled = false
return gifImage
}()
func showLoaderView() {
guard let window = UIApplication.shared.keyWindow else { return }
transparentView.frame = window.bounds
transparentView.backgroundColor = dimmingColor.withAlphaComponent(dimmingAlpha)
gifImageView.center = CGPoint(x: transparentView.bounds.midX, y: transparentView.bounds.midY)
transparentView.addSubview(gifImageView)
window.addSubview(transparentView)
}
func hideLoaderView() {
transparentView.removeFromSuperview()
}
}
Why you are using transparentView while you are have a CustomLoader instance view
Try to use this
class CustomLoader: UIView {
static let instance = CustomLoader()
var viewColor: UIColor = .black
var setAlpha: CGFloat = 0.5
var gifName: String = ""
init() {
super.init(frame: UIScreen.main.bounds)
backgroundColor = viewColor.withAlphaComponent(setAlpha)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
lazy var gifImage: UIImageView = {
var gifImage = UIImageView(frame: CGRect(x: 0, y: 0, width: 200, height: 60))
gifImage.backgroundColor = .red
gifImage.contentMode = .scaleAspectFit
gifImage.center = center
gifImage.isUserInteractionEnabled = false
gifImage.loadGif(name: gifName)
return gifImage
}()
func showLoaderView() {
addSubview(self.gifImage)
UIApplication.shared.keyWindow?.addSubview(self)
}
func hideLoaderView() {
removeFromSuperview()
}
}

how to copy one view to another view in Swift

I want to copy one UIView to another view without making it archive or unarchive.
Please help me if you have any solution.
I tried with by making an extension of UIView as already available an answer on Stack over flow. But its crashing when I pass the view with pattern Image Background color.
The code related to my comment below:
extension UIView
{
func copyView() -> UIView?
{
return NSKeyedUnarchiver.unarchiveObjectWithData(NSKeyedArchiver.archivedDataWithRootObject(self)) as? UIView
}
}
I've just tried this simple code in a Playground to check that the copy view works and it's not pointing the same view:
let originalView = UIView(frame: CGRectMake(0, 0, 100, 50));
originalView.backgroundColor = UIColor.redColor();
let originalLabel = UILabel(frame: originalView.frame);
originalLabel.text = "Hi";
originalLabel.backgroundColor = UIColor.whiteColor();
originalView.addSubview(originalLabel);
let copyView = originalView.copyView();
let copyLabel = copyView?.subviews[0] as! UILabel;
originalView.backgroundColor = UIColor.blackColor();
originalLabel.text = "Hola";
originalView.backgroundColor; // Returns black
originalLabel.text; // Returns "Hola"
copyView!.backgroundColor; // Returns red
copyLabel.text; // Returns "Hi"
If the extension wouldn't work, both copyView and originalView would have same backgroundColor and the same would happen to the text of the labels. So maybe there is the possibility that the problem is in other part.
Original Post
func copyView(viewforCopy: UIView) -> UIView {
viewforCopy.hidden = false //The copy not works if is hidden, just prevention
let viewCopy = viewforCopy.snapshotViewAfterScreenUpdates(true)
viewforCopy.hidden = true
return viewCopy
}
Updated for Swift 4
func copyView(viewforCopy: UIView) -> UIView {
viewforCopy.isHidden = false //The copy not works if is hidden, just prevention
let viewCopy = viewforCopy.snapshotView(afterScreenUpdates: true)
viewforCopy.isHidden = true
return viewCopy!
}

How to dim a parent UIView (50% transparent) for login?

I have a view with a Login button. When the button is clicked, I add a view with fields for login. When this happens, I need to dim the parent view. How I do that?
UIViews have a property named mask.
mask will always be on top of the UIView who owns it.
So, your approach should be something like this:
(This is for Swift, but it's easily converted to Obj-c)
self.view.mask = UIView(frame: self.frame)
self.view.mask?.backgroundColor = UIColor.black.withAlphaComponent(0.5)
//Do your work here, block UI, anything you need to, and then...
self.view.mask = nil
Update
Removed Swift 2 refernce as it's not relevant anymore. Just as a curiosity, then the property was called maskView
Add a UIView over the parent view that is initially transparent with a background color of black. When you need to dim it, change the view's alpha to 0.5. This will be 50% transparent.
I would go for a view with white background:
whiteView=[[UIView alloc]initWithFrame:viewToDim.frame];
[whiteView setBackgroundColor:[UIColor whiteColor]];
[whiteView setAlpha:0.5f];
[self.view insertSubview:whiteView aboveSubview:viewToDim];
class UIDecorator: NSObject {
static let sharedInstance = UIDecorator()
private let dimView = UIView()
private let loadingView = MOOverWatchLoadingView(frame: CGRectMake(0, 0, 100, 100),
autoStartAnimation: true)
func showLoadingView() {
if let currentPage = UIApplication.topViewController(){
dimView.frame = currentPage.view.frame
dimView.backgroundColor = UIColor.blackColor()
dimView.alpha = 0.5
currentPage.view.addSubview(dimView)
currentPage.view.userInteractionEnabled = false
loadingView.center = currentPage.view.center
loadingView.backgroundColor = UIColor.clearColor()
currentPage.view.addSubview(loadingView)
}
}
func dismissLocadingView() {
if let currentPage = UIApplication.topViewController(){
currentPage.view.userInteractionEnabled = true
dimView.removeFromSuperview()
loadingView.removeFromSuperview()
}
}
}

Resources