簡単に言えば:
複数のスクロール可能なウィジェット(たとえば、SingleSchildScrollView
)を一緒に同期させる方法はありますか?
1つをスクロールするときにもう1つをスクロールできる2つのスクロール可能ファイルが必要です。
このようにして、Stack
を使用してそれらを互いに重ね、後ろの方が前の方に続いてスクロールできます。
または、それらをColumn
またはRow
の別のセットに入れて別々にしますが、どちらかをスクロールするだけでスクロールします。
controller
を使用してみましたが、思ったとおりに動作していないようです。
たとえば、以下のコードを試してください。「RIGHT」は「LEFT」の前にあり、スクロールしようとすると、RIGHTのみが移動します。では、どうすれば両方を同時に移動できますか?
スタックをListView
の中に入れるように言わないでください、それは私が必要とするものではありません。
class _MyHomePageState extends State<MyHomePage> {
final ScrollController _mycontroller = new ScrollController();
@override
Widget build(BuildContext context) {
body:
Container(
height: 100,
child:
Stack( children: <Widget>[
SingleChildScrollView(
controller: _mycontroller,
child: Column( children: <Widget>[
Text('LEFT '),
Text('LEFT '),
Text('LEFT '),
Text('LEFT '),
Text('LEFT '),
Text('LEFT '),
],)
),
SingleChildScrollView(
controller: _mycontroller,
child: Column(children: <Widget>[
Text(' RIGHT'),
Text(' RIGHT'),
Text(' RIGHT'),
Text(' RIGHT'),
Text(' RIGHT'),
Text(' RIGHT'),
],)
),
])
)
}}
この質問は以前に複数のフォーラムで行われたことがあると思いますが、誰もこれに対する結論や解決策を提示していません。 ( ここ を参照)
offset
を使用して、ScrollNotification
を使用して、複数のスクロール可能オブジェクトを同期することができました。
大まかなコード例は次のとおりです。
_class _MyHomePageState extends State<MyHomePage> {
ScrollController _mycontroller1 = new ScrollController(); // make seperate controllers
ScrollController _mycontroller2 = new ScrollController(); // for each scrollables
@override
Widget build(BuildContext context) {
body:
Container(
height: 100,
child: NotificationListener<ScrollNotification>( // this part right here is the key
Stack( children: <Widget>[
SingleChildScrollView( // this one stays at the back
controller: _mycontroller1,
child: Column( children: <Widget>[
Text('LEFT '),
Text('LEFT '),
Text('LEFT '),
Text('LEFT '),
Text('LEFT '),
Text('LEFT '),
],)
),
SingleChildScrollView( // this is the one you scroll
controller: _mycontroller2,
child: Column(children: <Widget>[
Text(' RIGHT'),
Text(' RIGHT'),
Text(' RIGHT'),
Text(' RIGHT'),
Text(' RIGHT'),
Text(' RIGHT'),
],)
),
]),
onNotification: (ScrollNotification scrollInfo) { // HEY!! LISTEN!!
// this will set controller1's offset the same as controller2's
_mycontroller1.jumpTo(_mycontroller2.offset);
// you can check both offsets in terminal
print('check -- offset Left: '+_mycontroller1.offset.toInt().toString()+ ' -- offset Right: '+_mycontroller2.offset.toInt().toString());
}
)
)
}}
_
基本的に、各SingleChildScrollView
には独自のcontroller
があります。各controller
には独自のoffset
値があります。 _NotificationListener<ScrollNotification>
_を使用して、スクロールされたときに移動を通知します。
次に、スクロールジェスチャごとに(これはフレームごとにあると思います)、jumpTo()
コマンドを追加して、offset
sを好きなように設定できます。
乾杯!!
PS。リストの長さが異なる場合、オフセットが異なり、制限を超えてスクロールしようとするとスタックオーバーフローエラーが発生します。必ずいくつかの例外またはエラー処理を追加してください。 (つまり、_if else
_など)
@Chrisの回答に感謝します。同じ問題が発生し、その上にソリューションを構築しました。複数のウィジェットで機能し、「グループ」内の任意のウィジェットからの同期スクロールを可能にします。
PSA:これは正常に機能しているようですが、私はまだ始めたばかりで、想像できる最も素晴らしい方法で壊れるかもしれません
同期する必要があるスクロール可能なウィジェットごとに、NotificationListener<ScrollNotification>
と独立したScrollController
を使用して機能します。
クラスは次のようになります。
class SyncScrollController {
List<ScrollController> _registeredScrollControllers = new List<ScrollController>();
ScrollController _scrollingController;
bool _scrollingActive = false;
SyncScrollController(List<ScrollController> controllers) {
controllers.forEach((controller) => registerScrollController(controller));
}
void registerScrollController(ScrollController controller) {
_registeredScrollControllers.add(controller);
}
void processNotification(ScrollNotification notification, ScrollController sender) {
if (notification is ScrollStartNotification && !_scrollingActive) {
_scrollingController = sender;
_scrollingActive = true;
return;
}
if (identical(sender, _scrollingController) && _scrollingActive) {
if (notification is ScrollEndNotification) {
_scrollingController = null;
_scrollingActive = false;
return;
}
if (notification is ScrollUpdateNotification) {
_registeredScrollControllers.forEach((controller) => {if (!identical(_scrollingController, controller)) controller..jumpTo(_scrollingController.offset)});
return;
}
}
}
}
アイデアは、各ウィジェットScrollController
をそのヘルパーに登録して、スクロールする必要がある各ウィジェットへの参照を持つようにすることです。これを行うには、ScrollController
sの配列をSyncScrollController
sコンストラクターに渡すか、後でregisterScrollController
を呼び出してScrollController
をパラメーターとしてに渡します。関数。processNotification
メソッドをNotificationListener
のイベントハンドラーにバインドする必要があります。それはおそらくすべてウィジェット自体に実装できますが、私はまだ十分な経験がありません。
クラスの使用は次のようになります。
scollControllersのフィールドの作成
ScrollController _firstScroller = new ScrollController();
ScrollController _secondScroller = new ScrollController();
ScrollController _thirdScroller = new ScrollController();
SyncScrollController _syncScroller;
SyncScrollControllerを初期化します
@override
void initState() {
_syncScroller = new SyncScrollController([_firstScroller , _secondScroller, _thirdScroller]);
super.initState();
}
完全なNotificationListenerの例
NotificationListener<ScrollNotification>(
child: SingleChildScrollView(
controller: _firstScroller,
child: Container(
),
),
onNotification: (ScrollNotification scrollInfo) {
_syncScroller.processNotification(scrollInfo, _firstScroller);
}
),
スクロール可能なウィジェットごとに上記の例を実装し、SyncController
(パラメーターcontroller:)およびprocessNotification
scrollControllerパラメーターを編集します。 (上記_ firstScroller)それに応じて。上記のPSAが適用される_syncScroller != null
のチェックなど、さらにいくつかのフェイルセーフを実装する場合があります:)
私はちょうど同じ問題に直面していました、そして今そのための公式パッケージがあります: linked_scroll_controller 。
そのパッケージを使用して、マスターを作成する必要があります LinkedScrollControllerGroup
スクロールオフセットを追跡すると、個別のScrollController
sが提供されます(同期が維持されます) LinkedScrollControllerGroup.addAndGet()
経由。