【问题标题】:CALayer: add a border only at one sideCALayer:仅在一侧添加边框
【发布时间】:2011-10-24 18:12:33
【问题描述】:

我可以通过这种方式为 CALayer 添加边框:

[webView.layer setBorderColor: [[UIColor colorWithRed:0.6 green:0.7 blue:0.2 alpha:1] CGColor]];
[webView.layer setBorderWidth: 2.75];   

但是可以只在一侧添加边框吗?我只需要底部的边框。或者我可以通过其他属性来达到这个目的,例如框架、边界、掩码、...?

感谢您的帮助!


@Control-V

        UIWebView *webView = [[UIWebView alloc] init];
        CALayer *webViewLayer = webView.layer;

        // now you can do a lot of stuff like borders:
        [webViewLayer setBorderColor: [[UIColor greenColor] CGColor]];
        [webViewLayer setBorderWidth: 2.75];    

查看 CALayer 文档: https://developer.apple.com/documentation/quartzcore/calayer

看看这里: http://iosdevelopertips.com/cocoa/add-rounded-corners-and-border-to-uiwebview.html

【问题讨论】:

  • 我仍然想知道您是如何找到 UIWebView 的图层属性的。我在苹果官方文档中很难找到。
  • @Control-V:我为你编辑我的问题
  • 你在劫持 webview 的层?? 这是一个可怕的想法。请不要那样做。除非在极少数情况下,您应该始终将UIWebView 视为一个不可自省且完全不透明的对象。甚至不要试图乱搞诸如它的层之类的东西(因为它的层不是CALayer,而是CATiledLayer,例如),因为UIWebView 可以非常特别地说明事情应该如何进行配置。

标签: iphone objective-c core-animation calayer


【解决方案1】:

border 属性总是为视图的 4 边添加边框。 您可以制作自己的 draw 方法来在视图底部绘制边框。

但是,为什么不直接在 UIWebView 上方添加一个视图,让它看起来像一个边框呢?

