我在堆栈视图中屏蔽图像,但由于某些奇怪的原因,我的蒙版未正确对齐/调整图像大小。
以下是我在堆叠视图中动态添加此图像的实例,同时在其边界和间距内调整每个子视图的大小时,演示了什么。
如您所见,蒙版保留图像的原始大小,而不是调整大小的版本。我试过很多不同的宽度和宽度。高度变化包括 bounds.width,layer.frame.width,frame.width,frame.origin.x 等,并且没有运气。
Swift 2中的当前代码:
let testPicture:UIImageView = UIImageView(image: UIImage(named: "myPicture"))
testPicture.contentMode = .ScaleAspectFit
testPicture.layer.borderWidth = 1
testPicture.clipsToBounds = true
testPicture.layer.masksToBounds = true
view.layer.addSublayer(shapeLayer)
var width = testPicture.layer.frame.width
var height = testPicture.layer.frame.height
let center = CGPointMake(width/2, height/2)
let radius = CGFloat(CGFloat(width) / 2)
// Mask
let yourCarefullyDrawnPath = UIBezierPath()
yourCarefullyDrawnPath.moveToPoint(center)
yourCarefullyDrawnPath.addArcWithCenter(center,
radius: radius,
startAngle: 0,
endAngle: CGFloat( (0.80*360.0) * M_PI / 180.0),
clockwise: true)
yourCarefullyDrawnPath.closePath()
let maskPie = CAShapeLayer()
maskPie.frame = testPicture.layer.bounds
testPicture.clipsToBounds = true
testPicture.layer.masksToBounds = true
maskPie.path = yourCarefullyDrawnPath.CGPath
testPicture.layer.mask = maskPie
// Add Into Stackview
self.myStackView.addArrangedSubview(testPicture)
self.myStackView.layoutIfNeeded()
我怀疑我为了生成中心和半径变量而获取了错误的宽度和高度,尽管在尝试了所有不同的宽度和高度后,我仍然无法获得正确的尺寸。 : - (
答案 0 :(得分:1)
不幸的是,UIImageView
没有提供本机支持,但是你可以相当简单地计算。我已经created a function将采用一个给定的外部矩形和一个给定的内部矩形,并在它被安装在外部矩形内的方面后返回内部矩形。
该函数的Swift版本看起来像这样:
func aspectFitRect(outerRect outerRect:CGRect, innerRect:CGRect) -> CGRect {
let innerRectRatio = innerRect.size.width/innerRect.size.height; // inner rect ratio
let outerRectRatio = outerRect.size.width/outerRect.size.height; // outer rect ratio
// calculate scaling ratio based on the width:height ratio of the rects.
let ratio = (innerRectRatio > outerRectRatio) ? outerRect.size.width/innerRect.size.width:outerRect.size.height/innerRect.size.height;
// The x-offset of the inner rect as it gets centered
let xOffset = (outerRect.size.width-(innerRect.size.width*ratio))*0.5;
// The y-offset of the inner rect as it gets centered
let yOffset = (outerRect.size.height-(innerRect.size.height*ratio))*0.5;
// aspect fitted origin and size
let innerRectOrigin = CGPoint(x: xOffset+outerRect.origin.x, y: yOffset+outerRect.origin.y);
let innerRectSize = CGSize(width: innerRect.size.width*ratio, height: innerRect.size.height*ratio);
return CGRect(origin: innerRectOrigin, size: innerRectSize);
}
您需要做的另一件事是子类UIImageView
并覆盖layoutSubviews
方法。这是因为,当您将图片视图添加到UIStackView
时,您将无法再控制图片视图的图片。因此,通过覆盖layoutSubviews
,只要堆栈视图改变了视图的框架,您就能够更新掩码。
这样的事情应该达到预期的效果:
class MaskedImageView: UIImageView {
let maskLayer = CAShapeLayer()
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
override init(image: UIImage?) {
super.init(image: image)
commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
private func commonInit() {
// configure your common image view properties here
contentMode = .ScaleAspectFit
clipsToBounds = true
// mask your image layer
layer.mask = maskLayer
}
override func layoutSubviews() {
guard let img = image else { // if there's no image - skip updating the mask.
return
}
// the frame that the image itself will occupy in the image view as it gets aspect fitted
let imageRect = aspectFitRect(outerRect: bounds, innerRect: CGRect(origin: CGPointZero, size: img.size))
// update mask frame
maskLayer.frame = imageRect
// half the image's on-screen width or height, whichever is smallest
let radius = min(imageRect.size.width, imageRect.size.height)*0.5
// the center of the image rect
let center = CGPoint(x: imageRect.size.width*0.5, y: imageRect.size.height*0.5)
// your custom masking path
let path = UIBezierPath()
path.moveToPoint(center)
path.addArcWithCenter(center, radius: radius, startAngle: 0, endAngle: CGFloat(M_PI*2.0*0.8), clockwise: true)
path.closePath()
// update mask layer path
maskLayer.path = path.CGPath
}
}
然后,您可以从视图控制器创建图像视图,并将其正常添加到堆栈视图中。
let stackView = UIStackView()
override func viewDidLoad() {
super.viewDidLoad()
stackView.frame = view.bounds
stackView.distribution = .FillProportionally
stackView.spacing = 10
view.addSubview(stackView)
for _ in 0..<5 {
let imageView = MaskedImageView(image:UIImage(named:"foo.jpg"))
stackView.addArrangedSubview(imageView)
stackView.layoutIfNeeded()
}
}
给我以下结果:
在您的代码中注意到您正在执行此操作:
testPicture.clipsToBounds = true
testPicture.layer.masksToBounds = true
这些都做同样的事情。
UIView
只不过是基础CALayer
的包装器。但是为方便起见,某些CALayer
属性也具有UIView
等效项。所有与UIView
等效的内容都会转发至设置为CALayer
的消息,并在CALayer
获取时从clipsToBounds
获取值。
masksToBounds
和view.layer.masksToBounds = true
print(view.clipsToBounds) // output: true
view.layer.masksToBounds = false
print(view.clipsToBounds) // output: false
view.clipsToBounds = true
print(view.layer.masksToBounds) // output: true
view.clipsToBounds = false
print(view.layer.masksToBounds) // output: false
是这些对中的一对(虽然令人讨厌但他们没有共享相同的名称)。
尝试执行以下操作:
UIView
看到您正在使用clipToBounds
, u_l_f = unique_lines.keys()[var_test] //(...must be **variable** here... )
通常是首选的属性。