Flutter 实现类似 ins 的显示评论框效果

widgets_visibility_provider_ins_screenshot

前言

widgets_visibility_provider 有人用了~~还问了一个业务问题,如何实现类似 ins 的显示评论框效果,特意弄了个 example 增加在里面,也顺便更新了意下 bloc(bloc 真赞~)

具体效果

ins 的显示评论效果,主要就是如果你长时间看其中一个 item,就把评论框显示出来。当然,我们并不知道用户在看哪个 item,也不会用摄像头权限搞这些…
我测试过后发现,基本上是 item 处于中间位置一定时间,就当用户在看,一定时间内,貌似 4 秒?5 秒?不重要。
所以我们要做的是:

  • 定位到中间的 item
  • 在 item 没有改变的情况下,在一定时间后,获取回调改变 UI

定位 item

由于我做这个库,基本上提供了尽可能多 option 去配置,所以方法也比较灵活

Provider

通过WidgetsVisibilityProvidercondition,来改变监听范围,可以这样写:

1
2
3
4
5
6
7
8
9
10
11
WidgetsVisibilityProvider(
condition: (PositionData positionData) {
// `positionData.viewportSize`是`scollView`视口尺寸,除于 2 获取中间位置
var center = positionData.viewportSize / 2;
// 判断每一个的位置,我这边取的是 cneter 在 item 的位置内。
// 根据实际业务需要,你也可以增加 comment 的预计尺寸。
return center > positionData.startPosition &&
center < positionData.endPosition;
}
child: ...,
)

剩下的回调就看WidgetsVisibilityListener就可以回调了:

1
2
3
4
5
6
7
WidgetsVisibilityListener(
listener: (context, event) {
if (event.positionDataList.isNotEmpty)
// 由于我们上面判断,所以最多只会返回一个,剩下就可以根据业务需要加以使用,这个 data 是 VisibleNotifierWidget 的 data,可以是任意数据。
doSome(event.positionDataList.first.data);
}
)

Listener

聪明的小伙伴应该就知道了,直接在listener找出来不香么?是可以的,这样还能应对其他需要,直接改变WidgetsVisibilityProvidercondition是会影响下面所有回调 builder listener。

VisibleNotifierWidget

使用上面两种方法都可以使用,不过建议尽可能的使用WidgetsVisibilityProvider,一开始就决定了监听范围,就可以减少之后的判断计算。

Bloc

如果不能满足,可以直接使用WidgetsVisibilityProviderBloc,更为细致的掌控。

实际回调

如何判断单位时间内都是同一个 item 呢?实际上基本上很多人都用过,只是面对需求一时间没想起来,但是我说如何解决搜索框用户不断输入不断发送请求的问题,应该就能想起 debounce。
debounce 在 dart 的实现方法我想到有两种,一种是 rxdart 去处理,另一种是闭包。

我比较喜欢用 stream 的方式,直接配置 bloc 和 rxdart 就可以实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class ShowCommentBloc extends Bloc<int, Set<int>> {
ShowCommentBloc() : super({});

@override
Stream<Transition<int, Set<int>>> transformEvents(
Stream<int> events, transitionFn) =>
super.transformEvents(
// 我这里只有一种 event,如果有多种可以先筛选再合并
events
// 注意,如果使用闭包也记得需要先操作 distinct 保证重复数据不会再次发送到 debounce
.distinct()
.debounce((event) => TimerStream(event, Duration(seconds: 3))),
transitionFn,
);

@override
Stream<Set<int>> mapEventToState(int event) async* {
// 为了改变 hashCode
// for change hashCode
yield (state..add(event)).toSet();
}
}

总结

使用 widgets_visibility_provider 解决滑动相关的一些效果非常简单,比如淘宝京东页面,滑动到不同的位置,就改变 header bar 的 tab 位置,比如解决运营需求的曝光 item 问题或者其他效果,在 flutter 中使用也可以做到解耦,十分舒服~~

思考

我一直以来做库,基本上都是自己用到,觉得有用然后开源分享出去,很多时候我觉得简单的封装成通用易用已经够麻烦了,还需要写 readme,example,的确麻烦…
不过这种懒,也影响了使用的人,或许我应该以后应该起码 example 写多点?

推荐