【问题标题】:UIView set only side bordersUIView 只设置侧边框
【发布时间】:2012-06-29 11:58:24
【问题描述】:

有没有办法将 UIView 的边框设置为一种颜色,而顶部和底部另一种颜色?

【问题讨论】:

    标签: objective-c ios cocoa-touch uiview


    【解决方案1】:

    不——CALayer 边框不支持这种行为。完成您想要的最简单的方法是在视图的每一侧添加一个 n 点宽的不透明子视图,并使用所需的边框颜色作为其背景颜色。

    例子:

    CGSize mainViewSize = theView.bounds.size;
    CGFloat borderWidth = 2;
    UIColor *borderColor = [UIColor redColor];
    UIView *leftView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, borderWidth, mainViewSize.height)];
    UIView *rightView = [[UIView alloc] initWithFrame:CGRectMake(mainViewSize.width - borderWidth, 0, borderWidth, mainViewSize.height)];
    leftView.opaque = YES;
    rightView.opaque = YES;
    leftView.backgroundColor = borderColor;
    rightView.backgroundColor = borderColor;
    
    // for bonus points, set the views' autoresizing mask so they'll stay with the edges:
    leftView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleRightMargin;
    rightView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleLeftMargin;
    
    [theView addSubview:leftView];
    [theView addSubview:rightView];
    
    [leftView release];
    [rightView release];
    

    请注意,这与 CALayer 边框的行为不太匹配——左右边框视图将始终位于其父视图的边界内。

    【讨论】:

      【解决方案2】:

      类似于边框的视图的答案非常好,但请记住,每个视图都是一个消耗大量内存的 UI 对象。

      我应该使用 uivew 的图层在已经存在的 UIview 上绘制带有颜色的笔触。

      -(CAShapeLayer*)drawLineFromPoint:(CGPoint)fromPoint toPoint:(CGPoint) toPoint withColor:(UIColor *)color andLineWidth:(CGFloat)lineWidth{
      
      CAShapeLayer *lineShape = nil;
      CGMutablePathRef linePath = nil;
      
      linePath = CGPathCreateMutable();
      lineShape = [CAShapeLayer layer];
      
      lineShape.lineWidth = lineWidth;
      lineShape.strokeColor = color.CGColor;
      
      NSUInteger x = fromPoint.x;
      NSUInteger y = fromPoint.y;
      
      NSUInteger toX = toPoint.x;
      NSUInteger toY = toPoint.y;
      
      CGPathMoveToPoint(linePath, nil, x, y);
      CGPathAddLineToPoint(linePath, nil, toX, toY);
      
      lineShape.path = linePath;
      CGPathRelease(linePath);
      return lineShape;}
      

      并将其添加到我们的视图中。

      CAShapeLayer* borderLine=[self drawLineFromPoint:CGPointMake(0, 0) toPoint:CGPointMake(0,_myView.frame.size.height) withColor:[UIColor lightGrayColor] andLineWidth:1.0f];
      
      [_myView.layer addSublayer:borderLine];
      

      所以...我们取一个点,实际上从视图的顶部到底部绘制一条线。结果是有一条线看起来像一个像素宽度的边框。

      【讨论】:

        【解决方案3】:

        为 Swift 3.0 更新

        我编写了一个 Swift 扩展(用于 UIButton),它模拟将 UIView 任意一侧的边框设置为给定的颜色和宽度。它类似于@Noah Witherspoon 的方法,但基于自包含和自动布局约束。

         // Swift 3.0
        extension UIView {
        
          enum Border {
            case left
            case right
            case top
            case bottom
          }
        
          func setBorder(border: UIView.Border, weight: CGFloat, color: UIColor ) {
        
            let lineView = UIView()
            addSubview(lineView)
            lineView.backgroundColor = color
            lineView.translatesAutoresizingMaskIntoConstraints = false
        
            switch border {
        
            case .left:
              lineView.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
              lineView.topAnchor.constraint(equalTo: topAnchor).isActive = true
              lineView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
              lineView.widthAnchor.constraint(equalToConstant: weight).isActive = true
        
            case .right:
              lineView.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
              lineView.topAnchor.constraint(equalTo: topAnchor).isActive = true
              lineView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
              lineView.widthAnchor.constraint(equalToConstant: weight).isActive = true
        
            case .top:
              lineView.topAnchor.constraint(equalTo: topAnchor).isActive = true
              lineView.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
              lineView.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
              lineView.heightAnchor.constraint(equalToConstant: weight).isActive = true
        
            case .bottom:
              lineView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
              lineView.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
              lineView.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
              lineView.heightAnchor.constraint(equalToConstant: weight).isActive = true
            }
          }
        }    
        

        【讨论】:

        • .Right 的第二行应该包含lineView.rightAnchor:lineView.rightAnchor.constraintEqualToAnchor(self.rightAnchor, constant: 0).active = true
        • @ArthurClemens 你是对的。感谢您发现:)
        • 我不确定theWeight 做了什么,但去掉那条线似乎仍然有预期的效果。
        • 这个扩展不考虑被多次调用。它总是在现有边界上添加另一个边界,但应检查现有边界并在必要时将其删除。此外,应该可以删除边框,而不仅仅是添加它们。总而言之,这是一条崎岖不平的单行道。
        【解决方案4】:

        这听起来像是两个答案之一:

        如果您的视图是静态尺寸,那么只需在其后面放置一个比前视图宽 2 像素、短 2 像素的 UIView。

        如果它是非静态大小的,那么您也可以这样做,在调整前景视图大小时调整后备视图的大小,或者实现一个实现 UIView 的自定义对象,并实现(覆盖)您自己的 drawRect 例程。

        【讨论】:

          【解决方案5】:

          NAUIViewWithBorders 帮了我大忙。另请参阅创建者的SO post here。如果您需要此功能以获得多个视图,则值得一试。

          【讨论】:

            【解决方案6】:
            public extension UIView {
            // Border type and arbitrary tag values to identify UIView borders as subviews
            public enum BorderType: Int {
                case left = 20000
                case right = 20001
                case top = 20002
                case bottom = 20003
            }
            
            public func addBorder(borderType: BorderType, width: CGFloat, color: UIColor) {
                // figure out frame and resizing based on border type
                var autoresizingMask: UIViewAutoresizing
                var layerFrame: CGRect
                switch borderType {
                case .left:
                    layerFrame = CGRect(x: 0, y: 0, width: width, height: self.bounds.height)
                    autoresizingMask = [ .flexibleHeight, .flexibleRightMargin ]
                case .right:
                    layerFrame = CGRect(x: self.bounds.width - width, y: 0, width: width, height: self.bounds.height)
                    autoresizingMask = [ .flexibleHeight, .flexibleLeftMargin ]
                case .top:
                    layerFrame = CGRect(x: 0, y: 0, width: self.bounds.width, height: width)
                    autoresizingMask = [ .flexibleWidth, .flexibleBottomMargin ]
                case .bottom:
                    layerFrame = CGRect(x: 0, y: self.bounds.height - width, width: self.bounds.width, height: width)
                    autoresizingMask = [ .flexibleWidth, .flexibleTopMargin ]
                }
            
                // look for the existing border in subviews
                var newView: UIView?
                for eachSubview in self.subviews {
                    if eachSubview.tag == borderType.rawValue {
                        newView = eachSubview
                        break
                    }
                }
            
                // set properties on existing view, or create a new one
                if newView == nil {
                    newView = UIView(frame: layerFrame)
                    newView?.tag = borderType.rawValue
                    self.addSubview(newView!)
                } else {
                    newView?.frame = layerFrame
                }
                newView?.backgroundColor = color
                newView?.autoresizingMask = autoresizingMask
            }
            

            【讨论】:

              猜你喜欢
              • 2015-11-29
              • 1970-01-01
              • 2019-07-06
              • 2021-06-17
              • 1970-01-01
              • 1970-01-01
              • 2013-03-02
              • 1970-01-01
              相关资源
              最近更新 更多