In my application i used AVPlayer and video is playing well for first time, when i go back and again coming to player screen the layer is displaying and video sound also coming but video is not showing. Here is my Code
if (videoPlaying == true) {
videoView.isHidden = false
let targetTime:CMTime = CMTimeMake(0, 1)
videoPlayer.seek(to: targetTime)
videoPlayer.pause()
// audioplayer = nil
playerLayer.removeFromSuperlayer()
playerLayer=AVPlayerLayer(player: videoPlayer)
playerLayer.frame = CGRect(x:0 , y: 75 , width: videoView.frame.size.width , height: UIScreen.main.bounds.height-170)
playerLayer.backgroundColor = UIColor.black.cgColor
playerLayer.videoGravity = AVLayerVideoGravityResize
videoView.layer.addSublayer(playerLayer)
let url = NSURL(string: videoString)
let playerItem1 = AVPlayerItem(url: url! as URL)
videoPlayer.replaceCurrentItem(with: playerItem1)
videoPlayer.play()
AppDelegate.shared().showLoading()
// Setting slider max value
let duration : CMTime = videoPlayer.currentItem!.asset.duration
let seconds : Float64 = CMTimeGetSeconds(duration)
videoSlider.maximumValue = Float(seconds)
videoPlayButton.setImage(UIImage(named: "Pause"), for: .normal)
videoPlaying = true
//Adding Default Periodic Observer On Player
videoPlayer.addPeriodicTimeObserver(forInterval: CMTimeMakeWithSeconds(1, 1), queue: DispatchQueue.main) { (CMTime) -> Void in
if videoPlayer.currentItem?.status == .readyToPlay {
AppDelegate.shared().removeLoading()
self.videoSlider.value = Float(CMTimeGetSeconds(videoPlayer.currentTime()))
let currentTime : Int = Int(CMTimeGetSeconds(videoPlayer.currentTime()))
let minutes = currentTime/60
let seconds = currentTime - minutes * 60
self.durationLabel.text = NSString(format: "%02d:%02d", minutes,seconds) as String
}
}
}
else{
videoView.isHidden = true
let url = NSURL(string: videoString)
let playerItem = AVPlayerItem(url: url! as URL)
videoPlayer=AVPlayer(playerItem: playerItem)
playerLayer=AVPlayerLayer(player: videoPlayer)
playerLayer.frame = CGRect(x:0 , y: 75 , width: videoView.frame.size.width , height: UIScreen.main.bounds.height-170)
playerLayer.backgroundColor = UIColor.black.cgColor
playerLayer.videoGravity = AVLayerVideoGravityResize
videoView.layer.addSublayer(playerLayer)
}
i'm confused that do i have to remove playerlayer every time while coming to player screen? Help me
Thanks in advance
Related
I have a simple game in which players get three rounds to achieve the highest score . The gameScene exists inside a SwiftUI View and is created like this:
var gameScene: SKScene {
let scene = NyonindoGameScene(
size: CGSize(
width: UIScreen.main.bounds.width,
height: UIScreen.main.bounds.height
)
)
scene.viewModel = self.viewModel
scene.scaleMode = .aspectFill
return scene
}
It is called from the body of the view (inside a GeometryReader inside a ZStack) using SpriteView(). The code was working great until I tested on a new iPhone 13, which gave me all kinds of quirky and unexpected behaviors. I won't elaborate on them now as I have fixed most, but I am still left with a "phantom" start button. It is designed to display different text depending on the round being played (viz.: "Start," "Try Again," "Last Chance") using a var that is accurately counting rounds. However, I get this at the end of the first round:
When this Frankenstein button gets tapped, the new round begins. HOWEVER, SKPhysicsContactDelegate didBegin(_:) does not get called and collisions are ignored. (In my general bafflement here, I don't know if this is a separate issue or one that will go away when I solve the overlapping button problem.)
In any case, here is the relevant code for the startButton:
func addStartButton(text: String) {
startButton.removeFromParent() // added as one of many failed remedies
let startButtonLabel = SKLabelNode(text: text)
startButtonLabel.fontName = SKFont.bold
startButtonLabel.fontSize = 40.0
startButtonLabel.fontColor = UIColor.white
startButtonLabel.position = CGPoint(x: 0, y: -12)
startButton.position = CGPoint(x:self.frame.midX, y:self.frame.midY)
startButton.zPosition = 3
startButton.addChild(startButtonLabel)
addChild(startButton)
}
The initial start button is called like this in didMove(to view: SKView):
if attempts == 0 {
addStartButton(text: "Start")
}
And the buttons for the second and third round are called inside a gameOver() function like this:
if attempts == 1 {
startButton.removeFromParent() // again, this is overkill as it gets removed before this...
let text: String = "Try Again!"
addStartButton(text: text)
}
if attempts == 2 {
startButton.removeFromParent()
let text: String = "Last Chance!"
addStartButton(text: text)
}
I originally had a switch statement instead of the two if statements, but that generated the same problem. Print statements to the console suggest that only one button is being called for each round, but the results suggest something different.
Any clues? (Apologies if I haven't provided enough code for an assessment.)
why are you removing the button? change it's label:
class TTESTGameScene: SKScene {
var allBoxes: [SKSpriteNode] = []
var startButton: SKShapeNode = SKShapeNode(rect: CGRect(x: 0, y: 0, width: 200, height: 43), cornerRadius: 20)
override func didMove(to view: SKView) {
physicsBody = SKPhysicsBody(edgeLoopFrom: frame)
view.allowsTransparency = true
self.backgroundColor = .clear
view.alpha = 1.0
view.isOpaque = true
view.backgroundColor = SKColor.clear.withAlphaComponent(0.0)
let nextButton = SKShapeNode(rect: CGRect(x: 0, y: view.frame.maxY - 40, width: 66, height: 33), cornerRadius: 20)
nextButton.fillColor = .yellow
nextButton.name = "nextButton"
let nextLabel = SKLabelNode(text: "")
nextLabel.fontSize = 40.0
nextLabel.fontColor = UIColor.white
nextLabel.position = CGPoint(x: 0, y: -12)
nextButton.addChild(nextLabel)
addChild(nextButton)
startButton.fillColor = .red
startButton.name = "startButton"
let startButtonLabel = SKLabelNode(text: "000")
startButtonLabel.fontSize = 30.0
startButtonLabel.fontColor = UIColor.white
startButtonLabel.horizontalAlignmentMode = .center
startButtonLabel.position = CGPoint(x: startButton.frame.size.width/2, y: 10)
startButtonLabel.name = "startButtonLabel"
startButton.position = CGPoint(x:self.frame.midX - startButton.frame.size.width/2, y:self.frame.midY)
startButton.zPosition = 3
startButton.addChild(startButtonLabel)
addChild(startButton)
}
var attempts: Int = 0
func nextLevel() {
//startButton.removeFromParent() // added as one of many failed remedies
var text = ""
if attempts == 0 {
text = "Start"
}
else if attempts == 1 {
text = "Try Again!"
}
else if attempts == 2 {
text = "Last Chance!"
}
if let label = startButton.childNode(withName: "//startButtonLabel") as? SKLabelNode {
label.text = text
attempts += 1
attempts = attempts > 2 ? 0:attempts
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let touch = touches.first else { return }
let location = touch.location(in: self.view)
let sceneTouchPoint = self.convertPoint(fromView: location)
let touchedNode = self.atPoint(sceneTouchPoint)
print(touchedNode.name)
if touchedNode.name == "nextButton" {
nextLevel()
}
}
}
// A sample SwiftUI creating a GameScene and sizing it
// at 300x400 points
struct TTESTContentView: View {
var scene: SKScene {
let scene = TTESTGameScene()
scene.size = CGSize(width: 300, height: 400)
scene.scaleMode = .aspectFill
return scene
}
var body: some View {
SpriteView(scene: scene)
.frame(width: 300, height: 400)
//.ignoresSafeArea()
}
}
struct ContentViewTest_Previews: PreviewProvider {
static var previews: some View {
TTESTContentView()
}
}
I want to make a game when it's game over, a banner ad shows up, but I found out that the view takes at least one minute to load. I tried doing this on a different thread but it didn't work. I created the view in GameViewController.swift, and added the subview in the GameScene.swift. Also the Game Over Pop up is a set of SKSpriteNodes and SKLabelNodes.
GameViewController.swift
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
print("READY__$$$$$$$$$$$$$$$$$$$_________________.")
banner = GADBannerView(adSize: kGADAdSizeFullBanner)
banner.adUnitID = "ca-app-pub-3940256099942544/2934735716"
let request = GADRequest()
banner.load(request)
banner.frame = CGRect(x: 0, y: (view?.bounds.height)! - banner.frame.size.height, width: banner.frame.size.width, height: banner.frame.size.height)
banner.rootViewController = self
if let view = self.view as! SKView? {
// Load the SKScene from 'GameScene.sks'
if let scene = SKScene(fileNamed: "IntroScene") {
// Set the scale mode to scale to fit the window
scene.scaleMode = .aspectFill
// Present the scene
view.presentScene(scene)
}
view.ignoresSiblingOrder = true
view.showsFPS = true
view.showsNodeCount = true
}
}
override var shouldAutorotate: Bool {
return true
}
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
if UIDevice.current.userInterfaceIdiom == .phone {
return .allButUpsideDown
} else {
return .all
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Release any cached data, images, etc that aren't in use.
}
override var prefersStatusBarHidden: Bool {
return true
}
}
GameScene.swift
func spawnAd() {
print("READY___________________.")
DispatchQueue.main.async(execute: {
self.view?.addSubview(banner)
})
// DispatchQueue.global(qos: .userInteractive).async {
// DispatchQueue.main.async {
// self.view?.addSubview(banner)
// }
//
// }
}
The Game Over Screen Pop up
func spawnGameOverMenu() {
let dimPanel = SKSpriteNode(color: UIColor.brown, size: self.size)
dimPanel.alpha = 0.0
dimPanel.zPosition = 9
dimPanel.position = CGPoint(x: self.frame.midX, y: self.frame.midY)
self.addChild(dimPanel)
let fadeAlpha = SKAction.fadeAlpha(by: 0.5, duration: 0.6)
dimPanel.run(fadeAlpha)
gameOverMenu = SKSpriteNode(color: bgColor, size: CGSize(width: self.frame.width - 5, height: self.frame.height / 2))
gameOverMenu.position = CGPoint(x: self.frame.midX, y: self.frame.minY - self.frame.height)
gameOverMenu.name = "gameOverMenu"
gameOverMenu.zPosition = 10
self.addChild(gameOverMenu)
spawnGameOverLabel()
spawnResetLbl()
spawnAd()
let moveUp = SKAction.moveTo(y: self.frame.midY, duration: 1.0)
gameOverMenu.run(moveUp)
}
I figured out why it wasn't working, I set the root view controller after I loaded the request.
banner = GADBannerView(adSize: kGADAdSizeFullBanner)
banner.adUnitID = "ca-app-pub-3940256099942544/2934735716"
banner.rootViewController = self
let request = GADRequest()
banner.load(request)
banner.frame = CGRect(x: 0, y: (view?.bounds.height)! - banner.frame.size.height, width: banner.frame.size.width, height: banner.frame.size.height)
I want to add local notification in my app. I am filling information in textfields and set date, time and reminder before particular date selected for the exam. Anyone implement such a demo then please suggest me what to do.
Answer is based on what ever i understood, Please change the time and reminder string as per your requirement.
func scheduleNotification(InputUser:String) {
let now: NSDateComponents = NSCalendar.currentCalendar().components([.Hour, .Minute], fromDate: NSDate())
let cal = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)!
let date = cal.dateBySettingHour(now.hour, minute: now.minute + 1, second: 0, ofDate: NSDate(), options: NSCalendarOptions())
let reminder = UILocalNotification()
reminder.fireDate = date
reminder.alertBody = InputUser
reminder.alertAction = "Cool"
reminder.soundName = "sound.aif"
reminder.repeatInterval = NSCalendarUnit.Minute
UIApplication.sharedApplication().scheduleLocalNotification(reminder)
print("Firing at \(now.hour):\(now.minute+1)")
}
Set up Daily basic Local Notification 1 Day before or you can be modified it with the help of specific date in Swift 3.1
import UIKit
import UserNotifications
fileprivate struct AlarmKey{
static let startWorkIdentifier = "com.Reminder.Notification" //Add your own Identifier for Local Notification
static let startWork = "Ready for work? Toggle To \"Available\"."
}
class AlarmManager: NSObject{
static let sharedInstance = AlarmManager()
override init() {
super.init()
}
//MARK: - Clear All Previous Notifications
func clearAllNotifications(){
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().removeAllPendingNotificationRequests()
} else {
UIApplication.shared.cancelAllLocalNotifications()
}
}
func addReminder(with _ hour: Int, minutes: Int){
clearAllNotifications()
var dateComponent = DateComponents()
dateComponent.hour = hour // example - 7 Change you time here Progrmatically
dateComponent.minute = minutes // example - 00 Change you time here Progrmatically
if #available(iOS 10.0, *) {
dateComponent.timeZone = TimeZone.autoupdatingCurrent
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponent, repeats: false) //Set here **Repeat** condition
let content = UNMutableNotificationContent()
content.body = AlarmKey.startWork //Message Body
content.sound = UNNotificationSound.default()
let notification = UNNotificationRequest(identifier: AlarmKey.startWorkIdentifier, content: content, trigger: trigger)
UNUserNotificationCenter.current().delegate = self
UNUserNotificationCenter.current().add(notification) {(error) in
if let error = error {
print("Uh oh! We had an error: \(error)")
}
}
} else {
//iOS *9.4 below if fails the Above Condition....
dateComponent.timeZone = NSTimeZone.system
let calender = NSCalendar(calendarIdentifier: NSCalendar.Identifier.gregorian)!
let date = calender.date(from: dateComponent)!
let localNotification = UILocalNotification()
localNotification.fireDate = date
localNotification.alertBody = AlarmKey.startWork
localNotification.repeatInterval = NSCalendar.Unit.day
localNotification.soundName = UILocalNotificationDefaultSoundName
UIApplication.shared.scheduleLocalNotification(localNotification)
}
}
}
//This is optional method if you want to show your Notification foreground condition
extension AlarmManager: UNUserNotificationCenterDelegate{
#available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Swift.Void){
completionHandler([.alert,.sound])
}
}
Scenario: Create and display an overlay (ancillary) UIWindow.
Related Discussion: How do I toggle between UIWindows?
Code:
fileprivate func displayOverLay() {
let myWindow = {() -> UIWindow in
let cWindow = UIWindow(frame: CGRect(x: 10, y: 200, width: 300, height: 300))
cWindow.backgroundColor = UIColor.gray.withAlphaComponent(0.5)
cWindow.tag = 100
return cWindow
}()
myWindow.makeKeyAndVisible()
myWindow.windowLevel = UIWindowLevelAlert
let storyboard = UIStoryboard(name: "Hamburger", bundle: nil)
let vc = storyboard.instantiateInitialViewController()
myWindow.rootViewController = vc
return
}
Here's the shared UIApplication window status:
(lldb) po UIApplication.shared.windows
▿ 2 elements
- 0 : <UIWindow: 0x7fcffc804860; frame = (0 0; 375 667); autoresize = W+H; gestureRecognizers = <NSArray: 0x600000051280>; layer = <UIWindowLayer: 0x60000003e840>>
- 1 : <UIWindow: 0x7fcff9407240; frame = (10 200; 300 300); tag = 100; gestureRecognizers = <NSArray: 0x608000052810>; layer = <UIWindowLayer: 0x608000220420>>
(lldb) po UIApplication.shared.keyWindow!
<UIWindow: 0x7fcff9407240; frame = (10 200; 300 300); tag = 100; gestureRecognizers = <NSArray: 0x608000052810>; layer = <UIWindowLayer: 0x608000220420>>
Here's the result: no gray window sceen
Important Note: If I brake at the end of the displayOverLay() and do a 'po myWindow', and then continue, I do get the display.
So it appears that I'm missing some sort of event to have the UIWindow appear.
What is needed to force the new UIWindow w/contents to actually display?
You need to keep a reference to the created window, otherwise ARC will take care of disposing the window after you return from your function.
You could for instance return the newly created window from your function and store it in a property of the class from which your are calling the function.
Search bar not respond to tap/click?
First create UITableView in UIView
then add search bar in table header
and Cancel button respond, but search label not.
Conf method:
func configureSearchController() {
searchController = UISearchController(searchResultsController: nil)
searchController.searchResultsUpdater = self
searchController.dimsBackgroundDuringPresentation = false
searchController.searchBar.placeholder = "Search here..."
searchController.searchBar.delegate = self
searchController.searchBar.sizeToFit()
searchController.searchBar.showsCancelButton = true
tableView.tableHeaderView = searchController.searchBar
}
and call from here:
let dimension = CGRect(x: 0, y: 50, width: Int(dialogContainer.layer.frame.width), height: Int(dialogContainer.layer.frame.height - 100))
self.tableView = UITableView(frame: dimension, style: UITableViewStyle.plain)
self.tableView.delegate = self
self.tableView.dataSource = self
self.tableView.register(UINib(nibName: "DropdownCell", bundle: nil), forCellReuseIdentifier: "DropdownCell")
self.tableView.backgroundColor = .clear
self.tableView.separatorStyle = UITableViewCellSeparatorStyle.none
configureSearchController() // <-
dialogContainer.addSubview(tableView)
self.tableView.reloadData()