반응형

ListTile은 주로 ListView 의 각 항목을 표현하는

Text나 Icon 등을 나열하는데 사용된다.

child: ListView.builder(
    itemCount: _foundBleUARTDevices.length,
    itemBuilder: (BuildContext context, int index) => Card(
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(16.0),
      ),
      elevation: 4.0,
      child: ListTile(
        dense: true,
        enabled: !(!_connected && _scanning),
        trailing: GestureDetector(
          behavior: HitTestBehavior.translucent,
          onTap: () {
            //(!_connected && _scanning) || (!_scanning && _connected)? (){}: onConnectDevice(index);
          },
          child: Container(
            width: 48,
            height: 48,
            padding: const EdgeInsets.symmetric(vertical: 4.0),
            alignment: Alignment.center,
            child: const Icon(Icons.add_link),
          ),
        ),
        subtitle: Text(_foundBleUARTDevices[index].id),
        title: Text("${_foundBleUARTDevices[index].name}",style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20, color: Colors.black)),
      ),
    ),
  ),

- dense 속성은 위젯의 밀집 여부를 설정한다. true 또는 false값을 사용하며,

  true로 설정할 경우 해당 ListTile의 높이와 내부의 Text나 icon을 포함한 약간씩 작아진다.

- enabled은 ListTile이 상호작용을 하는 즉, 대화형인지 설정한다.

  true 또는 false 값을 사용하며, false인 경우 ListTile은 현재 ListTile 테마의

  비활성화된 색상으로 스타일이 지정되고, onTap 및 onLongPress 콜백이 작동하지 않는다.

- leading은 ListTile의 앞부분에 배치할 위젯을 설정한다.

- trailing은 ListTile의 뒷부분에 배치할 위젯을 설정한다.

- title은 ListTile의 주요 내용으로 leading의 내용과 trailing 내용 중간에 배치되는 위젯이다.

- subtitle은 title의 아래에 작게 표현되는 위젯이다.

- onTap 사용자가 ListTile을 터치했을 때 호출되는 콜백을 정의한다.

  (위에서 예를 든 onTap은 ListTile을 탭했을 때 수행되는 것이 아니라,

    trailing을 탭했을 때 수행된다.)

반응형
반응형

카드 형태를 표현하기 위한 위젯이다.

보통 ListView나 GridView와 같은 위젯으로 감싸서 사용된다.

주로 사용하는 속성은 shape 속성과 elevation 속성이 있다.

child: ListView.builder(
  itemCount: _foundBleUARTDevices.length,
  itemBuilder: (BuildContext context, int index) => Card(
    shape: RoundedRectangleBorder(	//모서리를 둥글게 설정
      borderRadius: BorderRadius.circular(16.0),
    ),
    elevation: 4.0,	//그림자의 깊이를 설정
    child: ListTile(
      dense: true,
      enabled: !(!_connected && _scanning),
      trailing: GestureDetector(
        behavior: HitTestBehavior.translucent,
        onTap: () {
          //(!_connected && _scanning) || (!_scanning && _connected)? (){}: onConnectDevice(index);
        },
        child: Container(
          width: 48,
          height: 48,
          padding: const EdgeInsets.symmetric(vertical: 4.0),
          alignment: Alignment.center,
          child: const Icon(Icons.add_link),
        ),
      ),
      subtitle: Text(_foundBleUARTDevices[index].id),
      title: Text("${_foundBleUARTDevices[index].name}",style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20, color: Colors.black)),
    ),
  ),
),
반응형
반응형

ListView 는 가장 일반적으로 사용되는 스크롤 위젯이며,

child는 ListView 의 내용을 채우는데 사용된다.

  • ListView : 일반적인 ListView를 명시적으로 호출하고 children을 전달하는 방법
  • ListView.builder : builder를 사용하여 동적으로 item을 추가하는 방법
  • ListView.separated : ListView.builder에서 item을 좀 더 명확하게 구분해서 보여주는 방법

