[Flutter] 슬라이드 가능한 이미지 비교 뷰 구현하기

길위에 히피·2024년 7월 4일
0

Flutter

목록 보기
28/44

Flutter에서 두 개의 이미지를 겹쳐놓고 슬라이드하여 왼쪽 또는 오른쪽 이미지를 비교할 수 있는 UI를 구현하는 방법을 소개합니다. 이 글에서는 GestureDetector와 Stack 위젯을 사용하여 두 개의 이미지를 슬라이드할 수 있도록 하며, 사용자가 이미지를 슬라이드할 때 왼쪽 이미지와 오른쪽 이미지가 교차하도록 합니다.

예제 코드

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ScreenUtilInit(
      designSize: Size(375, 812),
      builder: () => MaterialApp(
        home: ImageSlideScreen(),
      ),
    );
  }
}

class ImageSlideScreen extends StatefulWidget {
  @override
  _ImageSlideScreenState createState() => _ImageSlideScreenState();
}

class _ImageSlideScreenState extends State<ImageSlideScreen> {
  double _sliderValue = 0.5;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Image Slider'),
      ),
      body: Center(
        child: GestureDetector(
          onHorizontalDragUpdate: (details) {
            setState(() {
              _sliderValue += details.primaryDelta! / MediaQuery.of(context).size.width;
              _sliderValue = _sliderValue.clamp(0.0, 0.8); // 최대치를 0.8로 제한
            });
          },
          child: Stack(
            children: [
              // Background Image (Right Image)
              Container(
                padding: EdgeInsets.all(15),
                alignment: Alignment.topRight,
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.end,
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text("After", style: TextStyle(color: Colors.black), textAlign: TextAlign.right),
                  ],
                ),
                width: 95.w,
                height: 30.h,
                color: Colors.limeAccent,
              ),
              // Foreground Image (Left Image)
              ClipRect(
                child: Align(
                  alignment: Alignment.centerLeft,
                  widthFactor: _sliderValue,
                  child: Container(
                    padding: EdgeInsets.all(15),
                    alignment: Alignment.topRight,
                    child: Row(
                      mainAxisAlignment: MainAxisAlignment.start,
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        Text("Before", style: TextStyle(color: Colors.black), textAlign: TextAlign.right),
                      ],
                    ),
                    width: 95.w,
                    height: 30.h,
                    color: Colors.pinkAccent,
                  ),
                ),
              ),
              // Center Button
              Align(
                alignment: Alignment.centerLeft,
                child: FractionallySizedBox(
                  widthFactor: _sliderValue,
                  child: Container(
                    alignment: Alignment.centerRight,
                    child: GestureDetector(
                      onPanUpdate: (details) {
                        setState(() {
                          _sliderValue += details.delta.dx / MediaQuery.of(context).size.width;
                          _sliderValue = _sliderValue.clamp(0.0, 0.8); // 최대치를 0.8로 제한
                        });
                      },
                      child: CircleAvatar(
                        radius: 20,
                        backgroundColor: Colors.white,
                        child: Icon(Icons.compare_arrows, color: Colors.black),
                      ),
                    ),
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

코드 설명

스크린 유틸 초기화:

ScreenUtilInit을 사용하여 반응형 디자인을 설정합니다. 이를 통해 다양한 화면 크기에 대응할 수 있습니다.

상태 관리:

_sliderValue 변수를 통해 슬라이드 위치를 관리합니다. 기본값은 0.5로 설정하여 초기 상태에서 이미지가 반반씩 보이도록 합니다.

슬라이드 동작 감지:

GestureDetector의 onHorizontalDragUpdate 콜백을 사용하여 사용자가 수평 드래그를 할 때마다 _sliderValue를 업데이트합니다. 이때, _sliderValue가 0.0에서 0.8 사이로 제한되도록 합니다.

이미지 겹치기:

Stack 위젯을 사용하여 두 개의 이미지를 겹칩니다. 오른쪽 이미지는 Container 위젯을 사용하여 배치하고, 왼쪽 이미지는 ClipRect와 Align을 사용하여 슬라이드 값에 따라 보이는 부분을 조절합니다.

중앙 버튼 구현:

중앙 버튼은 Align과 FractionallySizedBox를 사용하여 배치합니다. GestureDetector의 onPanUpdate를 사용하여 버튼을 슬라이드할 때 _sliderValue를 업데이트합니다. CircleAvatar를 사용하여 중앙 버튼을 구현하고, Icons.compare_arrows 아이콘을 설정합니다.

결과

위 코드를 실행하면 두 개의 이미지가 겹쳐져 있고, 사용자가 중앙 버튼을 슬라이드할 때 왼쪽 또는 오른쪽 이미지가 보이도록 동작합니다. 이를 통해 사용자는 Before/After 이미지를 직관적으로 비교할 수 있습니다.

이와 같은 슬라이드 가능한 이미지 비교 뷰는 Before/After 비교, 제품 비교 등 다양한 용도로 활용될 수 있습니다.

profile
마음맘은 히피인 일꾼러

0개의 댓글