In my main UIViewController embed in UINavigationController I have add an UILabel to a navigationBar using that code:
if let navigationBar = self.navigationController?.navigationBar {
let frameDomanda = CGRect(x: navigationBar.frame.width/2 - domandaN.frame.width/2, y: -10, width: domandaN.frame.width, height: navigationBar.frame.height)
domandaN.frame = frameDomanda
let secondLabel = UILabel(frame: secondFrame)
secondLabel.text = "Second"
navigationBar.addSubview(domandaN)
}
But when I change Controller the UILabel is fixed. It doesn't disappear so I've added that code:
override func viewDidDisappear(animated: Bool) {
domandaN.removeFromSuperview()
}
It works but I want it to disappear immediately after the press of the back button. Not like this image:
(The "example" text goes away later)
Just add it in viewWillDisappear instead this:
override func viewWillDisappear(animated: Bool) {
domandaN.removeFromSuperview()
}
For the animation parameter:
If true, the disappearance of the view is being animated.
You can use viewWillDisappear, and don't forget to call super:
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
// you code here
}
Related
I add an image to my view by the following code if the count is zero and remove it otherwise:
var coverImageView = UIImageView()
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if count == 0 {
let coverImage = UIImage(named: "AddFirstRecord")!
coverImageView = UIImageView(image: coverImage)
coverImageView.frame = CGRect(x: 20, y: 5, width: tableView.frame.width-20, height: 100)
view.addSubview(coverImageView)
} else {
DispatchQueue.main.async {
self.coverImageView.removeFromSuperview()
}
}
}
The problem is that it adds the image to the view, but removeFromSuperview does not work. (I made sure that it reaches to the else condition by debugging). I did the process in the main queue as well to be sure that the problem does not relate to threads. I wonder where is the origin of the issue?
In viewWillAppear the view still is not prepared completely to view. So removingFromSuperview does not have any effects. Instead, we should do the action inside viewDidLayoutSubviews:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if fetchedResultsController.fetchedObjects?.count == 0 {
let coverImage = UIImage(named: "AddFirstRecord")!
coverImageView.image = coverImage
coverImageView.frame = CGRect(x: 20, y: 5, width: tableView.frame.width-20, height: 100)
view.addSubview(coverImageView)
} else {
coverImageView.removeFromSuperview()
}
}
From Apple Documentation :
viewDidLayoutSubviews()
Called to notify the view controller that its
view has just laid out its subviews.
Your view controller can override this method to make changes after
the view lays out its subviews. The default implementation of this
method does nothing.
This question already has answers here:
How to display UIView over keyboard in iOS
(7 answers)
Closed 5 years ago.
I need to present a help screen that overlays an open keyboard - the help screen should dim the whole view underneath and keep just a small hole with full transparency to "highlight" that piece. The point is to provide some information about several view components while highlighting them. Without a keyboard, I could just put a view at top of the hierarchy, but in this case the UI uses a keyboard with a custom input accessory that needs to be visible.
I tried to insert a new UIWindow and put it above all the UIWindows:
class CustomTextField: UITextField {
override var canResignFirstResponder: Bool {
return false
}
}
class ViewController: UIViewController {
var textField: UITextField = CustomTextField()
override func viewDidAppear(_ animated: Bool) {
view.backgroundColor = .white
super.viewDidAppear(animated)
textField.frame = CGRect(x: 0, y: 0, width: 200, height: 50)
view.addSubview(textField)
textField.backgroundColor = UIColor.gray
textField.becomeFirstResponder()
DispatchQueue.main.asyncAfter(wallDeadline: .now() + 1) {
self.window.windowLevel = 100000002.0 // based on experiments with UIApplication.shared.windows this should be the top most window
let controller = UIViewController()
controller.view.backgroundColor = UIColor.black.withAlphaComponent(0.5)
self.window.rootViewController = controller
self.window.makeKeyAndVisible()
}
}
let window = UIWindow(frame: UIScreen.main.bounds)
}
But there are two problems with this approach:
The keyboard gets hidden as soon as the window becomes key and visible.
Even when using windowLevel = 100000002.0 it seems that the keyboard is above the window (the keyboard gets animated, so while hiding, I can see that its above my window).
Any ideas how to deal with these two problems? Is it even possible?
OK, as pointed out by #Krunal, this is kind of a duplicate of this question. The trick there is to add the overlay view to the window in which keyboard is (which happens to be the UIApplication.shared.windows.last):
class ViewController: UIViewController {
var textField: UITextField = UITextField()
override func viewDidAppear(_ animated: Bool) {
view.backgroundColor = .white
super.viewDidAppear(animated)
textField.frame = CGRect(x: 0, y: 0, width: 200, height: 50)
view.addSubview(textField)
textField.backgroundColor = UIColor.gray
textField.becomeFirstResponder()
DispatchQueue.main.asyncAfter(wallDeadline: .now() + 1) {
// this does the trick
let customView = UIView(frame: self.view.bounds)
customView.backgroundColor = UIColor.black.withAlphaComponent(0.5)
customView.layer.zPosition = CGFloat(Float.greatestFiniteMagnitude)
UIApplication.shared.windows.last?.addSubview(customView)
}
}
}
Currently have a popup view which sets 3 picker values by tapping on the SET button:
However, I want to remove the SET button altogether, and have the picker values set upon tapping outside of the popup, which in turn hides the popup.
Here is the current code:
// function for selecting picker values
func pickerDidSet() {
let focusPeriodChoice = focusPeriodDataSource[pickerView.selectedRow(inComponent: 0)]
let breakPeriodChoice = breakPeriodDataSource[pickerView.selectedRow(inComponent: 1)]
let repeatCountChoice = repeatCountDataSource[pickerView.selectedRow(inComponent: 2)]
persistPickerChoice(focusPeriodChoice, dataType: .focusPeriod)
persistPickerChoice(breakPeriodChoice, dataType: .breakPeriod)
persistPickerChoice(repeatCountChoice, dataType: .repeatCount)
timerSummaryLabel.text = "\(focusPeriodChoice)m • \(breakPeriodChoice)m • \(repeatCountChoice)x"
UIView.animate(withDuration: 0.2, animations: { self.pickerContainerView.alpha = 0.0 }, completion: { finished in
self.pickerContainerView.isHidden = true
})
}
// Open popup, by tapping gear icon
#IBAction func openSettings(_ sender: Any) {
pickerView.selectRow(pickerChoiceIndex(forDataType: .focusPeriod), inComponent: 0, animated: false)
pickerView.selectRow(pickerChoiceIndex(forDataType: .breakPeriod), inComponent: 1, animated: false)
pickerView.selectRow(pickerChoiceIndex(forDataType: .repeatCount), inComponent: 2, animated: false)
self.pickerContainerView.isHidden = false
UIView.animate(withDuration: 0.2) {
self.pickerContainerView.alpha = 1.0
}
}
// Once pickers have been set, display the summary
private func configureSummaryLabel() {
let focusPeriodChoice = pickerChoice(forDataType: .focusPeriod)
let breakPeriodChoice = pickerChoice(forDataType: .breakPeriod)
let repeatCountChoice = pickerChoice(forDataType: .repeatCount)
timerSummaryLabel.text = "\(focusPeriodChoice)m • \(breakPeriodChoice)m • \(repeatCountChoice)x"
}
// Setting the picker “SET” button
private func addPickerSetButton(atX x: CGFloat, centerY: CGFloat) {
pickerSetButton.frame = CGRect(x: x, y: 0, width: 40, height: 20)
pickerSetButton.center = CGPoint(x: pickerSetButton.center.x, y: centerY)
pickerSetButton.setTitle("SET", for: .normal)
pickerSetButton.setTitleColor(UIColor.white, for: .normal)
pickerSetButton.setTitleColor(UIColor.darkGray, for: .highlighted)
pickerSetButton.titleLabel?.font = UIFont.boldSystemFont(ofSize: 17)
pickerSetButton.addTarget(self, action: #selector(pickerDidSet), for: .touchUpInside)
pickerHeaderView.addSubview(pickerSetButton)
}
If the Previous Black View is you default view of ViewController then all you need is to implemented below method.
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
// Check that the touched view is your background view
if touches.first?.view == self.view {
// Do What Every You want to do
}
}
Detail
Every ViewController has a default view object. As in your case the black overlay displaying behind your popup seems like the default view of that view controller. If that black overlay is not your default view then create and IBOutlet of that view which is black opacified in color. And then in the above method where you are check that which view is touch check that if touched view is your black view or not.
Suppose you black view's IBOutlet is backgroundView then the above check will be something like this.
if touches.first?.view == self.backgroundView {
//It means you have touched outside the pop and out side the pop there is only your backgroundView.
//Here you should do exactly the same which you were doing when `SET` button was clicked.
}
touchesBegan method didn't work if touched object is a button so as per you logic.
You need to check if the PickerView is visible then disable it instead of firing the other feature of that button.
Example.
Create a boolean variable named isPickerViewVisible in your class and when picker view is going to visible make it true and when picker view is getting hide just make it false. There might be an IBAction for that red button.
#IBAction didTapButton(_ sender: Any){
//Here you need to check if pickerView is open then disable it. I don't know what logic you have implemented to show picker view.
if isPickerViewVisible {
self.pickerDidSet()
}else {
//Here you should do the task that you do on clicking this button.
}
}
I have a ViewController embeded in a navigationBar. I want the back button in the navigation bar to have the following effect :
if a condition is fullfilled, apply the normal behavior of the back button
if the condition is not fullfilled, stay and remain on the same VC to do something else
Try like this :-
override func viewDidLoad() {
let transparentButton = UIButton()
transparentButton.frame = CGRectMake(0, 0, 50, 40)
transparentButton.backgroundColor = UIColor.orangeColor()
transparentButton.addTarget(self, action:"backAction:", forControlEvents:.TouchUpInside)
self.navigationController?.navigationBar.addSubview(transparentButton)
}
And the function is
func backAction(sender:UIButton) {
// check your condition
}
I want to show a custom UIView above my keyboard, when my text field is becoming first responder.
However, it seems that I can show view and keyboard both at the same time?
Is there is a way to overcome it?
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
phoneInputTextField.becomeFirstResponder()
NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardNotification), name: NSNotification.Name.UIKeyboardWillChangeFrame , object: nil)
}
func handleKeyboardNotification(notification: NSNotification) {
guard let userInfo = notification.userInfo,
let frameValue = userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue
else { return }
let customView = UIView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: frameValue.cgRectValue.width + 20))
customView.backgroundColor = UIColor.black
phoneInputTextField.inputView = customView
}
That code shows only keyboard.
You can use inputView and inputAccessoryView both.
inputView is used to assign a some custom view in replacement of UIKeyboard , like you can use UIPickerView , UIDatePicker etc while editing the textField
inputAccessoryView is also used to assign a some custom view but without replacing a UIKeyboard , it renders above the keyboard . like you can use UIToolbar above the keyboard and many other View as per your requirements.
In your case you can use inputAccessoryView
example :
yourTxtField.inputAccessoryView = yourCustomView()