小于1像素的渲染探究

2020-08-31  本文已影响0人  张_何

名词解释

背景

Flutter 测试

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("测试"),
      ),
      body: Container(
        color: Colors.white,
        child: Center(
          child: Column(
            children: <Widget>[
              _line(0.1),
              _line(0.2),
              _line(0.3),
              _line(0.4),
              _line(0.5),
              _line(0.6),
              _line(0.9),
              _line(1.0),
              _line(1.1),
              _line(1.4),
              _line(1.5),
              _line(1.9),
              _line(2.0),
              _line(5.0),
            ],
          ),
        ),
      ),
    );
  }

  Widget _line(double height){
    return Container(
      child: Row(
        children: <Widget>[
          Container(
            margin: EdgeInsets.only(left: 20,right: 10),
            child: Text("$height"),
          ),
//          _containerLine(height),
          _drawLine(height),
        ],
      ),
    );
  }
  // 测试用container 做的line
  Widget _containerLine(double height){
    return Container(
      height: 15,
      width: 200,
      color: Colors.white,
      child: Center(
        child: Container(
          height: height,
          width: 375,
          color: Colors.red,
        ),
      ),
    );
  }
//  测试画出来的线
  Widget _drawLine(double height){
    return CustomPaint(
      size: Size(250, 20),
      painter:TestPainter(height) ,
    );
  }
}
看一下0.2~0.5线的宽度是一样的,不过颜色在逐渐加重.png 从1.0~2.0的过程是线上下两边颜色逐渐由浅变深的过程,2.0时可以明显看出线的高度是1.0的两倍.png

下图看起来和使用Container做的线显示效果一样


WechatIMG24.jpeg 0.1~0.5线的宽度没变,颜色在逐渐加重.png 0.5~1.0线的宽度没变,颜色在逐渐加重.png 2.0是1.0线高的两倍.png

Flutter 官方对解释的不是很清楚

ios原生测试

#import "ViewController.h"

@interface RenderView: UIView

@end

@implementation RenderView

-(void)drawRect:(CGRect)rect{
    [super drawRect:rect];
    
    CGContextRef context = UIGraphicsGetCurrentContext();
    
    [self drawLine:context lineHight:0.1 startPoint:CGPointMake(50, 50) endPoint:CGPointMake(200, 50)];
    [self drawLine:context lineHight:0.2 startPoint:CGPointMake(50, 60) endPoint:CGPointMake(200, 60)];
    [self drawLine:context lineHight:0.3 startPoint:CGPointMake(50, 70) endPoint:CGPointMake(200, 70)];
    [self drawLine:context lineHight:0.5 startPoint:CGPointMake(50, 80) endPoint:CGPointMake(200, 80)];
    [self drawLine:context lineHight:0.7 startPoint:CGPointMake(50, 90) endPoint:CGPointMake(200, 90)];
    [self drawLine:context lineHight:0.9 startPoint:CGPointMake(50, 100) endPoint:CGPointMake(200, 100)];
    [self drawLine:context lineHight:1.0 startPoint:CGPointMake(50, 110) endPoint:CGPointMake(200, 110)];
    [self drawLine:context lineHight:1.05 startPoint:CGPointMake(50, 120) endPoint:CGPointMake(200, 120)];
    [self drawLine:context lineHight:1.2 startPoint:CGPointMake(50, 130) endPoint:CGPointMake(200, 130)];
    [self drawLine:context lineHight:1.4 startPoint:CGPointMake(50, 140) endPoint:CGPointMake(200, 140)];
    [self drawLine:context lineHight:1.5 startPoint:CGPointMake(50, 150) endPoint:CGPointMake(200, 150)];
    [self drawLine:context lineHight:1.7 startPoint:CGPointMake(50, 160) endPoint:CGPointMake(200, 160)];
    [self drawLine:context lineHight:1.9 startPoint:CGPointMake(50, 170) endPoint:CGPointMake(200, 170)];
    [self drawLine:context lineHight:2.0 startPoint:CGPointMake(50, 180) endPoint:CGPointMake(200, 180)];
    [self drawLine:context lineHight:5.0 startPoint:CGPointMake(50, 190) endPoint:CGPointMake(200, 190)];
}

-(void)drawLine:(CGContextRef )context lineHight:(CGFloat)height startPoint:(CGPoint)start endPoint:(CGPoint)end{
    CGContextMoveToPoint(context, start.x, start.y);
    CGContextAddLineToPoint(context, end.x, end.y);
    CGContextSetLineWidth(context,height);
    CGContextClosePath(context);
    [[UIColor redColor]setStroke];
    CGContextDrawPath(context, kCGPathStroke);
    
    NSString *string = [NSString stringWithFormat:@"%.2f",height];
    UIFont *fount = [UIFont systemFontOfSize:9];
    [string drawInRect:CGRectMake(20, start.y-10, 30, 20) withAttributes: @{NSFontAttributeName:fount}];
}
@end

