본문 바로가기
프로그래밍/Flutter & Dart

Flutter 이벤트, 애니메이션 위젯 정리

by 어느덧중반 2021. 8. 23.
반응형

 

요약 : GestureDetector, InkWell, Hero, AnimatedContainer, SliverAppBar/SliverFillRemaining/SliverList


GestureDetector, InkWell

- 텍스트나 이미지 등 이벤트효과 없는 위젯을 감싸서 onTap 등의 이벤트를 줄 수 있다.

 

Hero

- 화면 전환시 자연스럽게 연결되게 하는 애니메이션 위젯 (이미지 클릭하면 상세화면 보여줄 때 사용)

- 두 페이지를 Hero위젯으로 연결

- tag를 동일하게 사용해서 연결시켜줌

class _MyHomePageState extends State<MyHomePage> {

  var _selectedTime;

  @override
  Widget build(BuildContext context) {

    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: GestureDetector( // 해당 위젯을 이용해
          onTap: () {           // 탭하면
            Navigator.push(     // DetailPage로 화면 전환시켜줌
              context,
              MaterialPageRoute(builder: (context) => DetailPage()),
            );
          },
          child: Hero(
            tag: 'imageTag',
            child: Image.asset(
              'assets/sample.png',
              width: 200,
              height: 200
            )
          )
        )
      ),
    );
  }
}

class DetailPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar : AppBar(
        title: Text('Detail Page'),
      ),
      body: Hero(
        tag: 'imageTag',
        child: Image.asset('assets/sample.png'),
      ),
    );
  }
}

AnimatedContainer

Hero위젯은 화면 전환이었다면 AnimatedContainer위젯은 한 화면 내에서 setState함수를 이용해 애니메이션 효과를 주는 위젯

- duration : 애니메이션 되는 시간 Duration(시간)

- curve : 애니메이션 효과 Curves.xxx(각종효과)

class _MyHomePageState extends State<MyHomePage> {

  var _size = 200.0;

  @override
  Widget build(BuildContext context) {
    
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: GestureDetector(
          child: AnimatedContainer(
            duration: Duration(seconds: 1), // 애니메이션 효과 1초
            curve: Curves.fastOutSlowIn, // 애니메이션 효과
            child: Image.asset(
              'assets/sample.png',
              width: _size,
              height: _size
            )
          ),
          onTap: () { // 클릭시 이벤트 발생
            final random = Random();
            setState(() { // _size 상태 변경
              _size = random.nextInt(500).toDouble() + 200; // 200.0 ~ 700.0
            });
          },
        )
      ),
    );
  }
}

클릭할 때마다 사진의 크기가 자연스럽게 변경됨

SliverAppBar/SliverFillRemaining

화면 헤더부분을 움직이게 하는 위젯

헤더를 제일 위로 올리면 AppBar 형태로 애니메이션됨 (Sliver 효과)

- Sliver 애니메이션을 사용하려면 Scaffold의 appBar를 지정하지 않고 body에 CustomScrollView를 지정해준다

   그 후에 CustomScrollView 안에 SliverAppBar와 SliverFillRemaining을 지정해주면 된다.

- pinned(상단헤더 고정여부), expandedHeight(헤더 최대 높이), flexibleSpace(상단 늘어났을 때 UI) 값들은 필수값이다.

    return Scaffold(
      body: CustomScrollView(
        slivers: <Widget>[
          SliverAppBar( // 헤더 영역
            pinned: true, // 축소시 상단에 AppBar가 고정되는지 여부
            expandedHeight: 200.0, // 늘어나는 최대 높이
            flexibleSpace: FlexibleSpaceBar( // 늘어나는 영역부분
              title: Text(
                'Sliver App Bar',
                style: TextStyle(
                  fontSize: 30,
                  color: Colors.pinkAccent,
                  fontStyle: FontStyle.italic
                ),
              ),
              background: Image.asset(
                'assets/spring-5093894__480.jpg',
                fit: BoxFit.cover
              ),
            ),
          ),
          SliverFillRemaining( // 스크롤 영역에 표시될 화면
            child: Center(
              child: Text('contents~~~',
                style: TextStyle(
                  fontSize: 40
                ),
              ),
            ),
          ),
        ],
      ),
    );

헤더를 상단으로 올리면 AppBar처럼 줄어듦 (pinned 값을 false로 하면 고정되지 않는다)

SliverAppBar/SliverList

위의 SliverFillRemaining은 고정된 화면이지만 SliverList를 사용하면 하단부 화면을 List 형태로 사용이 가능하다.

- delegate 프로퍼티가 필수이며 SliverChildListDelegate를 지정해야 함 (ListTile 목록)

class _MyHomePageState extends State<MyHomePage> {

  final _list = List.generate(100, (i) => ListTile(title: Text('#$i')));

  @override
  Widget build(BuildContext context) {
    
    return Scaffold(
      body: CustomScrollView(
        slivers: <Widget>[
          SliverAppBar( // 헤더 영역
            pinned: true, // 축소시 상단에 AppBar가 고정되는지 여부
            expandedHeight: 200.0, // 늘어나는 최대 높이
            flexibleSpace: FlexibleSpaceBar( // 늘어나는 영역부분
              title: Text(
                'Sliver App Bar',
                style: TextStyle(
                  fontSize: 30,
                  color: Colors.pinkAccent,
                  fontStyle: FontStyle.italic
                ),
              ),
              background: Image.asset(
                'assets/spring-5093894__480.jpg',
                fit: BoxFit.cover
              ),
            ),
          ),
          SliverList( // 스크롤 영역에 표시될 화면
            delegate: SliverChildListDelegate(_list),
          ),
        ],
      ),
    );
  }
}

반응형

댓글