TextField bottom border swift - ios

I am using storyboard for UI builder, and I added this in viewDidLoad. But the bottom border doesn't go all the way the "EnteredEmail.frame.width" equals the size of the textfield in the storyboard which is iPhone SE
override func viewDidLoad() {
super.viewDidLoad()
let EmailBottomLine = CALayer()
EmailBottomLine.frame = CGRect(x: 0.0, y: EnteredEmail.frame.height-5, width: EnteredEmail.frame.width, height: 5)
EmailBottomLine.backgroundColor = UIColor.black.cgColor
EnteredEmail.layer.addSublayer(EmailBottomLine)
}

Simply you need to move your code to viewDidAppear() instead of viewWilllayoutSubviews().
viewDidAppear(_ animated: Bool)
This is called when the screen is shown to the user. This is a good place to put code where you might need to get the position of elements on the screen and run animations.
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let EmailBottomLine = CALayer()
EmailBottomLine.frame = CGRect(x: 0.0, y: EnteredEmail.frame.height-5, width: EnteredEmail.frame.width, height: 5)
EmailBottomLine.backgroundColor = UIColor.black.cgColor
EnteredEmail.layer.addSublayer(EmailBottomLine)
}

Related

UIView unable to get transparent property

I am trying to add a subview to the window (for using it as side menu). It has a child view which is transparent view. However I am unable to get the transparent property when it runs in simulator.
I am using the following code:
override func viewWillAppear(_ animated: Bool) {
frame = CGRect(x: 0, y:0, width:0, height:0)
frame.size.height = UIScreen.main.bounds.height
frame.size.width = UIScreen.main.bounds.width
sideMenuView.frame = frame
sideMenuTransparentView.isOpaque = false
sideMenuTransparentView.backgroundColor = UIColor.gray.withAlphaComponent(0.5)
UIApplication.shared.keyWindow?.addSubview(sideMenuView)
}
However I am seeing no effect of this to make the view as transparent. What's possibly wrong here and how should I proceed rectifying this?
The weird thing here is that when I replace the lines
sideMenuTransparentView.isOpaque = false
sideMenuTransparentView.backgroundColor = UIColor.gray.withAlphaComponent(0.5)
with
sideMenuView.isOpaque = false
sideMenuView.backgroundColor = UIColor.gray.withAlphaComponent(0.5)
I can see the effect. I am unable to understand what's going in here and how should I correct this.
You seem to have forgotten to add the transparent view to the main sideMenuView.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated) // You need to call super when overriding
frame = CGRect(x: 0, y:0, width:0, height:0)
frame.size.height = UIScreen.main.bounds.height
frame.size.width = UIScreen.main.bounds.width
sideMenuView.frame = frame
sideMenuTransaparentView.frame = yourFrame // required frame
sideMenuTransparentView.isOpaque = false
sideMenuTransparentView.backgroundColor = UIColor.gray.withAlphaComponent(0.5) // 100% transparency
sideMenuView.addSubview(view: sideMenuTransparentView)
UIApplication.shared.keyWindow?.addSubview(sideMenuView)
}
Also, you forgot to call super.

Paging by scrollView incorrect displayed

I don't understand why the iPhone 4,7 is displayed correctly, but on iphone 5,5 is not displayed correctly. I want make paging by ScrollView.
What should I do to be displayed correctly on all devices?
func showScrollView() {
var photoSlides = [Slides]()
for image in photo {
let slide: Slides = Bundle.main.loadNibNamed("Slide", owner: self, options: nil)?.first as! Slides
slide.slideImage.image = image.image
photoSlides.append(slide)
}
setupSlideScrollView(slides: photoSlides)
}
func setupSlideScrollView(slides : [Slides]) {
scrollView.contentSize = CGSize(width: scrollView.frame.width * CGFloat(slides.count), height: 200)
scrollView.isPagingEnabled = true
for i in 0 ..< slides.count {
slides[i].frame = CGRect(x: scrollView.frame.width * CGFloat(i), y: 0, width: scrollView.frame.width, height: scrollView.frame.height)
scrollView.addSubview(slides[i])
}
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let pageIndex = round(scrollView.contentOffset.x/scrollView.frame.width)
pageControl.currentPage = Int(pageIndex)
}
https://yadi.sk/i/ipS5WchP3aRtZ9 - correctly (iPhone 8)
https://yadi.sk/i/SPmriRFn3aRtgL - not correctly (iPhone 8 Plus)
If you have used storyboard or xib to design your UI, and then for some portion of your screen you want frame size to calculate frame of other controls then you have to use layoutIfNeeded method on that control. i.e in your case you can do something like below
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
scrollView.layoutIfNeeded()
// THEN CALL YOUR FUNCTION WHICH SETUP YOUR OTHER VIEWS
showScrollView()
}

