개요

Opacity는 자식 위젯을 부분적으로 투명하게 만드는 위젯입니다. Flutter의 Opacity 위젯에서 영감을 받았으며, 페이드 인/아웃 효과나 시각적 계층을 만들 때 사용합니다.

0.0 값일 때는 자식이 전혀 그려지지 않고, 1.0 값일 때는 완전 불투명하게 그려집니다. 0.0과 1.0 사이의 값은 중간 버퍼를 사용하므로 성능상 비용이 있을 수 있습니다.

참고: https://api.flutter.dev/flutter/widgets/Opacity-class.html

언제 사용하나요?

  • 위젯의 투명도를 조절해야 할 때
  • 페이드 인/아웃 효과를 만들 때
  • 비활성화된 UI 요소를 시각적으로 표현할 때
  • 오버레이나 모달 배경을 만들 때
  • 시각적 계층이나 깊이감을 표현할 때

기본 사용법

import { Opacity, Container } from '@meursyphus/flitter';

// 반투명 상자
const SemiTransparentBox = Opacity({
  opacity: 0.5,
  child: Container({
    width: 100,
    height: 100,
    color: '#3498db'
  })
});

// 거의 투명한 텍스트
const FadedText = Opacity({
  opacity: 0.3,
  child: Text('흐릿한 텍스트', {
    style: { fontSize: 18 }
  })
});

Props

opacity (필수)

값: number

투명도 값을 0.0부터 1.0까지의 범위로 지정합니다.

  • 0.0: 완전히 투명 (보이지 않음)
  • 1.0: 완전히 불투명 (기본 상태)
  • 0.0 ~ 1.0: 부분적으로 투명
// 완전히 투명
opacity: 0.0

// 반투명
opacity: 0.5

// 거의 불투명
opacity: 0.9

// 완전히 불투명
opacity: 1.0

child (선택)

값: Widget

투명도가 적용될 자식 위젯입니다. 자식이 없으면 아무것도 렌더링되지 않습니다.

실제 사용 예제

예제 1: 다양한 투명도 단계

import { Opacity, Container, Row, Column, Text } from '@meursyphus/flitter';

const OpacityLevels = Row({
  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  children: [0.0, 0.2, 0.4, 0.6, 0.8, 1.0].map(opacity =>
    Column({
      children: [
        Opacity({
          opacity: opacity,
          child: Container({
            width: 60,
            height: 60,
            color: '#e74c3c'
          })
        }),
        Text(`${opacity}`, {
          style: { fontSize: 12, marginTop: 8 }
        })
      ]
    })
  )
});

예제 2: 비활성화된 버튼 표현

import { Opacity, GestureDetector, Container, Text } from '@meursyphus/flitter';

const Button = ({ text, onPress, disabled = false }) => {
  const buttonContent = Container({
    padding: EdgeInsets.symmetric({ horizontal: 24, vertical: 12 }),
    decoration: new BoxDecoration({
      color: '#3498db',
      borderRadius: BorderRadius.circular(8)
    }),
    child: Text(text, {
      style: { color: 'white', fontSize: 16 }
    })
  });

  if (disabled) {
    return Opacity({
      opacity: 0.5,
      child: buttonContent
    });
  }

  return GestureDetector({
    onTap: onPress,
    child: buttonContent
  });
};

예제 3: 모달 오버레이

import { Opacity, Stack, Positioned, Container, GestureDetector } from '@meursyphus/flitter';

const Modal = ({ isVisible, onClose, child }) => {
  if (!isVisible) return null;

  return Stack({
    children: [
      // 배경 오버레이
      Positioned({
        top: 0,
        left: 0,
        right: 0,
        bottom: 0,
        child: GestureDetector({
          onTap: onClose,
          child: Opacity({
            opacity: 0.5,
            child: Container({
              color: 'black'
            })
          })
        })
      }),
      // 모달 컨텐츠
      Center({
        child: Container({
          margin: EdgeInsets.all(40),
          decoration: new BoxDecoration({
            color: 'white',
            borderRadius: BorderRadius.circular(12)
          }),
          child: child
        })
      })
    ]
  });
};

