【问题标题】:Render a line graph on Apple Watch using watchOS 2使用 watchOS 2 在 Apple Watch 上渲染折线图
【发布时间】:2015-07-06 22:16:22
【问题描述】:

我正在尝试使用 watchOS 2 在 Apple Watch 上呈现线/阶梯图。与 iOS 9 不同,watchOS 2 不支持 Quartz。它只支持核心图形。我尝试编写一些代码来绘制折线图,​​但出现错误“CG​​ContextRestoreGState:无效上下文 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 上的 Stocks 应用。每当用户点击特定股票时,他将能够查看/可视化该股票的统计数据。任何人都可以帮助我实现这一目标。

【问题讨论】:

  • 对不起,我不知道你的问题。但是您是否尝试过使用折线图的图像定义 ImageSequence?这将使您有机会在 WKInterfacePicker 中使用它并利用数字表冠。

标签: ios swift watchkit watchos-2


【解决方案1】:

我通过以下步骤成功渲染线条:

  • 创建基于位图的图形上下文并使用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)

您可以查看示例代码here

【讨论】:

  • 别忘了 Apple Watch 上的视网膜!要生成 ratina 上下文,请使用 UIGraphicsBeginImageContextWithOptions(size, false, 2.0) 和 uiimage = UIImage(cgImage: cgimage, scale: 2.0,orientation: .up)
【解决方案2】:

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

【讨论】:

  • 一旦你强制展开上下文,然后你将有条件地使用它......如何将整个上下文操作包含在“if let context = context”闭包中并使用不展开上下文的上下文所有……
【解决方案3】:

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

【讨论】:

    【解决方案4】:

    这里的示例项目展示了如何在 WatchKit 2.0 上制作动态图表

    https://github.com/vlm/ExampleWatchGraph

    它的要点在 GraphPainter.swift 文件中,其中 CoreGraphics 用于绘制到屏幕外缓冲区(如 @shu223 建议的那样),然后在 WKInterfaceImage 中显示此缓冲区。

    Animated Watch Interface GIF.

    【讨论】:

      【解决方案5】:

      图形渲染是借助 bezierPath 完成的,并将其转换为图像以附加到 Apple Watch

      //Swift-3 Xcode-8.1

      导入 UIKit 类接口控制器: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
              }
          }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-04-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-09-12
        • 2023-04-08
        • 1970-01-01
        相关资源
        最近更新 更多