Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

getPageConfig这个方法计算的内容有些页面显示不全 #26

Open
jackxuechen opened this issue Nov 21, 2023 · 29 comments
Open

Comments

@jackxuechen
Copy link

getPageConfig这个方法计算的内容有些页面显示不全,看了代码没看明白,大佬可以给解答下吗,用的是dev_2.0的分支

@jackxuechen
Copy link
Author

我打断点看了计算式正确的,但是实际显示出来会超出,感觉像是下面的方法出了问题
child: Text.rich(
TextSpan(children: pageContentConfig.paragraphContents),
// strutStyle: StrutStyle(forceStrutHeight: true, leading: 0.5),
),

@lwlizhe
Copy link
Owner

lwlizhe commented Nov 22, 2023

没想到还有人看这个垃圾项目……感觉有点惭愧……真能看下去那真是费心了…………
回正题,
这块的代码我基本忘光了,只记得基本原理,不过你说的这种情况,我感觉挺符合我踩过的一个坑:
flutter只能计算文字能不能展示,不负责计算能不能展示全,即使仅仅超几个像素,它也视为能够展示,因此我记得我特意把计算高度减去了一行的高度,这样flutter计算的结果就能保证一定能展示全,难道是我代码中忘了减去这一行的高度?

@jackxuechen
Copy link
Author

jackxuechen commented Nov 22, 2023

有减去高度
/// 当前段落内容计算偏移量
/// 为什么要减一个lineHeight?因为getPositionForOffset判断依据是只要能展示,
/// 所以即使展示不全,也在它的判定范围内,所以要减去一行高度,保证都能展示全
int endOffset = textPainter
.getPositionForOffset(Offset(
contentWidth, contentHeight - currentHeight - currentLineHeight))
.offset;
我把contentHeight的高度手动减少了很多,最中使用它Text.rich显示的时候还是有超出的情况,Text.rich实际渲染的比计算的高度要高
var contentHeight = constraints.maxHeight -
AppSize.statusBarHeight -
AppSize.bottomSafeMargin -
40 -
16 -
32 -
32 -16;

@lwlizhe
Copy link
Owner

lwlizhe commented Nov 22, 2023

