Notice
Recent Posts
Recent Comments
Link
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Archives
Today
Total
05-16 04:51
관리 메뉴

nomad-programmer

[Programming/Flutter] 쿠퍼티노 디자인 (Cupertino Design) 본문

Programming/Flutter

[Programming/Flutter] 쿠퍼티노 디자인 (Cupertino Design)

scii 2020. 10. 9. 14:49

머터리얼 디자인은 안드로이드에 적용하려고 구글이 만든 디자인 규칙이다. 그러므로 아이폰에는 어울리지 않는다.

좀 더 아이폰스러운 디자인을 적용하려면 쿠퍼니노 디자인을 사용해야 한다. flutter/cupertino.dart 패키지에는 다양한 쿠퍼티노 디자인용 UI 위젯이 준비되어 있다. Cupertino로 시작하는 이름의 클래스들이 이에 해당되며 사용 방법이 머터리얼 위젯과 비슷하므로 쉽게 적용할 수 있다. 여담이지만 두 디자인 컨셉을 섞어서 사용할 수도 있고 안드로이드 앱을 아이폰스럽게 만드는 것도 가능하다.

쿠퍼티노 기본 UI

쿠퍼티노 디자인에서는 AppBar 대신 CupertinoNavigationBar를 사용하며 CupertinoSwitch, CupertinoButton 등을 사용한다. 쿠퍼티노 디자인이라도 특별히 다른 점은 없다. 시작점인 MyApp 클래스도 동일하며 대신 cupertino.dart 패키지를 임포트해야 쿠퍼티노 위젯을 사용할 수 있다.

쿠퍼티노 디자인

머터리얼 디자인과 다른 부분을 살펴보자. 먼저 CupertinoNavigationBar 위젯은 머터리얼의 AppBar 위젯에 대응한다. leading, middle, trailing 프로퍼티는 각각 왼쪽, 가운데, 오른쪽 영역을 나타내면 middle 프로퍼티에는 주로 제목을 표시한다.

CupertinoSwitch는 머터리얼의 Switch와 사용 방법이 동일하다. 참고로 쿠퍼티노 디자인에서는 체크박스나 라디오 버튼이 따로 없고 스위치만 사용한다.

쿠퍼티노 디자인의 RaiseButton 버튼에 대응하는 것으로 CupertinoButton 위젯이 제공된다. 기본 형태는 버튼 형태가 없는 글지만 있는 버튼이다. borderRadius 프로퍼티를 설정하여 외곽선을 얼마나 둥글게 할지 설정할 수 있다.


CupertinoAlertDialog

쿠퍼티노 스타일의 AlertDialog이다.

기본적인 사용 방법은 머터리얼의 AlertDialog와 같다. showDialog() 함수의 builder 프로퍼티에 CupertinoAlertDialog 위젯 인스턴스를 지정한다. actions 프로퍼티에는 어떠한 위젯도 가능하지만 주로 CupertinoDialogAction 위젯의 인스턴스를 지정한다.

showDialog(
  context: context,
  builder: (context) => CupertinoAlertDialog(
    title: [위젯],
    content: [위젯],
    actions: <Widget>[
      CupertinoDialogAction(...),
      CupertinoDialogAction(...),
    ],
  ),
),

머터리얼의 AlertDialog와 동일하며 showDialog()함수의 bulider 프러퍼티에 CupertinoAlertDialog 인스턴스를 반환하는 것이 다르다.


CupertinoPicker

iOS에서 자주 사용되는 피커이다. 위 아래로 스크롤하고 피커 바깥을 클릭하면 선택한 값이 적용된다.

ShowCupertinoModalPopup() 함수를 사용하고 builder 프로퍼티에 CupertinoPicker 위젯을 적용한다. 기본적으로 전체 화면 크기가 되므로 Container 위젯으로 감싸고 높이를 조절하면 위 그림과 같이 하단의 일부가 되도록 할 수 있다.

CupertinoPicker 위젯의 itemExtend 프로퍼티는 표시할 아이템의 높이값을 지정한다. 

showCupertinoModalPopup(
  context: context,
  builder: (context) => Container(
    height: [double 값],  // 피커의 높이를 정해준다.
    child: CupertinoPicker(
      children: <Widget>[...],
      itemExtent: [double 값], // 표시할 항목의 높이
      onSelectedItemChanged: (int index) {
        // 선택된 항목의 인덱스 value를 처리
      }
    ),
  ),
),

onSelectedItemChanged 프로퍼티에 작성한 함수는 피커의 바깥 부분을 클릭했을 때 피커가 닫히면서 호출된다. 이 때 호출되는 함수의 인수인 index는 선택된 값의 인덱스 번호이다.


최종 코드

import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart'; // 쿠퍼티노 위젯

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(
        title: '쿠퍼티노 디자인 테스트',
      ),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  bool _isOn = false;

  void _showCupertinoDialog(BuildContext context) {
    showDialog(
      context: context,
      builder: (context) => CupertinoAlertDialog(
        title: Text('제목'),
        content: Text('내용'),
        actions: <Widget>[
          CupertinoDialogAction(
            child: Text('Cancel'),
          ),
          CupertinoDialogAction(
            child: Text('Ok'),
            onPressed: () {
              Navigator.of(context).pop();
            },
          )
        ],
      ),
    );
  }

  void _showCupertinoPicker(BuildContext context) async {
    // 0~9 까지의 숫자 리스트 생성
    final List<int> _items = List.generate(10, (index) => index);
    int result = _items[0]; // 기본 값

    await showCupertinoModalPopup(
      context: context,
      builder: (context) => Container(
        height: 200.0, // 피커의 높이는 200
        child: CupertinoPicker(
          // 0~9 까지의 숫자 표시
          children: _items.map((e) => Text('No. $e')).toList(),
          // 항목 1개의 높이는 50
          itemExtent: 50.0,
          onSelectedItemChanged: (int index) {
            result = _items[index];
          },
        ),
      ),
    );
    print(result);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      // 머터리얼의 AppBar에 대응
      appBar: CupertinoNavigationBar(
        middle: Text('쿠퍼티노 디자인'), // 머터리얼 AppBar의 title에 대응
      ),
      body: Column(
        children: <Widget>[
          CupertinoSwitch(
            value: _isOn,
            onChanged: (bool value) {
              setState(() {
                _isOn = value;
              });
            },
          ),
          CupertinoButton(
            child: Text('쿠퍼티노 AlertDialog'),
            onPressed: () {
              _showCupertinoDialog(context);
            },
            borderRadius: BorderRadius.circular(16.0),
            color: Colors.orange,
          ),
          CupertinoButton(
              child: Text('쿠퍼티노 Picker'),
              onPressed: () {
                _showCupertinoPicker(context);
              }),
        ],
      ),
    );
  }
}

showCupertinoModalPopup() 함수는 Future 타입을 반환하기 때문에 await 키워드를 사용하여 피커가 닫힐 때까지 대기한 후 result 변수의 값을 출력한다.

await 키워드를 사용하려면 메소드 선언시 async 키워드를 사용해야 한다.

Comments