【问题标题】:How to Draw a single point line in iOS如何在 iOS 中绘制单点线
【发布时间】:2014-03-27 16:24:46
【问题描述】:

我想知道绘制单点线的最佳方法是什么? 我的目标是在 tableViewCell 中绘制这条线,使其看起来就像原生单元格分隔符。 我不想使用原生分隔符,因为我想制作不同的颜色和不同的位置(不是底部..)。

起初我使用 1px UIView 并将其着色为灰色。但在 Retina 显示器中,它看起来像 2px。 也试过用这个方法:

- (void)drawLine:(CGPoint)startPoint endPoint:(CGPoint)endPoint inColor:(UIColor *)color {

    CGMutablePathRef straightLinePath = CGPathCreateMutable();
    CGPathMoveToPoint(straightLinePath, NULL, startPoint.x, startPoint.y);
    CGPathAddLineToPoint(straightLinePath, NULL, endPoint.x, endPoint.y);

    CAShapeLayer *shapeLayer = [CAShapeLayer layer];
    shapeLayer.path = straightLinePath;
    UIColor *fillColor = color;
    shapeLayer.fillColor = fillColor.CGColor;
    UIColor *strokeColor = color;
    shapeLayer.strokeColor = strokeColor.CGColor;
    shapeLayer.lineWidth = 0.5f;
    shapeLayer.fillRule = kCAFillRuleNonZero;
    [self.layer addSublayer:shapeLayer];
}

由于某种原因,它在 60% 的时间里都能正常工作。它有什么问题吗? 无论如何,我很乐意听到更好的方法。

谢谢。

【问题讨论】:

  • 你试过改变 1px UIView 的 alpha 吗?它看起来会更薄。
  • 我正在寻找一种更通用的方式,无论如何我需要一个纯色:/
  • 虽然这是一个很棒的 QA - 这里有一个更现代的解决方案 stackoverflow.com/a/34766567/294884

标签: ios uitableview retina-display


【解决方案1】:

我对@9​​87654322@ 类别做了同样的事情。这是我的方法:

#define SEPARATOR_HEIGHT 0.5

- (void)addSeparatorLinesWithColor:(UIColor *)color
{
    [self addSeparatorLinesWithColor:color edgeInset:UIEdgeInsetsZero];
}


- (void)addSeparatorLinesWithColor:(UIColor *)color edgeInset:(UIEdgeInsets)edgeInset
{

    UIView *topSeparatorView = [[UIView alloc] initWithFrame:CGRectMake(edgeInset.left, - SEPARATOR_HEIGHT, self.frame.size.width - edgeInset.left - edgeInset.right, SEPARATOR_HEIGHT)];
    [topSeparatorView setBackgroundColor:color];
    [self addSubview:topSeparatorView];

    UIView *separatorView = [[UIView alloc] initWithFrame:CGRectMake(edgeInset.left, self.frame.size.height + SEPARATOR_HEIGHT, self.frame.size.width - edgeInset.left - edgeInset.right, SEPARATOR_HEIGHT)];
    [separatorView setBackgroundColor:color];
    [self addSubview:separatorView];
}

只是为了补充 Rémy 的出色答案,这样做可能更简单。创建一个类 UILine.m

@interface UILine:UIView
@end
@implementation UILine
-(id)awakeFromNib
    {
    // careful, contentScaleFactor does NOT WORK in storyboard during initWithCoder.
    // example, float sortaPixel = 1.0/self.contentScaleFactor ... does not work.
    // instead, use mainScreen scale which works perfectly:
    float sortaPixel = 1.0/[UIScreen mainScreen].scale;
    UIView *topSeparatorView = [[UIView alloc] initWithFrame:
        CGRectMake(0, 0, self.frame.size.width, sortaPixel)];

    topSeparatorView.userInteractionEnabled = NO;
    [topSeparatorView setBackgroundColor:self.backgroundColor];
    [self addSubview:topSeparatorView];

    self.backgroundColor = [UIColor clearColor];
    self.userInteractionEnabled = NO;
    }
@end

在 IB 中,放入 UIView,单击身份检查器并将类重命名为 UILine。在 IB 中设置您想要的 宽度。将高度设置为 1 或 2 像素 - 以便您可以在 IB 中看到它。在 IB 中设置您想要的背景颜色。当你运行这个应用程序时,它会变成一个 1 像素的线,那个宽度,那个颜色。 (你可能不应该受到故事板/xib 中任何默认的自动调整大小设置的影响,我无法让它中断。)你已经完成了。

注意:您可能会想“为什么不在 awakeFromNib 的代码中调整 UIView 的大小?”在故事板应用程序中,在加载时调整视图大小是有问题的 - 请在此处查看有关它的许多问题!

