[Day3] UI Basics 2 - Flutter for SwiftUI Developers 번역
목차
- Displaying a list view
- Displaying a grid
- Responsive and adaptive design
- Managing state
- Animations
#Displaying a list view
SwiftUI에서는 List 기본 컴포넌트를 사용하여 item의 순서(시퀀스)를 표시합니다.
모델 객체의 시퀀스를 표시하려면 사용자가 모델 객체를 식별할 수 있는지 확인해야 합니다.
객체를 식별 가능하게 만들려면 Identifiable(식별 가능 프로토콜)을 사용합니다.
struct Person: Identifiable {
var name: String
}
var persons = [
Person(name: "Person 1"),
Person(name: "Person 2"),
Person(name: "Person 3"),
]
struct ListWithPersons: View {
let persons: [Person]
var body: some View {
List {
ForEach(persons) { person in
Text(person.name)
}
}
}
}
이는 Flutter의 List 위젯 빌드 방식과 유사합니다. Flutter는 List item을 식별할 필요가 없습니다. 표시할 항목의 수를 설정한 다음 각 item에 대한 위젯을 빌드하면 됩니다.
class Person {
String name;
Person(this.name);
}
var items = [
Person('Person 1'),
Person('Person 2'),
Person('Person 3'),
];
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(items[index].name),
);
},
),
);
}
}
Flutter에는 목록에 대한 몇 가지 주의 사항이 있습니다:
* ListView 위젯에는 builder 메서드가 있습니다. 이것은 SwiftUI의 List 구조체 내의 ForEach와 같이 작동합니다.
* ListView의 itemCount 매개 변수는 ListView에 표시할 항목 수를 설정합니다.
* itemBuilder에는 itemCount보다 0또는 1 보다 작은 index 매개 변수가 있습니다.
위 예제에서는 각 항목에 대한 ListTile 위젯을 반환했습니다.
ListTile 위젯에는 높이 및 글꼴 크기와 같은 속성이 포함되어 있습니다.
이러한 속성은 목록을 작성하는 데 도움이 됩니다. 하지만 Flutter에서는 데이터를 나타내는 거의 모든 위젯을 반환할 수 있습니다.
#Displaying a grid
SwiftUI에서 조건이 없는 grids를 구성할 때는 GridRow와 함께 Grid를 사용합니다.
Grid {
GridRow {
Text("Row 1")
Image(systemName: "square.and.arrow.down")
Image(systemName: "square.and.arrow.up")
}
GridRow {
Text("Row 2")
Image(systemName: "square.and.arrow.down")
Image(systemName: "square.and.arrow.up")
}
}
Flutter에서 그리드를 표시하려면 GridView 위젯을 사용합니다.
이 위젯에는 다양한 생성자가 있습니다.
각 생성자는 비슷한 목적을 가지고 있지만 서로 다른 입력 매개변수를 사용합니다.
다음 예제에서는 .builder() 이니셜라이저를 사용합니다:
const widgets = [
Text('Row 1'),
Icon(CupertinoIcons.arrow_down_square),
Icon(CupertinoIcons.arrow_up_square),
Text('Row 2'),
Icon(CupertinoIcons.arrow_down_square),
Icon(CupertinoIcons.arrow_up_square),
];
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: GridView.builder(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
mainAxisExtent: 40,
),
itemCount: widgets.length,
itemBuilder: (context, index) => widgets[index],
),
);
}
}
SliverGridDelegateWithFixedCrossAxisCount 델리게이트는 grid가 컴포넌트를 배치하는 데 사용하는 다양한 파라미터를 결정합니다.
여기에는 각 행에 표시되는 항목 수를 지정하는 crossAxisCount가 포함됩니다.
SwiftUI의 Grid와 Flutter의 GridView의 차이점은 SwiftUI의 Grid는 GridRow가 필요하다는 점입니다.
Flutter의 GridView는 델리게이트(delegate)를 사용해 그리드의 컴포넌트 배치 방법을 결정합니다.
#Responsive and adaptive design
SwiftUI에서는 GeometryReader를 사용하여 상대적인 뷰 크기를 생성합니다.
예를 들면 다음과 같습니다:
- geometry.size.width에 어떤 계수를 곱하여 너비를 설정합니다.
- GeometryReader를 중단점(breakpoint)으로 사용하여 앱의 디자인을 변경합니다.
horizontalSizeClass를 사용하여 size 클래스에 .regular 또는 .compact가 있는지 확인할 수도 있습니다.
Flutter에서 상대 뷰를 만들려면 두 가지 옵션 중 하나를 사용할 수 있습니다:
- LayoutBuilder 클래스에서 BoxConstraints 객체를 가져옵니다.
- 빌드 함수에서 MediaQuery.of()를 사용하여 현재 앱의 크기와 방향을 가져옵니다.
- 레이아웃 빌더 클래스: https://api.flutter.dev/flutter/widgets/LayoutBuilder-class.html
- 반응형앱 만들기 : https://docs.flutter.dev/ui/layout/responsive/adaptive-responsive
#Managing state
SwiftUI에서는 @State 프로퍼티 래퍼를 사용하여 SwiftUI 뷰의 내부 상태를 표현합니다.
struct ContentView: View {
@State private var counter = 0;
var body: some View {
VStack{
Button("+") { counter+=1 }
Text(String(counter))
}
}}
SwiftUI에는 ObservableObject (관찰 가능한 객체) 프로토콜과 같은 더 복잡한 상태 관리를 위한 몇 가지 옵션도 포함되어 있습니다.
Flutter는 StatefulWidget을 사용하여 로컬 상태를 관리합니다. 다음 두 클래스로 상태 저장 위젯을 구현합니다:
1.StatefulWidget의 서브클래스
2.State의 서브클래스
State 객체는 위젯의 상태를 저장합니다. 위젯의 상태를 변경하려면 State 서브클래스에서 setState()를 호출하여 프레임워크에 위젯을 다시 그리도록 지시합니다.
다음 예제는 카운터 앱의 일부를 보여줍니다:
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key});
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('$_counter'),
TextButton(
onPressed: () => setState(() {
_counter++;
}),
child: const Text('+'),
),
],
),
),
);
}
}
- 상태관리 : https://docs.flutter.dev/data-and-backend/state-mgmt
#Animations
1.암시적 애니메이션 : 현재 값에서 새 대상에 애니메이션을 적용
2.명시적 애니메이션 : 요청 시 애니메이션을 적용
Implicit Animation (암시적 애니메이션)
SwiftUI와 Flutter는 애니메이션에 대해 비슷한 접근 방식을 취합니다.
두 프레임워크 모두에서 duration(지속 시간) 및 curve(커브)와 같은 매개 변수를 지정합니다.
SwiftUI에서는 animate() 수정자를 사용하여 암시적 애니메이션을 처리합니다.
Button("Tap me!"){
angle += 45
}
.rotationEffect(.degrees(angle))
.animation(.easeIn(duration: 1))
Flutter에는 암시적 애니메이션을 위한 위젯이 포함되어 있습니다. 이는 일반적인 위젯 애니메이션을 단순화합니다.
Flutter는 이러한 위젯의 이름을 다음과 같은 형식으로 지정합니다: AnimatedFoo.
예를 들어 버튼을 회전하려면 AnimatedRotation 클래스를 사용합니다.
그러면 Transform.rotate 위젯에 애니메이션이 적용됩니다.
AnimatedRotation(
duration: const Duration(seconds: 1),
turns: turns,
curve: Curves.easeIn,
child: TextButton(
onPressed: () {
setState(() {
turns += .125;
});
},
child: const Text('Tap me!')),
),
Flutter를 사용하면 사용자 지정 암시적 애니메이션을 만들 수 있습니다. 새 애니메이션 위젯을 작성하려면 TweenAnimationBuilder를 사용합니다.
TweenAnimationBuilder : https://api.flutter.dev/flutter/widgets/TweenAnimationBuilder-class.html
Explicit Animation(명시적 애니메이션)
명시적 애니메이션의 경우 SwiftUI에서는 withAnimation() 함수를 사용합니다.
Flutter에는 FooTransition과 같은 형식의 이름을 가진 명시적 애니메이션 위젯이 포함되어 있습니다. 한 가지 예로 RotationTransition 클래스를 들 수 있습니다.
또한 Flutter에서는 AnimatedWidget 또는 AnimatedBuilder를 사용하여 사용자 정의 명시적 애니메이션을 만들 수 있습니다.
Flutter의 애니메이션에 대해 자세히 알아보려면 애니메이션 개요를 참조하십시오.
애니메이션 : https://docs.flutter.dev/ui/animations
Drawing on the Screen (화면에 그리기)
SwiftUI에서는 CoreGraphics를 사용하여 화면에 선과 도형을 그릴 수 있습니다.
Flutter에는 그리기를 도와주는 두 개의 클래스가 있는 Canvas 클래스를 기반으로 하는 API가 있습니다:
1.CustomPaint that requires a painter:
CustomPaint(
painter: SignaturePainter(_points),
size: Size.infinite,
),
2.CustomPainter that implements your algorithm to draw to the canvas.
class SignaturePainter extends CustomPainter {
SignaturePainter(this.points);
final List<Offset?> points;
@override
void paint(Canvas canvas, Size size) {
final Paint paint = Paint()
..color = Colors.black
..strokeCap = StrokeCap.round
..strokeWidth = 5;
for (int i = 0; i < points.length - 1; i++) {
if (points[i] != null && points[i + 1] != null) {
canvas.drawLine(points[i]!, points[i + 1]!, paint);
}
}
}
@override
bool shouldRepaint(SignaturePainter oldDelegate) =>
oldDelegate.points != points;
}
출처 :https://docs.flutter.dev/get-started/flutter-for/swiftui-devs#ui-basics
'플러터 > 플러터 개념' 카테고리의 다른 글
[Day6] UI Basics 3 - Flutter for SwiftUI Developers 번역 (0) | 2023.11.09 |
---|---|
[Day5] UI Layouts in Flutte 2 - Flutter for SwiftUI Developers 번역 (1) | 2023.11.09 |
[Day4] UI Layouts in Flutte 1 - Flutter for SwiftUI Developers 번역 (0) | 2023.11.08 |
[Day2] UI Basics 1 - Flutter for SwiftUI Developers 번역 (0) | 2023.11.07 |
[Day1] Views vs Widgets - Flutter for SwiftUI Developers 번역 (2) | 2023.11.06 |