在颤动中从 2 张图像设计背景 [英] Design a background from 2 images in flutter

查看:27
本文介绍了在颤动中从 2 张图像设计背景的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想创建一个新的无状态小部件类,它由 2 个图像(顶部、底部)和一条线(由一个函数定义,例如 (x){x+500},一个宽度(可以是 0,如果它不应该被绘制)和一个颜色)分隔两个图像.

对于每个像素:

  • 如果像素的y位置大于f(x) + width/2的结果,则绘制底部的像素
  • 如果它小于 f(x) - width/2 应绘制顶部像素
  • 否则应绘制给定线条颜色的像素

吹一下看看例子 mywidget({'top': A, 'bottom': B, 'f': (x){return sin(x)+500;}, 'width': 1, 'color': Color(0xFFFFFFFF)}); 可能看起来像:

(0,0)+------+|||一个 ||__ ||/\__||||乙|+--------+(例如 1920,1080)

是否有形状由(数学)函数定义的线条小部件?


示例源代码:

import 'dart:math';导入包:颤振/material.dart";无效的主要(){运行应用程序(材料应用程序(家:脚手架(正文:ClippedPartsWidget(顶部:容器(颜色:颜色.红色,),底部:容器(颜色:颜色.蓝色,),splitFunction: (Size size, double x) {//标准化 x 使其恰好是一个波最终归一化X = x/size.width * 2 * pi;最终 waveHeight = size.height/15;最终 y = size.height/2 - sin(normalizedX) * waveHeight;返回 y;},),),),);}类 ClippedPartsWidget 扩展 StatelessWidget {最终小部件顶部;最终的小部件底部;final double Function(Size, double) splitFunction;ClippedPartsWidget({@required this.top,@required this.bottom,@required this.splitFunction,});@覆盖小部件构建(BuildContext 上下文){返回堆栈(孩子们:<小部件>[//我将未修改的顶部小部件放在后面.我不会剪的.//相反,我将用裁剪的底部小部件覆盖它.最佳,对齐(对齐:Alignment.bottomCenter,孩子:剪辑路径(剪裁器:FunctionClipper(splitFunction:splitFunction),孩子:底部,),),],);}}类 FunctionClipper 扩展 CustomClipper;{final double Function(Size, double) splitFunction;FunctionClipper({@required this.splitFunction}) : super();路径 getClip(Size size) {最终路径 = 路径();//移动到分割线起点path.moveTo(0, splitFunction(size, 0));//绘制分割线for (double x = 1; x <= size.width; x++) {path.lineTo(x, splitFunction(size, x));}//关闭屏幕底部path.lineTo(size.width, size.height);path.lineTo(0, size.height);返回路径;}@覆盖bool shouldReclip(CustomClipper<Path> oldClipper) {//为了简单起见,我在这里返回固定的真"值,这不是实际问题的一部分//基本上这意味着剪辑将在任何更改时重新绘制返回真;}}

I'd like to create a a new stateless widget class that is defined by 2 images(top, bottom) and a line(defined by a function, e.g. (x){x+500}, a width(can be 0, if it shouldn't be drawn), and a color) separating the two images.

For each pixel:

  • If the y position of a pixel is greater than the result of f(x) + width/2 a pixel of bottom shall be drawn
  • If it's smaller than f(x) - width / 2 a pixel of top shall be drawn
  • Else a pixel of the given line color shall be drawn

Blow see an example of what mywidget({'top': A, 'bottom': B, 'f': (x){return sin(x)+500;}, 'width': 1, 'color': Color(0xFFFFFFFF)}); could look like:

(0,0)
+------+
|      |
|  A   |
| __   |
|/  \__|
|      |
|  B   |
+------+(e.g. 1920,1080)

Is there a line widget where the shape is defined by a (mathematic) function?

Is this the only way to do it? Or is there a container widget that already allows this? I have looked at the Stack widget but that's not quite solving the problem, as I'd need a structure to decide which pixel is rendered as described above. The function to decide which should happen should be supplyable by the user.

解决方案

ClipPath with CustomClipper<Path> can help you with it.
What you can get:

Example source code:

import 'dart:math';

import 'package:flutter/material.dart';

void main() {
  runApp(
    MaterialApp(
      home: Scaffold(
        body: ClippedPartsWidget(
          top: Container(
            color: Colors.red,
          ),
          bottom: Container(
            color: Colors.blue,
          ),
          splitFunction: (Size size, double x) {
            // normalizing x to make it exactly one wave
            final normalizedX = x / size.width * 2 * pi;
            final waveHeight = size.height / 15;
            final y = size.height / 2 - sin(normalizedX) * waveHeight;

            return y;
          },
        ),
      ),
    ),
  );
}

class ClippedPartsWidget extends StatelessWidget {
  final Widget top;
  final Widget bottom;
  final double Function(Size, double) splitFunction;

  ClippedPartsWidget({
    @required this.top,
    @required this.bottom,
    @required this.splitFunction,
  });

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: <Widget>[
        // I'm putting unmodified top widget to back. I wont cut it.
        // Instead I'll overlay it with clipped bottom widget.
        top,
        Align(
          alignment: Alignment.bottomCenter,
          child: ClipPath(
            clipper: FunctionClipper(splitFunction: splitFunction),
            child: bottom,
          ),
        ),
      ],
    );
  }
}

class FunctionClipper extends CustomClipper<Path> {
  final double Function(Size, double) splitFunction;

  FunctionClipper({@required this.splitFunction}) : super();

  Path getClip(Size size) {
    final path = Path();

    // move to split line starting point
    path.moveTo(0, splitFunction(size, 0));

    // draw split line
    for (double x = 1; x <= size.width; x++) {
      path.lineTo(x, splitFunction(size, x));
    }

    // close bottom part of screen
    path.lineTo(size.width, size.height);
    path.lineTo(0, size.height);

    return path;
  }

  @override
  bool shouldReclip(CustomClipper<Path> oldClipper) {
    // I'm returning fixed 'true' value here for simplicity, it's not the part of actual question
    // basically that means that clipping will be redrawn on any changes
    return true;
  }
}

这篇关于在颤动中从 2 张图像设计背景的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