Flutter

Flutter에서 반응형 배너 UI와 애니메이션 구현

Mr. Joo 2025. 1. 13. 13:47
728x90

Flutter를 활용하여 배너 UI를 구현하고, 배너 전환 애니메이션까지 적용한 과정을 공유합니다. 이번 작업에서는 반응형 디자인과 자연스러운 사용자 경험을 위해 애니메이션 효과를 추가하고, UI 구조를 체계적으로 구성했습니다.


구현 목표

  1. 상단 제목과 날짜 표시: 배너의 상단에 텍스트 형태로 제목과 날짜를 표시.
  2. 하단 반투명 배경과 버튼: 하단에는 반투명한 검정 배경 위에 "글자" 버튼과 숫자 수를 표시.
  3. 반응형 UI: 다양한 화면 크기를 지원하기 위해 ScreenUtil을 적용.
  4. 애니메이션 효과: 배너 전환 시 자연스러운 애니메이션 적용.
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';

class CustomSlideCard extends StatelessWidget {
  final String imagePath;
  final String title;
  final String dateRange;
  final VoidCallback onTap;
  final int visitCount;
  final int currentCount;

  const CustomSlideCard({
    super.key,
    required this.imagePath,
    required this.title,
    required this.dateRange,
    required this.onTap,
    required this.visitCount,
    required this.currentCount,
  });

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: onTap,
      child: Container(
        width: double.infinity,
        height: 200.h,
        decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(16.0.r),
          image: DecorationImage(
            image: AssetImage(imagePath),
            fit: BoxFit.cover,
            colorFilter: ColorFilter.mode(
              Colors.black.withOpacity(0.4),
              BlendMode.darken,
            ),
          ),
        ),
        child: Stack(
          children: [
            // 상단 제목 및 날짜
            Positioned(
              top: 16.h,
              left: 16.w,
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Text(
                    title,
                    style: TextStyle(
                      color: Colors.white,
                      fontSize: 18.sp,
                      fontWeight: FontWeight.bold,
                    ),
                  ),
                  SizedBox(height: 8.h),
                  Text(
                    dateRange,
                    style: TextStyle(
                      color: Colors.white70,
                      fontSize: 14.sp,
                    ),
                  ),
                ],
              ),
            ),
            // 하단 반투명 배경 및 버튼 섹션
            Positioned(
              bottom: 0,
              left: 0,
              right: 0,
              child: Container(
                padding: EdgeInsets.symmetric(vertical: 8.h, horizontal: 16.w),
                decoration: BoxDecoration(
                  color: Colors.black.withOpacity(0.6),
                  borderRadius: BorderRadius.only(
                    bottomLeft: Radius.circular(16.0.r),
                    bottomRight: Radius.circular(16.0.r),
                  ),
                ),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Row(
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: [
                        Text(
                          "글자",
                          style: TextStyle(
                            color: Colors.white,
                            fontSize: 16.sp,
                            fontWeight: FontWeight.bold,
                          ),
                        ),
                        const Icon(
                          Icons.arrow_forward_ios,
                          color: Colors.white,
                          size: 16,
                        ),
                      ],
                    ),
                    SizedBox(height: 8.h),
                    Row(
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: [
                        Row(
                          children: [
                            const Icon(Icons.people, color: Colors.white, size: 16),
                            SizedBox(width: 8.w),
                            Text(
                              "$visitCount명 방문",
                              style: TextStyle(
                                color: Colors.white,
                                fontSize: 14.sp,
                              ),
                            ),
                          ],
                        ),
                        Row(
                          children: [
                            const Icon(Icons.settings, color: Colors.white, size: 16),
                            SizedBox(width: 8.w),
                            Text(
                              "$currentCount명 숫자",
                              style: TextStyle(
                                color: Colors.white,
                                fontSize: 14.sp,
                              ),
                            ),
                          ],
                        ),
                      ],
                    ),
                  ],
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

 

2. 애니메이션 효과

애니메이션 효과를 구현하기 위해 CarouselSlider와 함께 전환 애니메이션을 추가했습니다.

import 'package:carousel_slider/carousel_slider.dart';

class CustomCarouselSlider extends StatelessWidget {
  final List<Widget> slides;
  final Duration autoPlayInterval;
  final Duration animationDuration;

  const CustomCarouselSlider({
    super.key,
    required this.slides,
    this.autoPlayInterval = const Duration(seconds: 3),
    this.animationDuration = const Duration(milliseconds: 800),
  });

  @override
  Widget build(BuildContext context) {
    return CarouselSlider(
      items: slides,
      options: CarouselOptions(
        height: 200.h,
        autoPlay: true,
        autoPlayInterval: autoPlayInterval,
        autoPlayAnimationDuration: animationDuration,
        viewportFraction: 1.0,
      ),
    );
  }
}

 

주요 구현 내용

  1. 배너 UI:
    • 상단에는 제목과 날짜를 배치.
    • 하단에는 반투명 배경과 함께 버튼 및 정보를 표시.
  2. 반응형 디자인:
    • ScreenUtil을 사용하여 다양한 화면 크기를 지원.
  3. 배너 전환 애니메이션:
    • autoPlayInterval과 autoPlayAnimationDuration을 설정하여 부드러운 전환 효과 구현.
  4. 확장성:
    • 클릭 이벤트와 데이터(방문자 수, 숫자 등)를 동적으로 설정할 수 있도록 구성.
728x90
LIST