안드로이드 커스텀뷰 프로그래밍 – 커스텀뷰의 크기 정하기

By | November 3, 2015

커스텀뷰의 크기(기하 혹은 좌표계) 정하기

뷰를 생각해 봅시다. 뷰는 하나의 사각형으로 화면에 무엇인가를 그리는 객체입니다. 그리고 사용자로부터 터치 이벤트를 받는 인터렉션의 주체이기도 합니다.

뷰를 생각할 때 가장 중요한 것은 하나의 사각형입니다. 우리가 뷰에 무엇을 그려야 하거나 어떤 뷰에 인터렉션이 발생했는지 알기 위해서는 뷰를 구분지을 영역이 필요하기 때문입니다.

커스텀뷰를 만들 때, 가장 먼저 해야할 일도 뷰의 사각형 영역을 정하는 것입니다. 보통 뷰의 기하 혹은 좌표계를 정의하는 단계라고 생각하면 됩니다. 절대좌표계를 사용하는 시스템에서는 이 과정이 무척 쉽습니다. 원하는 대로 내가 어디서부터 어디까지 사용하겠다고 정하기만 하면 되니까요.

안드로이드 뷰에서는 어떻게 사각형 영역을 설정할까요?

기억해야할 두 단계

안드로이드 뷰는 뷰의 영역을 설정하고 사용하는 두 단계가 있습니다. 하나는 뷰의 좌표계를 설정하는 단계이고 나머지 하나는 설정된 뷰의 좌표계를 사용하는 단계입니다.

뷰의 좌표계를 설정하는 단계는 measure단계입니다. 측정단계라고 할 수 있는데 무엇인가를 측정해서 뷰의 좌표계를 정하는 것입니다. 무엇을 측정하는 것일까요?

뷰의 좌표계를 사용하는 단계는 layout단계 또는 draw단계입니다. 이 단계에서 가장 중요하게 기억할 점은 이 단계에서는 이미 뷰의 좌표계가 정의되어 있다는 것입니다. 마치 절대 좌표계에서 코드를 작성하듯 이 단계에서는 그렇게 할 수 가 있습니다.

측정

안드로이드 뷰의 측정 단계를 이해하기 위해서는 안드로이드 뷰가 어떻게 존재하는지 알아야 합니다. 안드로이드 뷰는 그 홀로 존재할 수 없습니다. 반드시 뷰그룹(ViewGroup)에 담겨야 합니다. 그래서 측정이라는 단계가 필요합니다. 뷰가 자기 자신의 크기를 결정하기 위해서 자기 자신을 담고 있는 뷰그룹의 크기를 알아야 하고 뷰그릅에서 사용할 수 있는 영역의 크기도 알아야 할 것입니다. 그리고 자기가 사용할 영역의 크기도 알아야 하겠지요. 즉, 측정단계에서는 자신의 주변 환경과 자기 자신의 정보를 측정하는 것입니다. 측정한 내용을 바탕으로 자신의 크기를 결정하는 것입니다.

이제 코드를 작성해 가며 좀 더 실질적으로 살펴 보도록 하겠습니다.

Gitbook에서 계속읽을 수 있습니다. 링크를 클릭하면 Gitbook으로 이동합니다 🙂

