I am trying to render a line/step graph on Apple Watch using watchOS 2. Unlike iOS 9, watchOS 2 doesn\'t support Quartz. It only supports Core Graphics. I tried writing some cod
Graph render is done by the help of bezierPath and which is converted to image to attached to Apple Watch
//Swift-3 Xcode-8.1
import UIKit class InterfaceController: WKInterfaceController {
@IBOutlet var graphImage: WKInterfaceImage!
override func awake(withContext context: Any?) {
super.awake(withContext: context)
// Configure interface objects here.
}
override func willActivate() {
super.willActivate()
let path = createBeizePath()
//Change graph to image
let image:UIImage = UIImage.shapeImageWithBezierPath(bezierPath: path, fillColor: .red, strokeColor: .black)
graphImage.setImage(uiimage)
}
//Draw graph here
func createBeizePath() -> UIBezierPath
{
let path = UIBezierPath()
//Rectangle path Trace
path.move(to: CGPoint(x: 20, y: 100) )
path.addLine(to: CGPoint(x: 50 , y: 100))
path.addLine(to: CGPoint(x: 50, y: 150))
path.addLine(to: CGPoint(x: 20, y: 150))
return path
}
}
extension UIImage {
class func shapeImageWithBezierPath(bezierPath: UIBezierPath, fillColor: UIColor?, strokeColor: UIColor?, strokeWidth: CGFloat = 0.0) -> UIImage! {
bezierPath.apply(CGAffineTransform(translationX: -bezierPath.bounds.origin.x, y: -bezierPath.bounds.origin.y ) )
let size = CGSize(width: 100 , height: 100)
UIGraphicsBeginImageContext(size)
let context = UIGraphicsGetCurrentContext()
var image = UIImage()
if let context = context {
context.saveGState()
context.addPath(bezierPath.cgPath)
if strokeColor != nil {
strokeColor!.setStroke()
context.setLineWidth(strokeWidth)
} else { UIColor.clear.setStroke() }
fillColor?.setFill()
context.drawPath(using: .fillStroke)
image = UIGraphicsGetImageFromCurrentImageContext()!
context.restoreGState()
UIGraphicsEndImageContext()
}
return image
}
}
Here's code in watchOS 3
// Create a graphics context
let size = CGSize(width:self.contentFrame.size.width, height:100)
UIGraphicsBeginImageContext(size)
let context = UIGraphicsGetCurrentContext()
// Setup for the path appearance
context!.setStrokeColor(UIColor.white.cgColor)
context!.setLineWidth(4.0)
// Draw lines
context!.beginPath ();
context?.move(to: CGPoint())
context?.addLine(to: CGPoint(x: 100, y: 100))
context?.addLine(to: CGPoint(x: 0, y: 100))
context?.addLine(to: CGPoint(x: 100, y: 0))
context!.strokePath();
// Convert to UIImage
let cgimage = context!.makeImage();
let uiimage = UIImage(cgImage: cgimage!)
// End the graphics context
UIGraphicsEndImageContext()
self.graphGroup.setBackgroundImage(uiimage)
Here's the example project that shows how to do dynamic graphs on WatchKit 2.0
https://github.com/vlm/ExampleWatchGraph
The gist of it is in the GraphPainter.swift file, where CoreGraphics is used to draw into an off-screen buffer (as @shu223 suggested), then display this buffer in a WKInterfaceImage.
Animated Watch Interface GIF.
I succeeded to render lines with following steps:
UIGraphicsBeginImageContext
.Code:
// Create a graphics context
let size = CGSizeMake(100, 100)
UIGraphicsBeginImageContext(size)
let context = UIGraphicsGetCurrentContext()
// Setup for the path appearance
CGContextSetStrokeColorWithColor(context, UIColor.whiteColor().CGColor)
CGContextSetLineWidth(context, 4.0)
// Draw lines
CGContextBeginPath (context);
CGContextMoveToPoint(context, 0, 0);
CGContextAddLineToPoint(context, 100, 100);
CGContextMoveToPoint(context, 0, 100);
CGContextAddLineToPoint(context, 100, 0);
CGContextStrokePath(context);
// Convert to UIImage
let cgimage = CGBitmapContextCreateImage(context);
let uiimage = UIImage(CGImage: cgimage!)
// End the graphics context
UIGraphicsEndImageContext()
// Show on WKInterfaceImage
image.setImage(uiimage)
image
is WKInterfaceImage property. It works for me.
Also I can draw using UIBezierPath on watchOS as follow:
// Create a graphics context
let size = CGSizeMake(100, 100)
UIGraphicsBeginImageContext(size)
let context = UIGraphicsGetCurrentContext()
UIGraphicsPushContext(context!)
// Setup for the path appearance
UIColor.greenColor().setStroke()
UIColor.whiteColor().setFill()
// Draw an oval
let rect = CGRectMake(2, 2, 96, 96)
let path = UIBezierPath(ovalInRect: rect)
path.lineWidth = 4.0
path.fill()
path.stroke()
// Convert to UIImage
let cgimage = CGBitmapContextCreateImage(context);
let uiimage = UIImage(CGImage: cgimage!)
// End the graphics context
UIGraphicsPopContext()
UIGraphicsEndImageContext()
image.setImage(uiimage)
You can check the sample codes here.
The context here are not CGContext, thus you have the issue. I do not think you can use Core Graphics directly on Apple Watch.