简体   繁体   中英

How to Draw in a UIView with NSTimer

One section of the app that I am trying to develop needs to display a set of images without the user interacting with the phone during the display cycle. The user starts the display sequence, but shouldn't need to tell the phone when to stop. The app also needs to be able to capture an image between each display cycle. What I mean is that the phone displays an image, then captures the photo and saves it, and then displays the next image and the cycle continues.

I have a good understanding of the image capturing portion, but I am struggling with how to display my set of images in the manner described above. I understand that one of the difficulties with implementing this is that the iPhone updates the view on a display cycle and compiles all the code upon execution, so its hard to get the two to wait for one another.

I have tried using an NSTimer to call the UIView to update with my specific image but the image does not draw correctly. I am using Core Graphics to draw bars or white and black with increasing frequency. I don't think that creating and playing a movie of the correct sequence of patterns will work because I also need to be able to tell the iPhone to capture an image each time a pattern is displayed.

Any ideas or suggestions are much appreciated!

My UIViewController:

import UIKit

class ViewController: UIViewController, UINavigationControllerDelegate {

// MARK: Properties
var orientation = "Vertical"
var numberOfBarPairs = UInt64(1)
var maximumNumberOfBarPairs = UInt64()
var binaryPattern = BinaryPattern()
var timer = NSTimer()

// Hide the status bar so the image displayed is full screen
var statusBarIsHidden = true

override func viewDidLoad() {
    super.viewDidLoad()
}

// MARK: Actions
@IBAction func displayBinaryPattern(sender: UIButton) {
    // Initiate the phase display

    // Capture the view's frame size and location
    let viewWidth = view.frame.width
    let viewHeight = view.frame.height
    //let viewSize = CGFloat(20)
    let viewOrigin = view.frame.origin

    // Set the frame that displays the binary patterns
    let frame = CGRectMake(viewOrigin.x, viewOrigin.y, viewWidth, viewHeight)

    // Set maximum number of bar pairs based on frame size
    maximumNumberOfBarPairs = 128 //Int(viewSize)/2

    // Instance a binary pattern and add it as a subview to the main view
    binaryPattern = BinaryPattern(frame: frame)

    // set display interval
    let displayInterval = 5.0

    // Set a timer to call drawBarPairs every interval
    timer = NSTimer.scheduledTimerWithTimeInterval(displayInterval, target: self, selector: Selector("updateView"), userInfo: nil, repeats: true)
}

func updateView() {
    numberOfBarPairs = numberOfBarPairs*2
    print("\(orientation), \(numberOfBarPairs)")

    view.addSubview(binaryPattern)

    // Cal the draw view
    binaryPattern.orientation = orientation
    binaryPattern.numberOfBarPairs = numberOfBarPairs

    // Stop the display when we reach a termination condition
    if numberOfBarPairs == maximumNumberOfBarPairs && orientation == "Horizontal" {
        // Stop the timer
        timer.invalidate()
    }

    // Change the orientaiton of the bar pairs when the number counter reaches the maximum
    if numberOfBarPairs == maximumNumberOfBarPairs && orientation == "Vertical" {
        orientation = "Horizontal"
        numberOfBarPairs = 0
    }
  }
}

My UIView that draws the patterns:

import UIKit

class BinaryPattern: UIView {

// MARK: Properties
var numberOfBarPairs: UInt64 {
    didSet {
        print("Bars Set")
        setNeedsDisplay()
    }
}

var orientation: String {
    didSet {
        print("orientation set")
        setNeedsDisplay()
    }
}

override init(frame: CGRect) {
    self.numberOfBarPairs = 1
    self.orientation = "Vertical"
    super.init(frame: frame)
}

required init(coder aDecoder: NSCoder) {
    self.numberOfBarPairs = 1
    self.orientation = "Vertical"
    super.init(coder: aDecoder)!
}

override func drawRect(rect: CGRect) {

    // Obtains the current graphics context. Think of a graphics context as a canvas. In this case, the canvas is the View that we will be working with, but there are other types of contexts, such as an offscreen buffer that we later turn into an image. Note that contexts are stateful, or a value will remain that value until it is set with a method.
    let context = UIGraphicsGetCurrentContext()

    // Disable anti-aliasing, so pixel boundarys are shown jagged
    CGContextSetShouldAntialias(context, false)

    // Query the view frame size to draw the binary pattern within
    let frameHeight: CGFloat = 256
    let frameWidth: CGFloat = 256

    // Define white and black colors
    let blackColor: UIColor = UIColor.blackColor()
    let whiteColor: UIColor = UIColor.whiteColor()

    // Determine if bars should be vertical or horizontal
    if self.orientation == "Horizontal" {
        let barWidth = frameWidth
        let barHeight = frameHeight/CGFloat(2*self.numberOfBarPairs)

        // Generate the bar pairs and fill them with appropriate colors
     //   for bar in 1...self.numberOfBarPairs {
     //       let yOrigin1 = 2*(CGFloat(bar)-1)*barHeight
     //       let yOrigin2 = (2*CGFloat(bar)-1)*barHeight
     //       let xOrigin: CGFloat = 0

        let xOrigin: CGFloat = 0
        let yOrigin1: CGFloat = barHeight
        let yOrigin2: CGFloat = 0

            CGContextSetFillColorWithColor(context, blackColor.CGColor)
            CGContextFillRect(context, CGRectMake(xOrigin, yOrigin1, barWidth, barHeight))

            CGContextSetFillColorWithColor(context, whiteColor.CGColor)
            CGContextFillRect(context, CGRectMake(xOrigin, yOrigin2, barWidth, barHeight))
       // }
    }
    else {
        // Calculate the width of each bar by dividing the outer frame width by twice the number of bar pairs
        let barWidth = frameWidth/CGFloat(2*self.numberOfBarPairs)
        let barHeight = frameHeight

        print("Bar Width: \(barWidth), Bar Height: \(barHeight)\n")

        // Generate the bar pairs and fill them with appropriate colors
        for bar in 1...self.numberOfBarPairs {
        //    let xOrigin1 = 2*(CGFloat(bar)-1)*barWidth
            let xOrigin2 = (2*CGFloat(bar)-1)*barWidth
            let yOrigin: CGFloat = 0

            print("x Origin: \(xOrigin2)")

        //let xOrigin1 = barWidth
        //let xOrigin2: CGFloat = 50
        //let yOrigin: CGFloat = 0
            //CGContextSetFillColorWithColor(context, blackColor.CGColor)
            //CGContextFillRect(context, CGRectMake(xOrigin1, yOrigin, barWidth, barHeight))

            CGContextSetFillColorWithColor(context, whiteColor.CGColor)

            CGContextFillRect(context, CGRectMake(xOrigin2, yOrigin, barWidth, barHeight))

        }
    }
  }
}

The timer should be calling the view's setNeedsDisplay. The view's drawRect will then draw the current state of the view.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM