Video is not being loaded in page control in ios swift - ios

I am implmenting pages control, and in each page video will be playing, but i had made it with using xibs, load each video in each xib, only the first video is being get played, rest all videos not getting played, showing as blank screen.
Main Code
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
loadScrollView()
}
func loadScrollView() {
let pageCount : CGFloat = 3.0
scrollView.backgroundColor = UIColor.clear
scrollView.delegate = self
scrollView.isPagingEnabled = true
scrollView.contentSize = CGSize(width: scrollView.frame.size.width * pageCount, height: scrollView.frame.size.height)
scrollView.showsHorizontalScrollIndicator = false
pageController.numberOfPages = Int(pageCount)
let v1 = Video1.instanceFromNib() // xib with video 1
let v2 = Video2.instanceFromNib() // xib with video 2
let v3 = Video3.instanceFromNib() // xib with video 3
var videoClassArray = [v1,v2,v3] as [UIView]
for i in 0..<Int(pageCount) {
print(self.scrollView.frame.size.width)
var view = UIView(frame: CGRect(x: self.scrollView.frame.size.width * CGFloat(i), y: 0, width: self.scrollView.frame.size.width, height: self.scrollView.frame.size.height))
view = videoClassArray[i]
self.scrollView.addSubview(view)
}
}
//MARK: UIScrollView Delegate
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let viewWidth: CGFloat = scrollView.frame.size.width
// content offset - tells by how much the scroll view has scrolled.
let pageNumber = floor((scrollView.contentOffset.x - viewWidth / 50) / viewWidth) + 1
pageController.currentPage = Int(pageNumber)
}
//MARK: Page tap action
func pageChanged() {
let pageNumber = pageController.currentPage
var frame = scrollView.frame
frame.origin.x = frame.size.width * CGFloat(pageNumber)
frame.origin.y = 0
scrollView.scrollRectToVisible(frame, animated: true)
}
The above is the view controller where im loading the xibs into various views.And the xib code is in the below.
class Video1: UIView {
class func instanceFromNib() -> UIView {
return UINib(nibName: "Video1", bundle: nil).instantiate(withOwner: nil, options: nil)[0] as! UIView
}
var player: AVPlayer!
var playerLayer = AVPlayerLayer()
var videoName = "BoardSetup_1"
#IBOutlet weak var baseView: UIView!
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func layoutSubviews() {
super.layoutSubviews()
let videoURL = Bundle.main.url(forResource: videoName, withExtension: "mp4")
player = AVPlayer(url: videoURL!)
player?.actionAtItemEnd = .none
player?.isMuted = true
let playerLayer = AVPlayerLayer(player: player)
playerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
playerLayer.zPosition = -1
playerLayer.bounds = self.layer.bounds
playerLayer.frame = baseView.frame
baseView.layer.addSublayer(playerLayer)
baseView.backgroundColor = UIColor.blue
player?.play()
//loop video
NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object: player?.currentItem, queue: nil, using: { (_) in
DispatchQueue.main.async {
self.player?.seek(to: kCMTimeZero)
self.player.play()
}
})
}
}
The above code is for xib with loading the videos , the code is same for the rest xibs, so mentioning only 1 xib.
The issue im facing while loading the xib only the video will be get played in first view and in rest view its showing as blank screen.

Why not use should use UIPageViewController for pagination? It's possible to use UIScrollView but then you need to implement the page recycling yourself otherwise you end up wasting a lot of memory.

Related

Swift - how to resize a UIView dynamically based on the size of a video player frame

