본문 바로가기
플러터/플러터 개념

[Day3] UI Basics 2 - Flutter for SwiftUI Developers 번역

by 인생여희 2023. 11. 7.

[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