使用Swift(iOS)创建可点击的身体图解

11
我正在尝试在iOS应用程序中重新创建一些东西(使用Swift),这些东西我已经在HTML5中制作了(使用map和area-coords)。我想展示一个与用户点击/触摸交互的人体图。该身体由大约20个不同部分组成,用户可以选择一个或多个身体部位。每个身体部位都有一个选定状态的图像,当选定某个部位时,该图像应出现。单击选定的部位将取消选择。选择一个或多个部位后,用户可以继续并在下一个视图控制器中获得有关这些部位的一些信息。我附上了一个简化的图像来解释我的目标。

bodyparts selection

有人能解释一下实现这个目标的最佳方法是什么吗?在Swift中是否有类似的技术可以用来创建这样的交互式图像?

谢谢!


你想要它是二维还是三维? - rptwsthi
@sketchyTech CALayerhitTest 只适用于图层的矩形边界。OP 的插图显示了不规则的形状。我认为在这种情况下使用贝塞尔路径和 containsPoint 更好。(此外,图层是一个低级系统组件,引入了另一层复杂性。)它们确实很强大,但我认为在这种情况下它们不值得增加额外的复杂性。 - Duncan C
谢谢!我确实需要不规则的形状,所以我想我会深入研究CAShapeLayer。从我阅读的资料中得知,我必须为每个身体部位创建一个CAShapeLayer。要定义每个身体部位的形状,我可以将UIBezierPath定义为路径。我应该将所有这些CAShapeLayers定位在带有基本未选中身体图像的UIImageView上吗?我该如何做到这一点呢?通常我会使用约束来定位UIView / Button等,但是我认为CAShapeLayer无法使用约束,对吗? - klaaskox
1
iOS中图层没有自动布局约束,您需要做的是将UIImageView约束,然后将图层添加为其子图层。确保每个部分相对于身体图像的位置和大小进行定位。旋转不应该是一个问题,因为图像视图是受限制的,而图层在其中保持固定,但如果大小发生变化,例如分屏,则图层将需要调整大小和位置,但保持一切相对不应该是一个问题。您的另一个选择是使用一系列UIView子类和**drawRect:**。 - sketchyTech
我已经成功实现了形状定位,但我仍在努力弄清楚如何绑定触摸事件。尝试使用touchesBegan,并循环所有子层执行命中测试。这是正确的方式吗? - klaaskox
显示剩余5条评论
3个回答

0
一种非常简单的方法是在区域上放置不可见的按钮,然后将每个按钮连接到一个IBAction,并在其中放置任何想要发生的事情。
@IBAction func shinTapped(sender: UIButton) {
    tappedCounter = 0
    if tappedCounter == 0 {
      // set property to keep track
      shinSelected = true
      // TODO: set button image to selected state
      // increment counter
      tappedCounter++
      }else{
      // set property to keep track
      shinSelected = false
      // TODO: set button image to nil
      // reset counter
      tappedCounter = 0
  }

这可能会有点棘手,需要布局才能让每个按钮都处于正确的位置,但如果您使用大小类别进行工作,完全可以做到。 我相信有更优雅的方法来实现它,但这是一种方法。


0

修复完成!

首先我像这样向 UIImageView 添加了子图层

var path = UIBezierPath()
path.moveToPoint(CGPointMake(20, 30))
path.addLineToPoint(CGPointMake(40, 30))

// add as many coordinates you need...

path.closePath()

var layer = CAShapeLayer()
layer.path = path.CGPath
layer.fillColor = UIColor(red: 255, green: 0, blue: 0, alpha: 0.5).CGColor
layer.hidden = true

bodyImage.layer.addSublayer(layer)

然后我重写了touchesbegan函数,以便在点击形状时显示和隐藏。

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {

    if let touch = touches.first! as? UITouch {
        // get tapped position
        let position = touch.locationInView(self.bodyImage)

        // loop all sublayers
        for layer in self.bodyImage.layer.sublayers! as! [CAShapeLayer] {

            // check if tapped position is inside shape-path
            if CGPathContainsPoint(layer.path, nil, position, false) {
                if (layer.hidden) {
                    layer.hidden = false
                }
                else {
                    layer.hidden = true
                }
            }
        }
    }
}

嗨,我正在尝试做类似的事情,但我有点新手。你能否在github上发布一个示例代码让我开始学习?我不理解其中一些代码。谢谢! - Pangu
@Pangu 你有类似的样例吗?我也在寻找类似的东西。 - srivas
我只是想知道你是如何处理不同设备和应用于imageView的缩放的。这会使形状图层的坐标出现偏差。 - Moebius

0

没有内置机制来检测不规则形状的点击。标准的UIView点击检测使用框架矩形。(同样适用于CALayers,如sketchyTech在上面的评论中建议的那样。)

我建议将身体区域绘制为贝塞尔路径。您可以创建一个自定义的UIView子类(BodyView),它将管理包含贝塞尔路径的每个BodyRegion对象的数组。

UIBezierPath类包括一个containsPoint方法,让您知道一个点是否在路径内。您的BodyView可以使用它来决定哪个路径对象被点击。

贝塞尔路径将处理绘制身体区域确定哪个部分被点击。


你有这方面的示例吗?我也在寻找类似的东西。 - srivas
@srivas,不,我没有例子。这并不复杂。尝试使用我描述的containsPoint()方法,并在无法正确运行时发布问题。 - Duncan C

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接