如何在六边形“地图”视图中生成UIImages

时间:2019-02-12 14:21:40

标签: swift user-interface

我正在构建一个要在其中显示个人资料的应用程序。人们以六角形蜂巢样式“靠近你”的图片。

完整的蜂箱应该可以拖动,例如Google地图。

我的问题是,是否可以仅使用UIKit来完成此操作,或者一起使用UIKit和SpriteKit会更容易。

我希望有人能指出正确的方向,或者对如何实现有一些想法。谢谢您的时间!

更新: 只是为了让我的问题更加清楚。

This is how my view looks like atm

And this is what I want to achieve

在第一张图像中,我只是将UIImage中心的X和Y位置设置了。

我想创建某种函数,该函数可以获取不同profilePics的数组,然后以这种模式进行输出。

1 个答案:

答案 0 :(得分:1)

UIKit就可以完成这项工作:例如,您应该尝试在CALayer上使用UIImageView设置掩码。

可拖动行为可以通过在UIScrollView中添加并排列所有图像子视图来实现,也可以通过具有自定义流程的UICollectionView来实现,但是可能很难设置上。

对于六边形视图,您会在这里找到一个有趣的示例,可以根据自己的需要进行调整:http://sapandiwakar.in/make-hexagonal-view-on-ios/

这是Swift 4.2中Sapan Diwakar解决方案的改编,并使用扩展名:

extension UIBezierPath {
    convenience init(roundedPolygonPathInRect rect: CGRect, lineWidth: CGFloat, sides: NSInteger, cornerRadius: CGFloat = 0, rotationOffset: CGFloat = 0) {
        self.init()

        let theta: CGFloat = 2.0 * CGFloat.pi / CGFloat(sides) // How much to turn at every corner
        let width = min(rect.size.width, rect.size.height)        // Width of the square

        let center = CGPoint(x: rect.origin.x + width / 2.0, y: rect.origin.y + width / 2.0)

        // Radius of the circle that encircles the polygon
        // Notice that the radius is adjusted for the corners, that way the largest outer
        // dimension of the resulting shape is always exactly the width - linewidth
        let radius = (width - lineWidth + cornerRadius - (cos(theta) * cornerRadius)) / 2.0

        // Start drawing at a point, which by default is at the right hand edge
        // but can be offset
        var angle = CGFloat(rotationOffset)

        let corner = CGPoint(x: center.x + (radius - cornerRadius) * cos(angle), y: center.y + (radius - cornerRadius) * sin(angle))
        move(to: CGPoint(x: corner.x + cornerRadius * cos(angle + theta), y: corner.y + cornerRadius * sin(angle + theta)))

        for _ in 0 ..< sides {
            angle += theta

            let corner = CGPoint(x: center.x + (radius - cornerRadius) * cos(angle), y: center.y + (radius - cornerRadius) * sin(angle))
            let tip = CGPoint(x: center.x + radius * cos(angle), y: center.y + radius * sin(angle))
            let start = CGPoint(x: corner.x + cornerRadius * cos(angle - theta), y: corner.y + cornerRadius * sin(angle - theta))
            let end = CGPoint(x: corner.x + cornerRadius * cos(angle + theta), y: corner.y + cornerRadius * sin(angle + theta))

            addLine(to: start)
            addQuadCurve(to: end, controlPoint: tip)
        }

        close()
    }
}

extension UIImageView {
    func setupHexagonMask(lineWidth: CGFloat, color: UIColor, cornerRadius: CGFloat) {
        let path = UIBezierPath(roundedPolygonPathInRect: bounds, lineWidth: lineWidth, sides: 6, cornerRadius: cornerRadius, rotationOffset: CGFloat.pi / 2.0).cgPath

        let mask = CAShapeLayer()
        mask.path = path
        mask.lineWidth = lineWidth
        mask.strokeColor = UIColor.clear.cgColor
        mask.fillColor = UIColor.white.cgColor
        layer.mask = mask

        let border = CAShapeLayer()
        border.path = path
        border.lineWidth = lineWidth
        border.strokeColor = color.cgColor
        border.fillColor = UIColor.clear.cgColor
        layer.addSublayer(border)
    }
}

然后您可以像这样使用它:

let image = UIImageView(frame: CGRect(x: 30, y: 30, width: 300, height: 300))
image.contentMode = .scaleAspectFill
image.image = UIImage(named: "lenna.png")
image.setupHexagonMask(lineWidth: 5.0, color: .white, cornerRadius: 20.0)

view.addSubview(image)

编辑:正如我告诉您的,最简单的方法是使用UIScrollView来显示地图,并通过简单的数学运算就可以按所需的方式显示六边形。

这里是一个小示例,您必须调整以适应您的要求。例如,您应该格外小心性能。此示例不应按原样使用,如果您有很多图像,则应即时加载它们,并在不显示时将其删除。您甚至可以考虑使用背景渲染,如果帧/帧的帧数过多...

Example with the same image, here lenna.png

假设viewUIScrollView

let hexaDiameter : CGFloat = 150
let hexaWidth = hexaDiameter * sqrt(3) * 0.5
let hexaWidthDelta = (hexaDiameter - hexaWidth) * 0.5
let hexaHeightDelta = hexaDiameter * 0.25
let spacing : CGFloat = 5

let rows = 10
let firstRowColumns = 6

view.contentSize = CGSize(width: spacing + CGFloat(firstRowColumns) * (hexaWidth + spacing),
                          height: spacing + CGFloat(rows) * (hexaDiameter - hexaHeightDelta + spacing) + hexaHeightDelta)

for y in 0..<rows {
    let cellsInRow = y % 2 == 0 ? firstRowColumns : firstRowColumns - 1
    let rowXDelta = y % 2 == 0 ? 0.0 : (hexaWidth + spacing) * 0.5
    for x in 0..<cellsInRow {
        let image = UIImageView(frame: CGRect(x: rowXDelta + CGFloat(x) * (hexaWidth + spacing) + spacing - hexaWidthDelta,
                                              y: CGFloat(y) * (hexaDiameter - hexaHeightDelta + spacing) + spacing,
                                              width: hexaDiameter,
                                              height: hexaDiameter))
        image.contentMode = .scaleAspectFill
        image.image = UIImage(named: "lenna.png")
        image.setupHexagonMask(lineWidth: 5.0, color: .white, cornerRadius: 10.0)
        view.addSubview(image)
    }
}