Radial Gradience Colors Not Updating in UIView

I am attempting to use radial gradience within my app on a background UIView. My issue comes to play, where I want to update the view colors of the gradience multiple times. I have no errors with my code, but I can't seem to figure out how to get around this.
What I have tried is reloading the Input Views within the regular UIView as-well as the gradience class; remove the subview of the uiview, and adding a new view to the screen, which worked for only change of set colors; and I have looked over the internet, but can't seem to resolve this. All I want is for the UIView to update its colors based on the new color parameters I give it.
Here is my radial gradience code:
import UIKit
class RadialGradient: UIView {
var innerColor = UIColor.yellow
var outterColor = UIColor.red
override func draw(_ rect: CGRect) {
let colors = [innerColor.cgColor, outterColor.cgColor] as CFArray
let endRadius = min(frame.width, frame.height)
let center = CGPoint(x: bounds.size.width/2, y: bounds.size.height/2)
let gradient = CGGradient(colorsSpace: nil, colors: colors, locations: nil)
UIGraphicsGetCurrentContext()!.drawRadialGradient(gradient!,
startCenter: center,
startRadius: 0.0,
endCenter: center,
endRadius: endRadius,
options: CGGradientDrawingOptions.drawsAfterEndLocation)
}
}
Here is where I am using it:
import UIKit
class TestIssuesVC: UIViewController {
var check : Bool = false
#IBAction func buttonClicked(_ sender: Any) {
if check == true {
backgroundsetting.removeFromSuperview()
print("Why wont you change to purple and black?????")
cheapFix(inner: UIColor.purple, outter: UIColor.black)
} else {
backgroundsetting.removeFromSuperview()
cheapFix(inner: UIColor.red, outter: UIColor.blue)
check = true
}
}
func cheapFix(inner: UIColor, outter: UIColor) {
let backgroundsetting = RadialGradient()
backgroundsetting.innerColor = inner
backgroundsetting.outterColor = outter
backgroundsetting.frame = (frame: CGRect(x: self.view.frame.size.width * 0, y: self.view.frame.size.height * 0, width:self.view.frame.size.width, height: self.view.frame.size.height))
self.view.addSubview(backgroundsetting)
self.view.sendSubview(toBack: backgroundsetting)
self.reloadInputViews()
}
let backgroundsetting = RadialGradient()
override func viewWillAppear(_ animated: Bool) {
backgroundsetting.innerColor = UIColor.green
backgroundsetting.outterColor = UIColor.red
backgroundsetting.frame = (frame: CGRect(x: self.view.frame.size.width * 0, y: self.view.frame.size.height * 0, width:self.view.frame.size.width, height: self.view.frame.size.height))
self.view.addSubview(backgroundsetting)
self.view.sendSubview(toBack: backgroundsetting)
self.reloadInputViews()
}
}
I see two things.
Your cheapFix method never updates the backgroundsetting property. It creates its own local variable of the same name. So you are actually adding new views over and over but each is sent to the back so you only ever see the first one. This is why nothing ever appears to change.
None of that is necessary. Simply create one RadialGradient view. When you want its colors to change, simply update its colors. That class needs to be fixed so it redraws itself when its properties are updated.
Make the following change to the two properties in your RadialGradient class:
var innerColor = UIColor.yellow {
didSet {
setNeedsDisplay()
}
}
var outterColor = UIColor.red {
didSet {
setNeedsDisplay()
}
}
Those changes will ensure the view redraws itself when its colors are updated.

