Never give up

Flutter - Map<key, List<data>> with Listview(simple chatting screen) 본문

Flutter

Flutter - Map<key, List<data>> with Listview(simple chatting screen)

대기만성 개발자 2020. 11. 2. 18:19
반응형

데이터를 다루다보면 Map을 Listview로 표현해야될때가 있습니다

 

제가 사용한 데이터 타입은 Map<String, List<items>>입니다

(items은 String값의 reply와 user name입니다)

 

다양한 방법이 있지만 필자는 다음과 같은 방법을 사용했습니다

 

Main

class MapListViewExample extends StatefulWidget {
  @override
  _MapListViewExampleState createState() => _MapListViewExampleState();
}

class _MapListViewExampleState extends State<MapListViewExample> {
  TextEditingController _tController = TextEditingController();
  ScrollController _sController = ScrollController();

  @override
  void initState() {
    super.initState();
    Provider.of<MapExampleData>(context, listen: false).setName('하..');

    WidgetsBinding.instance.addPostFrameCallback((_) {
      _sController.jumpTo(_sController.position.maxScrollExtent);
    });
  }

  void addListener() {
    _sController.animateTo(_sController.position.maxScrollExtent,
        duration: Duration(milliseconds: 300), curve: Curves.ease);
  }

  @override
  void dispose() {
    _tController?.dispose();
    _sController?.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Consumer<MapExampleData>(
      builder: (context, items, child) {
        return Scaffold(
          backgroundColor: Colors.green,
          body: SafeArea(
            child: InkWell(
              focusColor: Colors.green,
              onTap: () => FocusScope.of(context).unfocus(),
              child: Column(
                children: [
                  Expanded(
                    child: Padding(
                      padding: const EdgeInsets.all(8.0),
                      child: ListView.builder(
                          controller: _sController,
                          itemCount: items.getLength,
                          itemBuilder: (context, index) {
                            var item = items.getList[index];
                            return MessageForm(
                                name: item.name,
                                message: item.message,
                                isOwner: (index % 2 == 1));
                          }),
                    ),
                  ),
                  Container(
                    padding: const EdgeInsets.only(left: 10),
                    color: Colors.white,
                    child: TextField(
                      controller: _tController,
                      style: TextStyle(color: Colors.black),
                      decoration: InputDecoration(
                        hintText: 'Reply...',
                        suffixIcon: Container(
                          color: Colors.yellow[600],
                          child: IconButton(
                              icon: Icon(Icons.search, color: Colors.white),
                              onPressed: () {
                                items.addData();
                                _tController.clear();
                                FocusScope.of(context).unfocus();
                                addListener();
                              }),
                        ),
                        border: InputBorder.none,
                      ),
                      onChanged: (value) => items.setMessage(value),
                      onSubmitted: (value) {
                        items.addData();
                        _tController.clear();
                        addListener();
                      },
                    ),
                  )
                ],
              ),
            ),
          ),
        );
      },
    );
  }
}

 

MessageForm

class MessageForm extends StatelessWidget {
  final String name, message;
  final bool isOwner;

  MessageForm({this.name, this.message, this.isOwner});

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(10.0),
      child: Column(
        crossAxisAlignment:
            isOwner ? CrossAxisAlignment.end : CrossAxisAlignment.start,
        children: <Widget>[
          Align(
              alignment: isOwner ? Alignment.topRight : Alignment.topLeft,
              child: CircleAvatar(child: Text(name[0]))),
          Padding(
            padding: isOwner
                ? EdgeInsets.only(right: 40)
                : EdgeInsets.only(left: 40),
            child: Card(
              shape: RoundedRectangleBorder(
                  borderRadius: isOwner
                      ? BorderRadius.only(
                          topLeft: Radius.circular(30),
                          bottomLeft: Radius.circular(30),
                          bottomRight: Radius.circular(30))
                      : BorderRadius.only(
                          bottomLeft: Radius.circular(30),
                          bottomRight: Radius.circular(30),
                          topRight: Radius.circular(30))),
              elevation: 5,
              color: isOwner ? Colors.lightGreen : Colors.white,
              child: Padding(
                padding:
                    const EdgeInsets.symmetric(vertical: 10, horizontal: 20),
                child: Text(
                  message,
                  style: TextStyle(
                      fontSize: 15,
                      color: isOwner ? Colors.white : Colors.lightGreen),
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

 

Item class

class MapExampleItem {
  String name, message;

  MapExampleItem({this.name, this.message});
}

 

Data class

class MapExampleData extends ChangeNotifier {
  Map<String, List<MapExampleItem>> _data = {};
  String _key = '';
  String _name, _message;

  UnmodifiableListView<MapExampleItem> get getList {
    if (_data[_key] == null) {
      _data[_key] = [];
    }
    return UnmodifiableListView(_data[_key]);
  }

  int get getLength => getList.length;

  void addData() {
    if (checkData) {
      _data[_key].add(MapExampleItem(name: _name, message: _message));
      notifyListeners();
    }
  }

  bool get checkData {
    return (_message != null && _name != null);
  }

  void setMessage(String value) {
    _message = value;
  }

  void setName(String value) {
    _name = value;
  }
}

 

먼저 리스트를 불러올 때는 getList부분에서 Map[key]를 사용하면 해당 value(List)를 가져올 수 있고

(getList부분에서 null처리를 안해주면 init값이 null이라서 에러가 납니다)

 

Listview형태로 출력을 해주는 간단한 방법인데 key에 따라 여러 List를 사용할 때 유용할거 같습니다

 

번외로 Map<Key, Value>를 Listview로 표현하는 방법에 대해 알아보자면

 

data class에서 다음과 같이 정의해주고

UnmodifiableMapView<key, value> get getMap => UnmodifiableMapView(_map);
  
int get getMapLength => _map.length;

 

Listview의 itemBuilder부분에서

ListView.builder(
    controller: _sController,
    itemCount: items.getLength,
    itemBuilder: (context, index) {
    String key = items.getMap.keys.elementAt(index);
    var item = items.getMap[key];
	return //위젯부분은 생략)

element위치에 따른 key값을 가져온 후

 

map에서 key에 해당되는 value값을 추출해서 사용하시면 됩니다

 

아니면 values.toList()를 사용하는것도 괜찮습니다

 

상황에 맞게 사용하시면 될거 같습니다

반응형
Comments