Skip to content

예인 캘린더, 스플래시

yenny07 edited this page Jan 15, 2021 · 7 revisions

캘린더 - 핵심 기능 구현 방법



(1) Material-Calendar 라이브러리 사용해 캘린더 배치하고, 크기 및 디자인 커스텀을 위해 item_calendar_cell.xml 작성
(2) 서버에서 약속, 공지를 한번에 받아 HashMap<String date, MutableList<CalendarDate>>에 저장하여 활용
(3) 날짜 클릭 시 해당 일자의 약속, 공지 목록을 RecyclerView에 배치
(4) 일정 종류의 경우의 수에 따라 해당하는 icon을 날짜 텍스트 아래 배치
(5) CardView 클릭 시 상세보기 뷰로 이동

구현 코드

(1) Material-Calendar 라이브러리 사용해 캘린더 배치하고, 디자인 커스텀을 위해 item_calendar_cell.xml 작성

  • fragment_calendar.xml
<com.applandeo.materialcalendarview.CalendarView  
  android:id="@+id/calendar"  
  android:layout_width="0dp"  
  android:layout_height="wrap_content"  
  android:paddingBottom="4dp"  
  app:abbreviationsLabelsColor="@color/gray_5"  
  app:daysLabelsColor="@color/gray_5"  
  app:eventsEnabled="true"  
  app:forwardButtonSrc="@drawable/icon_calendar_forwawrd"  
  app:headerColor="@color/white"  
  app:headerLabelColor="@color/primary_black"  
  app:layout_constraintEnd_toEndOf="parent"  
  app:layout_constraintStart_toStartOf="parent"  
  app:layout_constraintTop_toBottomOf="@id/txt_me"  
  app:previousButtonSrc="@drawable/icon_calendar_previous"  
  app:selectionColor="@color/primary_black"  
  app:selectionLabelColor="@color/white"  
  app:type="one_day_picker" />

(2) 서버에서 약속, 공지 목록을 한번에 받아 `HashMap>`에 저장하여 활용
* CalendarFragment.kt
var allData: HashMap<String, MutableList<CalendarData>> = hashMapOf()
fun calendarDataBind(data: ResponseCalendarData.Data) {  
      for (promise in data.promise) {  
          var year = promise.year  
		  var month = promise.month  
		  var day = promise.day  
		  var title = promise.title  
		  var time = promise.time  
		  var date = "${year}.${month}.${day}"  
		  
		  var promiseModel : CalendarData = CalendarData(  
		                      type = 0,  
							  noticeId = null,  
							  noticeTitle = null,  
							  noticeTime = null,  
							  issueId = promise.id,  
							  category = promise.category,  
							  solutionMethod = promise.solutionMethod,  
							  issueTitle = title,  
							  issueContents = promise.contents,  
							  promiseTime = time  
	        )  
  
            if(allData.containsKey(date)){  
                allData[date]!!.add(promiseModel)  
            }  
            else{  
                allData.put(date, mutableListOf(promiseModel))  
            }  
        }  
    for (notice in data.notice) {  
        var year = notice.year  
		var month = notice.month  
		var day = notice.day  
		  ...
		  // promise와 같은 로직
    }   
}

(3) 일정 종류의 경우의 수에 따라 해당하는 icon을 날짜 텍스트 아래 배치

  • CalendarFragment.kt
fun drawIcons(){  
    for (i in allData.keys){  
         var isNotice = false  
		 var isPromise = false  
		 var splitArr = i.split(".")  
         var newDate = Calendar.getInstance()  
         newDate.set(splitArr[0].toInt(), splitArr[1].toInt() - 1, splitArr[2].toInt())  
  
        for ( j in allData[i]!!){  
            if(j.type == 0){  isPromise = true  }  
            else{  isNotice = true  }  
            
		    if(isPromise && isNotice){  break  }  
        }  
  
        if (isNotice&&isPromise){events.add(EventDay(newDate, R.drawable.border_orange_blue_fill)) }  
        else if(isNotice){events.add(EventDay(newDate, R.drawable.border_blue_fill_5)) }  
        else if(isPromise){events.add(EventDay(newDate, R.drawable.border_orange_fill_5)) }  
  
        binding.calendar.setEvents(events)  
    }  
}

(4) 날짜 클릭 시 맵에서 해당 일자의 일정 데이터에 접근 -> 일정 종류대로 분기하여 RecyclerView에 배치

  • CalendarFragment.kt
override fun onDayClick(eventDay: EventDay) {  
    setRecyclerView(eventDay.calendar)  
    ...  
}

fun setRecyclerView(targetDay : Calendar){  
    var tempData : List<CalendarData>?  
    tempData = getDailyData(targetDay)  
    tempData?.let { dailyAdapter.data = it } ?: run { dailyAdapter.data = emptyList() }  
  dailyAdapter.notifyDataSetChanged()  
  
    Log.d("today", tempData.toString())  
}

fun getDailyData(clickedDay : Calendar) : List<CalendarData>? {  
    var year = clickedDay.get(Calendar.YEAR).toString()  
    ...
    var keyDate = "$year.$month.$day"  
 
    allData[keyDate]?.let{return allData[keyDate]} ?: run {return emptyList()}  
  
}
  • DailyAdapter.kt
class DailyAdapter(private val context: Context)  
    : RecyclerView.Adapter<RecyclerView.ViewHolder>() {  
  
    var data = listOf<CalendarData>()  
  
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {  
        if (viewType == 0) {  
            val view = LayoutInflater.from(context).inflate(R.layout.item_calendar_promise, parent, false)  
            return PromiseViewHolder(view)  
        } else {  
            val view = LayoutInflater.from(context).inflate(R.layout.item_calendar_notice, parent, false)  
            return NoticeViewHolder(view)  
        }  
    }  
  
    override fun getItemCount(): Int = data.size  
  
  override fun getItemViewType(position: Int): Int = data?.get(position).type  
  
  override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {  
        when(holder){  
            is PromiseViewHolder -> {  
    holder.onBind(data[position])  
    ...
}  
  
is NoticeViewHolder -> {  
    holder.onBind(data[position])  
    holder.itemView.setOnClickListener {  
  val intent = Intent(context, NoticeDetailActivity::class.java)  
        intent.putExtra("id", data[position].noticeId)  
        startActivity(context, intent, null)  
    }  
}
    }  
}

(5) CardView 클릭 시 공지는 공지 상세보기 뷰로, 약속은 약속 상세보기 뷰로 이동

override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {  
        when(holder){  
            is PromiseViewHolder -> {  
                 holder.onBind(data[position])  
                 holder.itemView.setOnClickListener {  
                     val intent = Intent(context, HomeDetailActivity::class.java)  
                     intent.putExtra("issueId", data[position].issueId)  
                     startActivity(context, intent, null)  
           }  
    }  
  
	    is NoticeViewHolder -> {  
    	          holder.onBind(data[position])  
    	          holder.itemView.setOnClickListener {  
      	               val intent = Intent(context, NoticeDetailActivity::class.java)  
              	       intent.putExtra("id", data[position].noticeId)  
                      startActivity(context, intent, null)  
                  }  
           }
    }  
}

스플래시 - 핵심 기능 구현 방법



(1) 로티 삽입을 위해 LottieAnimationView 생성
(2) 로티 재생 후 Coroutine에서 일정 시간 대기하고 LoginActivity 호출

구현 코드

  • activity_splash.xml
<com.airbnb.lottie.LottieAnimationView
        android:id="@+id/lottie"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:lottie_rawRes="@raw/splash_android_test2"
        app:lottie_autoPlay="true"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        android:scaleType="centerCrop"
        />
  • SplashActivity.kt
val lottie : LottieAnimationView = findViewById(R.id.lottie)
        lottie.playAnimation()

        CoroutineScope(Dispatchers.Main).launch {
            delay(time)
            val intent = Intent(this@SplashActivity, LoginActivity::class.java)
            startActivity(intent)
            finish()