본문 바로가기

IOS(Swift)

[IOS/Swift] 콘텐츠 검색 앱 구현 - 2. 채팅방 UI 구현

반응형

전편에 이어서 채팅방 UI를 구현해보겠다.

채팅방은 클럽하우스 앱의 UI를 참고하여 만들었다.

결과물 화면

 

결과물 예시

채팅방 상세 화면 구현

채팅방에는 각 유저별 프로필 사진이 들어가야 한다. 그렇기 때문에 프로필 화면도 구현해보자

프로필 화면 구현

프로필 화면의 프로필 사진은 추후 Amazon S3 를 활용해 관리할 예정이다. (REST API로 관련 URL 을 받을 예정). 그래서 이미지 URL 로 프로필 사진을 보여줄 수 있는 UI 가 별도로 필요하다.

Swift 에서는 AsyncImage를 사용해서 이미지의 url로(html 에서 image 태그를 사용하는 것과 유사) 사진을 보여줄 수 있다. 아래 코드를 구현하면 다음과 같다.

import SwiftUI

struct ProfileItem: View {
    var talkRoomTitle: String
    var imageUrl: String
    
    
    var body: some View {
        VStack(alignment: .leading){
            Circle() // Circle element 위에 image를 오버레이하여 프로필 사진을 만듬
                .overlay(
                    AsyncImage(
                        url: URL(string: imageUrl),
                        content: { image in
                            image.resizable()
                                .aspectRatio(contentMode: .fill)
                                .frame(width: 100, height: 100)
                                .clipShape(Circle())
                        },
                        placeholder: {
                            ProgressView()
                        }
                    )
                )
                .frame(width: 100, height: 100)
            Text(talkRoomTitle) // 채팅방에 들어가는 사용자의 이름
                .frame(width: 100)
                .lineLimit(2)
                .font(.subheadline)
        }
            
        
    }
}

struct ProfileItem_Previews: PreviewProvider {
    static var previews: some View {
        ProfileItem(
            talkRoomTitle: "John",
            imageUrl: "<https://cdn.pixabay.com/photo/2015/03/03/18/58/woman-657753_960_720.jpg>"
        )
    }
}

채팅방 상세화면(With 유저)

각 채팅방에 유저가 들어온 화면을 구현해보자.

import SwiftUI

struct TalkRoomDetail: View {
    @Environment(\\.presentationMode) var presentationMode
    
    var roomTitle: String
    var mbtiType: Array<String>
    
    let userList = ModelData().userInfos
    let columns = [
        GridItem(.adaptive(minimum: 100))
    ]
    
    
    var body: some View {
        ZStack(alignment: .leading){
            Color.white.ignoresSafeArea()
                .navigationBarBackButtonHidden(true)
                .navigationBarHidden(true)
            VStack(alignment: .leading){
                Button(action: {
                    self.showingAlert = true
                }){
                    Text("나가기")
                }.alert(isPresented: $showingAlert){
                    Alert(title: Text("채팅방 나가기"), message: Text("채팅방을 나가시겠습니까?"),
                          primaryButton: .destructive(Text("나가기"), action: {
                        presentationMode.wrappedValue.dismiss()
                    })
                          , secondaryButton: .cancel(Text("취소")))
                }
                .padding()
                Text(roomTitle)
                    .font(.title)
                    .bold()
                    .padding(.leading)
                    .padding(.top)
                Text(mbtiType.joined(separator: " "))
                    .font(.headline)
                    .bold()
                    .padding(.leading)
                
                Divider()
                
                ScrollView{
                    LazyVGrid(columns: columns, spacing: 10) {
                        ForEach(userList, id:\\.self) {i in
                            ProfileItem(talkRoomTitle: i.userId, imageUrl: i.profilePic)}
                    }
                }.frame(width: .infinity, height: 400)
                Divider()
            }
        }
    }
    
}

struct TalkRoomDetail_Previews: PreviewProvider {
    static var previews: some View {
        TalkRoomDetail(
            roomTitle: "제주도 여행썰",
            mbtiType: ["#ISTJ","#ENFP"]
        )
    }
}

채팅방 UI로 접근하기 위해 이전 UI에서는 NavigationView를 이용하여 접근한다. NavigationView를 이용해 접근하면 뒤로 돌아가는 화면(Navigation UI)이 자동으로 생성된다. 그래서 코드 내

@Environment(\\.presentationMode) **var** presentationMode 를 이용해 NavigationView로 접근한 View 에서 뒤로가기 버튼이 없도록 개발한다.

또한 채팅방의 유저는 함수의 파라미터로 받는 것이 아닌 별도 변수로 받아 처리하도록 하였다. (REST API 또는 NoSQL(Firebase or Mongo DB)에서 받아오도록)

Grid View 구현

유저별 프로필은 Grid View를 이용해 3 * N 개의 유저가 보여질 수 있도록 UI를 구성하였다.

여기에 사용한 코드는 다음과 같다.

LazyVGrid(columns: columns, spacing: 10) {
    ForEach(userList, id:\\.self) {i in
        ProfileItem(talkRoomTitle: i.userId, imageUrl: i.profilePic)}
}

채팅방 나가기 화면 구현

Navigation 기능에서 뒤로가기 버튼을 Hidden 시켰기 때문에 별도의 나가기 버튼을 만들었다.

Button(action: {
        self.showingAlert = true
    }){
        Text("나가기")
    }.alert(isPresented: $showingAlert){
        Alert(title: Text("채팅방 나가기"), message: Text("채팅방을 나가시겠습니까?"),
              primaryButton: .destructive(Text("나가기"), action: {
            presentationMode.wrappedValue.dismiss()
        })
              , secondaryButton: .cancel(Text("취소")))
    }
    .padding()

다음에는 키워드 검색을 구현하고(REST API 와 연결) 검색 화면을 구현해보자.

반응형