Adding UIButton to AVPlayer in iOS (Swift) When Video Plays in WebView - ios

I'm putting together an iOS app (using Swift) that contains a webview. A user will click on a video in the webview and the video will load, at which time I want to display a button on the video. I've been able to display the button but it is not responding to touches and I'm not sure why. I made the button huge just to make sure it was being hit. Here's my code. I extended AVPlayerViewController.
Thanks in advance for your time and patience.
extension AVPlayerViewController {
open override func viewDidLoad() {
let btn = UIButton(type: .roundedRect)
btn.backgroundColor = UIColor.red
btn.setTitle("Do stuff", for: .normal)
btn.frame = CGRect(x: 0, y: 330, width: 300, height: 300)
btn.addTarget(self, action: #selector(self.pressButton(button:)), for: .touchUpInside)
btn.isUserInteractionEnabled = true
btn.isEnabled = true
btn.clipsToBounds = true
self.contentOverlayView?.addSubview((btn as? UIButton)!)
self.showsPlaybackControls = false
}
func pressButton(button: UIButton) {
print("Worked")
}
}

In your extension of AVPlayerViewController, you have overridden viewDidLoad method, which is not correct in my view. Instead you can add the button adding logic in the extension and call that method eherever ypu have initialized the AVPlayerViewController.
extension AVPlayerViewController {
func addButton() {
let btn = UIButton(type: .roundedRect)
btn.backgroundColor = UIColor.red
btn.setTitle("Do stuff", for: .normal)
btn.frame = CGRect(x: 0, y: 330, width: 300, height: 300)
btn.addTarget(self, action: #selector(self.pressButton(button:)), for: .touchUpInside)
btn.isUserInteractionEnabled = true
btn.isEnabled = true
btn.clipsToBounds = true
self.contentOverlayView?.addSubview((btn as? UIButton)!)
self.showsPlaybackControls = false
}
func pressButton(button: UIButton) {
print("Worked")
}
}

Related

How to get scrollview to work properly with IOS Swift WKWebview

This code loads a webpage using WKWebview. This is swift for IOS. When one clicks the button what I would like it to do is scroll down specifically on a kindle book. When I load most web pages, I can scroll down using the button. But when I try to use the button to scroll down on my kindle books (using the online viewer), it does not work. I am not getting an error it simply does not scroll down. I have tried scrollview (shown).
Are there any solutions here?
class ViewController: UIViewController {
let webView = WKWebView()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(webView)
guard let url = URL(string: "https://read.amazon.com/kindle-library") else {
return
}
webView.load((URLRequest(url: url)))
let button = UIButton()
button.setTitle("ScanPage", for: .normal)
button.backgroundColor = .systemOrange
view.addSubview(button)
button.frame = CGRect(x: 50, y: 50, width: 100, height: 50)
button.layer.cornerRadius = 20
button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
}
#objc func buttonTapped(){
var scrollPoint = self.view.convert(CGPoint(x: 0, y: 0), to: webView.scrollView)
scrollPoint = CGPoint(x: scrollPoint.x, y: 600)
webView.scrollView.setContentOffset(scrollPoint, animated: true)
}
}

How to declare a programmed button as a var

I would to do a programmed button without the storyboard. The problem is that I can not call the button in a separate function like I can when I drag and drop a UIButton from a storyboard into a view controller. I do not want to use the storyboard at all.
//Trying to Create a var for btn
override func viewDidLoad() {
super.viewDidLoad()
let btn = UIButton(type: .custom) as UIButton
btn.backgroundColor = .blue
btn.setTitle("Button", for: .normal)
btn.frame = CGRect(x: 100, y: 100, width: 200, height: 100)
btn.addTarget(self, action: #selector(clickMe), for: .touchUpInside)
self.view.addSubview(btn)
}
#objc func clickMe(sender:UIButton!) {
print("Button Clicked")
}
func place() {
//do something to btn.
}
Read about variable scopes. In the question you have declared your button inside the method/function which restricts the scope of its usage within the method. When you declare the variable within the scope of the class/struct you can use it within other methods/functions.
let btn = UIButton(type: .custom)
override func viewDidLoad() {
super.viewDidLoad()
btn.backgroundColor = .blue
// .. other settings here
self.view.addSubview(btn)
}
#objc
func clickMe(sender:UIButton) {
print("Button Clicked")
}
func place() {
btn.backgroundColor = .red
}

Change Color of Programmatically Created Button when Pressed

I'm using a function to create multiple buttons for my game.
func createButton() {
let button = UIButton()
button.setTitle("", for: .normal)
button.frame = CGRect(x:15, y: 50, width: 200, height:100)
button.backgroundColor = UIColor.red
self.view.addSubview(button)
button.addTarget(self, action: Selector(("buttonPressed:")), for:
.touchUpInside)
}
I call this function once for testing in viewDidLoad function, but I don't know what code I should put into my buttonPressed() function for the color of my button to change? I tried doing
self.backgroundColor = UIColor.blue
but that didn't work. I also tried using UIButton and button instead of self, but both of those didn't work either. What should I do?
Your code isn't clean Swift 4 code. Here's how to do this:
Create your button like you are, but change Selector to #selector:
func createButton() {
let button = UIButton()
button.setTitle("", for: .normal)
button.frame = CGRect(x:15, y: 50, width: 200, height:100)
button.backgroundColor = UIColor.red
self.view.addSubview(button)
button.addTarget(self, action: #selector((buttonPressed)), for: .touchUpInside)
}
Use the sender that is automatically added:
#objc func buttonPressed(sender: UIButton) {
sender.backgroundColor = UIColor.blue
}
Additionally may I offer a few suggestions?
Check the background color before changing it. No sense in needlessly changing a button that is already blue.
Since you aren't setting the title to your button, set the tag property (you can even add this as a parameter to createButton). This way you can know which button was tapped.
Just make the button an instance property.
let changingButton = UIButton()
func createButton() {
changingButton.backgroundColor = UIColor.red
changingButton.addTarget(self, action: #selector(buttonPressed), for: .touchUpInside)
}
#objc func buttonPressed() {
changingButton.backgroundColor = UIColor.blue
}

