gpt4 book ai didi

swift - 如何描绘 iPhone 屏幕的边框(包括 X、11 或 12 系列的缺口)?

转载 作者:行者123 更新时间:2023-12-05 01:32:50 25 4
gpt4 key购买 nike

我正在尝试在主视图的外部描绘一条线 - 沿着屏幕的边缘描绘。下图显示了轮廓,下面的代码显示了它的动画效果。

iPhone border

问题是,动画首先绘制外边缘,然后绘制凹口周围的区域。

我需要它开始绘制外边缘,下降并围绕凹口绘制,然后继续沿着外边缘绘制直到完成。

import UIKit

class ViewController: UIViewController {

var layer: CAShapeLayer = CAShapeLayer()

override func viewDidLoad() {
super.viewDidLoad()

setupBorder()
animateBorder()
}

func setupBorder() {
let bounds = self.view.bounds

if UIDevice.current.hasNotch {

// FIXME: needs tweaks for:
// 12 pro max (corners and notch)
// 12 pro (corners)
// 12 mini (notch)
// the math works for all X and 11 series

// border around the phone screen
let framePath = UIBezierPath(roundedRect: bounds, byRoundingCorners: .allCorners, cornerRadii: CGSize(width: 40, height: 40))

// Math courtesy of:
// https://www.paintcodeapp.com/news/iphone-x-screen-demystified

let devicePointWidth = UIScreen.main.bounds.size.width
let w = devicePointWidth * 83 / 375
let n = devicePointWidth * 209 / 375

let notchBounds = CGRect(x: w, y: -10, width: n, height: 40)

let notchPath = UIBezierPath(roundedRect: notchBounds, byRoundingCorners: [.bottomLeft, .bottomRight], cornerRadii: CGSize(width: 20, height: 20))

// This is the problem. The framePath is drawn first,
// and then the notchPath is drawn. I need these to be
// mathematically merged

framePath.append(notchPath)
framePath.usesEvenOddFillRule = true

layer.path = framePath.cgPath
} else {
// if device is an 8 or lower, the border of the screen
// is a rectangle

layer.path = UIBezierPath(rect: bounds).cgPath
}

layer.strokeColor = UIColor.blue.cgColor
layer.strokeEnd = 0.0
layer.lineWidth = 20.0
layer.fillColor = nil
self.view.layer.addSublayer(layer)
}

func animateBorder() {
CATransaction.begin()

let animation = CABasicAnimation(keyPath: #keyPath(CAShapeLayer.strokeEnd))
animation.timingFunction = CAMediaTimingFunction(name: .linear)
animation.fromValue = 0.0
animation.toValue = 1.0
animation.duration = 6

CATransaction.setCompletionBlock { [weak self] in
self?.layer.strokeColor = UIColor.cyan.cgColor
self?.layer.strokeEnd = 1.0
}

layer.add(animation, forKey: "stroke-screen")
CATransaction.commit()

}

}

extension UIDevice {
var hasNotch: Bool {

// FIXME: Does not work with apps that use SceneDelegate
// Requires the window var in the AppDelegate

if #available(iOS 11.0, *) {
return UIApplication.shared.delegate?.window??.safeAreaInsets.bottom ?? 0 > 20
}
return false
}

}

上面的代码可以在新项目中使用,但是需要删除SceneDelegate.swift文件,中的Application Scene Manifest入口Info.plist 需要删除,var window: UIWindow? 需要添加到 AppDelegate.swift

最佳答案

您遇到这个问题是因为您要创建两个单独的形状并将一个附加到下一个。所以你的路径被正确绘制。

您需要使用精确坐标创建一个形状,以便正确绘制。
这是一个没有任何圆角的简单形状:

let framePath = UIBezierPath()
framePath.move(to: .zero)
framePath.addLine(to: CGPoint(x: w, y: 0))
framePath.addLine(to: CGPoint(x: w, y: 30))
framePath.addLine(to: CGPoint(x: w+n, y: 30))
framePath.addLine(to: CGPoint(x: w+n, y: 0))
framePath.addLine(to: CGPoint(x: devicePointWidth, y: 0))
framePath.addLine(to: CGPoint(x: devicePointWidth, y: self.view.bounds.height))
framePath.addLine(to: CGPoint(x: 0, y: self.view.bounds.height))
framePath.addLine(to: .zero)

然后您可以使用 addArc(withCenter:radius:startAngle:endAngle:clockwise:) 添加弯曲部分。

这是使用您计算出的一些值的粗略草稿:

let circleTop = CGFloat(3*Double.pi / 2)
let circleRight = CGFloat(0)
let circleBottom = CGFloat(Double.pi / 2)
let circleLeft = CGFloat(Double.pi)

let framePath = UIBezierPath()
framePath.move(to: CGPoint(x: 40, y: 0))
framePath.addLine(to: CGPoint(x: w-6, y: 0))
framePath.addArc(withCenter: CGPoint(x: w-6, y: 6), radius: 6, startAngle: circleTop, endAngle: circleRight, clockwise: true)
framePath.addArc(withCenter: CGPoint(x: w+20, y: 10), radius: 20, startAngle: circleLeft, endAngle: circleBottom, clockwise: false)
framePath.addLine(to: CGPoint(x: w+n-20, y: 30))
framePath.addArc(withCenter: CGPoint(x: w+n-20, y: 10), radius: 20, startAngle: circleBottom, endAngle: circleRight, clockwise: false)
framePath.addArc(withCenter: CGPoint(x: w+n+6, y: 6), radius: 6, startAngle: CGFloat(Double.pi), endAngle: circleTop, clockwise: true)
framePath.addLine(to: CGPoint(x: devicePointWidth-40, y: 0))
framePath.addArc(withCenter: CGPoint(x: devicePointWidth-40, y: 40), radius: 40, startAngle: circleTop, endAngle: circleRight, clockwise: true)
framePath.addLine(to: CGPoint(x: devicePointWidth, y: self.view.bounds.height - 40))
framePath.addArc(withCenter: CGPoint(x: UIScreen.main.bounds.size.width-40, y: UIScreen.main.bounds.size.height-40), radius: 40, startAngle: circleRight, endAngle: circleBottom, clockwise: true)
framePath.addLine(to: CGPoint(x: 40, y: self.view.bounds.height))
framePath.addArc(withCenter: CGPoint(x: 40, y: UIScreen.main.bounds.size.height-40), radius: 40, startAngle: circleBottom, endAngle: circleLeft, clockwise: true)
framePath.addLine(to: CGPoint(x: 0, y: 40))
framePath.addArc(withCenter: CGPoint(x: 40, y: 40), radius: 40, startAngle: circleLeft, endAngle: circleTop, clockwise: true)

enter image description here

关于swift - 如何描绘 iPhone 屏幕的边框(包括 X、11 或 12 系列的缺口)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65283017/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com