skip to Main Content

I have a Row with a list view and an Indicator view. I would like to animate the indicator view with respect to the selected item in the list.

If I select an item in the list view, the Indicator view should move to the respective position as in the given Image.enter image description here

Please suggest something to make this UI.

sample code is given below.

@override
  Widget build(BuildContext context) {
    return Row(
      children: [
        ListView.builder(
          shrinkWrap: true,
          itemCount: 6,
          itemBuilder: (context, index) => Padding(
            padding: const EdgeInsets.all(13),
            child: Text('Item$index'),
          ),
        ),
        Stack(
          children: [
            SvgPicture.asset(
              'assets/images/scale_img.svg',
            ),
            Positioned(
              right: 26,
              top: 310,
              child:Container(
                width: 40,
                height: 4,
                decoration: BoxDecoration(
                    borderRadius: BorderRadius.circular(5),
                    gradient: const LinearGradient(
                        begin: Alignment.topCenter,
                        end: Alignment.bottomCenter,
                        colors: [
                          Color(0xffFF7EB4),
                          Color(0xffAA16CF),
                        ]),
                    boxShadow: const [
                      BoxShadow(
                        blurRadius: 10,
                        spreadRadius: -1,
                        offset: Offset(0, 4),
                        color:   Color(0xffAA16CF),
                      )
                    ]),
              ),
            )
          ],
        )
      ],
    );
  }

2

Answers


  1. Chosen as BEST ANSWER

    We can find the position of the selected item using the RenderBox. using this position we can move the indicator to the respective position.

    Sample code is as follows.

    import 'package:flutter/material.dart';
    
    void main() {
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: Scaffold(
            appBar: AppBar(
              title: Text('Indicator Animation Example'),
            ),
            body: IndicatorListView(),
          ),
        );
      }
    }
    
    class IndicatorListView extends StatefulWidget {
      @override
      State<IndicatorListView> createState() => _IndicatorListViewState();
    }
    
    class _IndicatorListViewState extends State<IndicatorListView> {
      int selectedIndex = -1;
      int itemCount = 10;
      List<GlobalKey> _keys = [];
      Offset? _selectedOffset;
       
      @override
      void initState() {
        _keys = List<GlobalKey>.generate(itemCount, (index) => GlobalKey());
        
        super.initState();
      }
      
    
    
      @override
      Widget build(BuildContext context) {
        return Stack(
          children: [
            ListView.builder(
              itemCount: itemCount,
              itemBuilder: (context, index) {
                return ListTile(
                  key: _keys[index],
                  title: Text('Item $index'),
                  selected: index == selectedIndex,
                  onTap: () {
                    var renderBox = _keys[index].currentContext?.findRenderObject() as RenderBox;
                    _selectedOffset = renderBox.localToGlobal(Offset.zero);
                    setState(() {
                      selectedIndex = index;
                    });
                  },
                );
              },
            ),
            AnimatedPositioned(
              top: (_selectedOffset?.dy??0) - 35,
              right: 0,
              duration: const Duration(milliseconds: 300),
              child: Container(
                height: 5,
                width: 29,
                color: Colors.red,
              ),
            ),
          ],
        );
      }
    }
    

  2. import 'package:flutter/material.dart';
    
    void main() {
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: Scaffold(
            appBar: AppBar(
              title: Text('Indicator Animation Example'),
            ),
            body: IndicatorListView(),
          ),
        );
      }
    }
    
    class IndicatorListView extends StatefulWidget {
      @override
      State<IndicatorListView> createState() => _IndicatorListViewState();
    }
    
    class _IndicatorListViewState extends State<IndicatorListView> {
      int selectedIndex = -1;
      int itemCount = 50;
    
      @override
      Widget build(BuildContext context) {
        return Stack(
          children: [
            ListView.builder(
              itemCount: itemCount,
              itemBuilder: (context, index) {
                return ListTile(
                  title: Text('Item $index'),
                  selected: index == selectedIndex,
                  onTap: () {
                    setState(() {
                      selectedIndex = index;
                    });
                  },
                );
              },
            ),
            AnimatedPositioned(
              top: selectedIndex * (MediaQuery.of(context).size.height / itemCount),
              right: 0,
              duration: const Duration(milliseconds: 300),
              child: Container(
                height: MediaQuery.of(context).size.height / itemCount,
                width: 16,
                color: Colors.red,
              ),
            ),
          ],
        );
      }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search