예제 4: 애니메이션과 함께 사용 (AnimatedOpacity)

import { AnimatedOpacity, Container, GestureDetector } from '@meursyphus/flitter';

class FadeButton extends StatefulWidget {
  createState() {
    return new FadeButtonState();
  }
}

class FadeButtonState extends State {
  isVisible = true;
  
  toggleVisibility = () => {
    this.setState(() => {
      this.isVisible = !this.isVisible;
    });
  };
  
  build() {
    return Column({
      children: [
        GestureDetector({
          onTap: this.toggleVisibility,
          child: Container({
            padding: EdgeInsets.all(16),
            decoration: new BoxDecoration({
              color: '#9b59b6',
              borderRadius: BorderRadius.circular(8)
            }),
            child: Text('토글 버튼', {
              style: { color: 'white' }
            })
          })
        }),
        
        SizedBox({ height: 20 }),
        
        AnimatedOpacity({
          opacity: this.isVisible ? 1.0 : 0.0,
          duration: 500,
          child: Container({
            width: 200,
            height: 100,
            decoration: new BoxDecoration({
              color: '#e67e22',
              borderRadius: BorderRadius.circular(8)
            }),
            child: Center({
              child: Text('페이드 효과', {
                style: { color: 'white', fontSize: 18 }
              })
            })
          })
        })
      ]
    });
  }
}

예제 5: 중첩된 투명도 (곱셈 효과)

import { Opacity, Container, Row } from '@meursyphus/flitter';

const NestedOpacityExample = Row({
  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  children: [
    // 단일 투명도
    Container({
      width: 100,
      height: 100,
      child: Opacity({
        opacity: 0.5,
        child: Container({ color: '#3498db' })
      })
    }),
    
    // 중첩된 투명도 (0.5 × 0.5 = 0.25)
    Container({
      width: 100,
      height: 100,
      child: Opacity({
        opacity: 0.5,
        child: Opacity({
          opacity: 0.5,
          child: Container({ color: '#3498db' })
        })
      })
    })
  ]
});

예제 6: 조건부 투명도

import { Opacity, Container, Text } from '@meursyphus/flitter';

class ConditionalOpacity extends StatefulWidget {
  constructor(private isHighlighted = false) {
    super();
  }
  
  createState() {
    return new ConditionalOpacityState();
  }
}

class ConditionalOpacityState extends State {
  build() {
    return GestureDetector({
      onHover: (isHovered) => this.setState(() => {
        this.widget.isHighlighted = isHovered;
      }),
      child: Opacity({
        opacity: this.widget.isHighlighted ? 1.0 : 0.7,
        child: Container({
          padding: EdgeInsets.all(16),
          decoration: new BoxDecoration({
            color: '#2ecc71',
            borderRadius: BorderRadius.circular(8)
          }),
          child: Text('호버 효과', {
            style: { color: 'white' }
          })
        })
      })
    });
  }
}

주의사항

  • 성능: 0.0과 1.0이 아닌 값은 중간 버퍼를 사용하므로 성능에 영향을 줄 수 있습니다
  • 중첩 효과: 여러 Opacity 위젯이 중첩되면 투명도가 곱해집니다 (0.5 × 0.5 = 0.25)
  • 애니메이션: 부드러운 투명도 변화가 필요하면 AnimatedOpacity를 사용하세요
  • 히트 테스트: opacity가 0.0이어도 자식 위젯은 여전히 터치 이벤트를 받을 수 있습니다
  • 범위 검증: opacity 값은 반드시 0.0과 1.0 사이여야 합니다

관련 위젯

  • AnimatedOpacity: 부드러운 투명도 애니메이션이 필요할 때
  • FadeTransition: 더 복잡한 페이드 애니메이션 제어가 필요할 때
  • Visibility: 완전히 숨기거나 보여주는 단순한 제어가 필요할 때
  • Container: 배경색의 투명도만 조절하고 싶을 때