I have a video player and a UIView overlaying it which I use for Gesture Recognition in the video area. I am doing this so you can tap different area of the video to play, rewind and do other functions.
At the moment, this works fine in landscape but if I rotate the device to portrait. The UIView doesn't resize but the video player does. I tried to use constraints programmatically but I can't figure out how to access the NSLayout anchor of the video player.
I have a function which retrieve the size of the video frame which I currently use to set the UIView to the size of the video player.
The code below can be just copied into a project to play a video and show the UIView I want to adjust. You just need to add UIView to the UIViewController storyboard. The code does not contain the GestureRecogniser part.
import UIKit
import AVFoundation
class ViewController: UIViewController {
let controlContainerView: UIView = {
let view = UIView()
view.backgroundColor = UIColor(white: 0, alpha: 1)
return view
}()
let activityIndicatorView: UIActivityIndicatorView = {
let aiv = UIActivityIndicatorView(style: .whiteLarge)
aiv.translatesAutoresizingMaskIntoConstraints = false
aiv.startAnimating()
return aiv
}()
#IBOutlet weak var videoContainer: UIView!
var player: AVPlayer?
var playerLayer: AVPlayerLayer?
var tapRegionBounds: UIView!
var tapRegionAreaCreated: Bool = false
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let urlString = "https://www.radiantmediaplayer.com/media/bbb-360p.mp4"
videoPlayer(filename: urlString)
player?.addObserver(self, forKeyPath: "currentItem.loadedTimeRanges", options: .new, context: nil)
}
override func viewDidAppear(_ animated: Bool) {
self.playerLayer?.frame = CGRect(x: 0, y: 0, width: self.videoContainer.frame.width, height: self.videoContainer.frame.height)
updateTapRegions()
}
func videoPlayer(filename: String){
let item = AVPlayerItem(url: URL(string: filename)!)
player = AVPlayer(playerItem: item)
playerLayer = AVPlayerLayer(player: player)
playerLayer?.videoGravity = .resizeAspect
playerLayer?.frame = CGRect(x: 0, y: 0, width: self.videoContainer.frame.width, height: self.videoContainer.frame.height)
videoContainer.layer.addSublayer(playerLayer!)
player?.play()
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if keyPath == "currentItem.loadedTimeRanges" {
activityIndicatorView.stopAnimating()
controlContainerView.backgroundColor = .clear
}
}
func videoFrame() -> CGRect? {
guard let layer = playerLayer
else { return nil }
let frame = layer.videoRect
if frame.height > 0.0 {
let frameInWindow = layer.convert(frame, to: nil)
return view.convert(frameInWindow, from: nil)
} else {
return nil
}
}
//THE CODE BELOW KIND OF WORKS TO SHOW HOW I WANT IT TO WORK BUT WITHOUT HAVING TO DELETE THE VIEW EACH TIME
func updateTapRegions() {
guard let video = videoFrame() else { return }
let container = videoContainer.bounds
if tapRegionAreaCreated == true {
tapRegionBounds.removeFromSuperview()
tapRegionAreaCreated = false
}
tapRegionBounds = UIView()
tapRegionBounds.frame = CGRect(x: video.minX, y: video.minY, width: container.width, height: video.height)
tapRegionBounds?.alpha = 0.5
tapRegionBounds.backgroundColor = UIColor.red
if tapRegionAreaCreated == false {
view.addSubview(tapRegionBounds)
tapRegionAreaCreated = true
}
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
coordinator.animate(alongsideTransition: { (context) in
}) { (context) in
self.playerLayer?.frame = CGRect(x: 0, y: 0, width: self.videoContainer.frame.width, height: self.videoContainer.frame.height)
self.updateTapRegions()
}
}
}
I tried to update the frame in viewWillLayoutSubviews() but nothing changed either. I know my updateTapRegions function isn't the right way but if anyone could point me in the right direction that would be great thanks.
Unfortunately you didn't say in your question how you are resizing the video container view on which all this depends. But here's a possibility. I've used auto layout to get these results in portrait and landscape:
Now suppose we have a sublayer (an AVPlayerLayer) and a subview (the tap gesture view). Well, the subview can be resized to fit automatically using autolayout! So only the player layer is left; it doesn't automatically resize using autolayout, but you can resize it manually in viewDidLayoutSubviews.
Finally, I worked it out by moving the code from transition function(even though the video player resized properly) to viewDidLayoutSubviews which then worked fine. Also I no longer to create and remove the view each time the device changes orientation.
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
self.playerLayer?.frame = CGRect(x: 0, y: 0, width: self.videoContainer.frame.width, height: self.videoContainer.frame.height)
guard let video = videoFrame() else { return }
if tapRegionBounds != nil {
self.tapRegionBounds.frame = CGRect(x: video.minX, y: video.minY, width: video.width, height: video.height)
}
}

YouTube player opening unnecessarily during scrolling of CollectionView

