[flutter] ExpansionPanelList의 패널 확장/축소 상태 저장 방법

ExpansionPanelList는 UI에서 패널이 확장되거나 축소되는 기능을 제공하는 Flutter 위젯입니다. 하지만, 앱을 재시작하거나 화면을 이동할 때마다 패널의 상태는 초기화됩니다. 패널의 확장/축소 상태를 영구적으로 저장하고 복원하는 방법에 대해 알아보겠습니다.

상태 관리

패널의 확장/축소 상태를 영구적으로 저장하기 위해서는 상태 관리가 필요합니다. Flutter 앱에서 상태 관리를 위하여 provider 패키지를 사용하는 것을 추천합니다. provider를 사용하여 패널의 상태를 관리하고, 여러 화면에서 공유할 수 있도록 해줍니다.

provider 패키지를 사용하기 위해서는 provider 패키지를 추가해야 합니다. pubspec.yaml 파일에 다음과 같이 provider를 추가해주세요.

dependencies:
  flutter:
    sdk: flutter
  provider: ^4.3.2+2

그리고 패널의 확장/축소 상태를 저장하기 위한 ExpansionPanelItem 클래스를 정의합니다.

class ExpansionPanelItem {
  final String headerText;
  final Widget body;
  bool isExpanded;

  ExpansionPanelItem({this.headerText, this.body, this.isExpanded = false});
}

ExpansionPanelList 구현

ExpansionPanelList를 구현하기 위해 다음과 같은 코드를 작성합니다.

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

class MyExpansionPanelList extends StatefulWidget {
  @override
  _MyExpansionPanelListState createState() => _MyExpansionPanelListState();
}

class _MyExpansionPanelListState extends State<MyExpansionPanelList> {
  List<ExpansionPanelItem> _data = []; // 패널의 데이터를 저장할 리스트

  @override
  void initState() {
    super.initState();
    // 패널 데이터 초기화
    _data = [
      ExpansionPanelItem(headerText: '패널1', body: _createPanelBody(1)),
      ExpansionPanelItem(headerText: '패널2', body: _createPanelBody(2)),
      ExpansionPanelItem(headerText: '패널3', body: _createPanelBody(3)),
    ];
  }

  Widget _createPanelBody(int index) {
    return ListTile(
      title: Text('패널 $index'),
    );
  }

  @override
  Widget build(BuildContext context) {
    // 확장/축소 상태를 위한 Provider 설정
    return ChangeNotifierProvider(
      create: (context) => PanelState(),
      child: Consumer<PanelState>(
        builder: (context, panelState, _) {
          return ExpansionPanelList(
            elevation: 1,
            expandedHeaderPadding: EdgeInsets.all(0),
            expansionCallback: (index, isExpanded) {
              setState(() {
                _data[index].isExpanded = !isExpanded;
              });
              panelState.updatePanelState(_data); // 패널 상태 업데이트
            },
            children: _data.map<ExpansionPanel>((ExpansionPanelItem item) {
              return ExpansionPanel(
                headerBuilder: (BuildContext context, bool isExpanded) {
                  return ListTile(
                    title: Text(item.headerText),
                  );
                },
                body: item.body,
                isExpanded: item.isExpanded,
              );
            }).toList(),
          );
        },
      ),
    );
  }
}

class PanelState with ChangeNotifier {
  List<ExpansionPanelItem> _panelState; // 패널의 확장/축소 상태를 저장할 변수

  void updatePanelState(List<ExpansionPanelItem> panelState) {
    _panelState = panelState;
    notifyListeners(); // 상태 변경 알림
  }

  List<ExpansionPanelItem> get panelState => _panelState;
}

데이터 저장 및 복원

패널의 확장/축소 상태를 영구적으로 저장하기 위해서는 앱의 데이터 저장 방법을 이용해야 합니다. 일반적으로는 shared_preferences 패키지를 사용하여 데이터를 저장하고 복원할 수 있습니다.

shared_preferences 패키지를 사용하기 위해서는 shared_preferences 패키지를 추가해야 합니다. pubspec.yaml 파일에 다음과 같이 shared_preferences를 추가해주세요.

dependencies:
  flutter:
    sdk: flutter
  provider: ^4.3.2+2
  shared_preferences: ^2.0.6

다음은 shared_preferences 패키지를 사용하여 패널 상태를 저장하고 복원하는 예시 코드입니다.

import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Expansion Panel List'),
        ),
        body: FutureBuilder(
          future: _loadPanelState(),
          builder: (context, snapshot) {
            if (snapshot.hasData) {
              return MyExpansionPanelList();
            } else {
              return CircularProgressIndicator();
            }
          },
        ),
      ),
    );
  }

  Future<void> _loadPanelState() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    List<ExpansionPanelItem> panelState = [];
    bool isExpanded = false;
    for (int i = 0; i < 3; i++) {
      isExpanded = prefs.getBool('panel_$i') ?? false;
      panelState.add(ExpansionPanelItem(
        headerText: '패널${i + 1}',
        body: _createPanelBody(i + 1),
        isExpanded: isExpanded,
      ));
    }
    Provider.of<PanelState>(context, listen: false).updatePanelState(panelState);
  }

  Widget _createPanelBody(int index) {
    return ListTile(
      title: Text('패널 $index'),
    );
  }
}

위 코드에서 _loadPanelState 함수는 앱이 시작될 때 저장된 패널 상태를 불러와서 panelState에 저장합니다. 그리고 PanelStateupdatePanelState 메소드를 호출하여 패널 상태를 업데이트합니다.

저장된 패널 상태를 복원하기 위해서는 MyExpansionPanelList 위젯을 FutureBuilder와 함께 사용합니다. _loadPanelState 함수를 호출하여 패널 상태를 불러온 뒤, MyExpansionPanelList를 렌더링합니다.

결론

이제 ExpansionPanelList의 패널의 확장/축소 상태를 저장하고 복원하는 방법을 알게 되었습니다. provider 패키지를 사용하여 상태를 관리하고, shared_preferences 패키지를 사용하여 데이터를 저장하고 복원할 수 있습니다. 이를 활용하여 사용자 경험을 향상시키는 앱을 개발해보세요.

참고: Flutter Provider 패키지