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() )
Related
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)
The code below creates a red rectangle that is animated to move across the view from left to right. I would like to have an arbitrary shape loaded from an image to either superimpose or replace the rectangle. However, the circleLayer.contents = NSImage statement in the initializeCircleLayer function doesn't produce any effect. The diagnostic print statement seems to verify that the image exists and has been found, but no image appears in the view. How do I get an image into the layer to replace the animated red rectangle? Thanks!
CODE BELOW:
import Cocoa
class ViewController: NSViewController {
var circleLayer = CALayer()
override func viewDidLoad() {
super.viewDidLoad()
self.view.wantsLayer = true
initializeCircleLayer()
simpleCAAnimationDemo()
}
func initializeCircleLayer(){
circleLayer.bounds = CGRect(x: 0, y: 0, width: 150, height: 150)
circleLayer.position = CGPoint(x: 50, y: 150)
circleLayer.backgroundColor = NSColor.red.cgColor
circleLayer.cornerRadius = 10.0
let testIm = NSImage(named: NSImage.Name(rawValue: "testImage"))
print("testIm = \(String(describing: testIm))")
circleLayer.contents = NSImage(named: NSImage.Name(rawValue: "testImage"))?.cgImage
circleLayer.contentsGravity = kCAGravityCenter
self.view.layer?.addSublayer(circleLayer)
}
func simpleCAAnimationDemo(){
circleLayer.removeAllAnimations()
let animation = CABasicAnimation(keyPath: "position")
let startingPoint = NSValue(point: NSPoint(x: 50, y: 150))
let endingPoint = NSValue(point: NSPoint(x: 600, y: 150))
animation.fromValue = startingPoint
animation.toValue = endingPoint
animation.repeatCount = Float.greatestFiniteMagnitude
animation.duration = 10.0
circleLayer.add(animation, forKey: "linearMovement")
}
}
Why it doesn't work
The reason why
circleLayer.contents = NSImage(named: NSImage.Name(rawValue: "testImage"))?.cgImage
doesn't work is because it's a reference to the cgImage(forProposedRect:context:hints:) method, meaning that its type is
((UnsafeMutablePointer<NSRect>?, NSGraphicsContext?, [NSImageRep.HintKey : Any]?) -> CGImage?)?
You can see this by assigning NSImage(named: NSImage.Name(rawValue: "testImage"))?.cgImage to a local variable and ⌥-clicking it to see its type.
The compiler allows this assignment because circleLayer.contents is an Any? property, so literally anything can be assigned to it.
How to fix it
As of macOS 10.6, you can assign NSImage objects to a layers contents directly:
circleLayer.contents = NSImage(named: NSImage.Name(rawValue: "testImage"))
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.
Ghost = SKSpriteNode(imageNamed: "Ghost1")
Ghost.size = CGSize(width: 50, height: 50)
Ghost.position = CGPoint(x: self.frame.width / 2 - Ghost.frame.width, y: self.frame.height / 2)
Ghost.physicsBody = SKPhysicsBody(circleOfRadius: Ghost.frame.height / 1.4)
Ghost.physicsBody?.categoryBitMask = PhysicsCatagory.Ghost
Ghost.physicsBody?.collisionBitMask = PhysicsCatagory.Ground | PhysicsCatagory.Wall
Ghost.physicsBody?.contactTestBitMask = PhysicsCatagory.Ground | PhysicsCatagory.Wall | PhysicsCatagory.Score
Ghost.physicsBody?.affectedByGravity = false
Ghost.physicsBody?.isDynamic = true
Ghost.zPosition = 2
self.addChild(Ghost)
On my app i have an object that moves around on the screen and it name is "ghost". I am not sure how to set up a button that would change the code to say
Ghost = SKSpriteNode(imageNamed: "Ghost2")
instead of
Ghost = SKSpriteNode(imageNamed: "Ghost1")
To change the image for an SKSpriteNode you assign a different texture:
Ghost.texture = SKTexture(imageNamed:"Ghost2")
Note: You should use lower case letters for variable names to distinquish them from class names.
An example implementation that includes a Button and your Ghost would be like below with a red button created in the top right corner. See that the declaration of the button and the ghost now occurs outside of didMoveToView, so that these variables can be referenced later, when the user taps the screen.
class ButtonGhostScene: SKScene {
var button: SKNode! = nil
var ghost: SKSpriteNode! = nil
override func didMove(to view: SKView) {
button = SKSpriteNode(color: SKColor.redColor(), size: CGSize(width: 100, height: 44))
button.position = CGPoint(x:self.size.width, y:self.size.height)
ghost = SKSpriteNode(imageNamed: "Ghost1")
ghost.size = CGSize(width: 50, height: 50)
ghost.position = CGPoint(x: self.frame.width / 2 - Ghost.frame.width, y: self.frame.height / 2)
ghost.physicsBody = SKPhysicsBody(circleOfRadius: Ghost.frame.height / 1.4)
ghost.physicsBody?.categoryBitMask = PhysicsCatagory.Ghost
ghost.physicsBody?.collisionBitMask = PhysicsCatagory.Ground | PhysicsCatagory.Wall
ghost.physicsBody?.contactTestBitMask = PhysicsCatagory.Ground | PhysicsCatagory.Wall | PhysicsCatagory.Score
ghost.physicsBody?.affectedByGravity = false
ghost.physicsBody?.isDynamic = true
ghost.zPosition = 2
self.addChild(ghost)
self.addChild(button)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
// Loop over all the touches in this event
for touch: AnyObject in touches {
// Get the location of the touch in this scene
let location = touch.location(in: self)
// Check if the location of the touch is within the button's bounds
if button.containsPoint(location) {
ghost.texture = SKTexture(imageNamed:"Ghost2")
}
}
}
}
When the user taps the screen, touchesBegan is executed and a check is made to see if the users tap is on the button.
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)
}
}
}