Share on FacebookTweet about this on TwitterShare on Google+Share on RedditEmail this to someone
  • 김병희

    @ScrollView 안에서 EditText 의 onTouch 가로채이는 문제

    TextToSpeech 앱을 개발하고 있습니다.

    기본적인 문제는 대부분 해결했는데 하나 걸리는 것이 남아서 질문 드립니다.

    스크롤뷰에 에디트텍스트를 담아서 보여주며, 터치이벤트가 발생하면 그에 따른 처리를 해주고 있습니다.

    그런데 스크롤뷰가 터치이벤트를 가로채서 처리 결과가 원하는 대로 나오지 않고 있습니다.

    스크롤뷰를 벗겨버리면 정상적인 결과가 나오는 코딩을 했음에도 스크롤뷰에 막히는 문제를 해결해야 됩니다.

    에디트텍스트 자체만으로는 스크롤이 너무 느려서 답답하기 때문에 스크롤뷰를 버릴 수 없습니다.

    1. 커스텀 텍스트뷰

    시도해 보았으나, 실력이 짧아 성공하지 못했습니다.

    2. requestDisallowInterceptTouchEvent

    사용하면 스크롤이 되지 않고, 아무리 구글링하면서 베껴 돌려 보아도 스크롤도 코딩한 대로의 결과도 얻을 수 있는 requestDisallowInterceptTouchEvent 사용방법을 터득하지 못했습니다.

    3. 어떤 방법이든지 무관

    스크롤도 시원하게 되고, 터치이벤트에 따른 처리도 코딩한 대로 되는 소스코드가 필요합니다.

    커스텀 텍스트뷰로 구현하든지 requestDisallowInterceptTouchEvent 를 적절한 시점에 켰다 끄든지 어떤 방법이든지 위 요구사항만 만족되면 충분합니다.

    4. 상업적 의뢰 직전임

    애써 만든 앱을 혼자 사용하기 아까워서, 이 질문의 답변을 받아서 해결하지 못하면 샘플제작업체에 의뢰할 생각입니다.

    마지막 SOS에 도움 주시면 감사하겠습니다.

    관련 부분의 소스 발췌하여 붙입니다.

    프로젝트 전체 소스가 필요하면 메일을 가르쳐 주시기 바랍니다.

    감사합니다.

    – 레이아웃 –

    &gtScrollView

    android:id=”@+id/scrollView”

    android:layout_width=”match_parent”

    android:layout_height=”match_parent”

    android:background=”#cecfce”

    android:fillViewport=”true”>

    &gtEditText

    android:editable=”false”

    android:inputType=”none”

    android:layout_width=”match_parent”

    android:layout_height=”match_parent”

    android:id=”@+id/tts_editText”

    android:textSize=”18sp”

    android:lineSpacingExtra=”13dp”

    android:text=”고전 1:27 그러나 ㅓ하나님께서 世上의 미련한 것들을 擇하사 智慧 있는 者들을 부끄럽게 하려 하시고 ㅕ世上의 弱한 것들을 擇하사 强한 것들을 부끄럽게 하려 하시며 // ㅓ 약 2:5 ㅕ 시 8:2″

    android:maxLength=”100000″

    android:textIsSelectable=”true”

    android:textColorHighlight=”#cdefab”

    android:padding=”3dp”

    android:gravity=”top” />

    &gt/ScrollView>

    – 자바소스 –

    public class MainActivity extends AppCompatActivity implements OnInitListener, OnTouchListener {

    private static EditText tts_editText, helpText;

    private static ScrollView scrollView;

    protected void onCreate(Bundle savedInstanceState) {

    tts_editText = (EditText)findViewById(R.id.tts_editText);

    tts_editText.setOnTouchListener(this);

    scrollView = (ScrollView)findViewById(R.id.scrollView);

    }

    @Override

    public boolean onTouch(View v, MotionEvent event) {

    _LAST_ACTION = event.getAction();

    if (_LAST_ACTION==1) _LAST_ACTION = 3;

    String bmText;

    switch(event.getAction()) {

    case MotionEvent.ACTION_DOWN:

    x1 = event.getX();

    break;

    case MotionEvent.ACTION_UP:

    x2 = event.getX();

    dx = x2-x1;

    if(dx>50) { // (오른쪽)

    if(dx>100) {

    if (!_LAST_FILE.isEmpty()) {

    bmText = makeBookmark(al_bookMark, _LAST_FILE, tts_editText, event);

    if (!bmText.isEmpty()) {

    Toast.makeText(this, “===> Add bookmark !!!”, Toast.LENGTH_SHORT).show();

    saveBookmark(bmText, al_bookMark);

    saveBookmark(makeClone(bmText), al_bookMarkClone);

    lv_bookmark.setAdapter(bmAdapter);

    }

    }

    }

    else interSpeech(event);

    }

    else if(dx<-50) { // direction = "(왼쪽)";

    if (mTTS.isSpeaking()) mTTS.stop();

    }

    break;

    }

    // return true;

    return super.onTouchEvent(event);

    }

    }

    덧붙임 / 김병희2016년 5월 21일 오전 9:30

    테스트해본 것들도 다시 찾으려니까 힘듭니다.

    겨우 찾아서 우격다짐으로 다음과 같이 순진한 코딩을 했는데 …

    moveCursorToVisibleOffset

    는 성공했다는 신호를 보내면서 항상 옵셋 21만 내보냅니다.

    private void onSpeech() {

    if (inc_help.getVisibility()==View.VISIBLE)

    arrSpeak(et_help.getText().toString().split("n"));

    else {

    if (_fileText.isEmpty()) Snackbar.make(inc_tts, "탐색(선택)하지 않은 파일은 스피커 아이콘으로 읽으세요!", Snackbar.LENGTH_LONG).show();

    else {

    scrollView.requestDisallowInterceptTouchEvent(true);

    tts_editText.setSpannableFactory(Spannable.Factory.getInstance());

    if (tts_editText.moveCursorToVisibleOffset()) {

    int pos = tts_editText.getSelectionStart();

    textView.setText(""+pos);

    scrollView.requestDisallowInterceptTouchEvent(false);

    arrSpeak(File_Text.offRightText(tts_editText, pos).split("n"));

    }

    else {

    Snackbar.make(inc_tts, "??? 커서를 움식일 수 없어요, 엉, 어엉!", Snackbar.LENGTH_LONG).show();

    scrollView.requestDisallowInterceptTouchEvent(false);

    }

    }

    }

    }

    실패했다고 하든지, 성공했으면 옵셋 수치를 달리 내보내든지 …

    잠도 못자고(잠이 오지 않아서) 기억을 살려서 내가 이것까지 해 보았다는 기록 겸 부끄럽지만 올려봅니다.

    • 김병희

      많은 페이지를 참고한 끝에, 스스로 답을 찾았습니다.

      아래는 저의 개발일지 메모입니다.

      스크롤뷰에 담지 않은 EditText 의 텍스트를 마치 스크롤뷰에 담은 것처럼 스크롤시키는 기능을 구현하기 위해 참고한 소스들과 삽질 과정을 순서번호를 붙여서 올리고 있다.

      뷰(Button/TextView/EditText)에 Scroller 달기(1)/[Android] http://blog.daum.net/andro_java/187

      뷰(Button/TextView/EditText)에 Scroller 달기(2)/[Android] http://blog.daum.net/andro_java/191

      뷰(Button/TextView/EditText)에 Scroller 달기(3)/[Android] http://blog.daum.net/andro_java/192

      뷰(Button/TextView/EditText)에 Scroller 달기(4)/[Android] http://blog.daum.net/andro_java/193

      뷰(Button/TextView/EditText)에 Scroller 달기(5)/[Android] http://blog.daum.net/andro_java/194

      이것으로 준비는 끝났다.

      이제 우리 앱에 적용하는 일만 남았다.