iOS - Adding controls on top of AVPlayerViewController

I have a subclass of AVPlayerViewController that I want to add my custom controls on it. I successfully added my custom controls on top of the AVPlayerViewController. However, these controls are only responsive for a short time. After a few seconds, clicking any of the button won't trigger the touchUpInside event.
Below is the code I'm using:
class LSPlayerViewController : AVPlayerViewController {
private var btnPlay : UIButton!
func addControls() {
self.showsPlaybackControls = false
//PLAY BUTTON
let btnPlayRect = CGRect(x: 0, y: 0, width: 19, height: 25)
btnPlay = UIButton(frame: btnPlayRect)
btnPlay.center = self.view.center
btnPlay.setImage(#imageLiteral(resourceName: "PauseIcon"), for: .normal)
btnPlay.addTarget(self, action: #selector(self.playButtonTapped(sender:)), for: .touchUpInside)
btnPlay.alpha = 0
btnPlay.isUserInteractionEnabled = true
self.view.addSubview(btnPlay)
}
func playButtonTapped(sender: UIButton!) {
if sender.isPlayIconOn == true {
sender.setImage(#imageLiteral(resourceName: "PauseIcon"), for: .normal)
self.player?.play()
} else {
sender.setImage(#imageLiteral(resourceName: "PlayIcon"), for: .normal)
self.player?.pause()
}
}
I solved the issue by adding the following two lines alongside the addSubview function:
self.addChildViewController(playerViewController)
playerView.addSubview(playerViewController.view)
playerViewController.didMove(toParentViewController: self)

How can I get events to my (sub) UIView?

I'm new to Swift and have a hard time understand the event flow. The code below can be run directly in an xcode playground. I have a white UIView in the background. This view has a brown button and a red view as sub-views. Click on them and the events are logged in the controller, just as expected.
But the controller of this white view also adds another view, that has it's own controller class (SubviewController). SubviewController is green and has a blue subview with a black button. Question is... why don't I get any logs from the green, blue and black views/buttons?
import Foundation
import UIKit
import PlaygroundSupport
class TestViewController : UIViewController {
let playButton: UIButton = {
let playButton = UIButton(frame: CGRect(x: 155, y: 135, width: 160, height: 40))
playButton.setTitle("BROWN BUTTON", for: .normal)
playButton.backgroundColor = UIColor.brown
return playButton
}()
override func loadView() {
let viewWhite = UIView()
viewWhite.backgroundColor = UIColor.white
let viewRed = UIView()
viewRed.backgroundColor = UIColor.red
viewRed.frame = CGRect(x: 20, y: 20, width: 40, height: 10)
viewRed.clipsToBounds = true
let recognizer2 = UITapGestureRecognizer(target: self, action: #selector (self.handleTapRed(_:)))
viewRed.addGestureRecognizer(recognizer2)
let recognizer = UITapGestureRecognizer(target: self, action: #selector (self.handleTap(_:)))
viewWhite.addGestureRecognizer(recognizer)
playButton.addTarget(self, action: #selector (self.action) , for: .touchUpInside)
let catList = SubviewController()
viewWhite.addSubview(catList.view)
viewWhite.addSubview(playButton)
viewWhite.addSubview(viewRed)
self.view = viewWhite
}
func action() {
print("Brown button tapped")
}
func handleTap(_ sender:UITapGestureRecognizer){
print("WHITE VIEW (background view) TAPPED")
}
func handleTapRed(_ sender:UITapGestureRecognizer){
print("RED VIEW TAPPED")
}
}
class SubviewController: UIViewController {
let buttonBlack: UIButton = {
let button = UIButton(frame: CGRect(x: 40, y: 10, width: 170, height: 20))
button.backgroundColor = UIColor.black
button.setTitle("BLACK BUTTON", for: .normal)
return button
}()
let viewBlue: UIView = {
let v = UIView()
v.backgroundColor = UIColor.blue
v.frame = CGRect(x: 20, y: 40, width: 240, height: 60)
v.clipsToBounds = true
return v
}()
override func loadView() {
super.loadView()
self.view.backgroundColor = UIColor.green
buttonBlack.addTarget(self, action: #selector (self.blackKlick) , for: .touchUpInside)
self.view.addSubview(viewBlue)
self.view.frame = CGRect(x: 0, y: 40, width: 240, height: 60)
self.view.clipsToBounds = true
self.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector (self.handleTapGreen(_:))))
viewBlue.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector (self.handleTapBlue(_:))))
viewBlue.addSubview(buttonBlack)
}
func blackKlick() {
print("Black button tapped")
}
func handleTapBlue(_ sender:UITapGestureRecognizer){
print("BLUE VIEW TAPPED")
}
func handleTapGreen(_ sender:UITapGestureRecognizer){
print("GREEN VIEW TAPPED")
}
}
PlaygroundPage.current.liveView = TestViewController()
Thanks for any help!
This line in your current code:
let catList = SubviewController()
creates a local instance of SubvieController. As soon as you exit the loadView() func, that instance is gone.
So, you need a class-level variable to keep that instance around. Add this line:
class TestViewController : UIViewController {
var catList: SubviewController!
and then remove the let from the instantiation line in loadView():
catList = SubviewController()

Resources