목차

  1. 사용된 기능 설명
  2. 사용 예시

 

 

 

✅ 사용된 기능 설명

  • Stack() : 위젯들을 겹쳐서 쌓아 올리는 레이아웃 (= 중첩)
  • CarouselSlider() : 화면에 슬라이드를 보여주고, 자동 재생·페이징·애니메이션 등을 설정
    • carouselController : 슬라이더를 코드(버튼, 제스처 등)로 제어할 때 쓰는 컨트롤러를 전달 (컨트롤러로 특정 페이지로 이동, 현재 페이지 조회 등이 가능)
    • items : 슬라이드로 보여줄 위젯들의 리스트. (주로, imageList.map(...).toList() 형태로 생성)
    • options : 동작/모양을 설정하는 옵션 모음
  • NetworkImage() : 웹(HTTP/HTTPS)에서 이미지를 가져와 표시
  • AssetImage() : 앱 빌드에 포함한 로컬 에셋(프로젝트 assets/ 폴더)의 이미지를 사용 (pubspec.yaml에 assets를 등록 필수)
  • imageList.map((imgLink) => ...).toList() : imageList의 각 URL을 받아서 각각을 슬라이드용 Widget으로 변환하여 List<Widget>을 만드는 코드 (imgLink는 imageList 안의 개별 URL)
  • CarouselOptions() : 슬라이더의 동작을 지정하는 위젯
    • viewportFraction : 한 슬라이드가 뷰포트(화면) 너비를 차지하는 비율. (1.0이면 한 페이지 전체를 채움 (디폴트 : 0.8))
    • autoPlay : 이미지를 자동으로 넘길지 여부
    • autoPlayInterval : 자동으로 넘기는 시간
    • onPageChanged : 페이지 변경 시 콜백 
      • index : 새 페이지 인덱스
      • reason : 자동 재생/터치/프로그램적 이동 등 변경 원인
  • animateToPage() : CarouselSlider / PageController / TabController 같은 “페이지 단위로 스크롤되는 위젯”을 제어할 때 쓰이는 메서드로써, 특정 페이지(index)로 애니메이션 효과와 함께 이동시켜주는 메서드
    ** jumpToPage() : 순간이동하듯 바로 페이지를 바꿈
    ** animateToPage() : 부드럽게 스크롤 애니메이션이 적용
  • withOpacity(double opacity) : 해당 객체의 투명도 설정 (0.0(완전 투명) ~ 1.0(완전 불투명))
  • imageList.asMap() : 리스트를 Map 형태로 변환 (key = index, value = 리스트 값)
  • imageList.asMap().entries : Map의 (key, value) 쌍들을 추출
    ** 예시 1 : MapEntry(0, "img1"), MapEntry(1, "img2"), MapEntry(2, "img3"))
    ** 예시 2 :
    var fruits = ["apple", "banana", "cherry"]; 
    fruits.asMap().entries.forEach((entry) { 
         print("index: ${entry.key}, value: ${entry.value}"); 
    });

 

 

✅ 사용 예시

 

1️⃣ pubspec.yaml 설정

 

2️⃣ main.dart (import)

 

 

3️⃣ main.dart (전역 변수)

 

 

4️⃣ main.dart (body)

 

 

5️⃣ main.dart (sliderWidget)

 

 

6️⃣ main.dart (sliderIndicator)

 

 

7️⃣ 테스트

 

 

 

 

✔️ 사용된 코드

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

