我正在尝试创建类似下面的模型的个人资料图片视图。它带有一个小绿点,表示用户的在线状态。
我正在以编程方式创建视图,因此可以重用它。下面是到目前为止的代码。
import UIKit
@IBDesignable
class ProfileView: UIView {
fileprivate var imageView: UIImageView!
fileprivate var onlineStatusView: UIView!
fileprivate var onlineStatusDotView: UIView!
@IBInspectable
var image: UIImage? {
get { return imageView.image }
set { imageView.image = newValue }
}
@IBInspectable
var shouldShowStatusDot: Bool = true
override init(frame: CGRect) {
super.init(frame: frame)
initialize()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
initialize()
}
private func initialize() {
backgroundColor = .clear
imageView = UIImageView(frame: bounds)
imageView.backgroundColor = .lightGray
imageView.clipsToBounds = true
imageView.layer.cornerRadius = imageView.frame.height / 2
addSubview(imageView)
onlineStatusView = UIView(frame: CGRect(x: 0, y: 0, width: (bounds.height / 5), height: (bounds.height / 5)))
onlineStatusView.backgroundColor = .white
onlineStatusView.clipsToBounds = true
onlineStatusView.layer.cornerRadius = onlineStatusView.frame.height / 2
addSubview(onlineStatusView)
onlineStatusDotView = UIView(frame: CGRect(x: 0, y: 0, width: (onlineStatusView.bounds.height / 1.3), height: (onlineStatusView.bounds.height / 1.3)))
onlineStatusDotView.center = onlineStatusView.center
onlineStatusDotView.backgroundColor = UIColor(red: 0.17, green: 0.71, blue: 0.45, alpha: 1.0)
onlineStatusDotView.clipsToBounds = true
onlineStatusDotView.layer.cornerRadius = onlineStatusDotView.frame.height / 2
onlineStatusView.addSubview(onlineStatusDotView)
}
}
让我迷失的是如何将绿点视图固定在图像视图右上角的圆形边缘上。显然,视图的框架不是圆形的,因此我无法弄清楚在这种情况下要使用的自动布局约束。而且我也不想对值进行硬编码,因为它必须根据图像视图的大小移动。
我必须设置哪些自动布局约束才能将其放置在正确的位置?
我也在这里上传了demo project。
答案 0 :(得分:1)
使用以下命令更改初始化函数: 您可以在给定的图像链接中看到结果...
private func initialize() {
backgroundColor = .clear
imageView = UIImageView(frame: bounds)
imageView.backgroundColor = .lightGray
imageView.clipsToBounds = true
imageView.layer.cornerRadius = imageView.frame.height / 2
addSubview(imageView)
onlineStatusView = UIView(frame: CGRect(x: 0, y: 0, width: (bounds.height / 5), height: (bounds.height / 5)))
onlineStatusView.center = CGPoint(x: bounds.width / 7, y: bounds.height / 7)
onlineStatusView.backgroundColor = .white
onlineStatusView.clipsToBounds = true
onlineStatusView.layer.cornerRadius = onlineStatusView.frame.height / 2
addSubview(onlineStatusView)
onlineStatusDotView = UIView(frame: CGRect(x: 0, y: 0, width: (onlineStatusView.bounds.height / 1.3), height: (onlineStatusView.bounds.height / 1.3)))
onlineStatusDotView.center = CGPoint(x: onlineStatusView.frame.width / 2, y: onlineStatusView.frame.height / 2)
onlineStatusDotView.backgroundColor = UIColor(red: 0.17, green: 0.71, blue: 0.45, alpha: 1.0)
onlineStatusDotView.clipsToBounds = true
onlineStatusDotView.layer.cornerRadius = onlineStatusDotView.frame.height / 2
onlineStatusView.addSubview(onlineStatusDotView)
}
答案 1 :(得分:1)
将小绿色圆圈放在大圆圈的右上角:
.centerX
等于大圆的.trailing
,multiplier
为0.8536
。.centerY
等于大圆的.bottom
,multiplier
为0.1464
。 注意:使用三角学通过观察单位圆并计算比率multiplier
和{{ 1}}。在下面的示例代码中,我提供了一个名为(distance from top of square containing unit circle)/(height of unit circle)
的{{1}},它可以计算任意(distance from left edge of square containing unit circle)/(width of unit circle)
的度数。避免精确地func
和computeMultipliers(angle:)
的角度,因为这会产生自动版式不喜欢的angle
乘数。
这是一个独立的示例:
90
这是您代码的修改版本。我添加了一些约束来设置小圆圈的大小,并移动了将180
设置为0
的代码:
class ViewController: UIViewController {
var bigCircle: UIView!
var littleCircle: UIView!
override func viewDidLoad() {
super.viewDidLoad()
bigCircle = UIView()
bigCircle.translatesAutoresizingMaskIntoConstraints = false
bigCircle.backgroundColor = .red
view.addSubview(bigCircle)
bigCircle.widthAnchor.constraint(equalToConstant: 240).isActive = true
bigCircle.heightAnchor.constraint(equalToConstant: 240).isActive = true
littleCircle = UIView()
littleCircle.translatesAutoresizingMaskIntoConstraints = false
littleCircle.backgroundColor = .green
bigCircle.addSubview(littleCircle)
bigCircle.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
bigCircle.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
littleCircle.widthAnchor.constraint(equalToConstant: 60).isActive = true
littleCircle.heightAnchor.constraint(equalToConstant: 60).isActive = true
let (hMult, vMult) = computeMultipliers(angle: 45)
// position the little green circle using a multiplier on the right and bottom
NSLayoutConstraint(item: littleCircle!, attribute: .centerX, relatedBy: .equal, toItem: bigCircle!, attribute: .trailing, multiplier: hMult, constant: 0).isActive = true
NSLayoutConstraint(item: littleCircle!, attribute: .centerY, relatedBy: .equal, toItem: bigCircle!, attribute: .bottom, multiplier: vMult, constant: 0).isActive = true
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
bigCircle.layer.cornerRadius = 0.5 * bigCircle.frame.height
littleCircle.layoutIfNeeded()
littleCircle.layer.cornerRadius = 0.5 * littleCircle.frame.height
}
func computeMultipliers(angle: CGFloat) -> (CGFloat, CGFloat) {
let radians = angle * .pi / 180
let h = (1.0 + cos(radians)) / 2
let v = (1.0 - sin(radians)) / 2
return (h, v)
}
}