티스토리 뷰
Clone project - Book App - Step 1 (RecyclerView w Filter)
Agrafenaaa 2021. 10. 25. 02:08결과화면
1. ModelCategory
Firebase DB의 Category에 저장될 항목 설정 후 생성자 호출
2. AdapterCategory
Admin 계정 접속 시 보이는 카테고리 목록 RecyclerView용 Adapter
- Context 변수 선언
- context와 categoryArrayList 생성자 호출
- inner class인 HolderCategory 통하여 카테고리명과 삭제 휴지통 이미지 아이콘 ui 초기화
- row_category(카테고리 목록) 바인딩
- ViewHolder 바인딩 작업 (각 항목은 arraylist의 position에 따른 model로 선언)
- 삭제처리는 firebase의 removeValue()활용
- Filterable 상속
class AdapterCategory: RecyclerView.Adapter<AdapterCategory.HolderCategory>, Filterable {
private val context: Context
public var categoryArrayList: ArrayList<ModelCategory>
private var filterList: ArrayList<ModelCategory>
private var filter: FilterCategory? = null
private lateinit var binding: RowCategoryBinding
// constructor
constructor(context: Context, categoryArrayList: ArrayList<ModelCategory>) {
this.context = context
this.categoryArrayList = categoryArrayList
this.filterList = categoryArrayList
}
// inflate row_category
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HolderCategory {
binding = RowCategoryBinding.inflate(LayoutInflater.from(context), parent, false)
return HolderCategory(binding.root)
}
// data getter and setter w click handler
override fun onBindViewHolder(holder: HolderCategory, position: Int) {
// get data
val model = categoryArrayList[position]
val id = model.id
val category = model.category
val uid = model.uid
val timestamp = model.timestamp
// set data
holder.categoryTv.text = category
// delete btn click listener
holder.deleteBtn.setOnClickListener{
// alert message
val builder = AlertDialog.Builder(context)
builder.setTitle("Delete")
.setMessage("Do you want to delete?")
.setPositiveButton("Confirm"){a, d ->
Toast.makeText(context, "Deleting", Toast.LENGTH_SHORT).show()
deleteCategory(model, holder)
}
.setNegativeButton("Cancel"){a, d ->
a.dismiss()
}
.show()
}
}
private fun deleteCategory(model: ModelCategory, holder: HolderCategory) {
var id = model.id
val ref = FirebaseDatabase.getInstance().getReference("Categories")
ref.child(id)
.removeValue()
.addOnSuccessListener {
Toast.makeText(context, "Deleted successfully", Toast.LENGTH_SHORT).show()
}
.addOnFailureListener { e ->
Toast.makeText(context, "Unable to delete. Error: ${e.message}", Toast.LENGTH_SHORT).show()
}
}
override fun getItemCount(): Int {
return categoryArrayList.size
}
// Viewholder for row_category UI
inner class HolderCategory(itemView: View): RecyclerView.ViewHolder(itemView){
// initialize ui view
var categoryTv: TextView = binding.categoryTv
var deleteBtn: ImageButton = binding.deleteBtn
}
override fun getFilter(): Filter {
if(filter == null){
filter = FilterCategory(filterList, this)
}
return filter as FilterCategory
}
}
3. FilterCategory
- filterList와 adapterCategory 선언, 생성자 호출
- Filter를 상속받아 구현하는 performFiltering에 찾는 값이 null 혹은 빈값인지 확인 후 각 처리할 것(대문자 처리 필요하며 null 혹은 공백일 경우 전체 결과값을 추출해야 하므로 filerList의 값과 수를 반환)
- publishingResults에는 값이 변할 경우에 대비하여 각 값 설정
class FilterCategory: Filter {
// arraylist to search
private var filterList: ArrayList<ModelCategory>
// adapter where filter needs to be implemented
private var adapterCategory: AdapterCategory
// constructor
constructor(filterList: ArrayList<ModelCategory>, adapterCategory: AdapterCategory) : super() {
this.filterList = filterList
this.adapterCategory = adapterCategory
}
override fun performFiltering(constraint: CharSequence?): FilterResults {
var constraint = constraint
val results = FilterResults()
// value are NOT nullable and empty
if(constraint != null && constraint.isNotEmpty()){
// change to upper case
constraint = constraint.toString().uppercase()
val filteredModels: ArrayList<ModelCategory> = ArrayList()
for(i in 0 until filterList.size){
// validate data
if(filterList[i].category.uppercase().contains(constraint)){
// add
filteredModels.add(filterList[i])
}
}
results.count = filteredModels.size
results.values = filteredModels
} else{ // in case of null or empty
results.count = filterList.size
results.values = filterList
}
return results
}
override fun publishResults(constraint: CharSequence?, results: FilterResults) {
// apply filter changes
adapterCategory.categoryArrayList = results.values as ArrayList<ModelCategory>
// notify of them
adapterCategory.notifyDataSetChanged()
}
}
4. DashboardAdminActivity
- categoryArrayList와 adapterCategory 각 전역변수 선언
- filter 기능 - addTextChangeListener에 textWatcher 상속 받은 후 onTextChanged 이외 공백으로 남기기
- Dashboard 접속 시 초기화면용 카테고리 불러오기
class DashboardAdminActivity : AppCompatActivity() {
// arraylist to hold categories
private lateinit var categoryArrayList: ArrayList<ModelCategory>
// adapter
private lateinit var adapterCategory: AdapterCategory
// initialize firebase auth
firebaseAuth = FirebaseAuth.getInstance()
checkUser()
loadCategories()
// search event
binding.searchEt.addTextChangedListener(object: TextWatcher{
override fun beforeTextChanged(s: CharSequence?, p1: Int, p2: Int, p3: Int) {
}
override fun onTextChanged(s: CharSequence?, p1: Int, p2: Int, p3: Int) {
try {
adapterCategory.filter.filter(s)
}catch(e: Exception){
}
}
override fun afterTextChanged(s: Editable?) {
}
})
private fun loadCategories() {
// initialize arraylist
categoryArrayList = ArrayList()
// get all saved categories from firebase db
val ref = FirebaseDatabase.getInstance().getReference("Categories")
ref.addValueEventListener(object: ValueEventListener{
override fun onDataChange(snapshot: DataSnapshot) {
// clear list before adding data
categoryArrayList.clear()
for(ds in snapshot.children){
// get data
val model = ds.getValue(ModelCategory::class.java)
// add to arraylist
categoryArrayList.add(model!!)
}
// adapter
adapterCategory = AdapterCategory(this@DashboardAdminActivity, categoryArrayList)
// recyclerview
binding.categoriesRv.adapter = adapterCategory
}
override fun onCancelled(error: DatabaseError) {
}
})
}
느낀점: RecyclerView의 Adapter가 이제야 이해가 얼추 가는 듯하다 그러나 filter를 적용할 경우 재차 원점으로 돌아가는 느낌이며 흡사 스프링할 때 pagination과 찾기의 고통이 생각난다😅😅😅 Ну что поделать? Пока с большим удовольствием от нулевой безопасности адаптируюсь)))))
Ref: https://www.youtube.com/channel/UCT132T980-1lhm0hcZFy4ZA
'App > Android Native' 카테고리의 다른 글
Clone project - Book App - Step 3 (update/delete book info) (0) | 2021.11.01 |
---|---|
Clone project - Book App - Step 2 (uploading/loading pdf w firebase cloud) (0) | 2021.11.01 |
Android - Unsplash API w retrofit2 - 2 (0) | 2021.10.14 |
Android - Unsplash API w retrofit2 - 1 (0) | 2021.10.08 |
KOTLIN BASIC V (0) | 2021.10.08 |
- Total
- Today
- Yesterday
- laravel9
- FirebaseConfigurationForMultipleBuildTypes
- flutter_secure_storage_issue_iOS
- RunAFlutterProjectIniPhoneFromVSCode
- mvvm
- dagger-hilt
- querydslQclass
- Laravel
- Kotlin
- phplaravel
- querydsl5.0.0jakarta
- android_app_links
- FlutterWirelessDebuginAOS
- flutter
- unsplashAPI
- android_app_links_domain
- retrofit_generator_conflicts_with_freezed
- querydslKotlinError
- futter_api
- android_app_link_domain_works_with_adb_but_not_works_with_browser
- retrofit_generator
- flutter_storage_not_working_for_the_first_time
- WirelessDebug
- android_domain
- Android
- AndroidWirelessDebug
- MultipleFirebaseEnvironments
- retrofit_toJson()_error
- KotlinFlow
- flutter_android_app_links
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |