400 likes | 589 Views
9. 커스텀 위젯. 학습목표 기존 위젯을 변경하여 실제 프로젝트에 바로 사용할 수 있는 커스텀 위젯을 제작하는 방법을 익힌다 . 위젯이 상위의 뷰 그룹과 통신하는 방법을 연구한다 . 커스텀 속성을 통해 위젯의 활용성을 높이는 방법을 학습한다 . 내용 기존 위젯 변형 새로운 위젯 여러 가지 뷰. 1. 기존 위젯 변형. 위젯 수정 모바일 장비는 통신 수단이며 일종의 액세서리이므로 디자인 역시 중요하다 .
E N D
9 커스텀 위젯
학습목표 • 기존 위젯을 변경하여 실제 프로젝트에 바로 사용할 수 있는 커스텀 위젯을 제작하는 방법을 익힌다. • 위젯이 상위의 뷰 그룹과 통신하는 방법을 연구한다. • 커스텀 속성을 통해 위젯의 활용성을 높이는 방법을 학습한다. • 내용 • 기존 위젯 변형 • 새로운 위젯 • 여러 가지 뷰
1. 기존 위젯 변형 • 위젯 수정 • 모바일 장비는 통신 수단이며 일종의 액세서리이므로 디자인 역시 중요하다. • 디자인을 결정하는 주요 요소는 위젯이며, 기능적인 완벽함과 효율만큼 예쁜 외관과 동작의 참신함이 요구되고, 사용자와의 상호 작용이 직관적이면서도 독창적이어야 한다. • 기능적으로 집합을 표시한다는 면에서 동일하지만, 항목을 표시하는 방법은 다르다. • 아드로이드 표준 위젯은 디자인이 너무 사무적이며, 무난한 모양을 지향하고, 응용 프로그램들의 특수한 목적을 충족시키기에 기능이 너무 일반적이다. • 이에 안드로이드는 여러 가지 방법으로 커스텀 위젯 제작을 지원한다. • 기존 위젯 클래스를 상속받아 기능을 확장하거나 수정한다. - 전통적인 클래스 상속 기법이 그대로 적용. - 대부분의기능을 슈퍼 클래스에서 빌려 쓰고 필요한 부분만 수정 가능. • 기존 위젯들을 결합하여 복잡한 동작을 수행하는 위젯 그룹을 정의한다. - ViewGroup 또는 그 파생 클래스를 확장하여 만든다. - 그룹 내부 위젯끼리의 상호 작용까지 모두 정의해야 한다. • 기존의 존재하지 않는 새로운 위젯을 만든다. - 기능이나 모양이 특수하여 기존 위젯으로 사용이 불가능할 때 사용하는 방법이다. - 최상위 위젯 클래스인 View로부터 상속 받으며 난이도가 높다. ※ 만들고자 하는 위젯의 기능과 목적에 따라 적절한 방법을 선택해야 하며, 방법에 따라 확장 대상 클래스가 달라진다.
1. 기존 위젯 변형 • SoundEdit예제 • 기존 컨트롤 수정 방법이며, EditText클래스를 확장하여 키 입력시마다 소리를 내는 입력 위젯을 만든다. • 커스텀 위젯 클래스는 별도의 소스 파일에 따로 작성는 것이 관리에 편리하다. • EditText클래스를 확장하여 SoundEditWidget클래스를 파생 시켰으며, 생성자는 세 벌을 모두 정의하였다. - XML에서 전개 시 2개의 인수를 취하는 생성자가 호출 - new연산자로 생성 시 context인수만 취하는 첫 번째 생성자가 호출된다. • 범용성을 높이기 위해서는 모든 생성자를 다 구비하는 것이 바람직하다. - 예제에는 두 번째 생성자만 사용됨.
1. 기존 위젯 변형 • 파생 클래스의 생성자는 일단 슈퍼 클래스의 생성자를 호출하여 상속받은 멤버를 먼저 초기화해야 한다. • 세 생성자 모두 super호출문이 제일 앞에 오고 전달받은 모든 인수를 super로 넘겨준다. • 그 후 고유의 초기화 작업을 하며, 매 생성자마다 중복된 코드를 두는 것은 바람직하지 않다. • init초기화 메서드를 정의하고, 각 생성자는 이 메서드를 호출하여 고유의 초기화를 수행하는 것이 일반적이다.
1. 기존 위젯 변형 • 커스텀 위젯은 하나의 클래스이므로 동작에 필요한 객체나 상수들을 내부 멤버로 선언한다. • 예제 위젯은 소리를 내야 하므로 SoundPool 객체와 사운드 ID를 멤버로 선언, init메서드에서 초기화한다. • SoundPool객체 생성 후 mClick에 ID대입, 사운드 파일은 res/raw폴더에 mp3포맷으로 복사해 둔다. • 텍스트가 변경 시 onTextChanged메서드가 호출된다. • 문자 입력 시점이므로 onKeyDown메서드를 재정의. • 이 메서드는 키패드의 키를 누를때만 호출, 화면 키보드에 대해서는 호출되지 않는다. • 에디트가 생성될 때 빈 문자열로 초기화되며 이때도 onTextChanged메서드가 호출된다. • 이 시점은 mPool객체가 아직 초기화되기 전이므로 객체가 null인지 확인해야 한다. • 커스텀 위젯을 사용하는 방법도 표준 위젯과 동일하다. • new연산자로 실행 중 직접 생성, 레이아웃에 추가 가능하며 XML파일에 엘리먼트로 배치 가능하다. • 각 경우 호출되는 생성자가 다르며, 대응되는 생성자가 정의되어 있어야 한다.
1. 기존 위젯 변형 • SoundEdit예제 • 리니어 안에 안내 텍스트 뷰 하나와 커스텀 사운드 에디트를 배치한다. • XML파일에 커스텀 위젯을 배치 시 엘리먼트 이름에 위젯의 클래스 명을 적되 커스텀 위젯은 풀패키지 명을 다 적어야 한다. • SoundEditWidget도 EditText의 파생 클래스이며 View의 파생 클래스이므로 상위 클래스가 제공하는 모든 속성 사용이 가능하다. - onKeyDown : 16진수 입력 조절 가능 - onDraw : 배경 이미지 삽입 가능 [ SoundEdit예제 실행 결과 ]
1. 기존 위젯 변형 • 위젯 조합 • 개별 위젯들의 기능은 원자적이고 단순하여 복잡한 특정 작업 수행 시 여러 위젯들이 상호 협력적으로 동작해야 한다. • 관련 위젯들을 하나의 그룹으로 묶어 새로운 위젯으로 정의 가능하다. • 유기적으로 동작하는 위젯 그룹을 하나의 단위로 묶음으로써 통합성과 재사용성이 좋아진다. • NumEdit예제 • 에디트와 텍스트 뷰를 포함하는 수직 리니어 위젯을 정의. • 에디트는 자신의 길이를 텍스트 뷰에 출력하고, 텍스트 뷰는 에디트의 문자열을 참조하므로 이 둘은 긴밀히 연관된 하나의 묶음이며 항상 같이 사용된다. • 레이아웃에는 NumEditWidget하나만 배치한다. [ NumEdit예제 실행 결과 ]
1. 기존 위젯 변형 • NumEditWidget클래스는 LinearLayout을 상속 받아 차일드를 일렬로 배치 가능하다. • 클래스의 멤버로 mEdit, mText를 선언하고 init에서 두 객체를 생성하여 리니어에 추가한다. • 두 위젯의 상호 동작을 정의한다. - 에디트 내용 변경 시 문자열의 길이를 텍스트 뷰에 출력. - 위젯 자신이 TextWatcher리스너 구현, mEdit텍스트의 변경 리스너를 this로 지정. - 리스너의 onTextChanged메서드에서 문자열 변경 시 길이를 새로 조사하여 텍스트 뷰에 출력. • 문자열 변경 시점을 구한다는 점에서 이전 예제와 비슷. - SoundEdit예제 : TextView의 메서드 - NumEdit예제 : TextWatcher인터페이스의 메서드 • EditText를 멤버로 포함할 뿐이므로 onTextChanged 메서드를 재정의할 수 없다. • 와처를 등록, 이를 통해 문자열 변경 시점을 알아내야 한다.
1. 기존 위젯 변형 • 세 개 이상의 위젯을 묶어 복잡한 기능 수행이 가능하며, RelativeLayout, TableLayout을 확장하여원하는 모양으로 배치할 수 있다. • 합쳐진 그룹 위젯에 대해 여백이나 마진, 배경색 등 조정 가능하며, 커스텀 속성을 통해 내부 위젯의 속성 역시 조정 가능하다. • 포함되는 위젯의 개수가 많고 배치가 복잡하면 코드에서 생성, 배치가 번거로우므로 XML문서로 뷰 그룹을 디자인하여 배치와 속성을 지정해 놓고 코드에서 레이아웃을 전개하여 배치하면 된다. • numeditwidget예제
1. 기존 위젯 변형 • 커스텀 속성 • 안드로이드에서 레이아웃을 배치 시 주로 XML문서를 활용한다. • XML문서에 배치할 위젯의 클래스 명을 엘리먼트로 작성, 위젯의 속성을 엘리먼트의 속성으로 작성하며, 규모가 큰 레이아웃도 문서 작업만으로 생성 가능하다. • XML문서는 aapt툴에 의해 이진 형태로 컴파일되어 실행 파일에 포함, 전개자(Inflater)가 정보를 읽고 각 위젯을 생성한다. • 지정된 속성은 생성자의 두 번째 인수인 AttributeSet객체 형태로 생성자에게 전달, 이 객체안에 속성의 집합이 저장되어 있다. • 클래스의 주요 메서드는 아래와 같다. • intgetAttributeCount () • String getAttributeName (int index) • String getAttributeValue (int index) • intgetAttributeIntValue (int index, intdefaultValue) • booleangetAttributeBooleanValue (int index, booleandefaultValue) • float getAttributeFloatValue (int index, float defaultValue) • 속성의 개수, 이름과 값을 조사한다. • 속성들은 배열 형태로 저장되어 있으므로 첨자로 읽는다. • 속성의 타입을 정확히 알고 있는 경우 정수형, 실수형, 진위형 등의 타입으로 바로 읽을 수 있으며 속성이 생략된 경우의 디폴트 값 지정이 가능하다.
1. 기존 위젯 변형 • attribute예제 • 리니어 안에 버튼 위젯을 배치, 각 속성을 적용하고Text속성은 string.xml에 정의한 후 참조로 지정한다. • 각 속성들은 aapt에 의해 컴파일되며 전개자가 Button 객체를 생성할 때 생성자로 전달한다. • attrButton은 Button에서 파생, 생성자에서 attrs인수를 확인할 뿐 표준 버튼과 동작이 동일. • 전개자에 의해 생성되므로 두 번째 생성자만 정의.
1. 기존 위젯 변형 • 생성자 코드는 간단하며 attrs배열을 전부 순회, 속성의 이름과 값을 조사하고 조사된 속성값을 mText문자열에 누적시켜 둔다. • 생성자에서 출력이 불가능하므로 문자열 변수에 조사된 결과를 저장해 두고 생성 완료 후 이 변수를 읽는다. • onCreate에서 버튼과 에디트 생성 후 버튼의 mText를 읽어 아래의 에디트에 출력한다. • 버튼에 지정된 속성들이 문자열로 바뀌어 에디트에 출력된다. • 속성값을 버튼 위젯에 실제로 적용하는 주체는 super의 생성자이며 Button의 생성자를 거쳐 TextView의 생성자로 전달, 위젯에 설정된다. • layout으로 시작되는 레이아웃 파라미터는 객체가 완전히 초기화 된 후 부모 뷰에 추가될 때 적용된다. [ Attribute예제 실행 결과 ] • AttributeSet객체는 XML문서에 지정된 모든 속성을 포함하지만 문서상에 기록된 값을 액면 그대로 가지고 있으므로 직접 사용하기에 불편하다. • 문자열의 경우 strings.xml에 대한 참조로만 나타나므로 실제 문자열 조사를 위해서 리소스를 확인해야 한다. • 객체를 직접 사용하지 않고 메서드로 속성 집합을 한번 더 가공한다. • TypedArray obtainStyledAttributes (AttributeSet set, int[] attrs) • Resource.Theme클래스에 정의, Context가 래퍼를 제공하므로 컨텍스트로부터 바로 호출이 가능하며, 참조 리소스는 물론이고 스타일 지정된 값 역시 찾아주므로 최종적으로 적용할 값을 바로 구할 수 있다.
1. 기존 위젯 변형 • 사운드 속성 • 커스텀 위젯도 자신만의 속성을 정의하여 사용 가능하다. • SoundEdit 2 예제 • SoundEdit예제를 확장, 소리의 종류, 볼륨, 재생 속도 등을 속성으로 제공한다. • 커스텀 위젯의 속성은 attrs.xml에 정의하고, res/values폴더 안에 파일을 작성한다.(파일명은 사용자가 원하는 대로 지정 가능하다.) • declare-styleable엘리먼트의 name속성에 위젯의 이름 작성. • attr엘리먼트의 name에 속성의 이름, format에 속성의 타입 지정. • - ingeger, float, string, dimension, color등의 타입 지정 • - enum열거형으로 속성값에 개별 이름 설정 가능. • 문서에 속성을 정의해 놓으면 R.java에 styleable클래스가 자동으로 생성된다. • 클래스 명과 같은 이름으로 속성의 배열이 작성되며 각 속성의 첨자가 0부터 순서대로 부여된다. • 생성자에서는 이 값들을 참조하여 XML문서의 속성을 읽는다.
1. 기존 위젯 변형 • 커스텀 속성에 대한 네임 스페이스는 표준과 유사하되 마지막 부분을 프로젝트의 패키지명으로 수정하여 사용한다. • 세 개의 커스텀 위젯을 배치하되 하나는 sound를 2로지정했고, 하나는 속도와 볼륨을 절반으로 줄였다. [ SoundEdidt2예제 실행 결과 ]
1. 기존 위젯 변형 • 생성자는 attrs배열을 init메서드로 전달하되 new연산자로 직접 생성 시 null이 전달되며, init메서드는 전개자로부터 호출 시 attrs에 저장된 속성값을 읽어 위젯에 적용한다. • obtainStyledAttributes메서드로 R.java에 정의된 속성의 배열 전달 시 TypedArray객체로 리턴된다.
2. 새로운 위젯 • 크기 정하기 • 완전히 새로운 위젯을 만들 때는 최상위 클래스인 View로부터 상속받는다. • View는 화면에 모습을 그리기 위한 메서드들과 사용자와 통신하기 위한 이벤트 핸들러의 기본 원형을 제공한다. • 상속받은 뷰의 기능은 일반적이라 몇 개의 메서드를 반드시 재정의해야 한다. • onDraw - 뷰는 화면에 아무것도 그리지 않으므로 선택의 여지없이 재정의해야 한다. (재정의하지 않으면 화면에 아무 것도 나타나지 않는다.) • onMeasure - 부모 레이아웃은 차일드를 배치하기 위해 각 차일드의 크기를 조사하며이때 차일드의 measure메서드를 호출한다. - measure는 강제 레이아웃, 크기 변경 빈도 최소화, 치명적인 에러 처리 등 중요한 역할을 담당하므로 직접 재정의하는 것은 바람직하지 않다. - measure는 크기 결정 시 onMeasure를 호출하므로 onMeasure에서 위젯의 크기를 결정한다. void onMeasure (int widthMeasureSpec, int heightMeasureSpec) - 인수로 전달된 *Spec은 부모레이아웃이 차일드에게 제공하는 여유 공간의 폭과 높이에 대한 정보이며 이 안에 공간의 성질을 지정하는 모드와 공간의 크기값이 저장되어 있다. - 모드와 크기를 별도의 인수로 전달 시 하나의 정수에 두 값을 묶어서 전달한다.
2. 새로운 위젯 • 정수에서 두 값을 추출하거나 다시 합칠 때는 View.MeasureSpec클래스의 메서드를 사용한다. • 스펙의상위 2비트에 모드가 저장, 나머지 30비트가 실제 크기값이며 이들을 비트 연산하여 분리 및 조합하는 메서드이다. • 모드는 전달된 크기가 어떤 의미를 가지는지를 지정한다. • intgetMode (intmeasureSpec) • intgetSize (intmeasureSpec) • intmakeMeasureSpec (int size, int mode) • - AT_MOST가 전달된 경우 : 부모가 위젯에게 허용된 최대한의 크기를 알려주며, 차일드는 자신이 원하는 폭과 부모가 허락한 폭의 최소값을 취해야 한다. • - EXACTLY가 전달된 경우 : 부모가 제안한 폭을 사용한다. • - UNSPECIFIED가 전달된 경우 : 아무 제약이 없으므로 자신이 원하는 대로 폭을 차지해도 무방하다.
2. 새로운 위젯 • 레이아웃을 배치할 때 부모와 차일드는 메서드를 통해 대화하고 타협한다. • - 부모 : 차일드의 OnMeasure메서드를 호출하되 남은 여유 공간에 대한 정보를 스펙 인수로 전달 • - 차일드 : 전달받는 정보를 참조하여 적절한 크기를 부모에게 응답한다. • onMeasure에서 부모로 응답을 보낼 때는 아래의 메서드로 원하는 크기를 리턴한다. • void setMeasuredDimension (int measuredWidth, int measuredHeight) • - 두인수는차일드가 원하는 폭과 높이이다. • - 메서드가 두 값을 동시에 리턴할 수 없기 때문에 OnMeasure는 형식적으로 리턴값이 없는 것으로 선언되어 있지만 실제로는 이 메서드를 통해 두 값을 리턴해야 한다. • - 만약 이 OnMeasure가 메서드를 호출하지 않고 리턴해 버리면 부모가 레이아웃 중에 IllegalStateException예외를 일으키고 다운되어 버린다. • - 차일드가 크기를 밝히지 않으면 배치가 불가능하다. • ※ OnMeasure에서크기를 결정하는 방법은 절대적인 공식이 따로 없고 응용도 가능하여 다소 복잡하고 이론만으로 이해하기 어려우므로 실습이 꼭 필요하다.
2. 새로운 위젯 • Measuring예제 소스 코드
2. 새로운 위젯 • Measuring예제 소스 코드 • MeasView는 View로부터 상속받으며 생성자는 디폴트로만 정의. • onDraw는 빨간색으로 전체를 가득 채워 화면에 존재만 표시. • onMeasure에는 위젯의 크기를 결정하는 코드가 작성. - Width, Height는 150과 80으로 각각 상수 초기화되며 위젯의 내용물에 근거하여 계산됨. - 텍스트 뷰라면 문자열의 길이에 맞게, 이미지 뷰라면 비트맵의 크기에 맞게 크기가 결정됨. - MeasView는 사실상 내용물이 없으므로 임의의 크기를 가정한 것이다. • 위젯이 스스로 크기를 결정했다 해도 주변의 형제 위젯들과 부모의 영역을 나누어 가져야 하므로 항상 설정된 크기대로 배치되지 않는다. • 코드는 하나의 예일 뿐이며 위젯의 특성에 따라 고유한 크기 계산 알고리즘을 적용할 수 있다. • 최종 결정된 Width, Height를 setMeasuredDimension으로 전달한다.
2. 새로운 위젯 • 수직 리니어 안에 수평 리니어와 에디트 배치하였으며, 에디트는 배치 결과를 문자열로 확인하기 위한 장치이다. • 수평 리니어는 높이 100 픽셀의노란색 배경이 지정되어 있으며, 이 안에 폭 100 픽셀의 버튼을 양쪽에 배치, 중간에 MeasView를 끼워넣었다. [ Measuring예제 실행 결과 ] [ Measuring예제 실행 결과 ]
2. 새로운 위젯 • measuring 2 예제 • MeasView의 폭과 높이를 wrap_content에서 100px, 50px로 강제 지정한다. • measuring 3 예제 • 양쪽 버튼 2개를 없애고 MeasView만 남겨두되 폭과 높이를 fill_parent로 지정한다. • measuring 4 예제 • 버튼을남겨두고 MeasView의 폭과 높이를 fill_parent로 지정한다. [ Measuring 4예제 실행 결과 ] [ Measuring 2예제 실행 결과 ] [ Measuring 3예제 실행 결과 ]
2. 새로운 위젯 • 부모가 차일드에게 제안하는 스펙은 어디까지나 크기 결정을 위한 힌트일 뿐이며, 위젯이 자신의 필요에 따라 부모의 제안을 거절할 수 있고 일부 조정할 수도 있다. • 최초의 예제 Measuring에서 주석 처리된 부분을 주석 해제한 후 실행한다. • 시계처럼 정원을 그려야 한다거나 증명사진처럼 일정한 종횡비를 지켜야 한다면 부모가 제안한 크기를 거부하고 규칙에 맞게 강제로 조정한 크기를 리턴하면 된다. • 부모는 220*100만큼의 공간을 제안했지만 차일드는 높이를 내용물에 맞추어 80으로 강제 조정했다. • 이 경우는 내용물을 기준으로 종횡비를 맞추었으므로 크기가 작은데 부모가 제안한 영역에 맞춘다면 (100,100)이 되어 초대한 넓은 면적을 차지할 수도 있다. • EXACTLY인 경우는 종횡비를 맞추지 않도록 구현했지만 필요하다면 여백으로 나머지를 채우더라도 내용물의 종횡비를 유지할 수 있다. [ Measuring예제 실행 결과 ]
2. 새로운 위젯 • 차일드가 부모의 제안을 거부할 수 있듯 부모도 차일드의 요청을 다 들어주지 못하는 경우가 있다. • 레이아웃이 복잡하고 차일드 수가 많아져 한번의 대화로 완벽한 배치를 만들어 내기 어려우면 여러 차일드에게 반복적으로 질문을 날려 모두가 OK할 때까지 조정을 반복. • measuring 5 예제 • 세 위젯 모두 layout_weight속성을 지정하여 폭을 나누어 가지도록 하였다. [ Measuring 5예제 실행 결과 ]
2. 새로운 위젯 • 무지개 프로그래스 • 무지개색으로 작업의 진행 경과를 보여주는 수직 프로그래스 바 위젯이다. • 기존 클래스를 상속받거나 조합해서는 만들 수 없으며 최상위의 View를 상속받아 처음부터 다시 만들어야 한다. • 표준 프로그래스 바는 수평만 가능하므로 상속받아도 수직으로는 불가능하다. • RainbowTest예제
2. 새로운 위젯 • RainbowTest예제
2. 새로운 위젯 • RainbowTest예제 • 일정 범위에서 현재 위치값을 표시하는 것이 위젯의 주요 임무이므로 범위와 현재 위치인 mMax, mPos를 멤버로 가진다. • 범위의 최소값은 무조건 0으로 고정한다. • 두 멤버는 init에서 각각 100, 0으로 초기화되며 외부에서 setMax, setPos메서드로 변경 가능하다. • set*메서드는 규칙에 맞지 않는 값은 거부하여 스스로를 방어한다. - setMax : 1이상. - setPos : 0 ~ mMax범위 내. • 프로그래스 막대를 그리는 코드는 모드 onDraw에 작성되어 있다. • 최초 호출 시 패딩을 고려하여 높이를 계산해 놓고 이 높이를 가득 채우는 그러데이션 셰이더를 생성해 놓는다. • 나머지는 단순 좌표 계산과 그리기 코드이다.
2. 새로운 위젯 • 메인 레이아웃에 프로그래스와 버튼을 배치해 놓고 타이머로 작업을 진행시킨다. - 프로그래스 위젯에 패딩 속성을 지정했는데, 코드에서는 패딩만큼 안쪽 여백을 둬야 한다. - onDraw에서 셰이더와 외곽선 좌표를 구하는데 패딩을 고려하고 있다. - 마진의 경우 위젯 바깥쪽의 여백이므로 고려하지 않아도 좋다. - 액티비티는 버튼을 누를 때 핸드러를 호출하여 0.01초에 한번씩 프로그래스를 진행, Max에 도달하면 작업을 중지한다. [ RainbowTest예제 실행 결과 ]
3. 여러 가지 뷰 • ScrollView • 모바일 장비는 화면이 작아 많은 내용을 한번에 표시하기 어렵다. • 스크롤이라는 기법을 통해 상하좌우로 영역을 이동하며 가려진 부분을 확인한다. • ScrollView는 수직 스크롤 기능을 제공하는 뷰로, 현재 스크롤 위치의 내용을 보여주되 플리킹 동작이나 방향키 입력을 받아 이동한다. • 이 외에 리스트 뷰나 텍스트 뷰도 고유의 스크롤 기능을 제공한다. • 따라서 두 위젯은 굳이 스크롤 뷰와 함께 사용할 필요가 없으며, 사용해서는 안된다. • FrameLayout의 서브 클래스로 하나의 차일드만 가질 수 있지만, 리니어 레이아웃 같은 컨테이너를 배치하면 그 안에 많은 뷰를 배치할 수 있다. • 수직 리니어 안에 많은 위젯들을 배치해놓고 리니어를 스크롤 뷰로 감싼다. • 스크롤 뷰는 리니어의 전체 높이만큼 범위로 인식하고 플리킹 입력을 받아 화면의 위아래로 이동한다. • 스크롤은 주로 실행중에 내용물의 길이가 가변적으로 결정되는 동적 레이아웃에 흔히 사용되며, 정적 레이아웃은 리스트 뷰를 쓰는 것이 더 일반적이다.
3. 여러 가지 뷰 • ScrollViewTest예제 • 수직으로 긴 커스텀 뷰를 스크롤한다. • 메인 레이아웃에는 스크롤 뷰 하나만 배치, 커스텀 뷰는 실행중에 생성하여 스크롤 뷰의 차일드로 추가한다. • ColorView는 특별한 기능 없이 점점 진해지는 그러데이션을 보여준다. • 뷰의 크기는 onMeasure에서 폭 500, 높이 1024로 강제 지정했다. [ ScrollViewTest예제 실행 결과 ]
3. 여러 가지 뷰 • 아래의 메서드는 스크롤 뷰의 동작, 모양을 지정하는 메서드로, ScrollView의 메서드가 아니라 View의 메서드이다. • 즉, 모든 뷰는 스크롤 여부에 상관없이 이 메서드들을 호출할 수 있다. • 스크롤 바의 스타일을 지정하며, 아래 4가지 스타일 중 하나를 지정한다. • void setScrollBarStyle (int style) • INSIDE와 OUTSIDE는 스크롤 바를 패딩에 놓을 것인가, 가장자리에 놓을 것인가의 차이이다. • INSET과 OVERLAY는 자리를 차지할 것인가 아니면 배경 위에 얹힐 것인가를 지정한다.
3. 여러 가지 뷰 • 스크롤의 가장자리가 흐릿해지는 효과를 적용할 것인가 아닌가와음영의 길이를 지정. • 중간쯤으로 스크롤하면 윗 부분에 검정색 음영이 깔린다. • XML문서에서는 fadingEdge, fadingEdgeLength속성으로 이 값을 지정한다. • 스크롤 바를 사용할 것인가 아닌가를 지정한다. • View에서는 기본적으로 표시되지 않지만 ScrollView는 표시한다. • false로 변경 시 스크롤 바는 표시되지 않지만 숨겨진 상태이므로 스크롤은 사용할 수 있다. • ScrollView는 수직 스크롤만 지원하며 수평 스크롤은 지원하지 않는다. • 모바일 장비는 보통 세로로 길쭉하고 항목들을 아래위로 배치하며, 사람들의 손가락도 좌우 플리킹보다는 상하 플리킹에 더 익숙하기 때문이다. void setVerticalFadingEdgeEnabled (boolean verticalFadingEdgeEnabled) void setHorizontalFadingEdgeEnabled (boolean horizontalFadingEdgeEnabled) void setFadingEdgeLength (int length) void setVerticalScrollBarEnabled (booleanverticalScrollBarEnabled) void setHorizontalScrollBarEnabled (booleanhorizontalScrollBarEnabled)
3. 여러 가지 뷰 • 1.5버전부터 수평 스크롤 가능한 클래스가 추가되었으며 클래스 이름 앞에 Horizontal이 추가되었다. • HScrollViewTest예제 • 레이아웃에는ScrollView대신 HorizontalScrollView를 배치, 수직으로 그러데이션하는 대신 수평으로 그러데이션한다. [ HScrollViewTest예제 실행 결과 ]
3. 여러 가지 뷰 • WebView • 웹뷰는 이름 그대로 웹 페이지를 보여주는 위젯으로, 네트워크 입출력, 캐싱, 링크 클릭 처리, 확대, 축소, 히스토리 관리 등 웹 브라우저가 제공하는 모든 기능을 자체적으로 제공한다. • 안드로이드에 내장된 웹킷(WebKit) 라이브러리가 모든 것을 처리하며, 사용자는 원하는 곳에 배치하고 주소를 전달한다. • 웹킷은 오픈 소스이며 사파리, 크롬 등에 채용되어 성능을 입증, 높은 신뢰성을 제공한다. • 응용 프로그램이 웹 사이트의 페이지를 읽으려면 인터넷 엑세스를 해야 하므로 특별한 권한이 필요하다. • 모바일 장비에서의 인터넷 엑세스는 요금 문제와 연관이 있으므로 반드시 사용자의 허가나 동의가 필요하다. • 따라서 웹을 사용하는 프로그램은 매니페스트에 INTERNET퍼미션을 반드시 지정해야 한다. • Widget프로젝트의 매니페스트를 열면 아래와 같은 퍼미션 지정문이 작성되어 있다.
3. 여러 가지 뷰 • 웹뷰를 사용하면 간단한 웹 브라우저는 만들 수 있으며, 액티비티의 일부에 웹 페이지를 표시할 수 있다. • WebViewTest예제 • 레이아웃에 에디트와 버튼들을 상단에 배치, 나머지 영역을 웹 뷰로 가득 채우고 코드에서는 각 버튼이 클릭될 때 웹 뷰에게 명령을 내린다.
3. 여러 가지 뷰 • WebViewTest예제 • 웹 뷰에서 가장 중요한 정보는 연결할 사이트 주소이며, loadUrl메서드로 지정한다. - 웹 뷰는 URL을 전달받으면 액티비티 매니저에게 URL을 전달하며, 시스템에 등록된 웹 브라우저가 실행된다. - 이 경우 액티비티 안의 웹 뷰에 사이트를 열 수 없으며 응용 프로그램이 통제 불가능하다. - 따라서 응용 프로그램이 URL을 처리할 기회를 얻기 위해 웹 클라이언트를 별도로 선언, 관련 이벤트를 가로채야 하며, 예제에서는 MyWebClient라는 이름으로 클래스를 선언, shouldOverridUrlLoading메서드를 재정의하여 웹뷰가 url을 받도록 하였다. - 메서드가 true를 리턴하면 응용 프로그램이 직접 url을 처리한다는 뜻이다. • 준비해 둔 웹 클라이언트 모듈을 setWebViewClient메서드로 전달, 이후부터 웹 브라우저 대신 액티비티 안의 웹 뷰가 열린다. • 웹 클라이언트는 이 외에도 키보드 입력, 배율 변경, 에러 발생시의 이벤트를 처리할 수 있다. [ WebViewTest예제 실행 결과 ]
3. 여러 가지 뷰 • 웹 뷰의 설정 변경 시 setSettings메서드로 WebSettings객체를 얻은 후 이 객체의 set*메서드로 캐시 정책, 폰트 크기, 확대 여부, 스크립트 허용 여부 등의 설정을 변경할 수 있다. • 디폴트가 무난하지만 몇 가지 설정은 꼭 변경해야 한다. • 예제에서는 자바 스크립트와 내장 확대 기능을 사용하도록 설정하였다. • 자바 스크립트를 사용하지 않는 웹 사이트는 거의 없으므로 이 설정을 필수적이다. • 확대, 축소 기능을 사용하면 아래쪽에 확대, 축소 버튼이 나타나 사용자가 직접 배율을 조정할 수 있어 편리하다. • 웹 클라이언트 지정과 웹 뷰 설정까지 완료하면 loadUrl메서드로 이동하고자 하는 사이트로 바로 이동 가능하며, 여러 메서드를 호출하여 웹 뷰를 프로그래밍 가능하다. • Back, Forward버튼 : 히스토리의 앞, 뒤 이동 기능을 제공, 아래의 메서드를 사용한다. • void goBack() • void goForward() • Boolean canGoBack() • Boolean cnaGoForward()
3. 여러 가지 뷰 • 웹은 원격지의 페이지를 가져와 보여주지만 로컬의 HTML파일도 표시할 수 있다. • 로컬의 HTML파일은 asset폴더에 저장되며 HTML파일과 관련 이미지 파일을 넣어두고 file:///android_asset/파일명 식으로 읽는다. • HTML은 간단한 서식을 표현 가능하며 이미지나 도표도 포함할 수 있어 다양한 서식이 있는 복잡한 문서를 출력하는 용도로도 사용 가능하다. • WebViewTest예제 • 아래의 HTML파일을 test.html이라는 이름으로 작성해 둔다. • 예제의 Local버튼을 누르면 작성한 페이지가 나타난다. [ WebViewTest예제 실행 결과 ]