flutter_novel
flutter_novel copied to clipboard
getPageConfig这个方法计算的内容有些页面显示不全
getPageConfig这个方法计算的内容有些页面显示不全,看了代码没看明白,大佬可以给解答下吗,用的是dev_2.0的分支
我打断点看了计算式正确的,但是实际显示出来会超出,感觉像是下面的方法出了问题 child: Text.rich( TextSpan(children: pageContentConfig.paragraphContents), // strutStyle: StrutStyle(forceStrutHeight: true, leading: 0.5), ),
没想到还有人看这个垃圾项目……感觉有点惭愧……真能看下去那真是费心了………… 回正题, 这块的代码我基本忘光了,只记得基本原理,不过你说的这种情况,我感觉挺符合我踩过的一个坑: flutter只能计算文字能不能展示,不负责计算能不能展示全,即使仅仅超几个像素,它也视为能够展示,因此我记得我特意把计算高度减去了一行的高度,这样flutter计算的结果就能保证一定能展示全,难道是我代码中忘了减去这一行的高度?
有减去高度 /// 当前段落内容计算偏移量 /// 为什么要减一个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;
我打断点看了计算式正确的,但是实际显示出来会超出,感觉像是下面的方法出了问题 child: Text.rich( TextSpan(children: pageContentConfig.paragraphContents), // strutStyle: StrutStyle(forceStrutHeight: true, leading: 0.5), ),
看这段代码的话,好像没写上style,比如说给textPainter计算的fontSize是16,这里设置的20,那自然展示不下,会不会是这里的问题?
加上style显示也有问题 child: Text.rich( TextSpan(children: pageContentConfig.paragraphContents), style: TextStyle(color: Colors.red, fontSize: 16, height: 2), // strutStyle: StrutStyle(forceStrutHeight: true, leading: 0.5), ),
有点麻爪了,这块感觉能检查的部分,一个就是传入的高度是否是展示区域的高度,另一个就是单行的高度了……要不自己就在代码中写死高度值,比如说传入高度为16,看看计算的是一行还是两行,展示的时候是一行还是两行,单行没问题的话;那应该是段落部分的间距计算部分有问题,检查方式应该也用同理能算出来,记得涉及到内容计算的影响因素应该就是这行高、行间距、段落间距这几部分了;
要不这样,先一个个的排除,你先传入不带任何换行符的纯文字,看看计算的对不对;这部分用来判断单行与行间距部分的设置是否有问题; 这部分没问题的话,在模拟传入带换行符形成段落结构的文字内容,看看是不是涉及到段落部分就有问题
这块的代码目前还真还没下载下来细看,不过记得当初没遇到这种问题来着,现在想来,会不会也跟传入的文本内容有关呢
好的,我在看下,感谢
大哥,这个项目怎么跑起来,很多错误
@wengxianxun dev_2.0分支用flutter 2.8.1版本试下,我用这个可以跑起来
大哥,这个项目怎么跑起来,很多错误
额,很抱歉,当时就做到一半……后面做着做着发现动画性能方面确实提升不明显,在那个翻页翻到边角的情况下,还是有着肉眼可见的卡顿,也实在没检查出来哪里有问题,或者存在哪里的Path范围设置过大的问题,就没啥接着研究的动力了……
不过如果你还相信我这个鸽子精的话,我先画个饼: 发现了一个宝藏项目:https://github.com/Rahiche/riveo_page_curl
通过shader来实现的动画,性能方面对基于canvas或者其他customPainter之类的简直是降维打击:
这回先在本地完成后再上传
@lwlizhe 大佬, shader 实现仿真翻页有进展了吗?
@lwlizhe 大佬, shader 实现仿真翻页有进展了吗?
额,学习了shader的原理后写了一个demo,上来就遇到的一个问题就是……shader这块如何进行贝塞尔曲线对绘制内容进行划分,这个写法不知道咋搞,还是没上手学好…………(怪不得需要区分出一个顶点着色器……现在看来确实很有必要) 这个月底有空的时候还搞不定的话,那我就考虑一下,dart负责内容区域划分,shader负责最耗性能的转换与绘制处理dart划分好的区域,看看这样行不行
@lwlizhe 有一些写好的仿真翻页的shader, 但是我不知道怎么在flutter中使用.. 比如下面的 https://www.shadertoy.com/view/ls3cDB
@lwlizhe 有一些写好的仿真翻页的shader, 但是我不知道怎么在flutter中使用.. 比如下面的 https://www.shadertoy.com/view/ls3cDB
卧槽牛逼,这个感觉很有戏!
回正题,感觉你这个也就是将入参改下就行了,你这个demo中所需的参数,好像基本都能通过flutter提供上,比如说入参的iChannel1,iChannel0,就是图片嘛,增加传入参数,fragColor这个转换为flutter中的那个也就是单独定义一个参数当临时变量,剩下的uv,mouse啥的对应画布宽高,触摸点位置,这些东西都是可以提供,换个名字而已……我真感觉很有戏
@lwlizhe 有一些写好的仿真翻页的shader, 但是我不知道怎么在flutter中使用.. 比如下面的 https://www.shadertoy.com/view/ls3cDB
卧槽牛逼了,原来还有这种宝藏shader库
卧槽牛逼,这个感觉很有戏!
回正题,感觉你这个也就是将入参改下就行了,你这个demo中所需的参数,好像基本都能通过flutter提供上,比如说入参的iChannel1,iChannel0,就是图片嘛,增加传入参数,fragColor这个转换为flutter中的那个也就是单独定义一个参数当临时变量,剩下的uv,mouse啥的对应画布宽高,触摸点位置,这些东西都是可以提供,换个名字而已……我真感觉很有戏
@lwlizhe 不过这个只有翻下一页, 没有翻上一页的, 要自己补 我数学已经退化到小学水平了 实在搞不定....
期待大佬的发挥
卧槽牛逼,这个感觉很有戏! 回正题,感觉你这个也就是将入参改下就行了,你这个demo中所需的参数,好像基本都能通过flutter提供上,比如说入参的iChannel1,iChannel0,就是图片嘛,增加传入参数,fragColor这个转换为flutter中的那个也就是单独定义一个参数当临时变量,剩下的uv,mouse啥的对应画布宽高,触摸点位置,这些东西都是可以提供,换个名字而已……我真感觉很有戏
@lwlizhe 不过这个只有翻下一页, 没有翻上一页的, 要自己补 我数学已经退化到小学水平了 实在搞不定....
期待大佬的发挥
我尽力,说实话,也就看个大概懂,里面细节和实现啥的也不是很明白,说不定你glsl水平比我还高呢~~
@lwlizhe 有一些写好的仿真翻页的shader, 但是我不知道怎么在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文件路径],
),
)
@lwlizhe 看效果图还不错, 有空我试试 感谢
@lwlizhe 方便加个微信细聊吗? 我掘金上私聊你了.
demo中有两个问题,一个是demo初始化的时候,是卷着半边的,另一个是翻页时,下面的卷边是直线截掉的,有点生硬,不是贝塞尔曲线的那种弧度
demo中有两个问题,一个是demo初始化的时候,是卷着半边的,另一个是翻页时,下面的卷边是直线截掉的,有点生硬,不是贝塞尔曲线的那种弧度
额,第一个问题其实是当初直接把默认指针设置为左上角的(0,0)点了,所以修改的时候也简单,直接改成(-1,-1)之类特殊值,如果检测值是-1,直接走基本的纹理映射,不做翻页动画处理即可;
第二个有点没太看懂,额,你看下这篇文章的效果可以么。我猜测你说的是没加阴影,不知道是不是你说的问题。
文章中动图截图:
其实就是我圈出来的地方,正常应该是弧形弯过来,现在是直线切过来的
方便加个微信学习下吗
方便加个微信学习下吗
哈哈哈 感觉可以拉个群 集思广益下, 做个媲美iOS原生的
其实就是我圈出来的地方,正常应该是弧形弯过来,现在是直线切过来的
刚刚确认了下,确实有这个问题,跟半径啥的好像也没啥关系,好像就是裁剪掉了,这个计算模式还要调整下
方便加个微信学习下吗
额,这是我微信二维码,后面我在拉个群?
有一些写好的仿真翻页的着色器, 但是我不知道怎么在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看一下吗?
有一些写好的仿真翻页的着色器, 但是我不知道怎么在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文件,就是目前这块贴的这个