Programming-[CrossPlatform]/Flutter

Flutter 기본-22. 채팅앱 - 유저이름 표기, 다이얼로그(팝업)

컴퓨터 탐험가 찰리 2023. 2. 14. 18:05
728x90
반응형

Youtube 코딩셰프님의 강의를 요약 정리한 글이다. dart 언어나 이론 부분은 자바와 유사하여 대부분 제외하였고, flutter 기초 위주로 정리한다.

https://www.youtube.com/@codingchef

 

코딩셰프

향후 대세가 될 플러터를 단계별로 맛있게 학습하실 수 있습니다!

www.youtube.com

 

 

 

background image reference : https://wallpapercave.com/cartoon-chickens-wallpapers

 

 


 

1. 유저 이름 표기 추가하기

 

flutter_chat_bubble

작업 전 편의를 위해 pub.dev에서 제공하는 flutter_chat_bubble 라이브러리를 설치한다.

https://pub.dev/packages/flutter_chat_bubble

 

이 라이브러리는 챗 버블의 모양에 따라 여러 가지 다른 import 문을 제공한다. 강의에서는 맨 위 두 개 패키지와 chat_bubble_clipper_8번을 이용한다.

 

 

ChatBubble 클래스는 기존에 작성했던 ChatBubble 클래스와 이름이 중복되므로 ChatBubbles로 변경했다. 그리고 기존에 Row의 children으로 작성되어있던 부분은 모두 삭제하고 flutter_chat_bubble 라이브러리의 readMe/Examples/Example1에 있는 위쪽, 아래쪽 코드를 복사하여 붙여넣었다.

 

isMe 값을 inline if로 적용하여 ChatBubble 위젯을 적용하고, clipper는 8번으로, Text의 내용은 message 변수로 지정했다. 마지막으로 약간의 바깥쪽 여백을 위해 ChatBubble을 Padding으로 감싸고 fromLTRB 속성을 적용하여 각각 좌, 우측에서 5씩 떨어뜨려줬다.

class ChatBubbles extends StatelessWidget {
  //중략

  @override
  Widget build(BuildContext context) {
    return Row(
      mainAxisAlignment: isMe? MainAxisAlignment.end : MainAxisAlignment.start,
      children: [
        if(isMe)
          Padding(
            padding: const EdgeInsets.fromLTRB(0, 0, 5, 0),
            child: ChatBubble(
              clipper: ChatBubbleClipper8(type: BubbleType.sendBubble),
              alignment: Alignment.topRight,
              margin: EdgeInsets.only(top: 20),
              backGroundColor: Colors.blue,
              child: Container(
                constraints: BoxConstraints(
                  maxWidth: MediaQuery.of(context).size.width * 0.7,
                ),
                child: Text(
                  message,
                  style: TextStyle(color: Colors.white),
                ),
              ),
            ),
          ),
        if(!isMe)
        //이하 생략

 

 

유저 이름 표시

유저이름은 Text 위젯 바로 위에 표시하면 된다.

 

우선 메시지마다 userName이 등록되도록 'user' 컬렉션에서 userName을 가져와서 'chat' 컬렉션에 삽입한다.

void _sendMessage() async {
  FocusScope.of(context).unfocus();
  final user = FirebaseAuth.instance.currentUser;
  final userData = await FirebaseFirestore.instance.collection('user').doc(user!.uid)
  .get();
  FirebaseFirestore.instance.collection('chat').add({
    "text": _userEnterMessage,
    "time": Timestamp.now(),
    "userID": user!.uid,
    "userName": userData.data()!['userName']
  });
  _controller.clear();
}

 

chat_bubble에서 userName을 받아올 수 있도록 한다. 실제 메시지를 담는 Text 바로 위에 배치하기 위해서 Column 위젯을 두고 Text 위젯을 통해 userName을 표시한다.

class ChatBubbles extends StatelessWidget {
  const ChatBubbles(this.message, this.isMe, this.userName, {Key? key})
      : super(key: key);

  final String userName;
  final String message;
  final bool isMe;
  
  //중략
  
  child: Column(
         crossAxisAlignment: CrossAxisAlignment.start,
         children: [
           Text(
             userName,
             style: TextStyle(
               fontWeight: FontWeight.bold,
               color: Colors.black,
             ),
           ),
           Text(
             message,
             style: TextStyle(color: Colors.black),
           ),
         ],
       ),

 

ChatBubbles가 userName도 받게되어 있으므로, Messages에서 ChatBubbles 인스턴스를 생성할 때 userName 정보를 넣어주어야 한다.

return ListView.builder(
    reverse: true,
    itemCount: chatDocs.length,
    itemBuilder: (context, index) {
      return ChatBubbles(
          chatDocs[index]['text'],
          chatDocs[index]['userID'].toString() == user!.uid,
          chatDocs[index]['userName']
      );
    });

 

 

 

 

 

2. 이미지 삽입용 다이얼로그창

 

아이콘 삽입

삽입용 다이얼로그창을 띄우기 위해서 SIGNUP 텍스트 옆에 아이콘을 넣는다.

아이콘은 Icons.Image 이고, color는 isSignupScreen? cyan : grey이다. 배치나 밑줄 변경에 관한 건 이제 따로 적지 않아도 스스로 할 수 있을 것 같다. inline if를 적용하여 이 아이콘은 SignupScreen 일때만 표시되도록 하면 된다.

 

 

다이얼로그 창 띄우기

 

Icon을 GestureDetector로 감싸서 onTap 옵션을 준다. onTap 옵션에 적용하는 showAlert 메서드는 BuildContext를 인자로 갖도록 해주는데, 이것은 위젯 트리에 삽입되어 또 다른 위젯(Dialog)을 표시해줄 것이기 때문이다.

if(isSignupScreen)
GestureDetector(
  onTap: () {
    return showAlert(context);
  },
  child: Icon(
    Icons.image,
    color: isSignupScreen ? Colors.cyan : Colors.grey,
  ),
)

 

showAlert 메서드를 작성해준다. OutlineButton.icon, TextButton.icon을 제외하고는 전부 이미 학습했던 부분들이다.

void showAlert(BuildContext context) {
  showDialog(
    context: context,
    builder: (context) {
      return Dialog(
        backgroundColor: Colors.white,
        child: Container(
          padding: EdgeInsets.only(top: 10),
          width: 150,
          height: 300,
          child: Column(
            children: [
              CircleAvatar(
                radius: 40,
                backgroundColor: Colors.blue,
              ),
              SizedBox(
                height: 10,
              ),
              OutlinedButton.icon(
                  onPressed: (){},
                  icon: Icon(Icons.image),
                  label: Text('Add icon'),
              ),
              SizedBox(
                height: 80,
              ),
              TextButton.icon(
                onPressed: (){
                Navigator.pop(context);
              },
                icon: Icon(Icons.close),
                label: Text('Close'),
              )
            ],
          ),
        ),
      );
    },
  );
}

 

State 위젯 아래에 그냥 메서드 형태로 둬도 되지만, 코드가 너무 길어지는데다 하나의 기능을 갖기 때문에 add_image 폴더를 새로 만들고 해당 폴더에 add_image.dart 파일을 만들어서 분리하는 것이 좋다. 상태가 바뀌기 때문에 StatefulWidget으로 만들고, showAlert 하위의 Container 부분만 return 해주면 된다.

 

 

 

 

 

 

728x90
반응형