How to Scroll multiple scroll of same Controller at once with sync to another one horizontal scroll?

277 views Asked by At

so i have created a custom calender on top the dates will be in a horizontal scroll inside a list view builder and below some icons as per the number of the days in a month in anthor list view builder now the list view builder with icons is inside another list view builder which scroll vertically i have used linked scroll controller and if i scroll the top one with dates the whole screen list with horizonal scroll happens as expected But when i scroll any of the one row with icons only the date row is changing not the other rows with icon. so when i scroll row with icon only that one and the top horizontal scroll with the date is scrolling . what iam trying to achieve is to scroll al the icons horizontal scroll even when i scroll any one of it along with the rest

import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:linked_scroll_controller/linked_scroll_controller.dart';

import 'package:stacked/stacked.dart';

class TeamViewTab extends StatefulWidget {
  @override
  _TeamViewTabState createState() => _TeamViewTabState();
}

class _TeamViewTabState extends State<TeamViewTab> {
  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Expanded(
          child: _TeamViewList(),
        ),
      ],
    );
  }
}

class _TeamViewList extends StatefulWidget {
  @override
  __TeamViewListState createState() => __TeamViewListState();
}

class __TeamViewListState extends State<_TeamViewList> {
  DateTime now = DateTime.now();
  DateTime? _monthAndYear;
  DateTime? firstWeekDay;
  TeamViewTabViewModel _viewModel = TeamViewTabViewModel();
  LinkedScrollControllerGroup _mainScrollControllers =
      LinkedScrollControllerGroup();
  ScrollController _datesController = ScrollController();
  ScrollController _iconsController = ScrollController();

  int? _numberOfDays, selectedIndexList;
  final List<int> _date = [];
  final List<String> _weeks = [];
  void _goToElement(double today) {
    double jumpTo = _datesController.position.maxScrollExtent / _numberOfDays!;
    _datesController.animateTo(jumpTo * (today + 3),
        duration: const Duration(seconds: 1), curve: Curves.easeIn);
  }

  double today = 0.0;
  @override
  void initState() {
    super.initState();
    _mainScrollControllers = LinkedScrollControllerGroup();
    _datesController = _mainScrollControllers.addAndGet();
    _iconsController = _mainScrollControllers.addAndGet();
    _monthAndYear = now;
    today = now.day.toDouble();
    _numberOfDays =
        DateUtils.getDaysInMonth(_monthAndYear!.year, _monthAndYear!.month);

    for (var i = 1; i <= _numberOfDays!; i++) {
      _date.add(i);
      firstWeekDay = DateTime(_monthAndYear!.year, _monthAndYear!.month, i);
      String week = DateFormat("EEE").format(firstWeekDay!);
      _weeks.add(week.substring(0, 1));
    }
  }

