UIImageView 上的 directionalLayoutMargins 在水平堆栈视图中不起作用

Posted

技术标签:

【中文标题】UIImageView 上的 directionalLayoutMargins 在水平堆栈视图中不起作用【英文标题】:directionalLayoutMargins on UIImageView not working inside horizontal stack view 【发布时间】:2020-08-24 21:45:42 【问题描述】:

我正在创建一个水平堆栈视图:

let hs = UIStackView(forAutoLayout: ());
hs.axis = .horizontal
hs.spacing = 0
hs.alignment = .top
hs.distribution = .fill
hs.layoutMargins = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
hs.isLayoutMarginsRelativeArrangement = true
hs.translatesAutoresizingMaskIntoConstraints = false

然后放置几个孩子:

let label = UILabel(forAutoLayout: ());
hs.addArrangedSubview(label)
let image = UIImageView(frame: CGRect(x: 0, y: 0, width: 32, height: 32))
image.directionalLayoutMargins = NSDirectionalEdgeInsets(top: 64, leading: 0, bottom: 16, trailing: 16)
hs.addArrangedSubview(image)

水平堆栈视图布局看起来不错,但是我在图像中添加了似乎被忽略的布局边距。有没有办法在水平堆栈视图中围绕特定子项设置边距?

编辑:

我知道我可以将 UIImageView 扔到另一个视图中并设置约束。或者更简单,只需使用 EdgeInsets 将其放入另一个堆栈视图中:

let imageStack = UIStackView(forAutoLayout: ());
imageStack.axis = .vertical
imageStack.alignment = .fill
imageStack.distribution = .fill
imageStack.directionalLayoutMargins = NSDirectionalEdgeInsets(top: 64, leading: 0, bottom: 16, trailing: 16)
imageStack.isLayoutMarginsRelativeArrangement = true
imageStack.translatesAutoresizingMaskIntoConstraints = false

imageStack.addArrangedSubview(image)

// add imageStack to horizontal stack view, instead of image
hs.addArrangedSubview(imageStack)

添加到另一个视图或在 UIImageView 中使用图像矩形插入似乎只是为了在视图周围添加边距或内边距。来自 android,我可以在任何视图(包括图像视图)上设置填充和边距,而无需包装在另一个元素中,这对于如此简单的事情来说似乎是一项疯狂的工作。

【问题讨论】:

您是否要向图像视图“添加顶部填充”?如果是这样,那么这种方法是不正确的。见:***.com/questions/32551890/… 因此,要向图像视图添加插图或边距,您必须将其放在另一个视图中。看起来很荒谬,感谢 ios 【参考方案1】:

完全确定你想要什么,但听起来你想要:

水平堆栈视图 左侧标签 右侧的图像视图 图像视图 32x32 其 图像视图顶部距离标签顶部 64 分

所以,它看起来像这样:

绿色轮廓显示元素框架(包括堆栈视图)。

如果正确,您可以使用.withAlignmentRectInsets() 在运行时修改图像。

这是一个例子:

class StackTestViewController: UIViewController 
    
    let hs = UIStackView()
    let label = UILabel()
    let imageView = UIImageView()
    
    override func viewDidLoad() 
        super.viewDidLoad()
        
        hs.axis = .horizontal
        hs.spacing = 0
        hs.alignment = .top
        hs.distribution = .fill
        hs.isLayoutMarginsRelativeArrangement = true
        hs.translatesAutoresizingMaskIntoConstraints = false
        
        label.text = "Test Label"
        
        hs.addArrangedSubview(label)
        hs.addArrangedSubview(imageView)
        
        view.addSubview(hs)
        
        let g = view.safeAreaLayoutGuide
        
        NSLayoutConstraint.activate([
            
            hs.topAnchor.constraint(equalTo: g.topAnchor, constant: 80.0),
            hs.centerXAnchor.constraint(equalTo: g.centerXAnchor),
            
            imageView.widthAnchor.constraint(equalToConstant: 32.0),
            
            // we want the imageView to be 64-pts taller than its width
            imageView.heightAnchor.constraint(equalTo: imageView.widthAnchor, constant: 64)
            
        ])
        
        if let img = UIImage(named: "swiftBlue64x64") 
            // use withAlignmentRectInsets to create a new image with 64-pts "empty space" on top
            imageView.image = img.withAlignmentRectInsets(UIEdgeInsets(top: -64, left: 0, bottom: 0, right: 0))
        

        // so we can see the label frame
        label.backgroundColor = .yellow
        
    
    

我使用了这张 64x64 像素的图片:


编辑

来自 Apple 的文档:

讨论

使用此属性可指定此视图及其子视图的边缘之间所需的空间量(以磅为单位)。

因此,您可以将其应用于UIStackView作为一个整体或具有子视图的视图。这应该可以解释为什么它不能应用于UIImageView(无子视图)。

【讨论】:

谢谢。我更新了这个问题,我想它真的是关于我认为我对 directionalLayoutMargins 的误解。似乎我应该能够在 ImageView 上设置边距。我知道我可以将 UIIImageView 包装在另一个视图中,或者弄乱 ImageView 中的图像插图。但这似乎是一种解决方法,因为人们不能简单地在 ImageView 周围添加边距。

以上是关于UIImageView 上的 directionalLayoutMargins 在水平堆栈视图中不起作用的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Swift 中检测 UIImageView 上的 UIImageView 更改或 KVO 炒锅

UIImageView 上的重叠手势识别器

为啥 UIButton 上的 UIImageView 会在触摸时重新出现?

如何在动画过程中检测UIImageView上的点击?

UIImageView 上的按钮不可点击

UIImageView 上的多个按钮