- Published on
- ·9 min read
상하 대괄호([ ]) 모양(로또 용지 번호 모양) 만들기(android)
서비스 바로가기
로또 용지와 유사한 UI의 로또 번호 생성기 서비스는 웹 서비스와, 안드로이드 서비스로 각각 만들었습니다. 웹 서비스에서의 로또 용지 번호 모양 css는 아래 포스팅을 참고해 주세요.
상하 대괄호([ ]) 모양(로또 용지 번호 모양) 만들기(css)
설명할 내용
이번 포스팅에서는 안드로이드에서 로또 용지 번호 모양을 구현한 내용을 설명합니다.
아래 이미지의 1 ~ 45번까지 상하 대괄호([ ])로 표시된 부분이 어떻게 구현되었는지 알 수 있습니다.
구현
1. drawable 생성
- 선택되지 않은 번호 drawable:
app/src/main/res/drawable/border_lotto_number.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- @color/lotto 색상의 2dp 사이즈의 테두리가 있는 사각형 -->
<item>
<shape android:shape="rectangle">
<stroke android:width="2dp" android:color="@color/lotto"/>
<solid android:color="@color/lotto_background"/>
</shape>
</item>
<!-- 위/아래 10dp 떨어진 위치에 배경색 @color/lotto_background 사각형을 덮어줍니다 -->
<item android:top="10dp" android:bottom="10dp">
<shape android:shape="rectangle">
<!-- 포스팅 하면서 보니 아래 stroke 부분은 제거해도 동일하게 동작합니다. -->
<stroke android:width="2dp" android:color="@color/lotto_background"/>
<solid android:color="@color/lotto_background"/>
</shape>
</item>
</layer-list>
- 선택된 번호 drawable:
app/src/main/res/drawable/border_lotto_number_selected.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- @color/lotto 색상의 2dp 사이즈의 테두리가 있는 사각형 -->
<item>
<shape android:shape="rectangle">
<stroke android:width="2dp" android:color="@color/lotto"/>
<solid android:color="@color/lotto_background"/>
</shape>
</item>
<!-- 위/아래 10dp 떨어진 위치에 배경색 @color/lotto_background 사각형을 덮어줍니다 -->
<item android:top="10dp" android:bottom="10dp">
<shape android:shape="rectangle">
<stroke android:width="2dp" android:color="@color/lotto_background"/>
<solid android:color="@color/lotto_background"/>
</shape>
</item>
<!-- 상/하/좌/우 2dp씩 들어간 위치에 @color/black 사각형을 덮어줍니다 -->
<item android:top="2dp" android:bottom="2dp" android:left="2dp" android:right="2dp">
<shape android:shape="rectangle">
<solid android:color="@color/black"/>
</shape>
</item>
</layer-list>
위 Code를 안드로이드 스튜디오 > Design 또는 Split으로 미리 보기 하면 아래와 같이 보입니다.
2. drawable 리소스를 TextView의 background로 사용
위에서 생성된 drawable
리소스를 TextView의 background
로 사용합니다.
app/src/main/res/layout/number_item.xml > android:background="@drawable/border_lotto_number"
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/txt_lotto_number"
android:layout_width="29dp"
android:layout_height="45dp"
android:gravity="center"
tools:text="1"
android:background="@drawable/border_lotto_number"
android:textColor="@color/lotto"
android:textStyle="bold"
android:layout_marginBottom="10dp"
/>
위 Code를 안드로이드 스튜디오 > Design 또는 Split으로 미리보기하면 아래와 같이 보입니다.
3. RecyclerView에서 number_item 사용
RecyclerView
에서 GridLayoutManager
로 위에서 만든 number_item.xml
사용합니다.
아래 layout 코드에서는 number_item과의 연결을 찾을 수 없지만, 소스 코드에서 Adapter로 연결됩니다.
app/src/main/res/layout/game_item.xml > <androidx.recyclerview.widget.RecyclerView .../>
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="457dp"
android:background="@drawable/border_lotto"
android:layout_marginLeft="16dp"
android:layout_marginTop="16dp"
android:layout_marginRight="16dp"
android:layout_marginBottom="16dp"
>
<!-- 게임 회차 및 선택된 번호 표시 부분 축약-->
<LinearLayout
android:id="@+id/game_summary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<!-- 게임 회차 표시 부분 축약 -->
<TextView
android:id="@+id/txt_game_number"
tools:text="1"/>
</LinearLayout>
<!-- 여기가 로또 번호 표시 부분. LottoNumberAdapter 코드 참고 -->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/view_number_recycler"
android:layout_width="0dp"
android:layout_height="0dp"
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/game_summary"
app:layout_constraintBottom_toBottomOf="parent"
app:spanCount="7"
android:padding="16dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
위 Code를 안드로이드 스튜디오 > Design 또는 Split으로 미리 보기 하면 아래와 같이 보입니다. (item0 imtem1 item2...로 보이는 부분에 위에서 만든 number_item이 표시됩니다.)
소스 코드에서 위 RecyclerView
와 number_item
을 연결하는 부분입니다.
app/src/main/java/kr/sosone/lotto/adapter/LottoNumberAdapter.kt
package kr.sosone.lotto.adapter
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView
import kr.sosone.lotto.R
import kr.sosone.lotto.model.LottoNumber
class LottoNumberAdapter (private val context: Context, private val dataset: List<LottoNumber>)
: RecyclerView.Adapter<LottoNumberAdapter.ItemViewHolder>()
{
class ItemViewHolder(private val view: View) : RecyclerView.ViewHolder(view){
// number_item.xml에 정의된 TextView
val txtLottoNumber: TextView = view.findViewById(R.id.txt_lotto_number)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder {
val adapterLayout = LayoutInflater.from(parent.context)
.inflate(R.layout.number_item, parent, false)
return ItemViewHolder(adapterLayout);
}
override fun onBindViewHolder(holder: LottoNumberAdapter.ItemViewHolder, position: Int) {
val item = dataset[position]
if(item.isPick){
// 선택된 아이템일 경우 border_lotto_number_selected 배경 및 텍스트 색상 변경
holder.txtLottoNumber.setBackgroundResource(R.drawable.border_lotto_number_selected)
holder.txtLottoNumber.setTextColor(ContextCompat.getColor(context, R.color.white))
}
holder.txtLottoNumber.text = item.number.toString()
}
override fun getItemCount() = dataset.size
}
app/src/main/java/kr/sosone/lotto/model/LottoNumber.kt
package kr.sosone.lotto.model
data class LottoNumber(val number: Int, val isPick: Boolean)
위 LottoNumberAdapter
는 상위 RecyclerView Adapter에서 할당됩니다.
(해당 코드는 여기서 설명하려는 부분에서 벗어나는 부분이므로 축약합니다. )
app/src/main/java/kr/sosone/lotto/model/LottoGame.kt
class LottoGameAdapter(private val context: Context, private val dataset: List<LottoGame>)
: RecyclerView.Adapter<LottoGameAdapter.ItemViewHolder>()
{
class ItemViewHolder(private val view: View) : RecyclerView.ViewHolder(view){
// 중첩 RecyclerView 처리
val viewNumberRecycler: RecyclerView = view.findViewById(R.id.view_number_recycler)
}
override fun onBindViewHolder(holder: LottoGameAdapter.ItemViewHolder, position: Int) {
// 중첩 RecyclerView 처리
holder.viewNumberRecycler.adapter = LottoNumberAdapter(context, item.fullNumbers)
holder.viewNumberRecycler.setHasFixedSize(true)
}
}