공부/Flutter

Sliver와 애니메이션을 심화적으로 활용하는 고급 사례

micalcomanie 2025. 1. 1. 17:10
728x90
반응형
SMALL

Flutter의 Sliver와 애니메이션 기능을 결합하여 스크롤 가능한 고급 UI를 구현할 수 있습니다.
이 글에서는 고급 사례를 통해 Sliver와 애니메이션을 활용하는 방법을 소개합니다.


1. Sliver와 애니메이션 결합의 장점

  1. 향상된 사용자 경험: 스크롤에 따라 콘텐츠를 동적으로 변경하여 몰입감을 제공.
  2. 효율적인 성능: Sliver는 스크롤 영역의 요소를 동적으로 렌더링하므로 메모리 사용량이 줄어듦.
  3. 다양한 사용자 인터페이스: 애니메이션과 Sliver를 활용하면 독창적이고 세련된 UI를 제작 가능.

2. 고급 사례 1: Parallax 효과 구현

SliverAppBar와 스크롤 애니메이션을 활용하여 Parallax 효과를 구현합니다.

import 'package:flutter/material.dart';

class ParallaxSliverAppBar extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: CustomScrollView(
        slivers: [
          SliverAppBar(
            expandedHeight: 300.0,
            flexibleSpace: FlexibleSpaceBar(
              background: Stack(
                fit: StackFit.expand,
                children: [
                  Image.network(
                    'https://example.com/parallax-image.jpg',
                    fit: BoxFit.cover,
                  ),
                  Positioned(
                    bottom: 10.0,
                    left: 10.0,
                    child: Text(
                      'Parallax Effect',
                      style: TextStyle(
                        color: Colors.white,
                        fontSize: 24.0,
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                  ),
                ],
              ),
            ),
          ),
          SliverList(
            delegate: SliverChildBuilderDelegate(
              (context, index) => ListTile(
                title: Text('Item #$index'),
              ),
              childCount: 50,
            ),
          ),
        ],
      ),
    );
  }
}

3. 고급 사례 2: 스크롤 애니메이션 기반의 동적 배경

스크롤 위치에 따라 배경 색상이 변경되는 애니메이션 효과를 추가합니다.

import 'package:flutter/material.dart';

class DynamicBackgroundSliver extends StatefulWidget {
  @override
  _DynamicBackgroundSliverState createState() => _DynamicBackgroundSliverState();
}

class _DynamicBackgroundSliverState extends State<DynamicBackgroundSliver> {
  late ScrollController _scrollController;
  Color _backgroundColor = Colors.blue;

  @override
  void initState() {
    super.initState();
    _scrollController = ScrollController();
    _scrollController.addListener(_changeBackground);
  }

  void _changeBackground() {
    final offset = _scrollController.offset;
    setState(() {
      _backgroundColor = offset > 100 ? Colors.green : Colors.blue;
    });
  }

  @override
  void dispose() {
    _scrollController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: AnimatedContainer(
        duration: Duration(milliseconds: 300),
        color: _backgroundColor,
        child: CustomScrollView(
          controller: _scrollController,
          slivers: [
            SliverAppBar(
              expandedHeight: 200.0,
              flexibleSpace: FlexibleSpaceBar(
                title: Text('Dynamic Background'),
              ),
            ),
            SliverList(
              delegate: SliverChildBuilderDelegate(
                (context, index) => ListTile(
                  title: Text('Item #$index'),
                ),
                childCount: 30,
              ),
            ),
          ],
        ),
      ),
    );
  }
}

4. 고급 사례 3: SliverPersistentHeader로 섹션 헤더 고정

SliverPersistentHeader를 사용하여 스크롤 시 특정 섹션 헤더를 고정합니다.

import 'package:flutter/material.dart';

class StickyHeaderExample extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: CustomScrollView(
        slivers: [
          SliverPersistentHeader(
            pinned: true,
            delegate: _StickyHeaderDelegate(
              child: Container(
                color: Colors.red,
                child: Center(
                  child: Text(
                    'Sticky Header',
                    style: TextStyle(color: Colors.white, fontSize: 20.0),
                  ),
                ),
              ),
              minHeight: 50.0,
              maxHeight: 100.0,
            ),
          ),
          SliverList(
            delegate: SliverChildBuilderDelegate(
                  (context, index) => ListTile(
                title: Text('Item #$index'),
              ),
              childCount: 20,
            ),
          ),
        ],
      ),
    );
  }
}

class _StickyHeaderDelegate extends SliverPersistentHeaderDelegate {
  final Widget child;
  final double minHeight;
  final double maxHeight;

  _StickyHeaderDelegate({
    required this.child,
    required this.minHeight,
    required this.maxHeight,
  });

  @override
  double get minExtent => minHeight;

  @override
  double get maxExtent => maxHeight;

  @override
  Widget build(
      BuildContext context, double shrinkOffset, bool overlapsContent) {
    return Container(
      color: Colors.red.withOpacity(1 - shrinkOffset / maxExtent),
      child: child,
    );
  }

  @override
  bool shouldRebuild(covariant _StickyHeaderDelegate oldDelegate) {
    return oldDelegate.minHeight != minHeight ||
        oldDelegate.maxHeight != maxHeight ||
        oldDelegate.child != child;
  }
}

void main() => runApp(MaterialApp(home: StickyHeaderExample()));

5. 결론

Sliver와 애니메이션을 결합하면 스크롤 가능한 UI를 더욱 다이나믹하고 매력적으로 만들 수 있습니다. 위의 고급 사례를 통해 독창적인 애플리케이션을 개발해보세요. 다음 글에서는 Sliver를 활용한 비대칭 레이아웃과 더 복잡한 데이터 렌더링 기법을 다룰 예정입니다.


참고 자료

728x90
반응형
LIST