1. ListView

Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: Text(widget.title),
    ),
    body: Center(
      child: Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        Expanded(
          child: ListView(
            padding: const EdgeInsets.all(8),
            children: <Widget>[
              Container(
                height: 50,
                color: Colors.amber[100],
                child:const Center(child: Text('stage 1')),
              ),
              Container(
                height: 50,
                color: Colors.amber[50],
                child:const Center(child: Text('stage 2')),
              ),
            ]),
          ),
      ]),
    ),  
  );
}

위의 예제는 Expanded로 감싸지 않으면, 오류가 난다.

ListView가 가질 수 있는 공간을 알수 없기 때문에 남는 공간을

Expanded에게 준다는 뜻을 명시적으로 해두어야 한다.

Expanded에 대해서는 차후 좀 더 알아보도록 한다.

 

2. ListView.builder

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: Text(widget.title),
    ),
    body: SingleChildScrollView(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Container(
            margin: EdgeInsets.all(30),
            decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(10),
              border: Border.all(
                  color: Colors.blue,
                  width:2
              )
            ),
            height: MediaQuery.of(context).size.height*0.8,
            child: ListView.builder(
              itemCount: _foundBleUARTDevices.length,
              itemBuilder: (BuildContext context, int index) => Card(
                shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.circular(16.0),
                ),
                elevation: 4.0,
                child: ListTile(
                  dense: true,
                  enabled: !(!_connected && _scanning),
                  trailing: GestureDetector(
                    behavior: HitTestBehavior.translucent,
                    onTap: () {
                      //(!_connected && _scanning) || (!_scanning && _connected)? (){}: onConnectDevice(index);
                    },
                    child: Container(
                      width: 48,
                      height: 48,
                      padding: const EdgeInsets.symmetric(vertical: 4.0),
                      alignment: Alignment.center,
                      child: const Icon(Icons.add_link),
                    ),
                  ),
                  subtitle: Text(_foundBleUARTDevices[index].id),
                  title: Text("${_foundBleUARTDevices[index].name}",style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20, color: Colors.black)),
                ),
              ),
            ),
          ),
        ],
      ),
    ),
  );
}

2022.07.07 - [Flutter/기능 구현] - [Flutter / BLE] 기능 구현 - SCAN 에서 사용된 ListView.builder의 예이다.

itemBuilder를 사용하여 item을 itemCount에 맞춰서 ListView를 구성하면 된다.

BLE Device Scan과 같이 BLE Device(item)가 검색될 때마다 호출하여 리스트를 추가한다.

 

3. ListView.separated

child: ListView.separated(
  separatorBuilder: (BuildContext context, int index) => const Divider(
    height: 10,
    color: Colors.blue,
  ),
  itemCount: _foundBleUARTDevices.length,
  itemBuilder: (BuildContext context, int index) => Card(
      shape: RoundedRectangleBorder(
      borderRadius: BorderRadius.circular(16.0),
    ),
    elevation: 4.0,
    child: ListTile(
      dense: true,
      enabled: !(!_connected && _scanning),
      trailing: GestureDetector(
        behavior: HitTestBehavior.translucent,
        onTap: () {
          //(!_connected && _scanning) || (!_scanning && _connected)? (){}: onConnectDevice(index);
        },
        child: Container(
          width: 48,
          height: 48,
          padding: const EdgeInsets.symmetric(vertical: 4.0),
          alignment: Alignment.center,
          child: const Icon(Icons.add_link),
        ),
      ),
      subtitle: Text(_foundBleUARTDevices[index].id),
      title: Text("${_foundBleUARTDevices[index].name}",style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20, color: Colors.black)),
    ),
  ),
),

ListView.separated는 ListView.builder에 구분선이 추가된 것이다.

사용법은 ListView.builder와 동일하며, 추가적으로 separatorBuilder 속성이 추가되어

구분선에 대한 정의를 해준다.

반응형
반응형

SingleChildScrollView 는 Row나 Column 위젯과 같이 쓴다.