  @override
  void dispose() {
    _datesController.dispose();
    _iconsController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    double deviceWidth = MediaQuery.of(context).size.width;
    return Column(
      children: [
        Container(
          padding: const EdgeInsets.symmetric(horizontal: 10),
          color: containerBackgroundColorWhite,
          height: 120,
          width: deviceWidth,
          child: Column(
            children: [
              Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: [
                  Row(
                    mainAxisAlignment: MainAxisAlignment.start,
                    children: [
                      IconButton(
                        icon: const Icon(
                          NeOfficeIcons.chevron_left,
                          size: 12,
                          color: greyPrimaryTextColor,
                        ),
                        onPressed: () async {
                          await _onChangeOfMonth(false);
                        },
                      ),
                      Text(
                        DateFormat("MMMM yyyy").format(_monthAndYear!),
                        style: const TextStyle(
                            fontSize: 16,
                            fontWeight: FontWeight.w600,
                            color: titleTextColor),
                      ),
                      IconButton(
                        icon: const Icon(
                          NeOfficeIcons.chevron_right,
                          size: 12,
                          color: greyPrimaryTextColor,
                        ),
                        onPressed: () async {
                          await _onChangeOfMonth(true);
                        },
                      ),
                    ],
                  ),
                  IconButton(
                      onPressed: () {
                        _showLegend();
                      },
                      icon: Icon(Icons.info_outline_rounded,
                          color: infoIconColor, size: 21))
                ],
              ),
              Padding(
                padding: const EdgeInsets.only(left: 10.0),
                child: Row(
                  children: [
                    SizedBox(
                      width: 55,
                      child: Center(
                        child: Text(
                          DateFormat("MMM").format(_monthAndYear!),
                          style: const TextStyle(
                              fontSize: 16,
                              fontWeight: FontWeight.w600,
                              color: titleTextColor),
                        ),
                      ),
                    ),
                    Expanded(
                      child: SizedBox(
                        height: 60,
                        child: ListView.builder(
                            controller: _datesController,
                            scrollDirection: Axis.horizontal,
                            itemCount: _numberOfDays,
                            itemBuilder: (BuildContext context, int index) {
                              return GestureDetector(
                                onTap: () {
                                  setState(() {
                                    selectedIndexList = index;
                                  });
                                },
                                child: Container(
                                  width: 48,
                                  child: Column(
                                    mainAxisAlignment: MainAxisAlignment.center,
                                    children: [
                                      Text(_weeks[index],
                                          style: TextStyle(
                                              color: selectedIndexList !=
                                                          null &&
                                                      selectedIndexList == index
                                                  ? findMyFriendColor
                                                  : titleTextColor,
                                              fontSize: 12,
                                              fontWeight: FontWeight.bold)),
                                      const SizedBox(height: 10),
                                      Text('${_date[index]}',
                                          style: TextStyle(
                                              color: selectedIndexList !=
                                                          null &&
                                                      selectedIndexList == index
                                                  ? findMyFriendColor
                                                  : titleTextColor,
                                              fontSize: 12,
                                              fontWeight: FontWeight.bold)),
                                    ],
                                  ),
                                ),
                              );
                            }),
                      ),
                    )
                  ],
                ),
              ),
            ],
          ),
        ),
        TeamViewListWidget(
          numberOfDays: _numberOfDays!,
          selectedIndexList: selectedIndexList,
          iconsController: _iconsController,
          viewModel: _viewModel,
          jumpToCurrentDate: () {
            _goToElement(today);
          },
        )
      ],
    );
  }

  Future _onChangeOfMonth(bool direction) async {
    if (direction) {
      setState(() {
        _monthAndYear = DateTime(
            _monthAndYear!.year, _monthAndYear!.month + 1, _monthAndYear!.day);
        _viewModel.getRequiredDataOnChangeOfMonth(
            _monthAndYear!.month, _monthAndYear!.year, _monthAndYear!);
        _numberOfDays =
            DateUtils.getDaysInMonth(_monthAndYear!.year, _monthAndYear!.month);
        _weeks.clear();
        _date.clear();
        if (_monthAndYear!.month == now.month) {
          today = now.day.toDouble();
        } else {
          today = 0;
        }
        for (var i = 1; i <= _numberOfDays!; i++) {
          _date.add(i);
          firstWeekDay = DateTime(_monthAndYear!.year, _monthAndYear!.month, i);
          String week = DateFormat("EEE").format(firstWeekDay!);
          _weeks.add(week.substring(0, 1));
        }
      });
    } else {
      setState(() {
        _monthAndYear = DateTime(
            _monthAndYear!.year, _monthAndYear!.month - 1, _monthAndYear!.day);
        _viewModel.getRequiredDataOnChangeOfMonth(
            _monthAndYear!.month, _monthAndYear!.year, _monthAndYear!);
        _numberOfDays =
            DateUtils.getDaysInMonth(_monthAndYear!.year, _monthAndYear!.month);
        _weeks.clear();
        _date.clear();
        if (_monthAndYear!.month == now.month) {
          today = now.day.toDouble();
        } else {
          today = 0;
        }
        for (var i = 1; i <= _numberOfDays!; i++) {
          _date.add(i);
          firstWeekDay = DateTime(_monthAndYear!.year, _monthAndYear!.month, i);
          String week = DateFormat("EEE").format(firstWeekDay!);
          _weeks.add(week.substring(0, 1));
        }
      });
    }
  }

 
  }
}

// ignore: must_be_immutable
class TeamViewListWidget extends StatefulWidget {
  final int? numberOfDays;
  int? selectedIndexList;
  TeamViewTabViewModel? viewModel = TeamViewTabViewModel();
  ScrollController? iconsController = ScrollController();

  Function? jumpToCurrentDate;

  TeamViewListWidget({
    Key? key,
    this.numberOfDays,
    this.selectedIndexList,
    this.viewModel,
    this.iconsController,
    this.jumpToCurrentDate,
  }) : super(key: key);

  @override
  State<TeamViewListWidget> createState() => _TeamViewListWidgetState();
}

