flutter_novel icon indicating copy to clipboard operation
flutter_novel copied to clipboard

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

Open jackxuechen opened this issue 1 year ago • 29 comments

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

jackxuechen avatar Nov 21 '23 08:11 jackxuechen

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

jackxuechen avatar Nov 21 '23 11:11 jackxuechen

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

lwlizhe avatar Nov 22 '23 01:11 lwlizhe

有减去高度 /// 当前段落内容计算偏移量 /// 为什么要减一个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;

jackxuechen avatar Nov 22 '23 02:11 jackxuechen

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

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

lwlizhe avatar Nov 22 '23 02:11 lwlizhe

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

jackxuechen avatar Nov 22 '23 02:11 jackxuechen

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

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

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

lwlizhe avatar Nov 22 '23 02:11 lwlizhe

好的,我在看下,感谢

jackxuechen avatar Nov 22 '23 02:11 jackxuechen

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

wengxianxun avatar Nov 30 '23 02:11 wengxianxun

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

jackxuechen avatar Nov 30 '23 02:11 jackxuechen

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

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

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

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

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

lwlizhe avatar Nov 30 '23 10:11 lwlizhe

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

Liloupar avatar Jan 17 '24 10:01 Liloupar

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

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

lwlizhe avatar Jan 17 '24 10:01 lwlizhe

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

Liloupar avatar Jan 18 '24 03:01 Liloupar

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

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

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

lwlizhe avatar Jan 18 '24 03:01 lwlizhe

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

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

lwlizhe avatar Jan 18 '24 03:01 lwlizhe

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

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

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

期待大佬的发挥

Liloupar avatar Jan 18 '24 04:01 Liloupar

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

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

期待大佬的发挥

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

lwlizhe avatar Jan 18 '24 04:01 lwlizhe

@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文件路径],
            ),
          )

lwlizhe avatar Jan 19 '24 09:01 lwlizhe

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

Liloupar avatar Jan 19 '24 09:01 Liloupar

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

Liloupar avatar Feb 27 '24 08:02 Liloupar

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

xuyisheng avatar Mar 26 '24 09:03 xuyisheng

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

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

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

文章中动图截图: image

lwlizhe avatar Mar 26 '24 10:03 lwlizhe

image

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

xuyisheng avatar Mar 26 '24 11:03 xuyisheng

方便加个微信学习下吗

xuyisheng avatar Mar 26 '24 11:03 xuyisheng

方便加个微信学习下吗

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

Liloupar avatar Mar 26 '24 12:03 Liloupar

image

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

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

lwlizhe avatar Mar 27 '24 01:03 lwlizhe

方便加个微信学习下吗

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

lwlizhe avatar Mar 27 '24 01:03 lwlizhe

有一些写好的仿真翻页的着色器, 但是我不知道怎么在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看一下吗?

zesion1024 avatar Aug 13 '24 03:08 zesion1024

有一些写好的仿真翻页的着色器, 但是我不知道怎么在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文件,就是目前这块贴的这个

lwlizhe avatar Aug 13 '24 03:08 lwlizhe