I am working on a chatbot where the different type of response comes from the server and I display the response using UICollectionView cells in chat screen. Different type of cells presents according to server response. when server response with playing video, I am presenting the cell that contains youtube player. I am using https://github.com/kieuquangloc147/YouTubePlayer-Swift. The issue is when I scroll chat screen (collectionView) youtube player is opening again and again. Sometimes it is blocking all the UI element and stop scrolling. I tried different methods but can't able to resolve it. Here is the code:
PlayerView:
import UIKit
class PlayerView: UIView, YouTubePlayerDelegate {
override init(frame: CGRect) {
super.init(frame: frame)
addYotubePlayer()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// youtube player
lazy var youtubePlayer: YouTubePlayerView = {
let viewFrame = UIScreen.main.bounds
let player = YouTubePlayerView(frame: CGRect(x: 0, y: 0, width: viewFrame.width - 16, height: viewFrame.height * 1/3))
player.delegate = self
return player
}()
// used as an overlay to dismiss the youtube player
let blackView = UIView()
// youtube player loader
lazy var playerIndicator: UIActivityIndicatorView = {
let indicator = UIActivityIndicatorView()
indicator.activityIndicatorViewStyle = .whiteLarge
indicator.hidesWhenStopped = true
return indicator
}()
// shows youtube player
func addYotubePlayer() {
if let window = UIApplication.shared.keyWindow {
blackView.frame = window.frame
self.addSubview(blackView)
blackView.backgroundColor = UIColor(white: 0, alpha: 0.5)
let tap = UITapGestureRecognizer(target: self, action: #selector(handleDismiss))
tap.numberOfTapsRequired = 1
tap.cancelsTouchesInView = false
blackView.addGestureRecognizer(tap)
let centerX = UIScreen.main.bounds.size.width / 2
let centerY = UIScreen.main.bounds.size.height / 2
blackView.addSubview(playerIndicator)
playerIndicator.center = CGPoint(x: centerX, y: centerY)
playerIndicator.startAnimating()
blackView.addSubview(youtubePlayer)
youtubePlayer.center = CGPoint(x: centerX, y: centerY)
blackView.alpha = 0
youtubePlayer.alpha = 0
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {
self.blackView.alpha = 1
self.youtubePlayer.alpha = 1
}, completion: nil)
}
}
func play(_ videoID: String) {
youtubePlayer.loadVideoID(videoID)
}
#objc func handleDismiss() {
blackView.removeFromSuperview()
UIApplication.shared.keyWindow?.viewWithTag(24)?.removeFromSuperview()
UIApplication.shared.keyWindow?.removeFromSuperview()
}
func playerReady(_ videoPlayer: YouTubePlayerView) {
self.playerIndicator.stopAnimating()
}
func playerStateChanged(_ videoPlayer: YouTubePlayerView, playerState: YouTubePlayerState) {
}
func playerQualityChanged(_ videoPlayer: YouTubePlayerView, playbackQuality: YouTubePlaybackQuality) {
}
}
YouTubePlayerCell (Which I present in collectionView wthe hen server responds for video):
import UIKit
class YouTubePlayerCell: ChatMessageCell {
var player: PlayerView = PlayerView(frame: UIScreen.main.bounds)
override func setupViews() {
super.setupViews()
setupCell()
}
func setupCell() {
messageTextView.frame = CGRect.zero
textBubbleView.frame = CGRect.zero
}
func loadVideo(with videoID: String) {
player.tag = 24
UIApplication.shared.keyWindow?.addSubview(player)
player.play(videoID)
}
override func prepareForReuse() {
super.prepareForReuse()
player.removeFromSuperview()
UIApplication.shared.keyWindow?.viewWithTag(24)?.removeFromSuperview()
}
}
Here is how I am presenting the YouTubePlayerCell in cellForItemAt method of UICollectionView
let message = messages[indexPath.row]
if message.actionType == ActionType.video_play.rawValue {
if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: ControllerConstants.youtubePlayerCell, for: indexPath) as? YouTubePlayerCell {
self.resignResponders()
if let videoId = message.videoData?.identifier {
cell.loadVideo(with: videoId)
}
return cell
}
}
Full Source Code can be found here: https://github.com/imjog/susi_iOS/tree/ytplayer
I can see that in the below code
if let videoId = message.videoData?.identifier {
cell.loadVideo(with: videoId)
}
you are calling loadVideo method, which is responsible for showing the player.
So while scrolling you are reusing the cell and it calls loadVideo method and present the player. so the solution is don't start playing the video by default on displaying the cell, provide a play/pause button on the cell video overlay and on clicking the the button start playing the video.
If my analysis is wrong please let me know, what exact issue you have.
Why do you add the player as a subView each time you have to play the video ? My suggestion would be, as you are adding the player view on the whole screen, you can have just one instance of the view and add it just once(may be at the beginning) and keep it hidden. To play the video just unhide the player and load the video.
Instead best practice would be to have a View controller for Youtube Player and present it with the video id each time you need to play and then dismissing when done.
Thanks for your answers. I solve this by this way:
Rather than presenting Player on setting on the cell, I am now adding a thumbnail to the cell and a button on thumbnail view so that whenever the user clicks play button, it opens a new controller (Previously I was presenting in UIWindow) and presenting it as modalPresentationStyle of overFullScreen by using protocol because cell cannot present a ViewController.
Protocol: (In YouTubePlayerCell class)
protocol PresentControllerDelegate: class {
func loadNewScreen(controller: UIViewController) -> Void
}
Final YouTubePlayer.swift:
import UIKit
import Kingfisher
protocol PresentControllerDelegate: class {
func loadNewScreen(controller: UIViewController) -> Void
}
class YouTubePlayerCell: ChatMessageCell {
weak var delegate: PresentControllerDelegate?
var message: Message? {
didSet {
addThumbnail()
}
}
lazy var thumbnailView: UIImageView = {
let imageView = UIImageView()
imageView.image = ControllerConstants.Images.placeholder
imageView.contentMode = .scaleAspectFill
imageView.clipsToBounds = true
imageView.layer.cornerRadius = 15
imageView.isUserInteractionEnabled = true
return imageView
}()
lazy var playButton: UIButton = {
let button = UIButton(type: .system)
button.setImage(ControllerConstants.Images.youtubePlayButton, for: .normal)
button.addTarget(self, action: #selector(playVideo), for: .touchUpInside)
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
override func setupViews() {
super.setupViews()
setupCell()
prepareForReuse()
}
func setupCell() {
messageTextView.frame = CGRect.zero
textBubbleView.frame = CGRect(x: 8, y: 0, width: 208, height: 158)
textBubbleView.layer.borderWidth = 0.2
textBubbleView.backgroundColor = .white
}
override func prepareForReuse() {
super.prepareForReuse()
thumbnailView.image = nil
}
func addThumbnail() {
textBubbleView.addSubview(thumbnailView)
textBubbleView.addConstraintsWithFormat(format: "H:|-4-[v0]-4-|", views: thumbnailView)
textBubbleView.addConstraintsWithFormat(format: "V:|-4-[v0]-4-|", views: thumbnailView)
self.downloadThumbnail()
self.addPlayButton()
}
func addPlayButton() {
thumbnailView.addSubview(playButton)
playButton.heightAnchor.constraint(equalToConstant: 44).isActive = true
playButton.widthAnchor.constraint(equalToConstant: 44).isActive = true
playButton.centerXAnchor.constraint(equalTo: thumbnailView.centerXAnchor).isActive = true
playButton.centerYAnchor.constraint(equalTo: thumbnailView.centerYAnchor).isActive = true
}
func downloadThumbnail() {
if let videoID = message?.videoData?.identifier {
let thumbnailURLString = "https://img.youtube.com/vi/\(videoID)/default.jpg"
let thumbnailURL = URL(string: thumbnailURLString)
thumbnailView.kf.setImage(with: thumbnailURL, placeholder: ControllerConstants.Images.placeholder, options: nil, progressBlock: nil, completionHandler: nil)
}
}
#objc func playVideo() {
if let videoID = message?.videoData?.identifier {
let playerVC = PlayerViewController(videoID: videoID)
playerVC.modalPresentationStyle = .overFullScreen
delegate?.loadNewScreen(controller: playerVC)
}
}
}
Delegate implementation in CollectionViewController:
extension ChatViewController: PresentControllerDelegate {
func loadNewScreen(controller: UIViewController) {
self.present(controller, animated: true, completion: nil)
}
}
Final source code can be found here: https://github.com/fossasia/susi_iOS/pull/372

how to pass parameter in init method of UIView?

Let me know if i have made any mistake don't downcast the question.
here is the problem i am trying to play a video and following is code
import UIKit
import AVFoundation
// custom UIView to display frame for avplayer
class VideoPlayerView: UIView {
let urlString String?
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .blackColor()
//static url for video
urlString = "https://firebasestorage.googleapis.com/v0/b/gameofchats-762ca.appspot.com/o/message_movies%2F12323439-9729-4941-BA07-2BAE970967C7.mov?alt=media&token=3e37a093-3bc8-410f-84d3-38332af9c726"
if let url = NSURL(string: urlString) {
let player = AVPlayer(URL: url)
let playerLayer = AVPlayerLayer(player: player)
self.layer.addSublayer(playerLayer)
playerLayer.frame = self.frame
player.play()
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
// view controller to launch video player
class VideoPlayerController: UIViewController {
var message: Messages?{
didSet{
}
}
let overlayView: UIView = {
let view = UIView()
view.isUserInteractionEnabled = true
view.backgroundColor = UIColor(white: 0, alpha: 0.5)
return view
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .black
let height = view.frame.width * 9 / 16
let videoPlayerFrame = CGRect(x: 0, y: 0, width: view.frame.width, height: height)
let videoPlayerView = VideoContainerView(frame: videoPlayerFrame)
view.addSubview(videoPlayerView)
videoPlayerView.center = view.center
}
in the init method of VideoPlayerView i have used static url of video for urlString property which is playing fine. i want to set urlString property from my videoPlayerController class how i can do that ? because when i initialize
let view = VideoPlayerView(frame:frame) // this code will call init method before i can set the urlString property.
anyone have idea how to do that. please help. thank you in advance for any suggestions.
Just make other initializer with needed parameters and call it.
convenience init(frame: CGRect, urlString: String) {
self.init(frame: frame)
//make here what you want
}

tapgesture not working in collectionViewCell, Neither any UIElements is visible on cell which is added by storyboard

I have a collectionViewCell that either plays a video or displays and image.Now the elements in the cell are generated programatically. I added tap gesture to toggle the sound when video play. The gesture recognizer wasn't getting called. I tried to place a button in story and get its action, that also didn't recieve a call. Then, I tried to place a view inside the cell, that also didn't display.
Here is my code with tap gesture:
import UIKit
import AVKit
import AVFoundation
#IBDesignable class CHCollectionImageCell: UICollectionViewCell {
// MARK: Properties
var imgView: UIImageView! = UIImageView()
var screenWidth:CGFloat = 0
var screenHeight:CGFloat = 0
var playerLayer: AVPlayerLayer!
let tapOnCell = UITapGestureRecognizer(target: self, action: #selector (CHCollectionImageCell.changeMuteRegimeVideo))
// MARK: Functions
override func awakeFromNib() {
super.awakeFromNib()
}
func configureCell(insight: InsightModel) {
imgView.removeFromSuperview()
if playerLayer != nil {
playerLayer.removeFromSuperlayer()
playerLayer = nil
}
self.removeGestureRecognizer(tapOnCell)
if insight.isVideo {
guard let unwrappedVideoURLString = insight.videoURL,
let unwrappedVideoURL = URL(string: unwrappedVideoURLString) else {
return
}
let playerItem = AVPlayerItem(url: unwrappedVideoURL)
let player = AVPlayer(playerItem: playerItem)
playerLayer = AVPlayerLayer(player: player)
playerLayer.frame = self.bounds
player.isMuted = false
layer.addSublayer(playerLayer)
addGestureRecognizer(self.tapOnCell)
} else {
imgView.frame = CGRect(x: 0, y: 0, width: self.frame.size.width, height: self.frame.size.width)
imgView.image = UIImage(named: "stone")
imgView.contentMode = UIViewContentMode.scaleAspectFill
imgView.clipsToBounds = true
clipsToBounds = true
addSubview(self.imgView)
}
}
/*
#IBAction func tapToTurnOfSound(_ sender: Any) {
if isInsightViedo{
if let unwrappedPlayer = playerLayer.player {
unwrappedPlayer.isMuted = !unwrappedPlayer.isMuted
}
}
//Even Tried adding view as below in the cell
//let tapView = UIView()
//tapView.backgroundColor = ColorCodes.appThemeColor
//self.addSubview(tapView)
//self.bringSubview(toFront: tapView)
//tapView.addGestureRecognizer(tapOnCell)
}
*/
func configureCell() {
imgView.removeFromSuperview()
if playerLayer != nil {
playerLayer.removeFromSuperlayer()
playerLayer = nil
}
self.removeGestureRecognizer(tapOnCell)
imgView.frame = CGRect(x: 0, y: 0, width: self.frame.size.width, height: self.frame.size.width)
imgView.image = UIImage(named: "stone")
imgView.contentMode = UIViewContentMode.scaleAspectFill
imgView.clipsToBounds = true
clipsToBounds = true
addSubview(self.imgView)
}
func changeMuteRegimeVideo() {
if let unwrappedPlayer = playerLayer.player {
unwrappedPlayer.isMuted = !unwrappedPlayer.isMuted
}
}
}
Iam doing the same thing in my application by using the following code :
let longPressGesture:UILongPressGestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(viewController.longPress(_:)))
longPressGesture.minimumPressDuration = 0.8
longPressGesture.delegate = self
collectionView.addGestureRecognizer(longPressGesture)
and then call the function:
func longPress(_ longPressGestureRecognizer: UILongPressGestureRecognizer) {
if longPressGestureRecognizer.state == UIGestureRecognizerState.began {
let touchPoint = longPressGestureRecognizer.location(in: collectionView)
if eventsTableView.indexPathForRow(at: touchPoint) != nil {
let index = eventsTableView.indexPathForRow(at: touchPoint)//do whatever you want to do with this index
}}}
you can do whatever you want to do in this function. In my case i used this to enlarge the image in the collection view

iOS custom view doesn't show image immediately

I made a simple custom view in Swift which has a background image view with a photo and some labels in front. I then added the custom view to my storyboard and it displays well, I can see the background image and labels.
But when I run my app on my device the image view doesn't show immediately, if I navigate to another view then back, it is displayed. I only have a timer which scheduled some tasks in background in my scene. Did I miss anything here?
Here is the code of my custom view
import UIKit
#IBDesignable class GaugeView: UIImageView {
#IBOutlet weak var speedLabel: UILabel!
let circlePathLayer = CAShapeLayer()
var circleRadius: CGFloat = 50.0
var speed: CGFloat {
get {
return circlePathLayer.strokeEnd
}
set {
speedLabel.text = String(format: "%.2f", newValue)
if newValue < 20.0 {
circlePathLayer.strokeColor = UIColor.blueColor().CGColor
} else if newValue >= 25.0 {
circlePathLayer.strokeColor = UIColor.redColor().CGColor
} else {
circlePathLayer.strokeColor = UIColor.yellowColor().CGColor
}
if (newValue > 50) {
circlePathLayer.strokeEnd = 1
} else if (newValue < 0) {
circlePathLayer.strokeEnd = 0
} else {
circlePathLayer.strokeEnd = newValue / 49.9
}
}
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
xibSetup()
}
override init(frame: CGRect) {
super.init(frame: frame)
xibSetup()
}
override func layoutSubviews() {
super.layoutSubviews()
circleRadius = bounds.width / 2 - 2.6
circlePathLayer.frame = bounds
circlePathLayer.path = circlePath().CGPath
}
// Our custom view from the XIB file
var view: UIView!
let nibName = "GaugeView"
func xibSetup() {
view = loadViewFromNib()
// use bounds not frame or it'll be offset
view.frame = bounds
// Make the view stretch with containing view
view.autoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight
// Adding custom subview on top of our view (over any custom drawing > see note below)
addSubview(view)
// Configure speed circle layer
configure()
}
func configure() {
speed = 0.0
circlePathLayer.frame = bounds
circlePathLayer.lineWidth = 6
circlePathLayer.fillColor = UIColor.clearColor().CGColor
circlePathLayer.strokeColor = UIColor.blueColor().CGColor
layer.addSublayer(circlePathLayer)
backgroundColor = UIColor.whiteColor()
}
func circleFrame() -> CGRect {
var circleFrame = CGRect(x: 0, y: 0, width: 2*circleRadius, height: 2*circleRadius)
circleFrame.origin.x = CGRectGetMidX(circlePathLayer.bounds) - CGRectGetMidX(circleFrame)
circleFrame.origin.y = CGRectGetMidY(circlePathLayer.bounds) - CGRectGetMidY(circleFrame)
return circleFrame
}
func circlePath() -> UIBezierPath {
let center: CGPoint = CGPointMake(CGRectGetMidX(circlePathLayer.bounds), CGRectGetMidY(circlePathLayer.bounds))
let start = CGFloat(1.33 * M_PI_2)
let end = CGFloat( 1.64 * M_2_PI)
return UIBezierPath(arcCenter: center, radius: circleRadius, startAngle: start, endAngle: end, clockwise: true)
}
func loadViewFromNib() -> UIView {
let bundle = NSBundle(forClass: self.dynamicType)
let nib = UINib(nibName: nibName, bundle: bundle)
let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView
return view
}
}
Then I added the custom view to my storyboard and navigate to the scene programatically with performSegueWithIdentifier("dashboardSegue", sender: nil). I just noticed not only the custome view, but two progress bar on the scene are not displayed as well.
It's better show your code, but i am guessing your timer stuck the main UI thread. When you navigate to another view, your timer.invalidate() was called. Try to remove the NSTimer to see if it works well.

Resources