반응형
Greensky0026
삽질러의 대환장 공사판
Greensky0026
전체 방문자
오늘
어제
  • 분류 전체보기 (241)
    • Language (56)
      • JAVA (13)
      • Swift (38)
      • Kotlin (4)
      • Dart (0)
      • PHP (0)
      • JavaScript (1)
    • IDE & Framework (92)
      • Spring (10)
      • Android (48)
      • iOS (8)
      • NodeJS (1)
      • CodeIgniter (3)
      • Flutter (1)
      • 분류중 (18)
    • Infra (8)
    • Database (12)
    • VCS (4)
    • Debug Log (34)
      • java (7)
      • swift (3)
      • Android (9)
      • Web (7)
      • 삽질기 (7)
    • Others (19)
      • 코딩테스트 풀이 (0)
      • IT 이야기 (18)
    • 쉼터 (2)
    • 개발공부 (14)
      • Network (1)
      • 자료구조와 알고리즘 (2)
      • Code design (8)
      • ETC (1)
      • 아카이브 (1)

블로그 메뉴

    공지사항

    • 프로그래머스 코딩 테스트 관련글 비공개 처리

    인기 글

    태그

    • 프로그래밍
    • 구축
    • Java
    • ios
    • swfit
    • kotlin
    • 코딩테스트
    • swift
    • 개발
    • Android
    • level1
    • map
    • JSP
    • xcode
    • reduce
    • 공부
    • 프로그래머스
    • 예제
    • IT
    • 타입

    최근 댓글

    최근 글

    티스토리

    hELLO · Designed By 정상우.
    Greensky0026

    삽질러의 대환장 공사판

    [Kotlin] RecyclerView (2) - Filter와 SerachView로 검색기능 구현
    IDE & Framework/Android

    [Kotlin] RecyclerView (2) - Filter와 SerachView로 검색기능 구현

    2022. 2. 5. 23:26
    반응형

     RecyclerView 시리즈의 두번째 포스팅입니다.

    이번엔 SerachView, Filterable 위젯을 사용해 검색기능을 구현해 보겠습니다.

     

    SerachView는 커스텀하기가 쉽지 않아 EditText로 직접 구현하는 경우도 굉장히 많습니다.

    하지만 공식문서를 찾아보시면 생각보다 많은 속성이 있으니, 필요에 따라 쓰시면 되겠습니다.

    정리가 잘 된 블로그가 있어서 링크 공유드립니다.

    https://landroid.tistory.com/5

     

    SearchView, 속성 사용법

    안녕하세요! Landroid입니다~! 보통 안드로이드에서 검색 기능을 구현할 때 많이들 사용하시는데요. 의외로 자료가 많이 없어 구현하는데 애를 먹는 뷰이기도 합니다. 그래서 오늘은 SearchView 사용

    landroid.tistory.com

     

     이번 포스팅의 시퀀스 다이어그램을 한번 그려봤습니다..ㅎ

    자세한 내용은 이제 서술하도록 하겠습니다!

     

    재료

    1. SerachView

    2. SerachView의 OnQueryTextListener

    3. Adapter에 Filter 구현

        ㄱ. filterable 구현 및 원본/검색결과 배열을 구분

        ㄴ. Filter를 상속받는 class 구현

     

    재료 구현

    1. SerachView

       <SearchView
            android:id="@+id/search_view_phone_book"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="10dp"
            android:paddingTop="5dp"
            android:paddingBottom="5dp"
            android:iconifiedByDefault="false"/>

      오른쪽 그림의 빨간 테두리로 표시한것이 SeachView입니다.

    리스트가 있는 레이아웃에 추가해 줍니다.

    iconifiedByDefault속성을 사용해 밑줄쳐진 검색필드를 검색할때만 활성화 시킬 수 있습니다.

    기본값은 true이므로, SeachView를 아이콘화 시키고 싶다면 해당 속성을 따로 입력하지 않아도 됩니다.

     

    2. SerachView의 OnQueryTextListener

    var searchViewTextListener: SearchView.OnQueryTextListener =
        object : SearchView.OnQueryTextListener {
            //검색버튼 입력시 호출, 검색버튼이 없으므로 사용하지 않음
            override fun onQueryTextSubmit(s: String): Boolean {
                return false
            }
    
            //텍스트 입력/수정시에 호출
            override fun onQueryTextChange(s: String): Boolean {
                phoneBookListAdapter.getFilter().filter(s)
                Log.d(TAG, "SearchVies Text is changed : $s")
                return false
            }
        }

     SerachView에 문자를 입력하거나, 검색버튼을 눌렀을 때의 이벤트 리스너입니다.

    저는 입력할때마다 검색기능을 사용할 것이므로 onQueryTextChange만 사용하겠습니다.

    onQueryTextChange에 나오는 getFilter는 아래에 ItemFilter를 구현하며 만들어지는 메소드입니다.

     

     여기까지 해서 SerachView와 OnQueryTextListener의 작성이 끝났으므로,

    SerachView에 OnQueryTextListener를 부착시켜 주시면 됩니다.

    search_view_phone_book.setOnQueryTextListener(searchViewTextListener)

    3. Adapter에 Filter 구현

    ㄱ. filterable 구현 및 원본/검색결과 배열을 구분

     Adapter를 상속받은 PhoneBookListAdapter에 innerClass로 Filter를 상속받는 ItemFilter를 구현하겠습니다.

    주의점은, 원본 배열은 유지해야 하고, 사용자에게 보여줄 배열을 추가로 만들어야 합니다.

    그리고 저는 검색기능을 사용하지 않는다면 전체 배열을 보여줄 것이므로,

    복제한 배열의 초기값은 원본배열과 동일하게 구현하겠습니다.

    class PhoneBookListAdapter(var persons: ArrayList<Person>, var con: Context) :
        RecyclerView.Adapter<PhoneBookListAdapter.ViewHolder>(), Filterable {
        var TAG = "PhoneBookListAdapter"
    
        var filteredPersons = ArrayList<Person>()
        var itemFilter = ItemFilter()
        
        init {
            filteredPersons.addAll(persons)
        }
        //...
    }

     원본 persons를 복제한 filteredPersons배열과, 곧 구현할 ItemFilter의 인스턴스를 선언해 주었습니다.

    filteredPersons배열을 사용자에게 보여줘야 하므로,

    이전에 어댑터가 persons를 참조한걸 싹 다 filteredPersons를 참조하도록 수정하셔야 합니다.

    Filterable interface의 구현에 필요한 메서드 getFilter도 재정의 해주면 filter를 상속받는 class만 만들어주면 됩니다.

    override fun getFilter(): Filter {
        return itemFilter
    }

     

    ㄴ. Filter를 상속받는 class 구현

     Filter를 상속받는 클래스 ItemFilter 클래스를 Inner class로 구현했습니다.

    Filter는 performFiltering과 publishResults 두가지 메소드만 구현해주면 됩니다.

    이름 그대로, performFiltering는 입력받은 문자열에 대한 처리를,

    publishResults는 처리에 대한 결과물을 다루게 됩니다.

     

     performFiltering부터 보겠습니다.

    SeachView에서 입력받은 문자열 charSequence에 따른 처리를 하면 되겠습니다.

    우리는 검색 결과를 FilterResult()의 value와 count에 담아 반환하면 publishResults가 받게 됩니다.

    참고로, FilterResult()는 Fliter의 내부 클래스로, Objcet타입의 value, int타입의 count변수 두가지로만 구현되어 있습니다.

     

    저는 검색어가 없다면 원본 배열을, 2글자 이하라면 이름으로만, 3글자 이상이라면 이름+전화번호로 검색하게 하겠습니다.

    //-- filter
    
    inner class ItemFilter : Filter() {
        override fun performFiltering(charSequence: CharSequence): FilterResults {
            val filterString = charSequence.toString()
            val results = FilterResults()
            Log.d(TAG, "charSequence : $charSequence")
    
            //검색이 필요없을 경우를 위해 원본 배열을 복제
            val filteredList: ArrayList<Person> = ArrayList<Person>()
            //공백제외 아무런 값이 없을 경우 -> 원본 배열
            if (filterString.trim { it <= ' ' }.isEmpty()) {
                results.values = persons
                results.count = persons.size
    
                return results
            //공백제외 2글자 이하인 경우 -> 이름으로만 검색
            } else if (filterString.trim { it <= ' ' }.length <= 2) {
                for (person in persons) {
                    if (person.name.contains(filterString)) {
                        filteredList.add(person)
                    }
                }
            //그 외의 경우(공백제외 2글자 초과) -> 이름/전화번호로 검색
            } else {
                for (person in persons) {
                    if (person.name.contains(filterString) || person.phoneNumber.contains(filterString)) {
                        filteredList.add(person)
                    }
                }
            }
            results.values = filteredList
            results.count = filteredList.size
    
            return results
        }
    
        //...
    }

     

     마지막으로 publishResults입니다.

    performFiltering이 빈환한 FilterResult()클래스를 매개변수로 받아 처리하면 됩니다.

    검색의 결과를 보여줘야 하므로,

    Adapter 클래스에 선언한 복제 배열을 초기화 한뒤,

    FilterResult의 value의 값을 모두 복사하고,

    값이 바뀌었음으로 어댑터에 알리면 구현은 끝이 납니다.

    //-- filter
    
    inner class ItemFilter : Filter() {
    
    	//...
    
        @SuppressLint("NotifyDataSetChanged")
        override fun publishResults(charSequence: CharSequence?, filterResults: FilterResults) {
            filteredPersons.clear()
            filteredPersons.addAll(filterResults.values as ArrayList<Person>)
            notifyDataSetChanged()
        }
    }

     

    결과

     

     


    RecyclerView 시리즈 다른글 보러가기

    2022.01.30 - [IDE & Framework/Android] - [Kotlin] RecyclerView (1) - 기본 예제

     

    [Kotlin] RecyclerView (1) - 기본 예제

    새 시리즈 포스팅입니다. 기본 에제 - 좌/우 스와이프로 삭제/통화 걸기 구현 - 검색 구현 - AAC MVVM적용 이렇게 총 네편으로 포스팅 할 예정입니다.  RecyclerView란?  ViewHolder 패턴을 사용해 아이템

    greensky0026.tistory.com

    2022.02.08 - [IDE & Framework/Android] - [Kotlin] RecyclerView (3) - ItemTouchHelper로 Swipe event 구현

     

    [Kotlin] RecyclerView (3) - ItemTouchHelper로 Swipe event 구현

     RecyclerView 마지막 포스팅입니다. 왼쪽에서 오른쪽으로 스와이프를 하면 통화를, 반대로 오른쪽에서 왼쪽으로 스와이프를 하면 메세지 전송이 되도록 해보겠습니다. 필요한 과정 1. item_phonebook.x

    greensky0026.tistory.com

     

     

    전체 코드

    https://github.com/gr2nsky/RecyclerViewPractice/tree/Filterable

     

    GitHub - gr2nsky/RecyclerViewPractice

    Contribute to gr2nsky/RecyclerViewPractice development by creating an account on GitHub.

    github.com

     

    반응형
    저작자표시 비영리 (새창열림)

    'IDE & Framework > Android' 카테고리의 다른 글

    [Kotlin] PhoneStateListener deprecated, TelephonyCallback로 대체하기  (0) 2022.02.13
    [Kotlin] RecyclerView (3) - ItemTouchHelper로 Swipe event 구현  (0) 2022.02.08
    [Kotlin] ViewPager2 사용하기  (0) 2022.01.31
    [Kotlin] RecyclerView (1) - 기본 예제  (0) 2022.01.30
    Android Background Service 작업 제한  (1) 2022.01.22
      'IDE & Framework/Android' 카테고리의 다른 글
      • [Kotlin] PhoneStateListener deprecated, TelephonyCallback로 대체하기
      • [Kotlin] RecyclerView (3) - ItemTouchHelper로 Swipe event 구현
      • [Kotlin] ViewPager2 사용하기
      • [Kotlin] RecyclerView (1) - 기본 예제
      Greensky0026
      Greensky0026
      점이 모여 선이 된다. 내 삽질도 언젠간 거대한 지하 도시가 되겠지!

      티스토리툴바