flutter

Scroll to Section

오렌지데이77 2024. 2. 3. 07:53

Scroll to Section

수평 스크롤 내 ChoiceChip 클릭 시
SizedBox 내 ListView 중 특정 section으로 포커스가 이동하며
사용자에게도 애니메이션 효과를 함께 제공합니다.

import 'package:flutter/material.dart';

void main() {
  runApp(const MaterialApp(
    home: ScrollToSection(),
  ));
}

class ScrollToSection extends StatefulWidget {
  const ScrollToSection({super.key});

  @override
  State<ScrollToSection> createState() => _ScrollToSectionState();
}

class _ScrollToSectionState extends State<ScrollToSection> {
  List<String> sections = [
    'item 1',
    'item 2',
    'item 3',
    'item 4',
    'item 5',
  ];

  final List<GlobalKey> keys = [
    GlobalKey(),
    GlobalKey(),
    GlobalKey(),
    GlobalKey(),
    GlobalKey(),
  ];

  int _selectedIndex = 0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Scroll to Section'),
      ),
      body: Column(
        children: [
          SingleChildScrollView(
            scrollDirection: Axis.horizontal,
            child: Row(
              children: List.generate(
                sections.length,
                (index) => Padding(
                  padding: const EdgeInsets.all(5.0),
                  child: ChoiceChip(
                    label: Text(sections[index]),
                    selected: _selectedIndex == index,
                    onSelected: (selected) {
                      setState(() {
                        _selectedIndex = index;
                        final targetContext = keys[index].currentContext;
                        if (targetContext != null) {
                          Scrollable.ensureVisible( // This is the point
                            targetContext,
                            duration: const Duration(milliseconds: 300),
                            curve: Curves.easeInOut,
                          );
                        }
                      });
                    },
                  ),
                ),
              ),
            ),
          ),
          SizedBox(
            height: MediaQuery.sizeOf(context).height * 0.8,
            child: ListView(
              children: [
                ...sections
                    .asMap()
                    .map(
                      (index, element) => MapEntry(
                        index,
                        Container(
                          height: 200,
                          key: keys[index], // Using index as the key
                          margin: const EdgeInsets.all(10),
                          color: Colors.deepOrangeAccent,
                          child: Center(
                            child: Text(element),
                          ),
                        ),
                      ),
                    )
                    .values
                    .toList()
              ],
            ),
          )
        ],
      ),
    );
  }
}

Dartpad에서 실행해 보기