class _TeamViewListWidgetState extends State<TeamViewListWidget> {
  @override
  Widget build(BuildContext context) {
    double deviceWidth = MediaQuery.of(context).size.width;
    return ViewModelBuilder<TeamViewTabViewModel>.reactive(
      onModelReady: (_viewModel) {
        _viewModel.getRequiredDataOnModelReady();
      },
      builder: (context, model, child) {
        if (widget.viewModel!.isBusy) {
          return Expanded(
            child: Center(
              child: CircularProgressIndicator(
                color: primaryColor,
              ),
            ),
          );
        }
        if (!widget.viewModel!.isBusy) {
          widget.jumpToCurrentDate!.call();
        }

        return widget.viewModel!.isTeamDetailsAvailable
            ? Expanded(
                child: SizedBox(
                  width: deviceWidth,
                  child: ListView.builder(
                      controller: ScrollController(),
                      itemCount: widget.viewModel!.teamDetailsModel.length,
                      itemBuilder: (BuildContext context, int indexOfRow) {
                        return Container(
                          margin: const EdgeInsets.symmetric(vertical: 1),
                          height: 80,
                          color: indexOfRow % 2 == 0
                              ? null
                              : containerBackgroundColorWhite,
                          child: Padding(
                            padding:
                                const EdgeInsets.only(left: 15.0, right: 10),
                            child: Row(
                              children: [
                                Padding(
                                  padding: const EdgeInsets.only(right: 8.0),
                                  child: SizedBox(
                                    width: 55,
                                    child: Column(
                                      mainAxisAlignment:
                                          MainAxisAlignment.center,
                                      children: [
                                        widget
                                                    .viewModel!
                                                    .teamDetailsModel[
                                                        indexOfRow]
                                                    .profilePicUrl !=
                                                'NA'
                                            ? ClipRRect(
                                                child: Image.network(
                                                  widget
                                                      .viewModel!
                                                      .teamDetailsModel[
                                                          indexOfRow]
                                                      .profilePicUrl!,
                                                  loadingBuilder:
                                                      (context, widget, chunk) {
                                                    if (chunk == null)
                                                      return widget;

                                                    return Center(
                                                      child:
                                                          CircularProgressIndicator(
                                                        color: primaryColor,
                                                      ),
                                                    );
                                                  },
                                                  errorBuilder: (context, obj,
                                                      stackTrace) {
                                                    return UserProfileIconWidget(
                                                      widget
                                                          .viewModel!
                                                          .teamDetailsModel[
                                                              indexOfRow]
                                                          .userName!
                                                          .substring(0, 2)
                                                          .toUpperCase(),
                                                      onTap: () async {},
                                                    );
                                                  },
                                                  height: 35,
                                                  width: 35,
                                                ),
                                                borderRadius:
                                                    BorderRadius.circular(60),
                                              )
                                            : UserProfileIconWidget(
                                                widget
                                                    .viewModel!
                                                    .teamDetailsModel[
                                                        indexOfRow]
                                                    .userName!
                                                    .substring(0, 2)
                                                    .toUpperCase(),
                                                onTap: () async {},
                                              ),
                                        Text(
                                          widget
                                                      .viewModel!
                                                      .teamDetailsModel[
                                                          indexOfRow]
                                                      .userName!
                                                      .length <
                                                  7
                                              ? widget
                                                  .viewModel!
                                                  .teamDetailsModel[indexOfRow]
                                                  .userName!
                                              : widget
                                                  .viewModel!
                                                  .teamDetailsModel[indexOfRow]
                                                  .userName!
                                                  .substring(0, 7),
                                          overflow: TextOverflow.ellipsis,
                                          style: const TextStyle(
                                              fontSize: 12,
                                              fontWeight: FontWeight.bold),
                                        ),
                                      ],
                                    ),
                                  ),
                                ),
                                Expanded(
                                  child: SizedBox(
                                    height: 60,
                                    child: ListView.builder(
                                      scrollDirection: Axis.horizontal,
                                      // physics: NeverScrollableScrollPhysics(),
                                      controller: widget.iconsController,
                                      itemCount: widget.numberOfDays,
                                      itemBuilder: (BuildContext context,
                                          int indexOfIcon) {
                                        return GestureDetector(
                                          onTap: () {
                                            setState(() {
                                              widget.selectedIndexList =
                                                  indexOfIcon;
                                            });
                                          },
                                          child: Container(
                                            width: 48,
                                            child: Icon(
                                                widget.viewModel!
                                                                .monthlyDetailsOfTeam[
                                                            indexOfRow] !=
                                                        null
                                                    ? widget.viewModel!.monthlyDetailsOfTeam[
                                                                    indexOfRow]![
                                                                indexOfIcon] !=
                                                            null
                                                        ? _iconHelper(widget
                                                            .viewModel!
                                                            .monthlyDetailsOfTeam[
                                                                indexOfRow]![
                                                                indexOfIcon]!
                                                            .workMode)
                                                        : Icons.no_data
                                                    : Icons.no_data,
                                                size: 26,
                                                color: widget.selectedIndexList !=
                                                            null &&
                                                        widget.selectedIndexList ==
                                                            indexOfIcon
                                                    ? titleTextColor
                                                    : disabledIconColor),
                                          ),
                                        );
                                      },
                                    ),
                                  ),
                                ),
                              ],
                            ),
                          ),
                        );
                      }),
                ),
              )
            : Expanded(
                child: Center(
                  child: SizedBox(),
                ),
              );
      },
      viewModelBuilder: () => widget.viewModel!,
    );
  }


}
1

There are 1 answers

1
AKASH On

I cannot understand your question clearly But you are using singlechildscrollview .Instead of it you can try interactive viewer