SFSafariViewController NOT fullscreen / content presented on top

I'm making a very simple app for a demo and am trying to present a webpage using SFSafariViewController (I need to use SF versus WKWebView so to be able to access cookies).
I would really like to present the User with some UI buttons, but I've been unable to pull it off.
I tried this snippet (placed in the completion callback of presentViewController():
let width: CGFloat = 66
let x: CGFloat = self.view.frame.width - width
// It can be any overlay. May be your logo image here inside an imageView.
let overlay = UIView(frame: CGRect(x: x, y: 20, width: width, height: 44))
overlay.backgroundColor = UIColor.blackColor().colorWithAlphaComponent(0.5)
svc.view.addSubview(overlay)
... outlined in this post. In their case, they're attempting to cover the reload button with a small view. Regardless of the use-case, for me the view immediately disappears when I load SFSafariViewController (I can see it for a moment and it disappears).
I was thinking about presenting the button in an .OverContext modal, but then the User would be unable to interact with the SFSafariViewController, which also doesn't work.
Here's essentially what I'm after (pardon the gross, quick mockup) ... basically, SafariViewController with a view presented over it (see bottom) ... the transparency is just to show that it's being presented over Safari).
Any recommendations are greatly appreciated.
Figured it out ... there's likely some slight race condition going on that was preventing the recommended "draw a rectangle" code from working as desired. What I did:
Subclassed SFSafariWebViewController
In viewDidAppear, implemented a slight delay using NSTimer that draws any additional view elements
This also ended up helping me hide the status bar, which was giving me issues (see mockup).
Here's the relevant code:
import UIKit
import SafariServices
class MySafariVC: SFSafariViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
var frame = self.view.frame
let OffsetY: CGFloat = 44
frame.origin = CGPoint(x: frame.origin.x, y: frame.origin.y - OffsetY)
frame.size = CGSize(width: frame.width, height: frame.height + (1 * OffsetY))
self.view.frame = frame
NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "drawNavBar", userInfo: nil, repeats: false)
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
print("i laid out my subviews")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func prefersStatusBarHidden() -> Bool {
return true
}
func drawNavBar() {
let height: CGFloat = 44
let y: CGFloat = self.view.frame.height - height
// It can be any overlay. May be your logo image here inside an imageView.
let overlay = UIView(frame: CGRect(x: 0, y: y, width: self.view.frame.width, height: height))
overlay.backgroundColor = UIColor.blackColor().colorWithAlphaComponent(0.9)
self.view.addSubview(overlay)
}
}

How to switch custom in-app keyboards

Recently I learned to make custom in-app keyboards. Now I want to be able to swap between multiple custom keyboards. However, resetting the textField.inputView property does not seem to work.
I recreated a simplified version of this problem in the following project. The UIViews represent actual custom keyboards.
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var textField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
let blueInputView = UIView(frame: CGRect(x: 0, y: 0, width: 0, height: 300))
blueInputView.backgroundColor = UIColor.blueColor()
textField.inputView = blueInputView
textField.becomeFirstResponder()
}
#IBAction func changeInputViewButtonTapped(sender: UIButton) {
let yellowInputView = UIView(frame: CGRect(x: 0, y: 0, width: 0, height: 300))
yellowInputView.backgroundColor = UIColor.yellowColor()
// this doesn't cause the view to switch
textField.inputView = yellowInputView
}
}
Running this gives what I would initially expect: a blue input view pops up.
But when I tap the button to switch to the yellow input view, nothing happens. Why? What do I need to do to get this to work?
After a little more experimenting I have the solution now. I needed to resign the first responder and then set it again. Any first responder that is a subview of the top view can be resigned indirectly by calling endEditing.
#IBAction func changeInputViewButtonTapped(sender: UIButton) {
let yellowInputView = UIView(frame: CGRect(x: 0, y: 0, width: 0, height: 300))
yellowInputView.backgroundColor = UIColor.yellowColor()
// first do this
self.view.endEditing(true)
// or this
//textField.resignFirstResponder()
textField.inputView = yellowInputView
textField.becomeFirstResponder()
}
Thanks to this and this answer for the ideas.

Resources