接下上集!!,我们已经完成layout,还有上传照片了。那麽接下来我们要做的就是把选取时间的日历叫出来,好让我们的user选择邀约的时间!我们主要是透过 datePicker,然後让使用者按下date_time的edText的时候,会跳出日历让我们选取。
来看上一篇:https://ithelp.ithome.com.tw/articles/10271280
我们就直接建立setUpDatePickerDialog的funtion。
private fun setUpDatePickerDialog(){
//建立Calendar,好让我们可以把DatePicker拿到的资料放到Calendar,并且显示
val calendar = Calendar.getInstance()
//我们在这边先给它创立後,然後只要在onClick那边用show()把它叫出来
datePicker = DatePickerDialog(requireContext(),
{ _, year, month, dayOfMonth ->
//指定格式
val mFormat = "yyyy-MM-dd"
val sdf = SimpleDateFormat(mFormat, Locale.getDefault())
calendar.set(year,month,dayOfMonth)
//赋值给selectedDate,好让我们晚点传给Firestore
selectedDate = sdf.format(calendar.time)
binding.edAddInvitationDateTime.setText(sdf.format(calendar.time)) },calendar.get(Calendar.YEAR),calendar.get(Calendar.MONTH),calendar.get(Calendar.DAY_OF_MONTH))
}
在class下新增
private lateinit var datePicker: DatePickerDialog
private var selectedDate: String? = null
DatePickerDialog的参数
★我们用Calendar.getInstance()初始化的calendar会得到当下的年月份日期,所以我们这边用的get拿到的Calendar也是拿到当下的时间。
★记得不要直接把listener拿到的年月日期改成String显示喔! 因为它的月份是会-1的,譬如使用者选择的是1月,它的Month会拿到0。
然後在onCreateView呼叫
setUpDatePickerDialog()
//顺便新增EdText的listener
binding.edAddInvitationDateTime.setOnClickListener(this)
再onClick新增
binding.edAddInvitationDateTime -> {
datePicker.show()
}
这时候,我们发现
它竟然要点两次!! 这时候我们就要去layout的ed_add_invitation_date_time 新增一行
//预设是当EditText被触碰时,会得到focus,然後进到可编辑模式
//把它改成false时,它就不会得到focus,并且只响应onClick事件
android:focusableInTouchMode="false"
最後,我们发现,选择时间的时候,竟然可以让我们选择过去的时间!! 这就有点不符合逻辑啦,怎麽可以约昨天呢!!? 於是这边我们可以用设定minDate的方式来为我们强迫user只能往前选择! 依据就是今天的日期!
我们直接在setUpDatePickerDialog()新增
//直接把datePicker的最小日期设定成当前时间
datePicker.datePicker.minDate = System.currentTimeMillis()
可能有些人不太懂最小/最大时间是什麽意思
以下为DatePicker的范例!! 不用写在本App呦
那如果你要设定其他日期,概念上是都会有一个picker要用的calendar(也就是要set我们listener监听到的日期),另外一个calendar则是我们想要限制的最大/小的日期。
我们以设定最晚日期maxDate为例子,一样我们在setUpDatePickerDialog()里面新增
//新增一个显示最大日期的Calendar
val maxDateCalendar = Calendar.getInstance()
//把它设置时间,(year,month-1,day),记得月份要-1喔!
maxDateCalendar.set(2021,8,26)
//再把datePicker的最大日期设定成maxDateCalendar的时间就好啦
datePicker.datePicker.maxDate = maxDateCalendar.timeInMillis
如果要设定当下时间过多久後可以用
//新增一个显示最大日期的Calendar
val maxDateCalendar = Calendar.getInstance()
//把它设置时间,第一个参数填单位,第二个则是填Int
maxDateCalendar.add(Calendar.DAY_OF_MONTH,10)
//再把datePicker的最大日期设定成maxDateCalendar的时间就好啦
datePicker.datePicker.maxDate = maxDateCalendar.timeInMillis
Firestore的 add会自动产生新的id,set则是在写得时候就要填入id,而我们这次的做法,就是把透过add新增的文件(它就会有自动生成的id),把它update到我们资料原本里面的id,因为原本预设是""
我们先去MatchingViewModel新增以下
fun addInvitationToFireStore(fragment:AddInvitationFragment,invitation: Invitation){
Firebase.firestore.collection(Constant.INVITATION)
.add(invitation)
.addOnSuccessListener {
//我们透过HashMap来新增值
val mHashMap = HashMap<String,Any>()
mHashMap[Constant.ID] = it.id
it.update(mHashMap)
.addOnSuccessListener {
fragment.addInvitationSuccess()
}
.addOnFailureListener {
fragment.addInvitationFail(it.toString())
}
}
.addOnFailureListener {
fragment.addInvitationFail(it.toString())
}
}
我们希望文件id跟资料的id是保持一致,这样我们才可以快速找到想要的资料
新增完後,我们发现我们的Constant还需要新增一些资料
//新增collection的名称
const val INVITATION: String = "invitation"
//Invitation内id栏位
const val ID: String = "id"
最後在来到Fragment新增成功/失败的funtion
fun addInvitationSuccess(){
hideDialog()
showSnackBar(resources.getString(R.string.add_invitation_successful),false)
}
fun addInvitationFail(e: String){
hideDialog()
showSnackBar(e,true)
}
string
<string name="add_invitation_successful">上传邀约成功!</string>
既然我们都有许多editText,那我们当然要确认值
private fun validDataForm(): Boolean{
return when{
mUri.isNullOrBlank() ->{
showSnackBar(resources.getString(R.string.hint_select_your_image),true)
false
}
selectedPetType.isNullOrBlank() -> {
showSnackBar(resources.getString(R.string.hint_enter_pet_type),true)
false
} TextUtils.isEmpty(binding.edAddInvitationPetTypeDescription.text.toString().trim()) -> { showSnackBar(resources.getString(R.string.hint_enter_pet_type_description),true)
false
}
selectedArea.isNullOrBlank() -> {
showSnackBar(resources.getString(R.string.hint_enter_your_area),true)
false
}
TextUtils.isEmpty(binding.edAddInvitationDatePlace.text.toString().trim()) -> {
showSnackBar(resources.getString(R.string.hint_enter_date_place),true)
false
}
selectedDate.isNullOrBlank() ->{
showSnackBar(resources.getString(R.string.hint_enter_date_time),true)
false
}
TextUtils.isEmpty(binding.edAddInvitationNote.text.toString().trim()) ->{
showSnackBar(resources.getString(R.string.hint_enter_date_note),true)
false
}
else -> true
}
}
接下来回到 onClick
binding.btnAddInvitationFragmentSubmit ->{
showDialog(resources.getString(R.string.please_wait))
if (validDataForm()){
val invitation = Invitation(
user_id = accountViewModel.userDetail.value!!.id,
pet_image = mUri!!,
pet_type = selectedPetType!!,
pet_type_description = binding.edAddInvitationPetTypeDescription.text.toString().trim(),
area = selectedArea!!,
date_place = binding.edAddInvitationDatePlace.text.toString().trim(),
date_time = selectedDate!!,
note = binding.edAddInvitationNote.text.toString().trim()
)
matchingViewModel.addInvitationToFireStore(this,invitation)
}
}
再过来别忘了在onCreateView新增
binding.btnAddInvitationFragmentSubmit.setOnClickListener(this)
!!! 这时候我们发现一个错误,就是userDetail没有资料,尽管我们在AccountViewModel的地方是把getUserDetail的funtion放在init{}里面,但是有没有可能使用者根本还没有用到需要进到AccountViewModel的时候,就进来我们的AddInvitationFragment了呢? 所以我们就要在进到这个MatchingActivity的第一个Fragment的地方,就先把userDetail放到livedata啦!
到DashboardFragment的onCreateView来新增
accountViewModel.getUserDetail()
也别忘了在class下面新增
private val accountViewModel: AccountViewModel by sharedViewModel()
binding.toolbarAddInvitationFragment.setNavigationIcon(R.drawable.ic_baseline_arrow_back_24)
binding.toolbarAddInvitationFragment.setNavigationOnClickListener {
requireActivity().onBackPressed()
}
private fun dismissActivityActionBarAndBottomNavigationView(){
val activityInstance = this.activity as MatchingActivity
activityInstance.supportActionBar?.hide()
activityInstance.findViewById<BottomNavigationView>(R.id.nav_view).visibility = View.GONE
}
然後在 onCreateView呼叫就可以啦!!
大功告成!!!! 明天预计会在我们的HomeFragment新增我们有发成功的资料!!
<<: 追求JS小姊姊系列 Day10 -- 如果时间能重来,我不想跟工具人聊天(下)
>>: 聊聊structure concurrency 结构化并发
● 接下来几章都是先以模拟帐户作登入,尚未使用正式证券户帐户登入 如果尚未有永丰金证券帐户的朋友,但...
在前面我们介绍到了各种建立以及产生pod的方式,但是当你已经建构好一个系统後,写好的程序要更新以及测...
本文将於赛後同步刊登於笔者部落格 有兴趣学习更多 Kubernetes/DevOps/Linux 相...
在Vue的世界中,是由一个又一个的元件所构成,而我们可以透过自订元件的方式量身打造客制化的元件并进行...
Aloha~又是我少女人妻 Uerica!今天是教师节啊~大家小时候都会写感谢恩师的卡片吗?记得刚上...