iOS13+ Creating a constant button on top of every screen - ios

I maintain an app SDK that contains a button which should always be displayed on top of all screens in the application, but this functionality broke with iOS 13+ which seems to have changed some internals. The button disappears after changing from the first screen.
// My code that does not work anymore
var applicationWindow: UIWindow? = UIApplication.shared.keyWindow
...
button.frame = CGRect(x: 0, y: 0, width: 94, height: 73)
applicationWindow!.addSubview(button)
I saw similar posts on SOF suggesting code like
UIApplication.shared.windows.first(where: { $0.isKeyWindow })? but it doesn't work for me, and I'm struggling to create and manage a second UIWindow, any code sample would be really appreciated as I'm only a maintainer and I don't work actively on iOS anymore.

Related

Creating a view permanently underneath UINavigationBar

My issue is that i need to have a single view just below the UINavigationBar on screen at all times whilst navigating through a sign up journey. This is to display the current step in signing up. This needs to stay on screen at all times as the stages animate as they change so simply pushing a new view onto a UINavigationController isn't sufficient.
See an example of what i need to achieve below
I need to have the red item persist at all times even when a new view controller is pushed on
To try fix this I have created a custom UINavigationController in order to have a sticky view be present regardless of what view controller is showing.
I have created this code which suits my needs however doesnt feel like the correct option. Especially as I need to support iOS 10 and additionalSafeAreaInsets is not available
override func viewDidLayoutSubviews() {
stickyView.frame = CGRect(x: 0, y: navigationBar.frame.maxY, width: view.frame.size.width, height: 60)
children.forEach { $0.additionalSafeAreaInsets = UIEdgeInsets(top: 60, left: 0, bottom: 0, right: 0) }
}
What would be a good way to make sure that the view controllers frame starts below this header view? Or maybe an alternative approach?
There seems to be very little stuff on this topic from what i can see on stack overflow

Import Adobe After Effect animation to xcode