有趣的gotchya:您可能只会在情节提要上将 UIView 设置为 10 或 20 像素高,这样您就可以看到它。当然,它会在应用程序中消失,你会得到漂亮的一像素线。但!一定要记住self.userInteractionEnabled = NO,否则它可能会超过你的其他按钮!


2016 年解决方案! https://stackoverflow.com/a/34766567/294884

【讨论】:

  • 这不是我们所说的draw
  • 这正是绘画。 ascii 艺术是绘画。您经常会说“我使用正方形、视图、UIButtons、drawRect 和其他技术绘制了输入表单”。感谢您的精彩回答,雷米!
  • 最终使用 Joe Blow 的此解决方案版本创建了一个 UIView 类别。这是最简单的解决方案,效果很好。谢谢!
  • @JoeBlow 非常感谢!
  • 相反! de rein, avec merci
【解决方案2】:
shapeLayer.lineWidth = 0.5f;

这是一个常见的错误,这也是它仅在某些时候有效的原因。有时这会与屏幕上的像素完全重叠,有时则不会。绘制单点线始终有效的方法是在整数边界上绘制一个单点粗矩形,然后填充 .这样,它将始终完全匹配屏幕上的像素。

要将点转换为像素,如果您想这样做,请使用视图的比例因子。

因此,这将始终是一个像素宽:

CGContextFillRect(con, CGRectMake(0,0,desiredLength,1.0/self.contentScaleFactor));

这是一个屏幕截图,显示了用作分隔符的线条,绘制在每个单元格的顶部:

表格视图本身没有分隔符(如三个现有单元格下方的空白所示)。我可能不会在你想要的位置、长度和颜色上画线,但这是你的问题,不是我的问题。

【讨论】:

  • 好的,我尝试了这些代码行(称为 form drawRect: 方法) - 没有绘制任何内容,可以看到问题吗?:CGContextRef context = UIGraphicsGetCurrentContext(); CGContextFillRect(context, CGRectMake(startPoint.x, startPoint.y, width, 1.0/self.contentScaleFactor));
  • @matt,你碰巧知道吗:如果有人使用 Rémy 在下面提到的“UIView 高度”技巧。 (可能使用 1.0/self.contentScaleFactor 而不仅仅是“1/2” - 除非你专门用于视网膜,我猜。)事实上。这会遇到非整数边界问题吗?我无法“让它展示”非整数边界,但我可能还不够努力:) 我猜,如果你从界面构建器中放入 UIView,它确实总是在整数边界上(我认为)。谢谢,如果你知道,干杯
  • @JoeBlow 完全正确 - 都是关于整数边界的。视图应始终位于整数边界上。如果您在 IB 中执行此操作,则 IB 会强制执行此操作。如果您在代码中添加视图,如果您有任何疑问,您应该始终在其框架上调用 CGRectIntegral。这里主要出错的地方是如果您将视图定位在其中心:如果视图具有奇数维度,则它的框架现在位于非整数边界上。避免这种情况。
  • @matt - 太棒了。所以简而言之,如果您的视图仅由 IB 定位,它将是整数。如果您通过代码移动它,它确实可能是非整数。再次非常感谢。
【解决方案3】:

自动布局方法:

我使用一个普通的旧 UIView,并在 Interface Builder 中将其高度约束设置为 1。通过约束将其附加到底部。界面生成器不允许您将高度约束设置为 0.5,但您可以在代码中进行。

为高度约束创建一个连接器,然后调用它:

// Note: This will be 0.5 on retina screens
self.dividerViewHeightConstraint.constant =  1.0/[UIScreen mainScreen].scale 

为我工作。

FWIW 我认为我们不再需要支持非视网膜屏幕了。但是,我仍在使用主屏幕比例来验证应用程序的未来。

【讨论】:

    【解决方案4】:

    您必须考虑由于视网膜而导致的缩放,并且您不是指屏幕像素。见Core Graphics Points vs. Pixels

    【讨论】:

      【解决方案5】:

      除了 Rémy Virin 的答案,使用 Swift 3.0 创建 LineSeparator 类:

      import UIKit
      
      class LineSeparator: UIView {
      
      override func awakeFromNib() {
      
          let sortaPixel: CGFloat = 1.0/UIScreen.main.scale
      
          let topSeparatorView = UIView()
          topSeparatorView.frame = CGRect(x: 0, y: 0, width: self.frame.size.width, height: sortaPixel)
      
          topSeparatorView.isUserInteractionEnabled = false
          topSeparatorView.backgroundColor = self.backgroundColor
      
          self.addSubview(topSeparatorView)
          self.backgroundColor = UIColor.clear
      
          self.isUserInteractionEnabled = false   
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-01-19
        • 1970-01-01
        • 2022-07-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多