@interface ViewController ()
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor whiteColor];
    
//    RenderView *v = [[RenderView alloc] init];
//    v.frame = CGRectMake(0, 0, 300, 500);
//    v.backgroundColor = [UIColor whiteColor];
//    [self.view addSubview:v];
//
    float left = 50;
    [self lineRect:CGRectMake(left, 50, 100, 1)];
    [self lineRect:CGRectMake(left, 60, 100, 0.1)];
    [self lineRect:CGRectMake(left, 70, 100, 0.2)];
    [self lineRect:CGRectMake(left, 80, 100, 0.3)];
    [self lineRect:CGRectMake(left, 90, 100, 0.5)];
    [self lineRect:CGRectMake(left, 100, 100, 0.7)];
    [self lineRect:CGRectMake(left, 110, 100, 0.8)];
    [self lineRect:CGRectMake(left, 120, 100, 0.9)];
    [self lineRect:CGRectMake(left, 130, 100, 1.0)];
    [self lineRect:CGRectMake(left, 140, 100, 1.05)];
    [self lineRect:CGRectMake(left, 150, 100, 1.2)];
    [self lineRect:CGRectMake(left, 160, 100, 1.4)];
    [self lineRect:CGRectMake(left, 170, 100, 1.5)];
    [self lineRect:CGRectMake(left, 180, 100, 1.7)];
    [self lineRect:CGRectMake(left, 190, 100, 1.9)];
    [self lineRect:CGRectMake(left, 200, 100, 2.0)];
    [self lineRect:CGRectMake(left, 210, 100, 5.0)];
}

-(void)lineRect:(CGRect) rect{
    UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(20, rect.origin.y - 10, 30, 20)];
    label.text = [NSString stringWithFormat:@"%.1f",rect.size.height];
    label.font = [UIFont systemFontOfSize:9];
    [self.view addSubview:label];
    
    UIView  *v = [[UIView alloc] initWithFrame:rect];
    v.backgroundColor = [UIColor redColor];
    [self.view addSubview:v];
}
@end
图中我们看到当设置线的高度为0.1和0.2时并没有渲染出来.jpeg 图片放大后看到0.3到0.7线的宽度和颜色是一样的,可能是截图的原因,实际上0.3到0.7的颜色手机上看并没有显示的那么暗,高度确实比0.8的矮了一倍.png 1.4到1.7线的高度可以看出来比1.0时高了50%,注意是50%而不是一倍,1.9和2.0是确实比1.0时高了一倍,线上下边缘的颜色没有变,但内部的颜色值变从1.4到5.0都是一样的.png 放大后我们发下线的颜色也是由浅到深的变化,但是高度是每边的.png 从1.0到2.0的过程中,线的宽度是变宽了,不过随着线上下边缘颜色的逐渐加深,到2.0时可以明显看出2.0的线高比1.0确实高了一倍.png

总结

通过测试对比发现Flutter在渲染小于1逻辑像素的线的时候,其高度是按1逻辑像素去展示的,只不过看到的颜色会不一样,当设置线的高度不是整数逻辑像素时,线的高度是线上取整后的逻辑像素,只不过看到的线上下边缘的颜色会随着小数部分的值越大颜色越接近设置的颜色。也就是说flutter是以1逻辑像素的整数倍去显示的,如果是非整数倍逻辑像素线上下边缘的颜色会跟设置的不一样(以灰度的方式显示出来)。

ios 原生目前也可以展示小于1物理像素的点,但是以UIView的控件做的线,其高度有个临界值,低于临界值的线会显示不出来,而且其显示的线边缘比较锐利,其高度在到某一临界值后会直接变高,而不是在线上下边缘做灰度展示。而用原生绘制出来的线展示小于以逻辑像素的时候其高度均展示为1逻辑像素,不过颜色值会以灰度的方式展示出来,在达到逻辑像素的整数倍时展示设置的颜色,这是和flutter一样的。

结语

比如拿iPhone 6s 举例,其屏幕宽度是2.3英寸,横向上有750颗像素点,ppi = 750/2.3 = 326,既每寸上有326个物理像素,换算成厘米也就是 326/2.54 = 128.35,也就是说每厘米上有128.35个物理像素点,每毫米有13个物理像素点,也就是每个物理像素点的宽度是0.077毫米。6s 的逻辑宽度是375,横向上每厘米有375/(2.3*2.54) = 64逻辑像素/cm,也就是6s上每个逻辑像素的宽度是0.156毫米。当我们设置一逻辑像素宽度时其在6s上对应的宽度是0.156毫米。

上一篇 下一篇

猜你喜欢

热点阅读