skip to Main Content

I am trying to create the vertical list of items (Containers) of different height which could be scrolled to the fixed position with ScrollablePositionedList.builder. To manage my list of items, I want to use buttons located in horizontal (also scrollable) menu, one button (for instance, "About object") for one specific widget (for instance, _aboutObject). Now my code looks like that:

...
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
...

class _SaleOfficeState extends State<SaleOffice> {
  final itemController = ItemScrollController(); // for body
  final List<String> menuItems = ["Location", "About object"];

  Future scrollToItem(int index) async {
    itemController.scrollTo(
      index: index,
      alignment: 0,
      duration: Duration(seconds: 1),
    );
  }

  Widget _location() {Container(...)}

  Widget _aboutObject() {Container(...)}

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        // AppBar definition
      ),
      body: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Container(
            // Top menu container
            height: 50,
            child: ListView.builder(
              scrollDirection: Axis.horizontal,
              itemCount: menuItems.length,
              itemBuilder: (BuildContext context, int index) {
                return Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: TextButton(
                    onPressed: () {
                      print("top menu button is pressed");
                      scrollToItem(index); 
                    },
                    child: Text(
                      menuItems[index],
                    ),
                  ),
                );
              },
            ),
          ),
          Expanded(
            child: ScrollablePositionedList.builder(
              itemCount: menuItem.length, 
              itemScrollController: itemController,
              itemBuilder: (BuildContext context, int index) {
                  if (index == 0) {
                    return _location();
                  } else if (index == 1) {
                    return _aboutObject();
                  }
                  return Container();
                },
            ),
          ),
        ],
      ),
    );
  }
} 

It scrolls correctly when I press the relevant button with needed duration, but immediately goes back to the starting position. I want it to be pinned on the upper position, until another button is presses.

Another strange behavior is: if I use non-existent index, for instance, 2:

   await Scrollable.ensureVisible(context);
   itemController.scrollTo(
       index: 2,
       alignment: 0,
       duration: Duration(seconds: 1),
   );
 }

the code reacts and do the same as with index: index. It seems I do not understand how this scrollable_positioned_list works. Any advices are highly appreciated.

2

Answers


  1. Chosen as BEST ANSWER

    The task turned out to be more difficult than I thought. The fact is that my widgets, which should be scrolled in a vertical sheet, are of different heights. Therefore, I had to calculate their height dynamically:

        // Calculate the height of the container dynamically based on its content
        double _calculateContainerHeight(BuildContext context,
            Widget Function() widget) {
        final RenderBox? renderBox = context.findRenderObject() as RenderBox?;
        return renderBox?.paintBounds.size.height ?? 0.0;
        }
    

    and then take this into account when adjusting the scrolling:

        Expanded(
            child: ScrollablePositionedList.builder(
                itemCount: menuItems.length,
                itemScrollController: itemController,
                itemPositionsListener: itemListener,
                itemBuilder: (BuildContext context, int index) {
                    switch (index) {
                        case 0:
                          return _location();
                        case 1:
                          return !_isFirstBuild ? _aboutObject() : SizedBox();
                        default:
                          return Container();
                      }
                  },
                ),
              ),
    ```, with declaring a new variable `bool _isFirstBuild = true;`. If somebody knows more elegant solution, please let me know. Also, something tells me this isn't the end yet as I want to increase the number of scrollable widgets. Perhaps something else will come out along the way.
    

  2. You can get index of selected item and then remove that item from your list and insert that removed item into your list(now it appears as the first element in your list).

    for example, selected item index is 5

    myList.removeAt(5)  // 5 is your selected item index
    

    then

    myList.insert(0, element)  // element is type of your list(if your list type 
       //is string then element type will be string like "A" if it is a model 
       //class, then it will be model class)
    

    Happy Coding 🙂

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search