개요
Transform
은 자식 위젯을 그리기 전에 변형을 적용하는 위젯입니다. Flutter의 Transform에서 영감을 받았으며, Matrix4를 사용하여 회전, 크기 조절, 이동, 기울이기 등의 다양한 변형을 적용할 수 있습니다.
RotatedBox와 달리 Transform은 레이아웃 전이 아닌 그리기 직전에 변형을 적용하므로, 위젯이 차지하는 공간 계산에는 변형이 고려되지 않습니다. 이로 인해 성능상 이점이 있지만 레이아웃에 주의가 필요합니다.
참고: https://api.flutter.dev/flutter/widgets/Transform-class.html
언제 사용하나요?
- 위젯을 회전시켜야 할 때
- 위젯의 크기를 확대/축소해야 할 때
- 위젯을 이동(평행이동)시켜야 할 때
- 3D 효과나 원근법이 필요할 때
- 애니메이션 효과를 만들 때
- 시각적 효과나 장식이 필요할 때
기본 사용법
import { Transform, Matrix4, Container } from '@meursyphus/flitter';
// 45도 회전
const RotatedBox = Transform.rotate({
angle: Math.PI / 4, // 라디안 단위
child: Container({
width: 100,
height: 100,
color: '#3498db'
})
});
// 크기 조절
const ScaledBox = Transform.scale({
scale: 1.5, // 1.5배 확대
child: Container({
width: 100,
height: 100,
color: '#e74c3c'
})
});
// 이동
const TranslatedBox = Transform.translate({
offset: new Offset({ x: 50, y: 30 }),
child: Container({
width: 100,
height: 100,
color: '#2ecc71'
})
});
Props
transform (필수)
값: Matrix4
적용할 변형을 나타내는 4x4 변형 행렬입니다. Matrix4 클래스의 다양한 정적 메서드를 사용하여 생성할 수 있습니다.
// 이동 변형
transform: Matrix4.translationValues(50, 30, 0)
// 크기 조절 변형
transform: Matrix4.diagonal3Values(2.0, 1.5, 1.0) // X축 2배, Y축 1.5배
// 기울이기 변형
transform: Matrix4.skewX(0.5) // X축 기울이기
origin (선택)
값: Offset
변형의 기준점을 지정합니다. 지정하지 않으면 alignment에 따라 결정됩니다.
// 왼쪽 상단 모서리를 기준으로 회전
origin: new Offset({ x: 0, y: 0 })
// 우측 하단 모서리를 기준으로 회전
origin: new Offset({ x: 100, y: 100 })
alignment (선택)
값: Alignment (기본값: Alignment.center)
변형의 정렬 기준점을 지정합니다. origin이 지정되지 않았을 때 사용됩니다.
// 중앙 기준 (기본값)
alignment: Alignment.center
// 왼쪽 상단 기준
alignment: Alignment.topLeft
// 우측 하단 기준
alignment: Alignment.bottomRight
child (선택)
값: Widget
변형이 적용될 자식 위젯입니다.
편의 메서드
Transform 위젯은 일반적인 변형을 쉽게 적용할 수 있는 정적 메서드들을 제공합니다:
Transform.rotate()
Transform.rotate({
angle: number, // 회전 각도(라디안)
origin?: Offset, // 회전 기준점
alignment?: Alignment, // 정렬 기준
child?: Widget
})
Transform.scale()
Transform.scale({
scale?: number, // 균등 크기 조절
scaleX?: number, // X축 크기 조절
scaleY?: number, // Y축 크기 조절
origin?: Offset, // 크기 조절 기준점
alignment?: Alignment, // 정렬 기준
child?: Widget
})
Transform.translate()
Transform.translate({
offset: Offset, // 이동 거리
child?: Widget
})
실제 사용 예제
예제 1: 다양한 회전 변형
import { Transform, Container, Row, Column, Text } from '@meursyphus/flitter';
const RotationExamples = Row({
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Column({
children: [
Transform.rotate({
angle: Math.PI / 6, // 30도
child: Container({
width: 80,
height: 80,
color: '#e74c3c',
child: Center({
child: Text('30°', { style: { color: 'white' } })
})
})
}),
Text('30도 회전')
]
}),
Column({
children: [
Transform.rotate({
angle: Math.PI / 4, // 45도
child: Container({
width: 80,
height: 80,
color: '#3498db',
child: Center({
child: Text('45°', { style: { color: 'white' } })
})
})
}),
Text('45도 회전')
]
}),
Column({
children: [
Transform.rotate({
angle: Math.PI / 2, // 90도
child: Container({
width: 80,
height: 80,
color: '#2ecc71',
child: Center({
child: Text('90°', { style: { color: 'white' } })
})
})
}),
Text('90도 회전')
]
})
]
});
예제 2: 크기 조절 변형
import { Transform, Container, Row } from '@meursyphus/flitter';
const ScaleExamples = Row({
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
// 균등 확대
Transform.scale({
scale: 1.5,
child: Container({
width: 60,
height: 60,
color: '#9b59b6'
})
}),
// X축만 확대
Transform.scale({
scaleX: 2.0,
scaleY: 1.0,
child: Container({
width: 60,
height: 60,
color: '#e67e22'
})
}),
// Y축만 확대
Transform.scale({
scaleX: 1.0,
scaleY: 2.0,
child: Container({
width: 60,
height: 60,
color: '#1abc9c'
})
}),
// 축소
Transform.scale({
scale: 0.5,
child: Container({
width: 60,
height: 60,
color: '#f39c12'
})
})
]
});
예제 3: 복합 변형 (회전 + 크기 조절)
import { Transform, Matrix4, Container } from '@meursyphus/flitter';
const CombinedTransform = () => {
// Matrix4를 직접 조작하여 복합 변형 생성
const matrix = Matrix4.identity();
matrix.translate(50, 0, 0); // 이동
matrix.rotateZ(Math.PI / 4); // 45도 회전
matrix.scale(1.5, 1.5, 1.0); // 1.5배 확대
return Transform({
transform: matrix,
child: Container({
width: 80,
height: 80,
color: '#e74c3c',
child: Center({
child: Text('복합\n변형', {
style: {
color: 'white',
fontSize: 12,
textAlign: 'center'
}
})
})
})
});
};
예제 4: 3D 원근법 효과
import { Transform, Matrix4, Container } from '@meursyphus/flitter';
const PerspectiveCard = Transform({
transform: (() => {
const matrix = Matrix4.identity();
matrix.setEntry(3, 2, 0.001); // 원근법 효과
matrix.rotateX(Math.PI / 6); // X축 30도 회전
return matrix;
})(),
alignment: Alignment.center,
child: Container({
width: 200,
height: 120,
decoration: new BoxDecoration({
color: '#34495e',
borderRadius: BorderRadius.circular(12),
boxShadow: [
new BoxShadow({
color: 'rgba(0, 0, 0, 0.3)',
offset: new Offset({ x: 0, y: 8 }),
blurRadius: 16
})
]
}),
child: Center({
child: Text('3D 카드', {
style: {
color: 'white',
fontSize: 18,
fontWeight: 'bold'
}
})
})
})
});
예제 5: 애니메이션과 함께 사용
import { Transform, AnimationController, Tween } from '@meursyphus/flitter';
class AnimatedTransform extends StatefulWidget {
createState() {
return new AnimatedTransformState();
}
}
class AnimatedTransformState extends State {
animationController!: AnimationController;
rotationTween!: Tween<number>;
scaleTween!: Tween<number>;
initState() {
this.animationController = new AnimationController({
duration: 2000
});
this.rotationTween = new Tween({
begin: 0,
end: Math.PI * 2
});
this.scaleTween = new Tween({
begin: 0.5,
end: 1.5
});
this.animationController.addListener(() => this.setState());
this.animationController.repeat({ reverse: true });
}
dispose() {
this.animationController.dispose();
}
build() {
const rotation = this.rotationTween.evaluate(this.animationController);
const scale = this.scaleTween.evaluate(this.animationController);
return Transform({
transform: (() => {
const matrix = Matrix4.identity();
matrix.rotateZ(rotation);
matrix.scale(scale, scale, 1.0);
return matrix;
})(),
alignment: Alignment.center,
child: Container({
width: 100,
height: 100,
decoration: new BoxDecoration({
color: '#3498db',
borderRadius: BorderRadius.circular(12)
}),
child: Center({
child: Text('애니메이션', {
style: { color: 'white', fontWeight: 'bold' }
})
})
})
});
}
}
예제 6: 카드 뒤집기 효과
import { Transform, Matrix4, GestureDetector } from '@meursyphus/flitter';
class FlipCard extends StatefulWidget {
createState() {
return new FlipCardState();
}
}
class FlipCardState extends State {
isFlipped = false;
toggleFlip = () => {
this.setState(() => {
this.isFlipped = !this.isFlipped;
});
};
build() {
return GestureDetector({
onTap: this.toggleFlip,
child: Transform({
transform: (() => {
const matrix = Matrix4.identity();
matrix.rotateY(this.isFlipped ? Math.PI : 0);
return matrix;
})(),
alignment: Alignment.center,
child: Container({
width: 200,
height: 120,
decoration: new BoxDecoration({
color: this.isFlipped ? '#e74c3c' : '#3498db',
borderRadius: BorderRadius.circular(12),
boxShadow: [
new BoxShadow({
color: 'rgba(0, 0, 0, 0.2)',
offset: new Offset({ x: 0, y: 4 }),
blurRadius: 8
})
]
}),
child: Center({
child: Text(
this.isFlipped ? '뒷면' : '앞면',
{
style: {
color: 'white',
fontSize: 18,
fontWeight: 'bold'
}
}
)
})
})
})
});
}
}
주의사항
- 레이아웃 영향 없음: Transform은 위젯이 차지하는 공간에 영향을 주지 않으므로 다른 위젯과 겹칠 수 있습니다
- 성능: 복잡한 변형이나 많은 Transform 위젯은 성능에 영향을 줄 수 있습니다
- 각도 단위: 회전 각도는 라디안 단위를 사용합니다 (도수 * Math.PI / 180)
- 기준점 이해: origin과 alignment의 차이를 이해하고 적절히 사용하세요
- 3D 변형: Z축 변형 시 원근법 설정이 필요할 수 있습니다
- 애니메이션: 부드러운 변형 애니메이션을 위해 AnimationController와 함께 사용하세요
관련 위젯
- AnimatedContainer: 자동으로 애니메이션되는 변형이 필요할 때
- RotatedBox: 레이아웃에 영향을 주는 회전이 필요할 때
- FractionalTranslation: 크기 비율 기반 이동이 필요할 때
- AnimatedRotation: 회전 애니메이션이 필요할 때
- AnimatedScale: 크기 조절 애니메이션이 필요할 때