I have some trouble importing my animation from Adobe After Effect to Xcode and web.
I have made a character and rigged it with the Duik-plugin. I made the annimation i would like to get into xcode, and rendered it to JSON using bodymovin.
I have an image of the animation here:
Then i take the rendered JSON file and import it into my project. I use the Lottie-ios framework (https://github.com/airbnb/lottie-ios).
In my viewDidLoad() i use this code to show the animation:
let animationView = LOTAnimationView(name: "Velkomst")
animationView.frame = CGRect(x: 0, y: 100, width:
self.view.frame.size.width, height: 250)
view.addsubview(animatedView.contentMode = .scaleAspectFill
animationView.play()
But as you can see below, the result is pretty... Wierd...
I also created a demo file when i rendered the after effect aniation. On the demo-website it is a little closer to the animation. But still not there.
Can anyone tell me what i am doing wrong? Cause i cant figure it out :-(

iOS 11 breaks row selection

I've recently tested my app in iOS 11 and for some reason I'm not able to select one of the first 12 rows in a dynamically populated table view. The didSelectRow isn't even triggered for these rows. The other rows work fine, but even when scrolling down and back up (the cells should have been re-used again by then) the first 12 rows don't work.
Even on a static table view all cells that appear on screen when switching to that view controller will not respond, neither will controls inside them, even when they are in different sections. Cells that are out of screen initially again work fine.
I'll be trying to test this in an app with boilerplate code, but is this a known bug? I couldn't find anything online about it.
I've tested this after updating the devices to iOS 11, then again from Xcode 9 beta 6 without changes to the code, and again after migrating to Swift 4. Same behaviour inside the simulator. Up to iOS 10 everything is fine, only with iOS 11 the problem occurs.
This will break my app for users in two weeks, I need to fix it, so any help or advice very much appreciated!
UPDATE: As Paulw11 suggested, there is indeed another view blocking the rows. This was notable as row 12 could only be selected in the lower part of the cell, but not in the upper part.
The cause for this issue is the following code:
extension UIViewController {
func setBackgroundImage(forTableView tableView: UITableView) {
let bgImage = UIImage(named: "Background Image.png")
let bgImageView = UIImageView(image: bgImage)
tableView.backgroundView = bgImageView
let rect = bgImageView.bounds
let effect = UIBlurEffect(style: UIBlurEffectStyle.dark)
let blurView = UIVisualEffectView(effect: effect)
let height: CGFloat
switch screenSize.height {
case 480, 568: height = 455
case 736: height = 623
default: height = 554
}
blurView.frame = CGRect(x: 0, y: 0, width: rect.width, height: height)
let container = UIView(frame: rect)
bgImageView.addSubview(blurView)
let bgOverlay = UIImage(named: "Background Overlay.png")
let bgOverlayImageView = UIImageView(image: bgOverlay)
bgOverlayImageView.alpha = 0.15
bgImageView.addSubview(bgOverlayImageView)
self.view.insertSubview(container, at: 1)
}
}
Somehow since iOS 11 this background image seems to be rendered in front of the cells. Not inserting the container view into the table view's view will solve the issue. I've tried setting the zPosition of the container's layer but it does not help. How can I move the background image behind the cells again.
It's weird that this behaviour would change from iOS 10 to 11...
UPDATE 2: Inserting the container at index -1 fixes the issue:
self.view.insertSubview(container, at: -1)
I don't get why this works, though, shouldn't this index be out of range?
UPDATE 3: As Paulw11 pointed out below, the container is completely useless, it was left over from testing and removing it fixes the issue.
The container view seems to be appearing in front of the other views and preventing touches from making it through to the table view.
As an aside, I would see if you can refactor this to use constraints; It always worries me when you see hard-coded screen sizes, as that may break when new devices are released.

How to programmaticaly add button in iOS game app swift 3?

Can someone explain the code for a programatically added button in an iOS game application for swift 3 Xcode 8? All the other threads on this topic we're in single view and didn't work for me. I couldn't figure out how to add buttons to the game app Main.storyboard, so I'm trying to make a programattically added button. This is the code I'm trying to use now but doesn't work:
var playAgain = UIButton()
playAgain.setTitle("Play Again", for: .normal)
playAgain.setTitleColor(UIColor.black, for: .normal)
playAgain.backgroundColor = SKColor.green
playAgain.layer.borderWidth = 2
playAgain.layer.cornerRadius = 18
playAgain.frame = CGRect(x: (self.frame.width)/2, y: (self.frame.height)/2, width: 100, height: 36)
self.view?.addSubview(playAgain)
Why would the buttons in single view be different in game apps? Also, when(and if) this is created, how would I modify the Touches ended method to know when the button was touched?
Your code is adding the button to the .view, but using the coordinate system of the SKScene. So, your button is there, just not in view.
Assuming you want the button to be centered on the screen (at least, for now), change the placement to:
playAgain.frame = CGRect(x: 0, y: 0, width: 100, height: 36)
playAgain.center = (self.view?.center)!
self.view?.addSubview(playAgain)
This will put the button above the game scene (z-layer, that is), so you can use normal button tap without needing to deal with touches. So, right after you add the button:
self.view?.addSubview(playAgain)
playAgain.addTarget(self, action: #selector(playAgainTapped(_:)), for: .touchUpInside)
and then elsewhere in your class:
func playAgainTapped(_ sender: Any?) -> Void {
print("Play again was Tapped!")
// take whatever action you want here
}
There is another way to create a button programmatically. You can create an empty UIView and override touch method. Also you are able to process touch event on this view and simulate buttons action. I think this is a fastest way for you.

iOS dynamic UI in simple terms?

This may be too basic or require rephrasing. I am in the process of learning Swift and iOS programming and have developed a basic application that runs successfully on my iPhone 5. The app consists of a label, a button, and a UIImageView. It looks the way I want it to on my iPhone 5.
I figured most of this out by just playing around and so I am creating all these elements programatically. The code looks like this:
let banner = UILabel(frame: CGRect(x: 10, y: 10, width: 300.0, height: 75.0))
let button = UIButton(frame: CGRect(x: 45, y: 75, width: 235.0, height: 60.0))
let imageView = UIImageView(frame: CGRect(x: 22, y: 150, width: 280.0, height: 410.0))
And then I configure them in viewDidLoad to make them show stuff.
Now the question...how to I make them all the right size when running on different devices? I can load up the app on my iPad Mini but it's all scrunched over to the left of the view. So I need to do some kind of dynamic layout but not sure where to start.
All help appreciated!
Rather than creating the view sizes explicitly with initWithFrame: constructors, you can programmatically create and NSLayoutConstraints to your views to automatically layout your views, the same as if you used Auto Layout with the Interface Builder. See Apple's Auto Layout Guide for more details.

Resources