일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- pubspec
- Flutter
- 배움순서
- Android
- 플러터
- 에러 메시지를 잘보자 ^^
- 2D graphics library
- permission_handler
- retorift
- 테스트 주도 개발론
- dart
- 플러터 테스트
- 다트 테스트
- TDD 개발 방법론
- 다트
- 토큰갱신
- 안드로이드를 위한
- 인코딩방지
- Parameter specified as non-null is null
- pubspec.yaml
- dart test
- widget test
- 8시간 삽질
- Refresh Tocken
- Same parameter
- 객체 지향 설계
- 안드로이드
- SOLID 원칙
- 2D 그래픽 라이브러리
- refresh 토큰
- Today
- Total
Landroid
TextView 안에 #붙은 단어에만 스팬 적용하기 본문
안녕하세요~ Landroid입니다!
가끔 개발하다 보면 텍스트 뷰 안에 특정 부분에만 색상이나 폰트 같은걸 적용해야 하는 경우를 마주할 수 있습니다. 그래서 안드로이드에서는 스팬이라는 걸 사용해서 특정 부분에만 효과를 줄 수 있습니다.
하지만 만약 # 태그에만 스팬으로 처리해야 한다면 어떻게 해야 할까요?
구글링으로 찾아본 결과.........
없습니다.
??????
보이는 곳마다 스팬에서 시작 값과 끝 값을 항상 임의로 숫자를 주는 예제만 있고 텍스트가 동적으로 변할 때 적용하는 방법을 설명하는 곳이 단 한 군데도 없었습니다. ㅠㅠ
게다가 #태그만 스팬으로 처리하는 방법을 구글링해도 찾을 수가 없었습니다. ㅠㅠ
그래서 준비했습니다!
#태그만 스팬으로 처리하는 코드를!
<예제>
우선 메인 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">
<TextView
android:id="@+id/main_result"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:bufferType="spannable" // 스팬 적용하기 위해 이건 필수에요
android:text="Hello World!"
android:textColor="@color/black"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="@+id/main_edit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="32dp"
android:ems="10"
android:inputType="textPersonName"
app:layout_constraintBottom_toTopOf="@+id/main_result"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<Button
android:id="@+id/main_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="변환!"
android:textColor="@color/white"
app:layout_constraintBottom_toBottomOf="@+id/main_edit"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/main_edit"
app:layout_constraintTop_toTopOf="@+id/main_edit" />
</androidx.constraintlayout.widget.ConstraintLayout>
그다음 onClick에 들어갈 메서드입니다.(feat.kotlin)
fun firstSolve(view: View) {
val inputText = main_edit.text.toString()
main_result.text = inputText //1
var isCharacter = false // 2
val span: Spannable = main_result.text as Spannable
var index = 0 // 3
while (inputText.size >= count + 1) {
if (inputText[index] == '#') isCharacter = !isCharacter // 4
if (inputText[index] == ' ') isCharacter = false
if (isCharacter) { // 5
span.setSpan(
RelativeSizeSpan(1.5f),
index,
index + 1, // 6
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
)
}
index++
}
}
1. 입력받은 문자열을 main_result에 넣습니다.
2. true인 구간은 태그입니다.
3. 현재 인덱스 위치를 가지는 변수입니다.
4. 현재 확인하고 있는 문자가 #이면 공백 나오기 전까지는 true입니다.
5. 만약 참이면 그 문자만 스팬을 적용합니다.
6. 한 글자만 적용하기 위해 + 1 해줍니다.
이렇게 하면 #태그인 부분만 스팬을 적용시킬 수 있습니다.
하지만 단점은 태그를 단순히 적용시킨 것이기 때문에 태그를 가져오거나 할 순 없습니다.
그래서 두 번째 해결 방안이 있습니다.
fun secondSolve(view: View) {
val inputText = main_edit.text.toString()
main_result.text = inputText
var copy = "$inputText " // 끝에 공백 추가 안하면 인덱스 벗어남;;
val span: Spannable = main_result.text as Spannable
val result = ArrayList<String>() // 태그값을 저장할 배열
var count = 0 // 태그 갯수
var startIndex = 0 // 각 태그의 시작 인덱스를 저장할 변수
for (element in copy) { // 1
if (element == '#') count++
}
for (i in 0 until count) { // 2
for (j in copy) startIndex = copy.indexOf('#') // 3
try {
result.add( // 4
copy.substring(
startIndex,
(copy.substring(startIndex).indexOf(" ") + startIndex)
)
)
// 5
copy = copy.substring((copy.substring(startIndex).indexOf(" ") + startIndex) + 1)
} catch (e: Exception) {
println(e.message)
Toast.makeText(this, "#를 붙이지 마세요", Toast.LENGTH_LONG).show()
return
}
}
for (i in result) { // 태그만 가지고 스팬 적용
span.setSpan(
RelativeSizeSpan(1.5f),
main_result.text.toString().indexOf(i),
main_result.text.toString().indexOf(i) + i.length,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
)
}
}
1. 태그의 개수를 셉니다.
2. 태그 개수만큼 루프를 돕니다.
3. 각 태그의 시작 인덱스를 얻습니다.
4. result 변수에 copy로부터 분리된 태그를 추가합니다.
5. 문자열에서 맨 앞에 태그를 제거합니다.
이렇게 하면 #태그인 부분만 스팬을 적용시킬 수 있고 태그 값도 얻을 수 있습니다.
하지만 이것도 단점이 있다면 코드가 복잡한 건 둘째치고 "#A#B"처럼 태그가 붙어있으면 에러가 발생한다는 것입니다.
휴~ 좀 더 연구를 해봐야겠네요. ^^
'안드로이드' 카테고리의 다른 글
[Android] Interceptor로 토큰 갱신하기 (0) | 2021.04.14 |
---|---|
Postman에서 같은 이름의 파라미터를 Retrofit에서 구현하는 방법 (0) | 2020.11.13 |
SearchView, 속성 사용법 (2) | 2020.10.31 |
Parameter specified as non-null is null 해결 (0) | 2020.10.24 |
Retrofit 응답 상태 관리 (0) | 2020.10.10 |