使用watchOS 2在Apple Watch上绘制折线图

我正在尝试使用watchOS 2在Apple Watch上渲染线/步图。与iOS 9不同,watchOS 2不支持Quartz。 它只支持Core Graphics。 我试图写一些代码来绘制一个线图,但是我得到一个错误“CG​​ContextRestoreGState:invalid context 0x0。这是一个严重的错误。这个应用程序,或者它使用的一个库,正在使用一个无效的上下文,从而有助于整体系统稳定性和可靠性的降低,这是一个礼节性的问题:请解决这个问题,在即将到来的更新中,这将成为一个致命的错误。

以下是我使用的代码片段:

import WatchKit import Foundation import UIKit class InterfaceController: WKInterfaceController{ override func awakeWithContext(context: AnyObject?) { super.awakeWithContext(context) let path = UIBezierPath() let startPoint = CGPointMake(0.0, 0.0) path.moveToPoint(startPoint) let nextPoint = CGPointMake(20.0, 20.0) path.addLineToPoint(nextPoint) path.lineWidth = 1.0 UIColor.whiteColor().setStroke() path.stroke() } override func willActivate() { super.willActivate() } override func didDeactivate() { super.didDeactivate() } } 

我的最终结果应该是Apple Watch上的“股票”应用程序。 每当用户点击特定股票时,他将能够查看/可视化该股票的统计数据。 任何人都可以帮助我实现这一目标。

我成功地使用以下步骤来渲染线条:

  • 创build一个基于位图的graphics上下文,并使用UIGraphicsBeginImageContext使其成为当前上下文。
  • 绘制到上下文中。
  • 从上下文中提取CGImageRef并将其转换为UIImage对象。
  • 在WKInterfaceGroup或WKInterfaceImage上显示图像。

码:

 // 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是WKInterfaceImage属性。 这个对我有用。

我也可以在watchOS上使用UIBezierPath,如下所示:

 // 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) 

您可以在这里查看示例代码。

这里是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) 

这里的上下文不是CGContext,因此你有这个问题。 我不认为你可以直接在Apple Watch上使用Core Graphics。

下面是示例项目,演示如何在WatchKit 2.0上执行dynamicgraphics

https://github.com/vlm/ExampleWatchGraph

它的要点是在GraphPainter.swift文件中,CoreGraphics被用来绘制到屏幕外的缓冲区(如@ shu223build议),然后在WKInterfaceImage中显示这个缓冲区。

animation手表界面GIF 。

graphics渲染是通过bezierPath的帮助完成的,并且被转换为附加到Apple Watch的图像

// Swift-3 Xcode-8.1

导入UIKit类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 } }