使用 AspectRatio Widget

AspectRatio widget 是用来约束宽高比例的,如果你需要 widget 必须要有一定的宽高比,这个组件就很有用。

但 AspectRatio 并不总是如你所愿,我一度想直接设置宽高达到同样的目的,但当你了解了它的逻辑之后,发现这样做并不明智,因为即使是直接设置高度,这些逻辑也是少不了的。

AspectRatio 需要父容器至少 width 或 height 是有边界的。

想想也是合理的。如果约束是没有边界的,而 AspectRatio 本身又没有宽高属性,AspectRatio 就无法设置宽高,只能都是无限,就和宽高有比例这个要求相矛盾。

AspectRatio 的尺寸的计算逻辑

  1. 如果父元素的宽高都没有边界,抛异常。
  2. 如果收到的是 tight 约束,那么相当于 AspectRatio 无效,不会起到任何作用,只会透传约束。
  3. 优先以宽度为准,按比例设置高度。如果宽度无限,以高度为准按比例设置宽度。
  4. 无论是高度还是宽度都必须在约束的范围内。

AspectRatio 的代码逻辑

决定宽高的代码

 Size _applyAspectRatio(BoxConstraints constraints) {
    assert(constraints.debugAssertIsValid());
    assert(() {
      if (!constraints.hasBoundedWidth && !constraints.hasBoundedHeight) {
        throw FlutterError(
          '$runtimeType has unbounded constraints.\n'
          'This $runtimeType was given an aspect ratio of $aspectRatio but was given '
          'both unbounded width and unbounded height constraints. Because both '
          "constraints were unbounded, this render object doesn't know how much "
          'size to consume.',
        );
      }
      return true;
    }());

    if (constraints.isTight) {
      return constraints.smallest;
    }

    double width = constraints.maxWidth;
    double height;

    // We default to picking the height based on the width, but if the width
    // would be infinite, that's not sensible so we try to infer the height
    // from the width.
    if (width.isFinite) {
      height = width / _aspectRatio;
    } else {
      height = constraints.maxHeight;
      width = height * _aspectRatio;
    }

    // Similar to RenderImage, we iteratively attempt to fit within the given
    // constraints while maintaining the given aspect ratio. The order of
    // applying the constraints is also biased towards inferring the height
    // from the width.

    if (width > constraints.maxWidth) {
      width = constraints.maxWidth;
      height = width / _aspectRatio;
    }

    if (height > constraints.maxHeight) {
      height = constraints.maxHeight;
      width = height * _aspectRatio;
    }

    if (width < constraints.minWidth) {
      width = constraints.minWidth;
      height = width / _aspectRatio;
    }

    if (height < constraints.minHeight) {
      height = constraints.minHeight;
      width = height * _aspectRatio;
    }

    return constraints.constrain(Size(width, height));
  }

定好自己的宽高后,把 child 设置成和自己一样宽高

  
  void performLayout() {
    size = computeDryLayout(constraints);
    if (child != null) {
      child!.layout(BoxConstraints.tight(size));
    }
  }

AspectRatio 的 renderObject 继承自 RenderProxyBox。只可以有一个child,没有 alignment 属性,不能摆放 child的位置。

AspectRatio 的 aspectRatio 参数要求是 大于0 的 double ,但是一般都是用分数的形式来写,这样可读性会更好些。

AspectRatio(
      aspectRatio: 1 / 2,
);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
可以使用PyOpenGL库来实现这个功能,具体实现方法可以参考以下代码: ```python from PyQt5.QtWidgets import QApplication, QMainWindow, QOpenGLWidget from PyQt5.QtGui import QOpenGLShader, QOpenGLShaderProgram, QOpenGLTexture from PyQt5.QtCore import Qt import sys class OpenGLWidget(QOpenGLWidget): def __init__(self, parent=None): super().__init__(parent) self.vertices = [] self.indices = [] self.texture_coords = [] self.texture = None def initializeGL(self): self.initializeOpenGLFunctions() self.loadObjModel('model.obj') self.loadTexture('texture.png') def paintGL(self): glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) glLoadIdentity() glTranslatef(0.0, 0.0, -5.0) glRotatef(30, 1.0, 0.0, 0.0) glRotatef(30, 0.0, 1.0, 0.0) glEnable(GL_TEXTURE_2D) self.texture.bind() glBegin(GL_TRIANGLES) for i in range(0, len(self.indices), 3): v1 = self.vertices[self.indices[i]] v2 = self.vertices[self.indices[i+1]] v3 = self.vertices[self.indices[i+2]] t1 = self.texture_coords[self.indices[i]] t2 = self.texture_coords[self.indices[i+1]] t3 = self.texture_coords[self.indices[i+2]] glTexCoord2f(t1[0], t1[1]) glVertex3f(v1[0], v1[1], v1[2]) glTexCoord2f(t2[0], t2[1]) glVertex3f(v2[0], v2[1], v2[2]) glTexCoord2f(t3[0], t3[1]) glVertex3f(v3[0], v3[1], v3[2]) glEnd() def resizeGL(self, width, height): glViewport(0, 0, width, height) glMatrixMode(GL_PROJECTION) glLoadIdentity() aspect_ratio = width / height gluPerspective(45.0, aspect_ratio, 0.1, 100.0) glMatrixMode(GL_MODELVIEW) def loadObjModel(self, filename): with open(filename, 'r') as f: for line in f: if line.startswith('v '): self.vertices.append(list(map(float, line.split()[1:]))) elif line.startswith('vt '): self.texture_coords.append(list(map(float, line.split()[1:]))) elif line.startswith('f '): self.indices.extend([int(i.split('/')[0])-1 for i in line.split()[1:]]) def loadTexture(self, filename): self.texture = QOpenGLTexture(QImage(filename)) if __name__ == '__main__': app = QApplication(sys.argv) window = QMainWindow() glWidget = OpenGLWidget(window) window.setCentralWidget(glWidget) window.resize(800, 600) window.show() sys.exit(app.exec_()) ``` 这段代码实现了使用PyQt和PyOpenGL加载obj模型并显示纹理的功能。其中,loadObjModel()函数用于解析obj文件,loadTexture()函数用于加载纹理图片,paintGL()函数用于绘制模型。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IAM17前端

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值