Column 이나 Row에 나열하는 위젯이 많아져서 화면에 모두 출력되지 않을 때

SingleChildScrollView로 감싸주면 스크롤이 가능해진다.

Column이나 Row 위젯 외에도 단 한개의 위젯이 너무 커서 화면에 

모두 나타나지 않을 때에도 사용이 가능하다.

body: SingleChildScrollView(
        child: Column(
          children: [
          ...
          ],
        ),
     ),

 

반응형
반응형

사용자에게 상태를 알리거나 동작을 물어보는 용도로 사용되는 팝업 메세지를 구현하는 방법으로

AlertDialog가 있다.

- AlertDialog는 Title, Content, Actions영역으로 구분되며, 세 항목은 필수 항목은 아니다.

- AlertDialog는 showDialog라는 함수를 통하여 화면에 출력된다.

- Dialog를 닫을 때에는 Navigator.pop(context); 를 호출하여 이전 화면이 출력되도록 한다.

- 기본적으로 Dialog의 바깥 화면을 터치하면 Navigator.pop(context); 를 수행한 것처럼 Dialog가 닫힌다.

  이것을 방지하기 위해 showDialog의 barrierDismissible의 속성값을 false로 지정하면,

  Dialog 바깥 화면이 터치되지 않는다.

- Dialog의 모서리는 AlertDialog의 shape 속성에 RoundedRectangleBorder를 추가하면 된다.

 

 

void _showDialog() { 
    showDialog(
      context: context,
      barrierDismissible: false, 
      builder: (BuildContext context) { 
        return AlertDialog(
          shape: RoundedRectangleBorder(
            borderRadius: BorderRadius.circular(8.0)
          ),
          title: new Text("Alert Dialog title"),
          content: SingleChildScrollView(child:new Text("Alert Dialog body")),
          actions: <Widget>[ 
            new FlatButton(
              child: new Text("Close"),
              onPressed: () {
                Navigator.pop(context);
              },
            ),
          ],
        );
      },
    );
  }

 

반응형
반응형

Future와 async, await는 비동기식 프로그램 구현을 위한 키워드이다.

비동기 처리는 시간이 오래 걸리는 특정 로직의 실행이

끝날 때까지 기다려주지 않고 나머지 코드를 먼저 실행하고, 완료된 경우

해당 처리 결과를 즉시 반환한다.

 

일반적인 비동기 처리 예는 아래와 같다.

  • 네트워크를 통해 데이터를 수신
  • 데이터베이스에 쓰기
  • 파일에서 데이터 읽기
Future<List<Image>?> fetchImage() async{
  List<Image>? results = await fetchImageFromServer();
  return results;
}

- async는 해당 함수가 비동기 처리를 진행하는 함수라는 뜻이다.

- await는 오래 걸리는 작업 앞에 붙는 키워드로 오래 걸리는 작업이

  완료되기를 기다리겠다는 키워드이다.

- async와 await를 사용해 작성된 비동기 함수는 정상적으로 처리된 경우

  결과 값으로 List<Image> 를 가져온다.

- 비동기 작업처럼 오래 걸리는 작업은 과정 중 예기치 못한 에러나

  이벤트가 발생할 수 있다.

  즉, 결과 값이 List<Image> 라고 보장할 수 없다.

  이런 상태를 방지하기 위해 비동기 함수의 return 타입은

  항상 Future 타입으로 완료된다.

  정상적으로 처리했다면 List<Image> 로 반환될 수 있지만,

  그렇지 않을 수도 있다는 것을 표현한 키워드가 Future이다.

 

반응형

'Flutter > 기본' 카테고리의 다른 글

[Flutter / 기본] ListTile  (0) 2022.07.19
[Flutter / 기본] Card  (0) 2022.07.18
[Flutter / 기본] ListView  (0) 2022.07.18
[Flutter / 기본] SingleChildScrollView  (0) 2022.07.14
[Flutter / 기본] 팝업 메세지 - showDialog, AlertDialog  (0) 2022.07.13

+ Recent posts