我打断点看了计算式正确的,但是实际显示出来会超出,感觉像是下面的方法出了问题 child: Text.rich( TextSpan(children: pageContentConfig.paragraphContents), // strutStyle: StrutStyle(forceStrutHeight: true, leading: 0.5), ),

看这段代码的话,好像没写上style,比如说给textPainter计算的fontSize是16,这里设置的20,那自然展示不下,会不会是这里的问题?

@jackxuechen
Copy link
Author

加上style显示也有问题
child: Text.rich(
TextSpan(children: pageContentConfig.paragraphContents),
style: TextStyle(color: Colors.red, fontSize: 16, height: 2),
// strutStyle: StrutStyle(forceStrutHeight: true, leading: 0.5),
),

@lwlizhe
Copy link
Owner

lwlizhe commented Nov 22, 2023

有点麻爪了,这块感觉能检查的部分,一个就是传入的高度是否是展示区域的高度,另一个就是单行的高度了……要不自己就在代码中写死高度值,比如说传入高度为16,看看计算的是一行还是两行,展示的时候是一行还是两行,单行没问题的话;那应该是段落部分的间距计算部分有问题,检查方式应该也用同理能算出来,记得涉及到内容计算的影响因素应该就是这行高、行间距、段落间距这几部分了;

要不这样,先一个个的排除,你先传入不带任何换行符的纯文字,看看计算的对不对;这部分用来判断单行与行间距部分的设置是否有问题;
这部分没问题的话,在模拟传入带换行符形成段落结构的文字内容,看看是不是涉及到段落部分就有问题

这块的代码目前还真还没下载下来细看,不过记得当初没遇到这种问题来着,现在想来,会不会也跟传入的文本内容有关呢

@jackxuechen
Copy link
Author

好的,我在看下,感谢

@wengxianxun
Copy link

大哥,这个项目怎么跑起来,很多错误

@jackxuechen
Copy link
Author

@wengxianxun
dev_2.0分支用flutter 2.8.1版本试下,我用这个可以跑起来

@lwlizhe
Copy link
Owner

lwlizhe commented Nov 30, 2023

大哥,这个项目怎么跑起来,很多错误

额,很抱歉,当时就做到一半……后面做着做着发现动画性能方面确实提升不明显,在那个翻页翻到边角的情况下,还是有着肉眼可见的卡顿,也实在没检查出来哪里有问题,或者存在哪里的Path范围设置过大的问题,就没啥接着研究的动力了……

不过如果你还相信我这个鸽子精的话,我先画个饼:
发现了一个宝藏项目:https://github.com/Rahiche/riveo_page_curl

通过shader来实现的动画,性能方面对基于canvas或者其他customPainter之类的简直是降维打击:
image

这回先在本地完成后再上传

@Liloupar
Copy link

@lwlizhe 大佬, shader 实现仿真翻页有进展了吗?

@lwlizhe
Copy link
Owner

lwlizhe commented Jan 17, 2024

@lwlizhe 大佬, shader 实现仿真翻页有进展了吗?

额,学习了shader的原理后写了一个demo,上来就遇到的一个问题就是……shader这块如何进行贝塞尔曲线对绘制内容进行划分,这个写法不知道咋搞,还是没上手学好…………(怪不得需要区分出一个顶点着色器……现在看来确实很有必要)
这个月底有空的时候还搞不定的话,那我就考虑一下,dart负责内容区域划分,shader负责最耗性能的转换与绘制处理dart划分好的区域,看看这样行不行

@Liloupar
Copy link

@lwlizhe
有一些写好的仿真翻页的shader, 但是我不知道怎么在flutter中使用.. 比如下面的
https://www.shadertoy.com/view/ls3cDB

@lwlizhe
Copy link
Owner

lwlizhe commented Jan 18, 2024

@lwlizhe 有一些写好的仿真翻页的shader, 但是我不知道怎么在flutter中使用.. 比如下面的 https://www.shadertoy.com/view/ls3cDB

卧槽牛逼,这个感觉很有戏!

回正题,感觉你这个也就是将入参改下就行了,你这个demo中所需的参数,好像基本都能通过flutter提供上,比如说入参的iChannel1,iChannel0,就是图片嘛,增加传入参数,fragColor这个转换为flutter中的那个也就是单独定义一个参数当临时变量,剩下的uv,mouse啥的对应画布宽高,触摸点位置,这些东西都是可以提供,换个名字而已……我真感觉很有戏

@lwlizhe
Copy link
Owner

lwlizhe commented Jan 18, 2024

@lwlizhe 有一些写好的仿真翻页的shader, 但是我不知道怎么在flutter中使用.. 比如下面的 https://www.shadertoy.com/view/ls3cDB

卧槽牛逼了,原来还有这种宝藏shader库

@Liloupar
Copy link

Liloupar commented Jan 18, 2024

卧槽牛逼,这个感觉很有戏!

回正题,感觉你这个也就是将入参改下就行了,你这个demo中所需的参数,好像基本都能通过flutter提供上,比如说入参的iChannel1,iChannel0,就是图片嘛,增加传入参数,fragColor这个转换为flutter中的那个也就是单独定义一个参数当临时变量,剩下的uv,mouse啥的对应画布宽高,触摸点位置,这些东西都是可以提供,换个名字而已……我真感觉很有戏

@lwlizhe
不过这个只有翻下一页, 没有翻上一页的, 要自己补
我数学已经退化到小学水平了 实在搞不定....

期待大佬的发挥

@lwlizhe
Copy link
Owner

lwlizhe commented Jan 18, 2024

卧槽牛逼,这个感觉很有戏!
回正题,感觉你这个也就是将入参改下就行了,你这个demo中所需的参数,好像基本都能通过flutter提供上,比如说入参的iChannel1,iChannel0,就是图片嘛,增加传入参数,fragColor这个转换为flutter中的那个也就是单独定义一个参数当临时变量,剩下的uv,mouse啥的对应画布宽高,触摸点位置,这些东西都是可以提供,换个名字而已……我真感觉很有戏

@lwlizhe 不过这个只有翻下一页, 没有翻上一页的, 要自己补 我数学已经退化到小学水平了 实在搞不定....

期待大佬的发挥

我尽力,说实话,也就看个大概懂,里面细节和实现啥的也不是很明白,说不定你glsl水平比我还高呢~~

@lwlizhe
Copy link
Owner

lwlizhe commented Jan 19, 2024

@lwlizhe 有一些写好的仿真翻页的shader, 但是我不知道怎么在flutter中使用.. 比如下面的 https://www.shadertoy.com/view/ls3cDB

这个我改了下,至少翻页部分的UI效果可以用了:

demo

#include <flutter/runtime_effect.glsl>

uniform vec2 resolution;
uniform vec4 iMouse;
uniform sampler2D image;

#define pi 3.14159265359
#define radius 0.1
#define TRANSPARENT vec4(0.0, 0.0, 0.0, 0.0)

out vec4 fragColor;

void main() {
    vec2 fragCoord = FlutterFragCoord().xy;

    float aspect = resolution.x / resolution.y;

    vec2 uv = fragCoord * vec2(aspect, 1.0) / resolution.xy;

    vec2 mouse = iMouse.xy  * vec2(aspect, 1.0) / resolution.xy;
    vec2 mouseDir = normalize(abs(iMouse.zw) - iMouse.xy);
    vec2 origin = clamp(mouse - mouseDir * mouse.x / mouseDir.x, 0.0, 1.0);

    float mouseDist = clamp(length(mouse - origin)
    + (aspect - (abs(iMouse.z) / resolution.x) * aspect) / mouseDir.x, 0.0, aspect / mouseDir.x);

    if (mouseDir.x < 0.0)
    {
        mouseDist = distance(mouse, origin);
    }

    float proj = dot(uv - origin, mouseDir);
    float dist = proj - mouseDist;

    vec2 linePoint = uv - dist * mouseDir;



    if (dist > radius)
    {
        fragColor = TRANSPARENT;
        fragColor.rgb *= pow(clamp(dist - radius, 0.0, 1.0) * 1.5, 0.2);
    }
    else if (dist >= 0.0)
    {
        // map to cylinder point
        float theta = asin(dist / radius);
        vec2 p2 = linePoint + mouseDir * (pi - theta) * radius;
        vec2 p1 = linePoint + mouseDir * theta * radius;
        uv = (p2.x <= aspect && p2.y <= 1.0 && p2.x > 0.0 && p2.y > 0.0) ? p2 : p1;
        fragColor = texture(image, uv * vec2(1.0 / aspect, 1.0));
        fragColor.rgb *= pow(clamp((radius - dist) / radius, 0.0, 1.0), 0.2);
    }
    else
    {
        vec2 p = linePoint + mouseDir * (abs(dist) + pi * radius);
        uv = (p.x <= aspect && p.y <= 1.0 && p.x > 0.0 && p.y > 0.0) ? p : uv;
        fragColor = texture(image, uv * vec2(1.0 / aspect, 1.0));
    }
}

使用方式:

GestureDetector(
            onPanDown: (details) {
              setState(() {
                downPosition = details.localPosition;
                updatePosition = details.localPosition;
                developer.log(details.toString(), name: 'down');
              });
            },
            onPanUpdate: (details) {
              setState(() {
                updatePosition = details.localPosition;
                developer.log(details.localPosition.toString(), name: 'update');
              });
            },
            onPanEnd: (details) {
              setState(() {
                downPosition = Offset.zero;
                updatePosition = Offset.zero;
                developer.log(details.velocity.toString(), name: 'end');
              });
            },
            onPanCancel: () {
              setState(() {
                downPosition = Offset.zero;
                updatePosition = Offset.zero;
                developer.log('', name: 'cancel');
              });
            },
            child: ShaderBuilder(
              (context, shader, _) {
                return AnimatedSampler(
                  (image, size, canvas) {
                    shader
                      ..setFloat(0, size.width) // resolution
                      ..setFloat(1, size.height) // resolution
                      ..setFloat(2, updatePosition.dx) // mouse
                      ..setFloat(3, updatePosition.dy) // mouse
                      ..setFloat(4, downPosition.dx) // mouse
                      ..setFloat(5, downPosition.dy) // mouse
                      ..setImageSampler(0, image); // image

                    ShaderHelper.drawShaderRect(shader, size, canvas);
                  },
                  child: [要展示的控件],
                );
              },
              assetKey: [frag文件路径],
            ),
          )

@Liloupar
Copy link

@lwlizhe 看效果图还不错, 有空我试试 感谢

@Liloupar
Copy link

@lwlizhe
方便加个微信细聊吗? 我掘金上私聊你了.

@xuyisheng
Copy link

demo中有两个问题,一个是demo初始化的时候,是卷着半边的,另一个是翻页时,下面的卷边是直线截掉的,有点生硬,不是贝塞尔曲线的那种弧度

@lwlizhe
Copy link
Owner

lwlizhe commented Mar 26, 2024

demo中有两个问题,一个是demo初始化的时候,是卷着半边的,另一个是翻页时,下面的卷边是直线截掉的,有点生硬,不是贝塞尔曲线的那种弧度

额,第一个问题其实是当初直接把默认指针设置为左上角的(0,0)点了,所以修改的时候也简单,直接改成(-1,-1)之类特殊值,如果检测值是-1,直接走基本的纹理映射,不做翻页动画处理即可;

第二个有点没太看懂,额,你看下这篇文章的效果可以么。我猜测你说的是没加阴影,不知道是不是你说的问题。

文章中动图截图:
image

@xuyisheng
Copy link

image

其实就是我圈出来的地方,正常应该是弧形弯过来,现在是直线切过来的

@xuyisheng
Copy link

方便加个微信学习下吗

@Liloupar
Copy link

方便加个微信学习下吗

哈哈哈 感觉可以拉个群 集思广益下, 做个媲美iOS原生的

@lwlizhe
Copy link
Owner

lwlizhe commented Mar 27, 2024

image

其实就是我圈出来的地方,正常应该是弧形弯过来,现在是直线切过来的

刚刚确认了下,确实有这个问题,跟半径啥的好像也没啥关系,好像就是裁剪掉了,这个计算模式还要调整下

@lwlizhe
Copy link
Owner

lwlizhe commented Mar 27, 2024

方便加个微信学习下吗

额,这是我微信二维码,后面我在拉个群?
img_v3_029c_1352d36a-8623-448b-86b0-e88717b3928g

@zesion1024
Copy link

有一些写好的仿真翻页的着色器, 但是我不知道怎么在flutter中使用..比如下面的 https://www.shadertoy.com/view/ls3cDB

这个我改了下,至少翻页部分的UI效果可以用了:

演示

#include <flutter/runtime_effect.glsl>

uniform vec2 resolution;
uniform vec4 iMouse;
uniform sampler2D image;

#define pi 3.14159265359
#define radius 0.1
#define TRANSPARENT vec4(0.0, 0.0, 0.0, 0.0)

out vec4 fragColor;

void main() {
    vec2 fragCoord = FlutterFragCoord().xy;

    float aspect = resolution.x / resolution.y;

    vec2 uv = fragCoord * vec2(aspect, 1.0) / resolution.xy;

    vec2 mouse = iMouse.xy  * vec2(aspect, 1.0) / resolution.xy;
    vec2 mouseDir = normalize(abs(iMouse.zw) - iMouse.xy);
    vec2 origin = clamp(mouse - mouseDir * mouse.x / mouseDir.x, 0.0, 1.0);

    float mouseDist = clamp(length(mouse - origin)
    + (aspect - (abs(iMouse.z) / resolution.x) * aspect) / mouseDir.x, 0.0, aspect / mouseDir.x);

    if (mouseDir.x < 0.0)
    {
        mouseDist = distance(mouse, origin);
    }

    float proj = dot(uv - origin, mouseDir);
    float dist = proj - mouseDist;

    vec2 linePoint = uv - dist * mouseDir;



    if (dist > radius)
    {
        fragColor = TRANSPARENT;
        fragColor.rgb *= pow(clamp(dist - radius, 0.0, 1.0) * 1.5, 0.2);
    }
    else if (dist >= 0.0)
    {
        // map to cylinder point
        float theta = asin(dist / radius);
        vec2 p2 = linePoint + mouseDir * (pi - theta) * radius;
        vec2 p1 = linePoint + mouseDir * theta * radius;
        uv = (p2.x <= aspect && p2.y <= 1.0 && p2.x > 0.0 && p2.y > 0.0) ? p2 : p1;
        fragColor = texture(image, uv * vec2(1.0 / aspect, 1.0));
        fragColor.rgb *= pow(clamp((radius - dist) / radius, 0.0, 1.0), 0.2);
    }
    else
    {
        vec2 p = linePoint + mouseDir * (abs(dist) + pi * radius);
        uv = (p.x <= aspect && p.y <= 1.0 && p.x > 0.0 && p.y > 0.0) ? p : uv;
        fragColor = texture(image, uv * vec2(1.0 / aspect, 1.0));
    }
}

使用方式:

GestureDetector(
            onPanDown: (details) {
              setState(() {
                downPosition = details.localPosition;
                updatePosition = details.localPosition;
                developer.log(details.toString(), name: 'down');
              });
            },
            onPanUpdate: (details) {
              setState(() {
                updatePosition = details.localPosition;
                developer.log(details.localPosition.toString(), name: 'update');
              });
            },
            onPanEnd: (details) {
              setState(() {
                downPosition = Offset.zero;
                updatePosition = Offset.zero;
                developer.log(details.velocity.toString(), name: 'end');
              });
            },
            onPanCancel: () {
              setState(() {
                downPosition = Offset.zero;
                updatePosition = Offset.zero;
                developer.log('', name: 'cancel');
              });
            },
            child: ShaderBuilder(
              (context, shader, _) {
                return AnimatedSampler(
                  (image, size, canvas) {
                    shader
                      ..setFloat(0, size.width) // resolution
                      ..setFloat(1, size.height) // resolution
                      ..setFloat(2, updatePosition.dx) // mouse
                      ..setFloat(3, updatePosition.dy) // mouse
                      ..setFloat(4, downPosition.dx) // mouse
                      ..setFloat(5, downPosition.dy) // mouse
                      ..setImageSampler(0, image); // image

                    ShaderHelper.drawShaderRect(shader, size, canvas);
                  },
                  child: [要展示的控件],
                );
              },
              assetKey: [frag文件路径],
            ),
          )

大佬着色器是用的 flutter_shaders 这个包吗?能上传一个demo看一下吗?

@lwlizhe
Copy link
Owner

lwlizhe commented Aug 13, 2024

有一些写好的仿真翻页的着色器, 但是我不知道怎么在flutter中使用..比如下面的 https://www.shadertoy.com/view/ls3cDB

这个我改了下,至少翻页部分的UI效果可以用了:
演示

#include <flutter/runtime_effect.glsl>

uniform vec2 resolution;
uniform vec4 iMouse;
uniform sampler2D image;

#define pi 3.14159265359
#define radius 0.1
#define TRANSPARENT vec4(0.0, 0.0, 0.0, 0.0)

out vec4 fragColor;

void main() {
    vec2 fragCoord = FlutterFragCoord().xy;

    float aspect = resolution.x / resolution.y;

    vec2 uv = fragCoord * vec2(aspect, 1.0) / resolution.xy;

    vec2 mouse = iMouse.xy  * vec2(aspect, 1.0) / resolution.xy;
    vec2 mouseDir = normalize(abs(iMouse.zw) - iMouse.xy);
    vec2 origin = clamp(mouse - mouseDir * mouse.x / mouseDir.x, 0.0, 1.0);

    float mouseDist = clamp(length(mouse - origin)
    + (aspect - (abs(iMouse.z) / resolution.x) * aspect) / mouseDir.x, 0.0, aspect / mouseDir.x);

    if (mouseDir.x < 0.0)
    {
        mouseDist = distance(mouse, origin);
    }

    float proj = dot(uv - origin, mouseDir);
    float dist = proj - mouseDist;

    vec2 linePoint = uv - dist * mouseDir;



    if (dist > radius)
    {
        fragColor = TRANSPARENT;
        fragColor.rgb *= pow(clamp(dist - radius, 0.0, 1.0) * 1.5, 0.2);
    }
    else if (dist >= 0.0)
    {
        // map to cylinder point
        float theta = asin(dist / radius);
        vec2 p2 = linePoint + mouseDir * (pi - theta) * radius;
        vec2 p1 = linePoint + mouseDir * theta * radius;
        uv = (p2.x <= aspect && p2.y <= 1.0 && p2.x > 0.0 && p2.y > 0.0) ? p2 : p1;
        fragColor = texture(image, uv * vec2(1.0 / aspect, 1.0));
        fragColor.rgb *= pow(clamp((radius - dist) / radius, 0.0, 1.0), 0.2);
    }
    else
    {
        vec2 p = linePoint + mouseDir * (abs(dist) + pi * radius);
        uv = (p.x <= aspect && p.y <= 1.0 && p.x > 0.0 && p.y > 0.0) ? p : uv;
        fragColor = texture(image, uv * vec2(1.0 / aspect, 1.0));
    }
}

使用方式:

GestureDetector(
            onPanDown: (details) {
              setState(() {
                downPosition = details.localPosition;
                updatePosition = details.localPosition;
                developer.log(details.toString(), name: 'down');
              });
            },
            onPanUpdate: (details) {
              setState(() {
                updatePosition = details.localPosition;
                developer.log(details.localPosition.toString(), name: 'update');
              });
            },
            onPanEnd: (details) {
              setState(() {
                downPosition = Offset.zero;
                updatePosition = Offset.zero;
                developer.log(details.velocity.toString(), name: 'end');
              });
            },
            onPanCancel: () {
              setState(() {
                downPosition = Offset.zero;
                updatePosition = Offset.zero;
                developer.log('', name: 'cancel');
              });
            },
            child: ShaderBuilder(
              (context, shader, _) {
                return AnimatedSampler(
                  (image, size, canvas) {
                    shader
                      ..setFloat(0, size.width) // resolution
                      ..setFloat(1, size.height) // resolution
                      ..setFloat(2, updatePosition.dx) // mouse
                      ..setFloat(3, updatePosition.dy) // mouse
                      ..setFloat(4, downPosition.dx) // mouse
                      ..setFloat(5, downPosition.dy) // mouse
                      ..setImageSampler(0, image); // image

                    ShaderHelper.drawShaderRect(shader, size, canvas);
                  },
                  child: [要展示的控件],
                );
              },
              assetKey: [frag文件路径],
            ),
          )

大佬着色器是用的 flutter_shaders 这个包吗?能上传一个demo看一下吗?

额,可以看下我这篇文章 https://juejin.cn/post/7337207433867886619 ,其中有如何使用flutter_shader部分的代码,至于所使用的glsl文件,就是目前这块贴的这个

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants