본문 바로가기
Android/[Kotlin]

[Android][Kotlin] Schedule App - Fragment(1)

by PhoB 2023. 5. 9.

이전에 메인 액티비티에서 프레그먼트를 사용하기 위해 프레임 레이아웃을 설정해 주었습니다.

그렇다면 오늘은 그 프레임 레이아웃에 들어갈 프레그먼트 레이아웃을 구성해 보도록 합시다

이번에 구성해볼 프레그먼트 레이아웃은 스케쥴을 추가하는 프레그먼트입니다.

구성은

  • 일정 제목
  • 시작일,종료일(DatePicker,TimePicker사용)
  • 약속장소
  • 지도버튼
  • 확인, 취소 버튼

이렇게 총 5가지로 구성할 생각입니

우선 위젯들의 종류에맞게 xml을 작성해 주도록 합시다.

<EditText
    android:id="@+id/title"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:hint="일정 제목을 입력하세요"
    android:textSize="30dp"
    />
<TextView
    android:id="@+id/start_date"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="시작일"
    android:layout_marginTop="20dp"
    android:layout_below="@+id/title"
    android:textSize="20dp"
    android:textStyle="bold"
    android:textColor="@color/black"
    />
<TextView
    <!-- 종료일 텍스트뷰 -->
    />
<Button
    android:id="@+id/set_date"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignBaseline="@id/start_date"
    android:layout_alignParentEnd="true"
    android:layout_toEndOf="@id/start_date"
    android:layout_marginLeft="40dp"
    android:contentDescription="시작일 설정"
    android:background="@drawable/button_rectangle"
    />
<Button
    <!-- 종료일 설정 버튼 -->
    />

맨 아래의 버튼 두개는 시작일과 종료일을 설정하는 DatePicker와 TimePicker를 활성화(확장)시키는 역할을 위해 버튼으로 설정하였습니다.

Date&TimePicker의 xml입니다.

<DatePicker
    android:id="@+id/start_picker"
    android:layout_width="wrap_content"
    android:layout_height="0dp"
    android:datePickerMode="spinner"
    android:calendarViewShown="false"
    android:layout_below="@+id/start_date"
    android:autoHandwritingEnabled="true"
    />
<TimePicker
    android:id="@+id/start_time"
    android:layout_width="wrap_content"
    android:layout_height="0dp"
    android:timePickerMode="spinner"
    android:layout_toRightOf="@id/start_picker"
    android:layout_below="@id/start_date"
    />
    <!-- End Date&TimePicker는 id와 위치만 다를 뿐 나머지는 같다-->

캘린더 형식으로 하기엔 화면이 넘칠것 같아서 android:timePickerMode = "spinner"로 설정해 주었습니다.

이후 장소와 지도 관련 위젯들입니다.

<TextView
    android:id="@+id/place"
    <!-- wrap_content -->
    android:text="장    소"
    <!-- black , 20dp , bold -->
    android:layout_below="@id/end_picker"
    android:layout_marginTop="40dp"
    />
<TextView
    android:id="@+id/place_text"
    android:layout_width="230dp"
    android:layout_height="wrap_content"
    android:layout_alignBaseline="@+id/place"
    android:layout_toStartOf = "@+id/map_button"
    android:layout_marginRight="10dp"
    android:hint="장소 입력"
    android:textSize="25dp" />

<ImageButton
    android:id="@+id/map_button"
    <!-- 50dp -->
    android:layout_alignBottom="@id/place_text"
    android:background="@drawable/outline_location_on_24"
    android:layout_alignParentEnd="true"
    android:contentDescription="장소 설정"
    />

최종 레이아웃이다.

이제 프레그먼트 클래스 파일을 작성해보겠습니다

프레그먼트이므로 Fragment()를 상속해주었습니다.

class Add_schedule_fragment : Fragment() {}

그리고 역시 뷰 바인딩을 해주었습니다.

private lateinit var binding: FragmentAddScheduleFragmentBinding
private val mBinding get() = binding!!

기본적으로 프레그먼트는 onCreate()가 있긴하지만 onCreateView()를 사용하여 그 기능을 대신했습니다.

onCreateView()는 Fragment가 화면에 그려질 때 Fragment의 레이아웃을 만드는데 사용됩니다. 이 메소드는 Fragment의 뷰 계층 구조를 인플레이트하고 구성합니다.

onCreateView()에서 해줄 것은 TimPicker들이 디폴트로 사용하자니 시간을 오전 00시 오후00시 이렇게 밖에 설정하지 못해서 오전 오후를 사용하지 않고 24시간 기준으로 설정하도록 바꿔주는 코드와 Picker를 열었을때 현재시간으로 설정해주는 메소드를 호출해 주었습니다.

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
    binding = FragmentAddScheduleFragmentBinding.inflate(inflater, container, false)
    mBinding.startTime.setIs24HourView(true) //24시간 타입으로 설정
    mBinding.endTime.setIs24HourView(true)
    setDefaultDate() //디폴트 값은 현재 날짜 및 시간
    return mBinding.root
}
fun setDefaultDate(){
    val currentDate = SimpleDateFormat("yyyy년 MM월 dd일 (E) a hh:mm", Locale.getDefault()).format(Date())
    mBinding.setDate.text= currentDate
    mBinding.setEndDate.text = currentDate
}

setDefaultDate() 메소드입니다. Date&TimePicker에 표시되는 형식에 맞춰서 SimpleDateFormat의 타입을 정해주었습니다.

 

이후 onViewCreated()메소드를 통해서 onCreateView()를통해 생성된 View의 요소들을 참조하여 view가 생성된 이후에 사용할 코드들을 작성합니다. 예를들어 인텐트라던지, DB에 데이터 삽입 같은 행동들이 있겠네요

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    var WigetHeight: Int?  = 0

    mBinding.setDate.setOnClickListener {
       WigetHeight =  mBinding.startPicker.layoutParams.height
        if(WigetHeight != 0){
            setLayoutHeightWrapContent(mBinding.startPicker,mBinding.startTime,false,300)
        }else{
            setLayoutHeightWrapContent(mBinding.startPicker,mBinding.startTime,true,300)
        }
    }
    //종료일도 동일

    //시간값 조절
    mBinding.startPicker.setOnDateChangedListener { view,year,month,dayOfMonth ->
        updateDate(mBinding.startPicker,mBinding.startTime,mBinding.setDate)
    }
    //3개 더있음
}

기존코드에는  DB와 연결 및 데이터 추가하는 코드와 카카오맵에 인텐트하는 코드도 있었지만 이후에 해당 부분을 다루면서 추가할 계획입니다

일단 picker들의 높이를 지정해주어 확장및 축소를 담당하는 setLayoutHeightWrapContent()메소드를 작성해주겠습니다.

fun setLayoutHeightWrapContent(layout: View , layout2 :View, type : Boolean) {
    val layoutParams = layout.layoutParams
    val layoutParams2 = layout2.layoutParams

    if (type == false){
        layoutParams.height = 0
        layoutParams2.height = 0
    }else{
        layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT
        layoutParams2.height = ViewGroup.LayoutParams.WRAP_CONTENT
    }

    layout.layoutParams = layoutParams
}

DatePicker와 TimePicker 두개 위젯의 높이를 조절해 주어야하니 파라미터로 2개의 위젯을 받고 활성화 상태와 비활성화 상태에 따라서 높이를 변화시켜주었습니다.

그리고 그 다음은 Picker에서 설정한 날짜와 시간을 텍스트로 가져와 위젯에 설정해주는 updateDate()메소드를 작성해 주겠습니다.

fun updateDate(datePicker: DatePicker, timePicker: TimePicker , setView : Button) {
    //DatePicker에서 설정한 날짜들 가져오기
    val year = datePicker.year
    val month = datePicker.month + 1
    val day = datePicker.dayOfMonth

    //TimePicker에서 설정한 시간값 가져오기
    val hour = timePicker.hour
    val minute = timePicker.minute

    //형식 설정
    // Date 객체를 만들어서 SimpleDateFormat으로 형식에 맞게 포맷팅
    val date = Date(year - 1900, month - 1, day, hour, minute)
    val dateString = dateFormat.format(date)

    //설정
    setView.text = dateString
}

dateFormat은 전역변수로 설정해 주었습니다

private val dateFormat = SimpleDateFormat("yyyy년 MM월 dd일 (E) a hh:mm", Locale.getDefault())

그리고 마지막으로 확인버튼 누르면 다시 일정 리스트로 돌아가는 메소드를 작성해 주겠습니다~

fun moveFrag(){
        val recyclerViewFragment = RecycleView_Frag()
        val transaction = parentFragmentManager.beginTransaction()
        transaction.setCustomAnimations(R.anim.enter_animate, R.anim.exit_animate)
        transaction.replace(R.id.main_frame, recyclerViewFragment).addToBackStack(null).commit()
    }

이렇게해서 마무리가 되었습니다

현재까지 구현된 기능은 Date&TimePicker의 확장 및 축소 기능, 그리고 Picker에서 설정한 값들을 위젯에 텍스트로 설정하는 기능과 "확인"버튼을 누르면 다시 일정이 기록된 리스트로 돌아가는 기능이 구현되었습니다.