이번 포스팅부터는 방식을 조금 바꿔서, 하나의 완성도 있는 어플리케이션을 만들어보도록 하겠습니다. 저희가 만들어 볼 앱은 소개팅 어플리케이션으로, 소개팅 앱을 만들기 위한 여러가지 기능을 추가해나갈 예정입니다. 그중에서 이번 포스팅에서 다뤄볼 내용은 아래와 같습니다.
소개팅 앱의 전체 코드는 아래의 깃허브 링크에서 확인하실 수 있습니다.
>> 깃허브 링크
① dating app이라는 이름으로 프로젝트를 생성한다.
② 먼저 drawable 디렉토리에 좋아요, 싫어요 표시를 위한 아이콘, 기본 프로필 이미지, 스플래시 화면에 사용할 이미지를 추가한다.
③ Card Stack View를 사용하기 위해 app 수준의 build.gradle 파일의 dependencies에 아래의 의존성을 추가한다.
implementation("com.yuyakaido.android:card-stack-view:2.3.4")
④ settings.gradle 파일의 dependencyResolutionManagement에 jcenter()를 추가해야 CardStackView를 사용할 수 있다.
dependencyResolutionManagement {
repositories {
...
jcenter()
}
}
⑤ activity_main.xml 파일에 기존 TextView 태그는 지우고, CardStackView 태그를 추가한다.
<com.yuyakaido.android.cardstackview.CardStackView
android:id="@+id/cardStackView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
⑥ layout 디렉토리 하위로 item_card라는 이름의 Resource 파일을 추가한다.
⑦ LinearLayout을 CardView로 변경하고, 아래의 코드를 추가한다.
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="20dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageView
android:id="@+id/profileImage"
android:src="@drawable/profile"
android:layout_width="match_parent"
android:layout_height="400dp"
android:scaleType="fitXY"/>
<TextView
android:layout_marginVertical="20dp"
android:layout_marginHorizontal="10dp"
android:text="이름"
android:textSize="30sp"
android:textColor="#000000"
android:textStyle="bold"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:layout_marginVertical="20dp"
android:layout_marginHorizontal="10dp"
android:text="나이"
android:textSize="30sp"
android:textColor="#000000"
android:textStyle="bold"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:layout_marginVertical="20dp"
android:layout_marginHorizontal="10dp"
android:text="지역"
android:textSize="30sp"
android:textColor="#000000"
android:textStyle="bold"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
</androidx.cardview.widget.CardView>
⑧ CardStackAdapter라는 이름의 Kotlin 클래스를 추가한다.
class CardStackAdapter(val context : Context, val items: MutableList<String>) : RecyclerView.Adapter<CardStackAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CardStackAdapter.ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_card, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: CardStackAdapter.ViewHolder, position: Int) {
holder.bindItems(items[position])
}
override fun getItemCount(): Int {
return items.size
}
inner class ViewHolder(itemView : View) : RecyclerView.ViewHolder(itemView) {
fun bindItems(item : String) {
}
}
}
⑨ MainActivity에 CardStackView를 적용하자.
lateinit var cardStackAdapter : CardStackAdapter
lateinit var manager : CardStackLayoutManager
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val cardStackView = findViewById<CardStackView>(R.id.cardStackView)
manager = CardStackLayoutManager(baseContext, object : CardStackListener {
override fun onCardDragging(direction: Direction?, ratio: Float) {
}
override fun onCardSwiped(direction: Direction?) {
}
override fun onCardRewound() {
}
override fun onCardCanceled() {
}
override fun onCardAppeared(view: View?, position: Int) {
}
override fun onCardDisappeared(view: View?, position: Int) {
}
})
val initList = mutableListOf<String>()
initList.add("a") // 테스트 용 더미데이터
initList.add("b") // 테스트 용 더미데이터
cardStackAdapter = CardStackAdapter(baseContext, initList)
cardStackView.layoutManager = manager
cardStackView.adapter = cardStackAdapter
}
코드를 실행시킨 후, CardView 이미지를 swipe해보자. 이미지가 CardStackView의 형태로 잘 쌓여있음을 확인할 수 있다.
프로필 사진을 왼쪽으로 swipe하면 싫어요 아이콘을, 오른쪽으로 swipe하면 좋아요 아이콘을 표기해보기로 하자.
① 계속해서 item_card.xml 파일의 LinearLayout 컨테이너 아래에 FrameLayout 컨테이너를 추가한다.
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/left_overlay"
android:src="@drawable/bad"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_gravity="center"/>
</FrameLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/right_overlay"
android:src="@drawable/good"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_gravity="center"/>
</FrameLayout>
② 다시 코드를 실행시켜보자. 이미지를 좌측으로 swipe하면 싫어요 아이콘이, 우측으로 swipe하면 좋아요 아이콘이 나와야 한다.
애플리케이션 상태 바의 색깔이 현재는 보라색으로 되어 있다. 이 상태 바의 색깔을 메인 화면의 색깔과 동일한 색깔을 맞춰주기로 하자.
① 먼저 메인화면의 색깔을 분홍색으로 변경해보자. activity_main.xml 파일의 ConstraintLayout 컨테이너의 아래의 속성을 추가한다.
android:background="#ff9999"
② values > themes > themes.xml과 themes.xml(night) 파일의 style 컨테이너에 아래와 같이 item 컨테이너를 추가한다.
<style name="Base.Theme.DatingApp"
<item name="android:windowLightStatusBar">true</item>
<item name="android:statusBarColor">#ff9999</item>
</style>
③ 코드를 실행시켜보면 상태 바와 메인화면의 색깔이 동일하게 맞춰진 것을 확인할 수 있다.
④ 16진수 색상 값을 사용하는 대신 색상을 등록할 수도 있다. values > colors.xml 파일의 resources 컨테이너 안에 아래의 내용을 추가하자.
<resources>
<color name="pink">#FF9999</color>
</resources>
⑤ 이제 #FF9999 대신 @color/pink를 사용하여 동일한 결과를 얻을 수 있다.
<style name="Base.Theme.DatingApp" parent="Theme.Material3.DayNight.NoActionBar">
<item name="android:windowLightStatusBar">true</item>
<item name="android:statusBarColor">@color/pink</item>
</style>
① default 패키지 하위로 SplashActivity와 IntroActivity를 추가한다.
② SplashActivity의 onCreate 메서드 안에 아래의 내용을 입력한다.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_splash)
Handler().postDelayed({
startActivity(Intent(this, IntroActivity::class.java))
finish()
}, 3000)
}
③ Splash 화면이 가장 먼저 나타날 수 있도록, AndroidManifest.xml 파일의 activity 컨테이너를 수정한다.
<activity
android:name=".IntroActivity"
android:exported="false" />
<activity
android:name=".SplashActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".MainActivity"
android:exported="true">
</activity>
④ 미리 준비한 스플래시 화면의 이미지를 넣어주자. activity_splash.xml 파일의 ConstraintLayout 컨테이너의 속성에 아래의 내용을 추가한다.
android:background="@drawable/date"
⑤ TextView도 추가한다.
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="120dp"
android:text="♡ 소중한 인연으로\n장식할 우리의 내일 ♡"
android:textColor="@color/white"
android:textSize="35sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
⑥ 이번에는 activity_intro.xml 파일에서 배경을 지정해주자. 여기서는 스플래시 화면과 동일한 배경을 사용하겠다.
android:background="@drawable/date"
⑦ ConstraintLayout 컨테이너 안에 LinearLayout 컨테이너를 추가한다.
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.919"
tools:layout_editor_absoluteX="9dp">
<Button
android:id="@+id/join"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="15dp"
android:background="@color/pink"
android:textColor="@color/white"
android:textStyle="bold"
android:textSize="20sp"
android:text="회원 가입" />
<Button
android:id="@+id/login"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="15dp"
android:background="@color/pink"
android:textColor="@color/white"
android:textStyle="bold"
android:textSize="20sp"
android:text="로그인" />
</LinearLayout>
※ Button의 배경색이 적용되지 않는 경우
values > themes > themes.xml 파일의 style 컨테이너 속성 값을 아래와 같이 변경해야 한다.<style name="Base.Theme.DatingApp" parent="Theme.AppCompat.Light">
※ 타이틀 바가 자동 생성되는 경우
themes.xml 파일의 style 컨테이너 안에 아래와 같이 item 컨테이너를 추가해야 한다.<item name="windowNoTitle">true</item>