I am experimenting not using storyboards and just writing the UI in code. I have the button attributes, i added to the subview to the viewDidLoad and also set up the constraints. I should be seeing a button in the middle of the screen.
class ViewController: UIViewController {
var setupButton: UIButton = {
let button = UIButton(type: .system)
button.backgroundColor = UIColor(r: 80, g: 101, b: 161, a: 256)
button.setTitle("Button", for: .normal)
button.setTitleColor(UIColor.white, for: .normal)
button.translatesAutoresizingMaskIntoConstraints = false
button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 18)
return button
}()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
view.addSubview(setupButton)
coolButton()
}
func coolButton() {
setupButton.centerXAnchor.constraint(equalTo: view.centerXAnchor)
setupButton.centerYAnchor.constraint(equalTo: view.centerYAnchor)
setupButton.widthAnchor.constraint(equalTo: view.widthAnchor, constant: -24)
setupButton.heightAnchor.constraint(equalToConstant: 150)
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
extension UIColor {
convenience init(r: CGFloat, g: CGFloat, b: CGFloat, a: CGFloat) {
self.init(red: r/255, green: g/255, blue: b/255, alpha: a/255)
}
}
From NSLayoutConstraint docs:
Note that only active constraints affect the calculated layout.
For newly created constraints, the active property is NO by default.
You just have to set the isActive property to true for your constraints.
setupButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
setupButton.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
setupButton.widthAnchor.constraint(equalTo: view.widthAnchor, constant: -24).isActive = true
setupButton.heightAnchor.constraint(equalToConstant: 150).isActive = true
Related
I am using UIHostingController in one of the apps I'm working on and I have a problem. The embedded SwiftUI View changes its' height dynamically, but I can't seem to get the grasp on how to update it in the view it is embedded in.
The problem doesn't seem to be in the implementation as even the most basic one has this issue.
The UIView is written like this:
var hostingController = UIHostingController(rootView: GrowingView())
override func viewDidLoad() {
super.viewDidLoad()
prepareHostingController()
}
func prepareHostingController() {
view.addSubview(hostingController.view)
hostingController.view.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
hostingController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
hostingController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),
hostingController.view.topAnchor.constraint(equalTo: view.topAnchor, constant: 100)
])
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
}
}
and the SwiftUI View is like this:
struct GrowingView: View {
#State var height: CGFloat = 100
var body: some View {
Button(action: tap) {
Rectangle()
.foregroundColor(.red)
.frame(height: height)
}
}
func tap() {
height = 200
}
}
Is there anything obvious I'm missing or is this just the behaviour of the UIHostingController which I can do nothing about? It seems like the latter shouldn't be the case.
I have 5 UITextFields, everytime I clicked on the textfield, keyboard appeared. when user touch outside of the textfield, keyboard will hide. However, there is one special textField is for Pop Up. When Pop up appear, the previous textfield couldn't hide the keyboard. How am I gonna hide the keyboard first, and then show the pop up?
func textFieldDidBeginEditing(_ textField: UITextField) {
if textField == self.customerAddress{
scrollView.setContentOffset(CGPoint(x: 0,y:5), animated: true)
}
else if textField == self.district{
textField.resignFirstResponder()
scrollView.setContentOffset(CGPoint(x: 0,y:20), animated: true)
visualEffectView.isHidden = false
districtpicker.selectRow(3, inComponent: 0, animated: false)
self.view.addSubview(districtPopUp)
districtPopUp.center = self.subView.convert(CGPoint(x:subView.frame.size.width/2,y:subView.frame.size.height/3), to: subView)
districtPopUp.transform = CGAffineTransform.init(scaleX: 1.3, y: 1.3)
UIView.animate(withDuration: 0.4, animations: {
self.visualEffectView.alpha = 0.5
self.districtPopUp.alpha = 1
self.districtPopUp.transform = CGAffineTransform.identity
})
}
}
#IBAction func districtPopDismiss(_ sender: UIButton) {
scrollView.setContentOffset(CGPoint(x: 0,y:-64), animated: true)
UIView.animate(withDuration: 0.3, animations: {
self.districtPopUp.transform = CGAffineTransform.init(scaleX: 1.3, y: 1.3)
self.visualEffectView.alpha = 1
}) { (success) in
self.districtPopUp.removeFromSuperview()
}
self.visualEffectView.isHidden = true
}
func textFieldDidEndEditing(_ textField: UITextField) {
textField.resignFirstResponder()
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
scrollView.setContentOffset(CGPoint(x: 0,y:-64), animated: true)
textField.resignFirstResponder()
return true
}
override func viewDidLoad() {
super.viewDidLoad()
let tapGesture: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(CustomerViewController.hideKeyboard))
subView.addGestureRecognizer(tapGesture)
visualEffectView.isHidden = true
self.customerName.delegate = self
self.customerAddress.delegate = self
self.customerContact.delegate = self
self.customerIC.delegate = self
self.ticketNumber.delegate = self
self.latitudeGPS.delegate = self
self.longitudeGPS.delegate = self
self.district.delegate = self
// Do any additional setup after loading the view.
}
func hideKeyboard(){
scrollView.setContentOffset(CGPoint(x: 0,y:-64), animated: true)
self.customerName.resignFirstResponder()
self.customerAddress.resignFirstResponder()
self.customerContact.resignFirstResponder()
self.customerIC.resignFirstResponder()
self.ticketNumber.resignFirstResponder()
self.latitudeGPS.resignFirstResponder()
self.longitudeGPS.resignFirstResponder()
self.district.resignFirstResponder()
}
Instead of invoking resignFirstResponder() on each of your textFields you can just invoke view.endEditing(true) and keyboard will hide. Try to invoke this before the logic responsible for presenting the popup.
Simple and easy for all view controller swift 3+
This code help you to hide keyboard on touch anywhere on viewcontrol
extension UIViewController {
func hideKeyboardWhenTappedAround() {
let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(UIViewController.dismissKeyboard))
tap.cancelsTouchesInView = false
view.addGestureRecognizer(tap)
}
#objc func dismissKeyboard() {
view.endEditing(true)
}
}
Use below code in your viewDidLoad
self.hideKeyboardWhenTappedAround()
How to disable user's interaction with front view controller - namely with class ViewController in my case, when the rear menu is shown. With the current code, when rear menu is shown, bookCleaningButton is not disabled.
import UIKit
class ViewController: UIViewController, SWRevealViewControllerDelegate {
#IBOutlet weak var menuButton: UIBarButtonItem!
#IBOutlet weak var bookCleaningButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
self.revealViewController().rearViewRevealWidth = self.view.frame.width - 80
//revela the menu if it is not nil
if self.revealViewController() != nil {
self.revealViewController().delegate = self
menuButton.target = self.revealViewController()
menuButton.action = #selector(SWRevealViewController.revealToggle(_:))
self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer()
}
}
func revealController(revealController: SWRevealViewController!, willMoveToPosition position: FrontViewPosition) {
if revealController.frontViewPosition == FrontViewPosition.left {
self.view.isUserInteractionEnabled = false
}
else {
self.view.isUserInteractionEnabled = true
}
}
}
You should handle this in your Menu view controller rather. The reveal view controller has access to the frontViewController and that property can be used to set the userInteractionEnabled as false.
So, in your Menu View Controller write this this code in the viewWillAppear method:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.revealViewController().view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
self.revealViewController().frontViewController.revealViewController().tapGestureRecognizer()
self.revealViewController().frontViewController.view.isUserInteractionEnabled = false
}
And in the same Menu view Controller add the following code in the viewWillDisappear method:
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.revealViewController().frontViewController.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
self.revealViewController().frontViewController.view.isUserInteractionEnabled = true
}
The above code also adds other gestures, but those can be optional. The main action happens at these two lines:
self.revealViewController().frontViewController.view.isUserInteractionEnabled = false
self.revealViewController().frontViewController.view.isUserInteractionEnabled = true
Hope this solves your issue. Cheers.
In your front view controller class. Write this code on the viewdidload() method.
override func viewDidLoad() {
super.viewDidLoad()
menuBtn.addTarget(self.revealViewController(), action: #selector(SWRevealViewController.revealToggle(_:)), for: .touchUpInside)
revealViewController().delegate = self
// Once time - See documented SWRevealViewController.h
revealViewController().tapGestureRecognizer()
revealViewController().panGestureRecognizer()
}
and then use this delegate from the SWRevealviewcontroller in the frontviewcontroller
func revealController(_ revealController: SWRevealViewController!, willMoveTo position: FrontViewPosition) {
if position == FrontViewPosition.right {
revealController.frontViewController.view.isUserInteractionEnabled = false
}
else {
revealController.frontViewController.view.isUserInteractionEnabled = true
}
}
this will work up to your expectation....
I am trying to integrate UIGestureRecognizer into my swift playground so that wherever I tap in my playground, my sprite goes to that point. I've tried everything! Watching countless youtube videos, and going on stack overflow for answers but everyone starts with making a class called view that is a UIView and in their code they keep referring to "self". I instead made a variable named "view" that was a SKView. I try to get parts of their code, put it in mine, and change it, but it just doesn't work. Here's the work that I got so far.
view.addGestureRecognizer(UIGestureRecognizer(target: view, action: #selector(handleTap(sender:))))
func handleTap(sender: UITapGestureRecognizer) {
player.position = sender.location(in: view)
}
My playground keeps telling me that i'm using an unresolved identifier 'handleTap(sender:)'
UIGestureRecognizer example with different states of Gesture recogniser in Playground
swift3+
import UIKit
import PlaygroundSupport
class ViewController : UIViewController {
var yellowView: UIView!
var redView: UIView!
var yellowViewOrigin: CGPoint!
override func loadView() {
// UI
let view = UIView()
view.backgroundColor = .white
yellowView = UIView()
yellowView.backgroundColor = .yellow
view.addSubview(yellowView)
redView = UIView()
redView.backgroundColor = .red
view.addSubview(redView)
// Layout
redView.translatesAutoresizingMaskIntoConstraints = false
yellowView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
yellowView.topAnchor.constraint(equalTo: view.topAnchor, constant: 20.0),
yellowView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20.0),
yellowView.heightAnchor.constraint(equalToConstant: 80.0),
yellowView.widthAnchor.constraint(equalToConstant: 80.0),
redView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -20.0),
redView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20.0),
redView.heightAnchor.constraint(equalToConstant: 80.0),
redView.widthAnchor.constraint(equalToConstant: 80.0)
])
self.view = view
}
override func viewDidLoad() {
super.viewDidLoad()
let pan = UIPanGestureRecognizer(target: self, action: #selector(self.handlePanGesture(_:)))
yellowView.addGestureRecognizer(pan)
yellowViewOrigin = yellowView.frame.origin
view.bringSubview(toFront: yellowView)
}
#objc func handlePanGesture(_ sender: UIPanGestureRecognizer) {
let targetView = sender.view!
let translation = sender.translation(in: view)
switch sender.state {
case .began,.changed:
targetView.center = CGPoint(x: targetView.center.x + translation.x
,y: targetView.center.y + translation.y)
sender.setTranslation(CGPoint.zero, in: view)
case .ended:
if targetView.frame.intersects(redView.frame){
UIView.animate(withDuration: 0.3) {
targetView.alpha = 0.0
}
}
else{
UIView.animate(withDuration: 0.3) {
targetView.frame.origin = self.yellowViewOrigin
}
}
break
default:
break
}
}
}
PlaygroundPage.current.liveView = ViewController()
I think you need to add the #objc mark in front of the function declaration, so that handleTap will be visible to #selector.
#objc func handleTap(sender: UITapGestureRecognizer) {
player.position = sender.location(in: view)
}
func handleTap has to be called from your view type.
Please try to add it inside an SKView extension:
extension SKView {
func handleTap(sender: UITapGestureRecognizer) {
player.position = sender.location(in: view)
}
}
I want to hide the back button and set a title.
I'm using the following code:
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.title = "Einstellungen"
navigationItem.hidesBackButton = true }
But the title isn't shown and the back button is still there but if I touch it nothing happens. Can anybody help me please?
I found a solution on my own.
If I'm setting the title and the hidesBackButton from my previous ViewController everything works fine.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destinationVC = segue.destination as? ViewControllerFirstSettings {
destinationVC.navigationItem.hidesBackButton = true
destinationVC.navigationItem.title = "Einstellungen"
}
}
This code may help :
// MARK: - CUSTOM METHODS
func createNavBar() {
let leftNavigationButton = UIButton()
leftNavigationButton.setImage(UIImage(named: "ic_back.png"), forState: .Normal)
leftNavigationButton.frame = CGRectMake(10, 10, 20, 15)
leftNavigationButton.addTarget(self, action: "onBackButtonPressed:", forControlEvents: UIControlEvents.TouchUpInside)
let customBarItem = UIBarButtonItem(customView: leftNavigationButton)
self.navigationItem.leftBarButtonItem = customBarItem;
//set TitleAppIcon
let GR = UITapGestureRecognizer(target: self, action: Selector("headerLogoTapAction:"))
let imageView = UIImageView(frame: CGRect(x: 90, y: 0, width: ((UIScreen.mainScreen().bounds.width)/3), height: 40))
imageView.addGestureRecognizer(GR)
imageView.userInteractionEnabled = true
navigationItem.titleView = imageView
}