ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 안드로이드 EditText 가상키보드 없애기 - RadioButton편
    카테고리 없음 2020. 10. 12. 17:39

    (현재 글의 코드 예시는 코틀린으로 작성되었습니다.)

     

    최종 목표: 아래 동영상처럼 동작하는 코드 만들기.

     

    완성된 동작

    저번 글에서 EditText를 누르면 생기는 가상키보드가 흰 바탕을 클릭했을 때 자동으로 접히게 하는 방법을 알아보았다.

    이전 글 보기: nerdymint.tistory.com/2

     

     

    아래 동영상은 별다른 설정을 하지 않은 라디오버튼의 동작이다. 가상키보드를 자동으로 접어주지는 않는다.

     

    아무 설정도 하지 않은 기본 라디오버튼의 동작.

    먼저, 저번 글에서 한 것 처럼 EditText의 OnFocusChangeListener를 set해야 한다.

    이전 글 보기: nerdymint.tistory.com/2

    EditText가 여러개일 때, 코드를 재활용하려면 아래 코드처럼 OnFocusChangeListener객체를 미리 만들어놓고 EditText에 갖다 붙이기만 하는 방법을 추천한다.

     

    Kotlin Extension의 기능을 이용하여 findViewById는 사용하지 않았으며, et1와 et2는 각각 EditText객체이다.

    class MainActivity : AppCompatActivity() {
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
    
            val editTextListener = OnFocusChangeListener { v, hasFocus ->
                if (!hasFocus) {
                    val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
                    imm.hideSoftInputFromWindow(v.windowToken, 0)
                }
            }
    
            et1.onFocusChangeListener = editTextListener
            et2.onFocusChangeListener = editTextListener
        }
    }

    (여기까지는 저번 글의 내용과 동일하다.)

     

    그 다음 과정은 xml의 focusableInTouchMode 설정이다. (이것도 어쩌면 저번 글과 비슷할지도...)

    이전 글 보기: nerdymint.tistory.com/2

    저번 글의 맨 아래 몇 줄에서 언급한대로 부모 뷰에서 focusableInTouchMode 설정을 하더라도 버튼에서 또 따로 focusableInTouchMode설정을 해야된다. (이유는 알 수 없지만 TextView는 그냥 둬도 부모 뷰의 설정을 알아서 따라간다.) 라디오버튼의 경우도 마찬가지로 focusableInTouchMode설정을 따로 해준다.

     

    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout
        // 생략
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:clickable="true"
        android:focusableInTouchMode="true">
        <EditText
            android:id="@+id/et1"
            // 생략
            />
        <EditText
            android:id="@+id/et2"
            // 생략
            />
        <RadioGroup
            // 생략
            >
            <RadioButton
                android:id="@+id/rb1"
                android:text="선택지1"
                android:focusableInTouchMode="true"
                // 생략
                />
            <RadioButton
                android:id="@+id/rb2"
                android:text="선택지2"
                android:focusableInTouchMode="true"
                // 생략
                />
        </RadioGroup>
    </androidx.constraintlayout.widget.ConstraintLayout>

    위의 코드처럼 RadioButton에 focusableInTouchMode를 true로 설정했다.

     

    이제 라디오버튼을 클릭하면 가상키보드가 사라진다. 그러나 Radio Button을 두 번 클릭해야 체크가 되는 새로운 문제가 생겼다.. 직접 보자.

     

    라디오버튼을 두 번 눌러야 하는 문제가 발생.

    마치 영상이 잠깐 멈췄다가 다시 재생되는 것 같지만 그렇지 않다. 라디오버튼의 문제이다.

    해결방법: 포커스를 가지면 체크를 시켜주자.

     

    class MainActivity : AppCompatActivity() {
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
    
            val editTextListener = OnFocusChangeListener { v, hasFocus ->
                if (!hasFocus) {
                    val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
                    imm.hideSoftInputFromWindow(v.windowToken, 0)
                }
            }
    
            val radioButtonListener = OnFocusChangeListener { v, hasFocus ->
                if (hasFocus) {
                    (v as RadioButton).isChecked = true
                }
            }
    
            et1.onFocusChangeListener = editTextListener
            et2.onFocusChangeListener = editTextListener
    
            rb1.onFocusChangeListener = radioButtonListener
            rb2.onFocusChangeListener = radioButtonListener
        }
    }

     

    EditText는 포커스를 잃을 때 (not hasFocus) 가상키보드를 숨기고, RadioButton은 포커스를 얻을 때 (hasFocus) checked가 true가 된다.

     

    OnFocusChangeListener는 포커를 가지게 될 때 뿐 아니라 포커를 잃을 때도 호출되기 때문에, 조건문으로 hasFocus인지 아닌지 꼭 검사를 해줘야 한다. 리스너가 불렸다고 무조건 라디오버튼에 체크하게 되면 심히 곤란한 상황이 연출될 수 있다. 왜 그런지 궁금하면 로그를 찍어보면 알 수 있다.

    물론 궁금하지 않다면 그냥 넘어가도 무방하다.

    val radioButtonListener = OnFocusChangeListener { v, hasFocus ->
        Log.d(TAG, "RadioButtonListener")
        if (hasFocus) {
            Log.d(TAG, "hasFocus true")
    //      (v as RadioButton).isChecked = true
        } else {
            Log.d(TAG, "hasFocus false")
        }
    

    위는 로그 예시. 로그를 찍는 방법을 잘 모르면 Toast메시지를 띄워도 되고 마음대로 하면 된다.

     

    이렇게 하면 (로그 부분은 제외해도 무방함) 글의 맨 위에 있는 동영상처럼 작동한다.

     

    댓글

Designed by Tistory.