MaterialApp
、DefaultTabController
、Scaffold
とTabBarView
を使ってビルドする画面があります。
この画面では、StreamBuilder
を使用してSQLITEから要素のリストを再現するボディコンテンツがあります。 ListView
を使用して、正確な100個の要素(「有限リスト」)が表示されます。
私の質問、_ListView.builder
_、この画面が開かれたときに特定のインデックスにジャンプする方法は?
マイスクリーン:
_...
ScrollController controller = ScrollController();
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner : false,
home: DefaultTabController(
length: 3,
child: Scaffold(
appBar: AppBar(
backgroundColor: Pigment.fromString(UIData.primaryColor),
elevation: 0,
centerTitle: true,
title: Text(translations.text("quran").toUpperCase()),
bottom: TabBar(
tabs: [
Text("Tab1"),
Text("Tab2"),
Text("Tab3")
],
),
leading: Row(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Expanded(
child: InkWell(
child: SizedBox(child: Image.asset("assets/images/home.png"), height: 10, width: 1,),
onTap: () => Navigator.of(context).pop(),
)
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _scrollToIndex,
tooltip: 'Testing Index Jump',
child: Text("GO"),
),
body:
TabBarView(
children: [
Stack(
children: <Widget>[
MyDraggableScrollBar.create(
scrollController: controller,
context: context,
heightScrollThumb: 25,
child: ListView(
controller: controller,
children: <Widget>[
Padding(
padding: EdgeInsets.fromLTRB(30, 15, 30, 8),
child: Container(
alignment: Alignment.center,
height: 30,
child: ClipRRect(
borderRadius: BorderRadius.circular(8),
child: TextField(
style: TextStyle(color: Colors.green),
decoration: new InputDecoration(
contentPadding: EdgeInsets.all(5),
border: InputBorder.none,
filled: true,
hintStyle: new TextStyle(color: Colors.green, fontSize: 14),
prefixIcon: Icon(FontAwesomeIcons.search,color: Colors.green,size: 17,),
hintText: translations.text("search-quran"),
fillColor: Colors.grey[300],
prefixStyle: TextStyle(color: Colors.green)
),
onChanged: (val) => quranBloc.searchSurah(val),
),
)
)
),
//surah list
streamBuilderQuranSurah(context)
],
)
) // MyDraggableScrollBar
],
),
Icon(Icons.directions_transit),
Icon(Icons.directions_bike),
],
)
)));
}
Widget streamBuilderQuranSurah(BuildContext ctx){
return StreamBuilder(
stream: quranBloc.chapterStream ,
builder: (BuildContext context, AsyncSnapshot<ChaptersModel> snapshot){
if(snapshot.hasData){
return ListView.builder(
controller: controller,
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount:(snapshot.data.chapters?.length ?? 0),
itemBuilder: (BuildContext context, int index) {
var chapter =
snapshot.data.chapters?.elementAt(index);
return chapterDataCell(chapter);
},
);
}
else{
return SurahItemShimmer();
}
},
);
}
...
_
classmydraggableScrollBar.dart:
_import 'package:draggable_scrollbar/draggable_scrollbar.Dart';
import 'package:flutter/material.Dart';
class MyDraggableScrollBar {
static Widget create({
@required BuildContext context,
@required ScrollController scrollController,
@required double heightScrollThumb,
@required Widget child,
}) {
return DraggableScrollbar(
alwaysVisibleScrollThumb: true,
scrollbarTimeToFade: Duration(seconds: 3),
controller: scrollController,
heightScrollThumb: heightScrollThumb,
backgroundColor: Colors.green,
scrollThumbBuilder: (
Color backgroundColor,
Animation<double> thumbAnimation,
Animation<double> labelAnimation,
double height, {
Text labelText,
BoxConstraints labelConstraints,
}) {
return InkWell(
onTap: () {},
child: Container(
height: height,
width: 7,
color: backgroundColor,
),
);
},
child: child,
);
}
}
_
私は他の解決策を見つけましたが、たとえば機能していないようです indexed_list_view それは無限リストのみをサポートしています
そしてそれはまだこれに特徴を持っていないのは、 この問題
何か案が ?
使用できます https://pub.dev/packages/scrollable_positioned_list 。初期インデックスをウィジェットに渡すことができます。
ScrollablePositionedList.builder(
initialScrollIndex: 12, //you can pass the desired index here//
itemCount: 500,
itemBuilder: (context, index) => Text('Item $index'),
itemScrollController: itemScrollController,
itemPositionsListener: itemPositionsListener,
);
_
一般的な解決策:
文字列の数/文字列/リストとして表すことができるものを格納するには、Flutterは強力な使いやすいプラグインを提供しています。次に必要なときに必要なときに、その値が必要なのはそのキーを取得または更新する必要があります。
開始するには、pubspec.yamlファイルに shared_preferences プラグインを追加します。
_dependencies:
flutter:
sdk: flutter
shared_preferences: "<newest version>"
_
_flutter pub get
_をターミナルから実行するか、Intellijを使用している場合は_Packages get
_をクリックするだけで、_pubspec.yaml
_ファイルを表示している間に画面の右上隅のそばにあることがわかります。
上記のコマンドが正常に実行されたら、_main.Dart
_または関係するファイルの下のファイルをインポートします。
_ import 'package:shared_preferences/shared_preferences.Dart';
_
これで、 ScrollController をListView.builder()
ウィジェットに添付して、最終/最後のオフセットがすべての方法でアプリを離したときにshared_preferencesを使用して特定のキーと一緒に格納されていることを確認してください。あなたの関心のあるウィジェットのinitstateが呼び出されたときに設定されます。
私たちのアプリの状態の変化を検出し、それに従って行動することを知るために、私たちは私たちのクラスにWidgetsBindingObserver
を継承します。
以下の手順:
WidgetSbindingObServerクラスをに並びステートフルウェイの状態クラスを延長します。
上記のクラスの関数メンバーとして、非同期関数resumeController()
を定義します。
_ Future<void> resumeController() async{
_sharedPreferences = await SharedPreferences.getInstance().then((_sharedPreferences){
if(_sharedPreferences.getKeys().contains("scroll-offset-0")) _scrollController= ScrollController(initialScrollOffset:_sharedPreferences.getDouble("scroll-offset-0"));
else _sharedPreferences.setDouble("scroll-offset-0", 0);
setState((){});
return _sharedPreferences;
});
_
_ ScrollController _scrollController;
SharedPreferences _sharedPreferences;
_
resumeController()
を呼び出して、WidgetSbindingクラスのインスタンスオブジェクトのaddobServerメソッドにクラスを渡します。_ resumeController();
WidgetsBinding.instance.addObserver(this);
_
_ @override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
_scrollController.dispose();
super.dispose();
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
if(state==AppLifecycleState.paused || state==AppLifecycleState.inactive || state==AppLifecycleState.suspending)
_sharedPreferences.setDouble("scroll-offset-0", _scrollController.offset);
super.didChangeAppLifecycleState(state);
}
_
ScrollController()
を心配するスクロール可能に渡します。実装例:
_class MyWidget extends StatefulWidget {
@override
_MyWidgetState createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> with WidgetsBindingObserver{
//[...]
ScrollController _scrollController;
SharedPreferences _sharedPreferences;
Future<void> resumeController() async{
_sharedPreferences = await SharedPreferences.getInstance().then((_sharedPreferences){
if(_sharedPreferences.getKeys().contains("scroll-offset-0")) _scrollController= ScrollController(initialScrollOffset:_sharedPreferences.getDouble("scroll-offset-0"));
else _sharedPreferences.setDouble("scroll-offset-0", 0);
setState((){});
return _sharedPreferences;
});
}
@override
void initState() {
resumeController();
WidgetsBinding.instance.addObserver(this);
super.initState();
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
_scrollController.dispose();
super.dispose();
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
if(state==AppLifecycleState.paused || state==AppLifecycleState.inactive || state==AppLifecycleState.suspending)
_sharedPreferences.setDouble("scroll-offset-0", _scrollController.offset);
super.didChangeAppLifecycleState(state);
}
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: AppBar(
title: Text("Smart Scroll View"),
),
body: ListView.builder(
itemCount: 50,
controller: _scrollController,
itemBuilder: (c,i)=>
Padding(
padding: EdgeInsets.symmetric(horizontal: 24,vertical: 16),
child: Text((i+1).toString()),
),
),
),
);
}
}
_
https://pub.dev/packages/indexed_list_view パッケージはあなたをこれに役立てることができます。このようなものを使う:
IndexedListView.builder(
controller: indexScrollController,
itemBuilder: itemBuilder
);
indexScrollController.jumpToIndex(10000);
_
ウィジェットのサイズを知らずに見つけられない解決策は、インデックスから最後まで逆の「サブリスト」を表示してから、「サブリスト」の上部までスクロールしてリスト全体をリセットします。リバースリストのように、アイテムはリストの上部に追加され、あなたはあなたの位置(インデックス)に滞在します。
問題は、リストのサイズを変更する必要があるため、ListView.Builderを使用できないことです。
class _ListViewIndexState extends State<ListViewIndex> {
ScrollController _scrollController;
List<Widget> _displayedList;
@override
void initState() {
super.initState();
_scrollController = ScrollController();
_displayedList = widget.items.sublist(0, widget.items.length - widget.index);
if (SchedulerBinding.instance.schedulerPhase == SchedulerPhase.persistentCallbacks) {
SchedulerBinding.instance.addPostFrameCallback((_) {
//here the sublist is already build
completeList();
});
}
}
completeList() {
//to go to the last item(in first position)
_scrollController.jumpTo(_scrollController.position.maxScrollExtent);
//reset the list to the full list
setState(() {
_displayedList = widget.items;
});
}
@override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
ListView(
controller: _scrollController,
reverse: true,
children: _displayedList,
),
]
);
}
}
_