【讨论】:

    【解决方案2】:

    我用这个做了一个右边框:

    leftScrollView.clipsToBounds = YES;
    
    CALayer *rightBorder = [CALayer layer];
    rightBorder.borderColor = [UIColor darkGrayColor].CGColor;
    rightBorder.borderWidth = 1;
    rightBorder.frame = CGRectMake(-1, -1, CGRectGetWidth(leftScrollView.frame), CGRectGetHeight(leftScrollView.frame)+2);
    
    [leftScrollView.layer addSublayer:rightBorder];
    

    【讨论】:

    • 感谢您的回复,我会尽快查看您的代码!
    • @Kazzar,在您的第一行中,您的意思是 [CALayer layer] 还是 [webView layer]?
    • 如果您尝试在不剪切子视图的视图上使用它,那么它将不起作用。您可以在 IB 的“属性检查器”选项卡中切换它(称为“剪辑子视图”),或通过代码使用 view.clipsToBounds = YES; 设置属性。
    • 我认为帧码应该是leftBorder.frame = CGRectMake(0, 0, 1, leftScrollView.frame.size.height);
    • 不,这会在右侧绘制边框,但不在任何其他边缘上。但是,您可以调整偏移量以获得不止一侧的边框。这是保存为多个边缘绘制多个图层的一种巧妙方法。需要更多解释才能弄清楚实际发生了什么,但这是一个很好的解决方案。
    【解决方案3】:

    最简单的方法是添加一个 subLayer 来绘制选择性边框,但是在选择此解决方案时需要考虑一些事项,最大的问题是确保边框 subLayer 始终位于顶部,并且边框在您更改图层的框架。

    我实现了一个解决这些问题的开源解决方案,并让您像这样声明选择性边界:

    myView.borderDirection = AUIFlexibleBordersDirectionRight | AUIFlexibleBordersDirectionTop;
    

    您可以获取代码,并阅读更多信息here

    【讨论】:

    • 非常酷的代码。使用简单,非常适合我的目的。非常感谢!!
    • 这个答案比上面的正确答案更好,因为它支持视图的自动布局。
    【解决方案4】:

    这是 swift 等价物

    leftScrollView.clipsToBounds = true
    let rightBorder: CALayer = CALayer()
    rightBorder.borderColor = UIColor.darkGrayColor().CGColor
    rightBorder.borderWidth = 1
    rightBorder.frame = CGRectMake(-1, -1, CGRectGetWidth(leftScrollView.frame), CGRectGetHeight(leftScrollView.frame)+2)
    leftScrollView.layer.addSublayer(rightBorder)
    

    【讨论】:

    • 刚试过这个,结果是有边框,但宽度与我添加的按钮的大小不匹配,边框几乎是两倍长。
    • 赞成这个,但你现在可以用属性替换那些 C 风格的 getter ......并使用 CGRect 的 init 方法
    【解决方案5】:

    还有另一种方法可以做到这一点。 CAShapeLayer 具有名为“strokeStart”和“strokeEnd”的属性。考虑到描边从 0 开始,到达原点后在 1 结束,从而完成了路径,您可以设置开始和结束的值以在一侧绘制边框。

    开始抚摸路径的相对位置。 动画。 此属性的值必须在 0.0 到 1.0 的范围内。此属性的默认值为 0.0。 结合 strokeEnd 属性,该属性定义描边路径的子区域。此属性中的值指示开始描边的路径上的相对点,而 strokeEnd 属性定义结束点。值 0.0 表示路径的开始,而值 1.0 表示路径的结束。两者之间的值沿路径长度线性解释。

    例子:

    let path = UIBezierPath(roundedRect: bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
    let mask = CAShapeLayer()
    mask.path = path.CGPath
    mask.strokeColor = UIColor.redColor().CGColor
    mask.strokeStart = 0.45
    mask.strokeEnd = 0.92
    self.layer.mask = mask
    

    【讨论】:

    • 当您已经在使用形状图层时,为什么还要努力计算出那些奇怪的数字?只需锻炼线条的路径,将其赋予形状图层 + 无需图层蒙版
    【解决方案6】:

    我的 Swift 解决方案。它涉及四个不同的功能,都是对 UIView 的扩展。每个函数都添加了不同的边框。

    extension UIView {
    @discardableResult func addRightBorder(color: UIColor, width: CGFloat) -> UIView {
        let layer = CALayer()
        layer.borderColor = color.cgColor
        layer.borderWidth = width
        layer.frame = CGRect(x: self.frame.size.width-width, y: 0, width: width, height: self.frame.size.height)
        self.layer.addSublayer(layer)
        return self
        }
    @discardableResult func addLeftBorder(color: UIColor, width: CGFloat) -> UIView {
        let layer = CALayer()
        layer.borderColor = color.cgColor
        layer.borderWidth = width
        layer.frame = CGRect(x: 0, y: 0, width: width, height: self.frame.size.height)
        self.layer.addSublayer(layer)
        return self
        }
    @discardableResult func addTopBorder(color: UIColor, width: CGFloat) -> UIView {
        let layer = CALayer()
        layer.borderColor = color.cgColor
        layer.borderWidth = width
        layer.frame = CGRect(x: 0, y: 0, width: self.frame.size.width, height: width)
        self.layer.addSublayer(layer)
        return self
        }
    @discardableResult func addBottomBorder(color: UIColor, width: CGFloat) -> UIView {
        let layer = CALayer()
        layer.borderColor = color.cgColor
        layer.borderWidth = width
        layer.frame = CGRect(x: 0, y: self.frame.size.height-width, width: self.frame.size.width, height: width)
        self.layer.addSublayer(layer)
        return self
        }
    }
    

    【讨论】:

    • 你可能想将 self.layer.addSublayer(layer) 切换到 self.layer.insertSublayer(layer, at: UInt32(self.layer.sublayers?.count ?? 0))
    • 我的仍然有正确的填充,我不想要这个。
    • 完美,接受的答案给了我一些这个没有的问题。
    【解决方案7】:

    以下适用于 Swift 4.2 沿现有 UIView 应用边框。

    extension UIView {
        enum Side {
            case top
            case bottom
            case left
            case right
        }
    
        func addBorder(to side: Side, color: UIColor, borderWidth: CGFloat) {
            let subLayer = CALayer()
            subLayer.borderColor = color.cgColor
            subLayer.borderWidth = borderWidth
            let origin = findOrigin(side: side, borderWidth: borderWidth)
            let size = findSize(side: side, borderWidth: borderWidth)
            subLayer.frame = CGRect(origin: origin, size: size)
            layer.addSublayer(subLayer)
        }
    
        private func findOrigin(side: Side, borderWidth: CGFloat) -> CGPoint {
            switch side {
            case .right:
                return CGPoint(x: frame.maxX - borderWidth, y: 0)
            case .bottom:
                return CGPoint(x: 0, y: frame.maxY - borderWidth)
            default:
                return .zero
            }
        }
    
        private func findSize(side: Side, borderWidth: CGFloat) -> CGSize {
            switch side {
            case .left, .right:
                return CGSize(width: borderWidth, height: frame.size.height)
            case .top, .bottom:
                return CGSize(width: frame.size.width, height: borderWidth)
            }
        }
    }
    

    你可以这样称呼它:

    myView.addBorder(to: .left, color: .black, borderWidth: 2.0)
    

    发生了什么:

    • 用户提供枚举中定义的Side,以及colorborderWidth
    • 一个新的子层被创建并被赋予borderColorborderWidth
    • 计算原点,由边确定
    • 大小是计算出来的,也是由边决定的
    • 最后,层被赋予一个框架,然后添加为子层

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-07-26
      • 2013-03-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多