void main() async {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(primarySwatch: Colors.blue),
      home: const HomePage(),
    );
  }
}

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

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {

  int _current = 0; // 현재 슬라이드를 체크하는 변수
  final CarouselSliderController _controller = CarouselSliderController() ;
  List imageList = [    // 인터넷에서 받은 이미지 사용 (.jpg(확장자) 필수)
    "https://cdn.pixabay.com/photo/2024/09/07/02/34/penguins-9028827_1280.jpg",
    "https://cdn.pixabay.com/photo/2018/11/09/02/20/animal-3803640_640.jpg",
    "https://cdn.pixabay.com/photo/2020/06/04/05/44/cat-5257303_640.jpg",
    "https://cdn.pixabay.com/photo/2020/07/05/15/01/cat-5373337_640.jpg",
    "https://cdn.pixabay.com/photo/2021/04/22/06/40/duck-6198196_640.jpg",
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Crousel Slider Test"),
      ),
      body: Column(
        children: [
          SizedBox(
            height: 200,
            child: Stack( // Stack() : 위젯들을 겹쳐서 쌓아 올리는 레이아웃 (중첩)
              children: [
                sliderWidget(),
                sliderIndicator(),
              ]
            ),
          ),
          Container(
            padding: const EdgeInsets.all(20),
            child: const Text("Welcome to the Carousel Slider app"),
          ),
        ],
      ),
    );
  }

  Widget sliderWidget(){
    return CarouselSlider(              // CarouselSlider() : 화면에 슬라이드를 보여주고, 자동 재생·페이징·애니메이션 등을 설정
      carouselController: _controller,  // carouselController : 슬라이더를 코드(버튼, 제스처 등)로 제어할 때 쓰는 컨트롤러를 전달 (컨트롤러로 특정 페이지로 이동, 현재 페이지 조회 등이 가능)
      items: imageList.map((imgLink) {  // items : 슬라이드로 보여줄 위젯들의 리스트. (주로, imageList.map(...).toList() 형태로 생성)
        return Builder(
          builder: (context){
            return SizedBox(
              //width: MediaQuery.of(context).size.width,
              width: MediaQuery.of(context).size.width,
              child: Image(
                fit: BoxFit.fill,
                image: NetworkImage(  // NetworkImage() : 웹(HTTP/HTTPS)에서 이미지를 가져와 표시 / AssetImage() : 앱 빌드에 포함한 로컬 에셋(프로젝트 assets/ 폴더)의 이미지를 사용 (pubspec.yaml에 assets를 등록해야 함)
                  imgLink,
                ),
              ),
            );
          },
        );
      }).toList(),                    // imageList.map((imgLink) => ...).toList() : imageList의 각 URL을 받아서 각각을 슬라이드용 Widget으로 변환하여 List<Widget>을 만드는 코드 (imgLink는 imageList 안의 개별 URL)
      options: CarouselOptions(       // options : 동작/모양을 설정하는 옵션 모음  / CarouselOptions() : 슬라이더의 동작을 지정하는 위젯
        height: 300,
        viewportFraction: 1.0,        // viewportFraction : 한 슬라이드가 뷰포트(화면) 너비를 차지하는 비율. (1.0이면 한 페이지 전체를 채움 (디폴트 : 0.8))
        autoPlay: true,               // autoPlay : 이미지를 자동으로 넘길지 여부
        autoPlayInterval: const Duration(seconds: 4), // autoPlayInterval : 자동으로 넘기는 시간
        onPageChanged: (index, reason) {    // onPageChanged : 페이지 변경 시 콜백. index는 새 페이지 인덱스, reason은 자동 재생/터치/프로그램적 이동 등 변경 원인
          setState(() {
            _current = index;
          });
        },
      ),
    );
  }

  Widget sliderIndicator(){
    return Align(
      alignment: Alignment.bottomRight,
      // 점자 형태의 Indicator
      child: Row(
        mainAxisAlignment: MainAxisAlignment.center,
        children: imageList.asMap().entries.map((entry){
          return GestureDetector(
            onTap: () => _controller.animateToPage(entry.key),  // imageList 에 담긴 index 를 key 값으로 가져옴 / animateToPage() : 특정 페이지(index)로 애니메이션 효과와 함께 이동시켜주는 메서드.
            child: Container(
              width: 12,
              height: 12,
              margin: const EdgeInsets.symmetric(vertical: 8, horizontal: 4),
              decoration: BoxDecoration(
                shape: BoxShape.circle,
                color: Colors.white.withOpacity(_current == entry.key ? 0.9 : 0.4), // withOpacity(double opacity) : 해당 객체의 투명도 설정 (0.0(완전 투명) ~ 1.0(완전 불투명))
              ),
            ),
          );
        }).toList(),
        // imageList.asMap().entries.map((entry){ ... }).toList() 추가 설명
        // 1. imageList.asMap() : 리스트를 Map 형태로 변환 (key = index, value = 리스트 값)
        // 2. imageList.asMap().entries : Map의 (key, value) 쌍들을 추출 (ex. MapEntry(0, "img1"), MapEntry(1, "img2"), MapEntry(2, "img3"))
        // 3. entry : 유저가 임의로 명명한 map 함수의 매개변수
        // 4. 최종적으로 해당 코드는 "리스트의 인덱스(key)와 값(value)을 동시에 가져와서 위젯(또는 다른 객체) 리스트로 변환"하는 코드
      ),
      /*
      // 현재 슬라이더 / 전체 슬라이더
      child: Padding(
        padding: const EdgeInsets.all(8.0), // Indicator로 표기되는 텍스트 여백 주기
        child: Text(
          "${_current + 1} / ${imageList.length}", // 현재 슬라이드 인덱스 +1 / 전체 슬라이드
          style: const TextStyle(
            color: Colors.white,
            fontSize: 13,
            fontWeight: FontWeight.bold,
            shadows: [    // 글자에 그림자 효과
              Shadow(     // Shadow() : 글자(Text) 또는 다른 UI 요소에 그림자를 표현하기 위한 클래스
                offset: Offset(1,1),  // offset : 그림자의 위치 이동값 (x, y)
                blurRadius: 3,        // blurRadius : 그림자가 얼마나 퍼져서 흐려질지
                color: Colors.black54,
              )
            ],
          ),
        ),
      ),
      */
    );
  }
}

 

+ Recent posts