如何滚动到文本小部件中给定字符串的第一次出现



假设我有一个歌词应用程序,只有一个Scaffold带有一个文本小部件,可以显示整个歌词,歌词以格式编写

合唱:…

  1. 。。。。

  2. 。。。。

并且我有一个FAB,点击它我需要文本自动滚动到文本";合唱:";,这段文字确实出现在每首歌中,但当歌词大约为4+时,它们通常会从屏幕上消失,因此,用户通常必须在每首超过屏幕高度的歌词后手动再次滚动到合唱,但我需要点击按钮自动完成

向上滚动直到字符串";合唱";在视图中,我将如何在颤振中做到这一点

文本

const kTheAstronomers = '''1. Yeah, you woke up in London
At least that's what you said
I sat here scrollin'
And I saw you with your aunt
A demon on your left
An angel on your right
But you're hypocritical
Always political

Chorus:
Say you mean one thing
But you go ahead and lie
Oh, you lie-lie, lie-lie
And you say you're not the bad type

2. Oh, you posted on Twitter
Said you had other plans
But your mother, she called me
Said, "Come have lunch with the fam"
Guess you didn't tell her that
You should've called me back
I guess you changed your number or somethin' '''

LYRIC屏幕

@override
Widget build(BuildContext context) {
return Scaffold(
extendBody: true,
body: SafeArea(
child: SingleChildScrollView(
physics: const BouncingScrollPhysics(),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20.0, vertical: 10),
child: Text(
kTheAstronomers,
style: const TextStyle(
fontSize: 30,
fontFamily: 'Montserrat',
fontWeight: FontWeight.w600,
),
),
),
),
)
floatingActionButton: FAB(onPressed: autoScrollToChorus),

您可以创建一个GlobalKey并使用currentContext滚动到Chorus部分。

final _key = GlobalKey()

autoScrollToChorus方法中,您可以添加:

final context = _key.currentContext!;
await Scrollable.ensureVisible(context)

我找到了一种方法。

我不得不改变显示文本的方式,而不是使用一个文本小部件,我使用ListView构建器来显示两个文本,但在此之前,在initState中,当我的页面接收到文本时,我将文本拆分为两个单独的文本列表,一个包含第一部分,另一个包含从Chorus向下的部分,然后我把这个列表交给listview构建器(你也可以只使用一列,创建两个单独的小部件,然后把滚动键传给第二个文本,知道它是文本的第二部分(

final GlobalKey _key = GlobalKey();
void _autoScrollToChorus() async {
BuildContext context = _key.currentContext!;
await Scrollable.ensureVisible(context);
}

late List<String> lyricList;
@override
initState() {
lyricList =
kTheAstronomers.split(RegExp("(?=chorus)", caseSensitive: false));
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: ListView.builder(
itemCount: lyricList.length,
itemBuilder: (context, idx) {
return Text(
key: idx == 1 ? _key : null,
lyricList[idx],
style: const TextStyle(
fontWeight: FontWeight.w600,
fontSize: 30,
),
);
}),
),
floatingActionButton: lyricList.length > 1 ? FloatingActionButton(
onPressed: _autoScrollToChorus,
child: const Padding(
padding: EdgeInsets.all(8.0),
child: Text("Chorus"),
),
) : null,
);
}

多亏了@Priyaank,我知道可以使用密钥并滚动到特定的小部件

一种更高级的解决方案,可以在合唱时使用SCROLLABLE_POSITIONED_LIST包隐藏按钮

final GlobalKey _key = GlobalKey();
final ItemScrollController _itemScrollController = ItemScrollController();
final ItemPositionsListener _itemListener = ItemPositionsListener.create();
late List<String> lyricList;
bool chorusIsVisible = true;
void _autoScrollToChorus() {
// BuildContext context = _key.currentContext!;
// await Scrollable.ensureVisible(context);
_itemScrollController.scrollTo(
index: 1,
duration: const Duration(milliseconds: 500),
alignment: 0.5
);
}
@override
initState() {
lyricList =
kTheAstronomers.split(RegExp("(?=chorus)", caseSensitive: false));
super.initState();
if(lyricList.length > 1) {
_itemListener.itemPositions.addListener(() {
chorusIsVisible = _itemListener.itemPositions.value.where((item) {
final isTopVisible = item.itemLeadingEdge >= 0;
return isTopVisible;
}
).map((item) => item.index).toList().contains(1);
setState(() {});
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: ScrollablePositionedList.builder(
itemScrollController: _itemScrollController,
itemPositionsListener: _itemListener,
itemCount: lyricList.length,
itemBuilder: (context, idx) {
return Text(
lyricList[idx],
style: const TextStyle(
fontWeight: FontWeight.w600,
fontSize: 30,
),
);
}),
),
floatingActionButton: lyricList.length > 1 && !chorusIsVisible ? FloatingActionButton(
onPressed: _autoScrollToChorus,
child: const Padding(
padding: EdgeInsets.all(8.0),
child: Text("Chorus"),
),
) : null,
);
}
}

最新更新