I am attempting to set up a UISlider programmatically but cannot get it to work. On the one hand slider.addTarget() works perfectly. When I move the slider the function rotateSlider(_:) gets called perfectly.
On the other hand when I try to set the start value programmatically it does not move the handle. Also if I try to hide the slider with slider.isHidden = true, nothing happens and it is not removed from the view.
var slider1: UISlider {
let frame = CGRect(x: 0, y: 0, width: 300, height: 40)
let slider1 = UISlider(frame: frame)
slider1.center = CGPoint(x: Int(self.view.frame.width) / 2, y: Int(self.view.frame.height) / 2)
slider1.minimumValue = -3
slider1.maximumValue = 3
slider1.addTarget(self, action: #selector(self.rotateSlider(_:)), for: .allTouchEvents)
return slider1
}
#objc func rotateSlider(_ sender: UISlider) {
print("rotated")
}
override func viewDidLoad() {
super.viewDidLoad()
self.view.addSubview(slider1)
slider1.setValue(1.0, animated: true) // This does not work
slider1.isHidden = true // This does not work
}
I know it is something trivial that I am missing?!
Thanks.
Related
I'm writing an iOS app where the user can add text fields, then drag them around the screen to reposition them, layout-style, sort of like Keynote.
I'm currently appending the user-added UITextFields to an #IBOutlet Collection and defaulting to .borderStyle = .roundedRect to get a faint border around the selected text, indicating the field is selected. Any UITextField will be set to .roundedRect border style when textFieldDidBeginEditing is called, and switch to textField.borderStyle = .none when textFieldDidEndEditing is called.
All seems to work with one problem: when switching border style to .none, the text field loses indentation that was around the border, shifting text outward and putting it in a spot where the user hadn't intended (graphic adds a background color red, just to show the shift, but I'll eventually allow the user to set background colors, so just shifting the UITextField isn't an option).
I've also tried adapting the answer at:
Create space at the beginning of a UITextField
setting a no-padding inset for the TextView when it's a .roundedRect, but adding padding when .borderStyle is .none. This seems to have no effect.
Other answers have suggested setting
textField.layer.borderColor = UIColor.clear.cgColor
or
textField.layer.borderWidth = 0.0
but these don't seem to have any effect, either
I'm eventually going to allow the user to change fonts & sizes of each TextField, so I'd like any indentation to be consistent whether the UITextField is selected or nots elected, and regardless of font choices.
Code is below. Recommendations are most welcome, as well as setting me on a new approach, if I'm missing a better solution.
Thanks!
John
class ViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var screenView: UIView! // a 320 x 240 view
#IBOutlet var fieldCollection: [UITextField]! // Not connected, fields created programmatically
// below are used in .inset(by:) but seems to have no effect
let padding = UIEdgeInsets(top: 0, left: 5, bottom: 0, right: 5)
let noPadding = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
override func viewDidLoad() {
super.viewDidLoad()
// hide keyboard if we tap outside of a field
let tap = UITapGestureRecognizer(target: self.view, action: #selector(UIView.endEditing(_:)))
tap.cancelsTouchesInView = false
self.view.addGestureRecognizer(tap)
createNewField()
}
// Select / deselect text fields
func textFieldDidBeginEditing(_ textField: UITextField) {
textField.borderStyle = .roundedRect
// textField.bounds.inset(by: noPadding) // effect is the same if left out
}
func textFieldDidEndEditing(_ textField: UITextField) {
textField.borderStyle = .none
// textField.bounds.inset(by: padding) // effect is the same if left out
}
// UITextField created & added to fieldCollection
func createNewField() {
let newFieldRect = CGRect(x: 0, y: 0, width: 320, height: 30)
let newField = UITextField(frame: newFieldRect)
newField.borderStyle = .roundedRect
newField.isUserInteractionEnabled = true
newField.addGestureRecognizer(addGestureToField())
screenView.addSubview(newField)
if fieldCollection == nil {
fieldCollection = [newField]
} else {
fieldCollection.append(newField)
}
newField.delegate = self
newField.becomeFirstResponder()
}
func addGestureToField() -> UIPanGestureRecognizer {
var panGesture = UIPanGestureRecognizer()
panGesture = UIPanGestureRecognizer(target: self, action: #selector(draggedView(_:)))
return panGesture
}
// event handler when a field(view) is dragged
#objc func draggedView(_ sender:UIPanGestureRecognizer){
sender.view!.becomeFirstResponder()
let selectedView = sender.view as! UITextField
selectedView.bringSubviewToFront(selectedView)
let translation = sender.translation(in: screenView)
selectedView.center = CGPoint(x: selectedView.center.x + translation.x, y: selectedView.center.y + translation.y)
sender.setTranslation(CGPoint.zero, in: screenView)
}
#IBAction func addFieldPressed(_ sender: UIButton) {
createNewField()
}
}
I was able to work around the problem by subclassing UITextField:
class PaddedTextField: UITextField {
let padding = UIEdgeInsets(top: 0, left: 8, bottom: 0, right: 8)
let noPadding = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
override open func textRect(forBounds bounds: CGRect) -> CGRect {
if self.borderStyle == .none {
let content = bounds.inset(by: padding)
return content
} else {
return bounds.inset(by: noPadding)
}
}
}
I then changed the newField object creation from using UITextField to:
let newField = PaddedTextField(frame: newFieldRect)
One more change. The height needed to be more appropriately calculated. Since all of my text fields can start out the full length of the enclosing superview (320 points), I modified the original newFieldRect, used .sizeToFit() to create a textbox with the appropriate height. The other dimensions won't be correct b/c I don't have anything in the text view, but I extract the .height and reuse this with my original initliazation parameters.
newField.sizeToFit()
let newFieldHeight = newField.frame.height
newFieldRect = CGRect(x: 0, y: 0, width: 320, height: newFieldHeight)
newField.frame = newFieldRect
Here's hoping it helps save someone time.
Swift 4. Very simple project, all I did - just added a NSImageView programmatically, backgroundColor and NSImage from the .jpg file. I see the good pink color, but can't see the image at all! I tried many different approaches and some was successful (Image showed up well in collection view and if NSImageView was added manually in the story board) but I need in simple programmatically method. Here is all of my code:
class ViewController: NSViewController {
var image: NSImage = NSImage()
var ivTest = NSImageView()
override func viewDidLoad() {
super.viewDidLoad()
self.view.addSubview(self.ivTest)
self.ivTest.wantsLayer = true
self.ivTest.layer?.backgroundColor = NSColor.systemPink.cgColor
self.ivTest.layer?.frame = NSRect(x: 0, y: 0, width: 100, height: 100)
let manager = FileManager.default
var url = manager.urls(for: .documentDirectory, in: .userDomainMask).first
url = url?.appendingPathComponent("night.jpg")
image = NSImage(byReferencing: url!)
if (image.isValid == true){
print("valid")
print("image size \(image.size.width):\(image.size.height)")
self.ivTest.image = image
} else {
print("not valid")
}
}
override var representedObject: Any? {
didSet {
// Update the view, if already loaded.
}
}
}
output:
result:
thank so much...
--- edited ---
Yes, thank You! Just added this and saw image:
self.ivTest.frame = NSRect(x: 0, y: 0, width: 100, height: 100)
I'm loading a web with UIWebView, everything works fine except that the iphoneX is cut off the bar where I put an "OK" button and a label with a title.
// webView
var webView: WKWebView!
override func viewDidLoad() {
super.viewDidLoad()
let myURL = URL(string: "https://google.com")
let myRequest = URLRequest(url: myURL!)
webView = WKWebView(frame: CGRect( x: 0, y: 60, width: self.view.frame.width, height: self.view.frame.height - 60 ), configuration: WKWebViewConfiguration() )
//webView.backgroundColor = UIColor.blue
self.view.addSubview(webView)
webView.load(myRequest)
self.webView.allowsBackForwardNavigationGestures = true
//hide navegation bar
self.navigationController?.setNavigationBarHidden(true, animated: true)
// add cornerRadius to view
navegador.layer.cornerRadius = 10
//add observer to get estimated progress value
self.webView.addObserver(self, forKeyPath: "estimatedProgress", options: .new, context: nil)
}
Any suggestions to solve this impasse.
The height of the StatusBar in the iPhoneX is higher than in the other devices, it is necessary to calculate this height and use this value for the WebView coordinates.
Add a view to place the OK button:
#IBOutlet weak var myTopBar: UIView!
Calculate height of statusBar:
//Get height status bar
let statusBarHeight = UIApplication.shared.statusBarFrame.height
// to see correctly on all device models the new height will be:
let heightTotal = self.myTopBar.frame.height + statusBarHeight
3: In the webView, use this height:
webView = WKWebView(frame: CGRect( x: 0, y: heightTotal, width: self.view.frame.width, height: self.view.frame.height - heightTotal), configuration: WKWebViewConfiguration() )
Is there any way to center a window in the center of the screen in OSX?
I am using the code below but it changes just the size but not the position on screen.
override func viewDidLoad() {
super.viewDidLoad()
let ScreenStart = NSSize(width: (NSScreen.mainScreen()?.frame.width)! / 1.5, height: (NSScreen.mainScreen()?.frame.height)! / 1.5)
self.view.frame.size = ScreenStart
self.view.frame.origin = NSPoint(x: (NSScreen.mainScreen()?.frame.origin.x)!/2, y: (NSScreen.mainScreen()?.frame.height)! / 2)
}
For future references this is done inside NSWindowController class using self.window?.center()
I had the same question, when using a Modal presentation of a NSTabViewController.
I like this answer: How to constrain second NSViewController minimum size in OS X app?
I used NSWindowDelegate to access the NSWindow properties and functions. This included self.view.window?.center() as #SNos said.
class YDtabvc: NSTabViewController, NSWindowDelegate {
public let size = NSSize(width: 500, height: 800)
override func viewWillAppear() {
super.viewWillAppear()
self.view.window?.delegate = self
self.view.window?.minSize = size
self.view.window?.center()
}
override func viewDidAppear() {
super.viewDidAppear()
var frame = self.view.window!.frame
frame.size = size
self.view.window?.setFrame(frame, display: true)
}
}
I'm trying to create a vertical progress bar in my Cocoa app, i.e, the progress bar should grow from bottom to top. I'm using NSProgressIndicator, and I can't find a way to specify vertical or horizontal. Can anybody please tell me is it possible to do it?
Thanks,
Lee
You can set the transform of the control to rotate it pi/2 radians (90 degrees). That seems to be a common solution most people take.
import UIKit
class ViewController: UIViewController {
// THis is custom Progress view
var progessView:VerticalProgressView!
// We can also use default progress view given by UIKIT
var defaultProgressView:UIProgressView!
override func viewDidLoad() {
super.viewDidLoad()
// Custom Progress view
progessView = VerticalProgressView(frame: CGRect(x: 0, y: 160, width: 15, height: 200))
progessView.center.x = self.view.center.x - 80
self.view.addSubview(progessView)
//Default Progress view
defaultProgressView = UIProgressView(progressViewStyle: .bar)
self.view.addSubview(defaultProgressView)
}
override func viewDidLayoutSubviews() {
defaultProgressView.frame = CGRect(x: self.view.center.x + 30, y: 300, width: 100, height: 300)
defaultProgressView.progressTintColor = UIColor.green
defaultProgressView.backgroundColor = UIColor.clear
defaultProgressView.layer.borderWidth = 0.3
//defaultProgressView.layer.borderColor = [UIColor.redColor]
// Change the width of default Progress view
let customWidth = CGAffineTransform(scaleX: 5.0, y: 3.0)
// Transform from default horizontal to vertical
let rotate = CGAffineTransform(rotationAngle: (CGFloat.pi/2 + CGFloat.pi))
//Two transforms should be concated and applied
defaultProgressView.transform = rotate.concatenating(customWidth)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.progessView.setProgress(progress: 0.50, animated: true)
UIView.animate(withDuration: 0.95) {
self.defaultProgressView.setProgress(0.50, animated: true)
}
}
}