Nuke Olaf - Log Store
[Android] 안드로이드 - Api 를 사용한 MultiAutoCompleteTextView (태그자동완성 기능) 본문
[Android] 안드로이드 - Api 를 사용한 MultiAutoCompleteTextView (태그자동완성 기능)
NukeOlaf 2020. 5. 11. 00:58안드로이드에서 EditText 에 태그 자동완성 기능을 추가하려고 한다.
사용자가 입력하는 단어와 관련있는 태그를 하단에 리스트로 뿌려줄 것이다.
이럴 때 사용하는 View 가 바로 AutoCompleteTextView 이다.
이때, AutoCompleteTextView 를 extend 하는 EditText 를 사용하면, 사용자가 전체 텍스트를 입력하지 않아도 입력하는 텍스트와 연관된 단어들을 제안할 수 있다.
AutoCompleteTextView 는 한 개의 단어만을 자동으로 완성시키지만, MultiAutoCompleteTextView 는 콤마로 구분된 여러개의 단어들을 자동으로 완성시켜줄 수 있다.
0. multiAutoCompleteTextView 기본적인 사용 예시
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// contries 라는 이름의 Array 초기화
val countries = resources.getStringArray(R.array.countries_array)
ArrayAdapter<String>(
this,
android.R.layout.simple_list_item_1,
countries
).also { adapter ->
autocomplete.setAdapter(adapter) // ArrayAdpater 는 검색어 목록을 보여주는데 사용
autocomplete.setTokenizer(SpaceTokenizer()) // Tokenizer 는 단어들을 띄어쓰기로 구분
}
}
1. activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<MultiAutoCompleteTextView
android:id="@+id/autocomplete"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:completionThreshold="2"
android:completionHint="검색결과"
android:hint="검색어를 입력해주세요"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toTopOf="@id/autocomplete"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
completionHint 는 검색 시 검색 리스트 맨 하단에 뜨는 문장
compeltionThreshold 는 검색어가 최소 몇자리일때 자동완성 기능을 실행할 것인가 (compeltionThreshold 가 2로 되어있다면, 1글자짜리 문자 상태에서는 검색이 시작되지 않고, 2글자가 되는 순간부터 자동완성 검색이 시작됨)
2. Adpater
사용자가 EditText 에 검색어를 입력하기 시작하면, 해당 검색어와 연관된 추천 검색어 목록이 EditText 하단에 리스트뷰로 보여진다. 이때 검색어 목록을 리스트뷰로 보여주도록 하기 위해 Adpater 를 사용한다.
0번의 예시와 같이 기본적인 ArrayAdapter 를 사용할 수도 있고, ArrayAdapter 를 상속받는 커스텀 Adapter 를 작성하여 사용할수도 있다.
class AutoSuggestAdapter(
context: Context,
resource: Int
) : ArrayAdapter<String>(context, resource), Filterable {
private var suggests: MutableList<String> = mutableListOf()
fun setSuggests(list: List<String>) {
suggests.clear()
suggests.addAll(list)
}
override fun getCount(): Int {
return suggests.size
}
override fun getItem(position: Int): String? {
return suggests[position]
}
override fun getFilter(): Filter {
return object : Filter() {
override fun performFiltering(constraint: CharSequence?): FilterResults {
val filterResults = FilterResults()
if (constraint != null) {
filterResults.apply {
values = suggests
count = suggests.size
}
}
return filterResults
}
override fun publishResults(constraint: CharSequence?, results: FilterResults?) {
if (results != null && results.count > 0) {
notifyDataSetChanged()
} else {
notifyDataSetInvalidated()
}
}
}
}
}
3. Tokenizer
MultiAutoCompleteTextView 는 Tokenizer 를 사용해야 한다.
tokenizer 는 기본적으로 제공하는 commaTokenizer() 를 사용할 수도 있고, Tokenizer 를 상속받아 커스텀하여 사용할 수도 있다. tokenizer 는 단어들을 구별할만한 특정한 기호들을 정해서 단어들을 구분해줄 수 있는 기능을 한다.
나는 콤마가 아닌 공백으로 단어들을 구별하고 싶어 SpaceTokenizer 를 커스텀하여 사용했다.
class SpaceTokenizer : MultiAutoCompleteTextView.Tokenizer {
override fun findTokenStart(text: CharSequence?, cursor: Int): Int {
var i = cursor
while (i > 0 && text!![i - 1] != ' ') {
i--
}
while (i < cursor && text!![i] == ' ') {
i++
}
return i
}
override fun findTokenEnd(text: CharSequence?, cursor: Int): Int {
var i = cursor
val len = text!!.length
while (i < len) {
if (text[i] == ' ') {
return i
} else {
i++
}
}
return len
}
override fun terminateToken(text: CharSequence?): CharSequence {
var i = text!!.length
while (i > 0 && text[i - 1] == ' ') {
i--
}
return if (i > 0 && text[i - 1] == ' ') {
text
} else {
if (text is Spanned) {
val sp = SpannableString("$text ")
TextUtils.copySpansFrom(
text, 0, text.length,
Any::class.java, sp, 0
)
sp
} else {
"$text "
}
}
}
}
4. AutoSuggestAdapter 를 사용하여 서버에서 검색어 추천목록을 가져오는 MultiAoutoTextView 구현하기
class MainActivity : AppCompatActivity() {
companion object {
private const val TAG = "ActivityPostSecond"
private const val TRIGGER_AUTO_COMPLETE = 200
private const val AUTO_COMPLETE_DELAY = 300L
}
private lateinit var adpater: AutoSuggetAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_post_second)
initMutliAutoCompleteTextView()
}
private fun initMutliAutoCompleteTextView() {
adapter = AutoSuggestAdapter(this, android.R.layout.simple_list_item_1)
val handler = Handler(Handler.Callback { msg ->
if (msg.what == TRIGGER_AUTO_COMPLETE) {
if (autocomplete.text.isNullOrEmpty()) {
getSuggestionApi(autocomplete.text.toString())
}
}
false
})
autocomplete.apply {
setAdapter(adapter)
setTokenizer(SpaceTokenizer())
addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable?) {}
override fun beforeTextChanged(
s: CharSequence?,
start: Int,
count: Int,
after: Int
) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
handler.removeMessages(TRIGGER_AUTO_COMPLETE)
handler.sendEmptyMessageDelayed(
TRIGGER_AUTO_COMPLETE,
AUTO_COMPLETE_DELAY
)
}
})
}
}
private fun getSuggestionsApi(query: Text) {
RetrofitClient.getTagRecommendation(query)
.enqueue(object :
Callback<List<String>> {
override fun onResponse(
call: Call<List<String>>,
response: Response<List<String>>
) {
val body = response.body()
if (body != null && response.isSuccessful) {
adapter.setSuggests(body)
} else {
// 통신 에러 처리
}
}
override fun onFailure(call: Call<List<String>>, t: Throwable) {
// 통신 에러 처리
}
})
}
}
참고 사이트 >>>
https://en.proft.me/2016/10/20/autocompletetextview-and-multiautocompletetextview/
http://www.codeplayon.com/2019/06/android-multiautocompletetextview-with-api-example-tutorial/
https://www.truiton.com/2018/06/android-autocompletetextview-suggestions-from-webservice-call/
https://sharp57dev.tistory.com/12
https://parkho79.tistory.com/83
'Android' 카테고리의 다른 글
[Android] 안드로이드 - DataBinding 에서 String Format 적용 (0) | 2020.05.31 |
---|---|
[Android] 안드로이드 - AAC View Model 과 Live data (0) | 2020.05.26 |
[Android] 안드로이드 - 액티비티 중복 실행 방지 (0) | 2020.05.08 |
[Android] 안드로이드 카카오 로그아웃/탈퇴 코드 (0) | 2020.05.08 |
[Android] 안드로이드 - 다이얼로그로 웹 뷰 띄우기 (0) | 2020.05.08 |