텍스트 뷰

  • text 속성에 직접 글자를 넣을 수도 있지만, /res/values 폴더 안에 들어있는 strings.xml에 넣어둔 태그의 값으로 설정할 수 있다
  • text 속성의 값으로 @string/태그네임 으로 넣어줄 수 있다. 

위 방식은 다국어를 설정할 때 유용하다.

/res/values-en 폴더와 /res/values-ko 폴더를 만들고 그 안에 strings.xml 파일을 같이 넣어주었다면 @string/name으로 참조하는 글자는 단말의 Locale에 따라 달라집니다. 

단말이 한국어로 설정되어 있다면 /res/values-ko/strings.xml 파일 안에 들어있는 name 태그의 값을 가져옵니다.


버튼 

  • 텍스트뷰를 상속하여 만들어졌기 때문에 TextView에서 Button으로 바꾸기만 해도 버튼이 화면에 보이게 된다.
  • 텍스트뷰의 속성외에 추가적인 기능이나 속성을 가지고 있다.
  • 라디오 버튼이나 체크박스 등으로 나누어 사용될 수 있다.
  • 라디오 버튼은 라디오그룹을 이용해 하나의 그룹으로 묶어줄 수 있다. ( 체크박스: 중복선택, 라디오버튼:단일선택)

라디오버튼을 그룹으로 만들기

<RadioGroup
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:orientation="horizontal">
  
  <RadioButton
    android:id="@+id/radio1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="남자" />
  <RadioButton
    android:id="@+id/radio2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="여자" />
    
</RadioGroup>

EditText (PlainText)

  • 텍스트를 입력받고 처리하는 기능을 제공
  • inputType을 지정할 수 있다.
  • hint 속성을 이용하여 안내글을 표시할 수 있다.

이미지 뷰 

  • 이미지를 보여준다.
  • Drawable폴더에 이미지를 넣을 때 이미지 파일의 이름은 소문자와 특수기호 중 언더스코어만 넣을 수 있다는 점에 주의해야 한다.
  • 이미지 파일의 확장자는 jpg, png, gif 등이 가능하며, 그중에서 png형식의 이미지를 권장한다.
  • scaleType속성은 이미지가 영역을 꽉 채울 것인지 아니면 이미지 원본의 크기대로 보여줄 것인지 등을 결정하는데 사용된다.

뷰가 background속성을 이용하면 배경색을 지정할 수도 있고 /res/drawable 폴더에 넣어둔 이미지 파일을 배경으로 할 수도 있다. 그런데 배경으로 설정하면 이미지는 아무런 변화가 없다. 버튼이 눌렸을 때 눌린 이미지가 보이도록 하고 싶은 경우에는 드로어블을 사용하면 된다.

드로어블을 사용하면 뷰나 화면 일부를 그래픽으로 그리는 기능을 XML로 만들 수 있다.

 

드로어블 ( Drawable )

  • Drawable은 뷰에 설정할 수 있는 객체이며 그래픽으로 그릴 수 있다.
  • Drawable은 소스 코드에서 만들 수도 있지만 XML로 만들어 사용하는 경우가 많다.
  • /res/drawable 폴더에서 우클릭 -> New -> Drawable resource file로 파일을 만들고 코드를 작성한다.
  • 이미지 파일을 보여주는 상태 드로어블, 두 개의 드로어블 간에 바뀌도록 만드는 전환 드로어블, 색상과 그라데이션을 포함하여 도형 모양을 정의할 수 있는 쉐이프 드로어블 등이 있다.
  • 지정한 거리만큼 안쪽으로 들어오도록 만들 수 있는 인셋 드로어블(InsetDrawable)은 뷰가 실제 범위보다 작은 백그라운드가 필요할 때 유용하게 사용된다.
  • 다른 드로어블을 클리핑하는 클립 드로어블은 진행률 표시 줄과 같은 항목을 구현하는데 많이 사용한다.
  • 그 외로 다른 드로어블의 크기를 바꿀 수 있는 스케일 드로어블도 있다.

상태 드로어블 ( StateListDrawable )

  • 뷰의 상태에 따라 보여줄 그래픽을 다르게 지정할 수 있도록 한다.
  • 최상위 태그는 <selector>이다.
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true"  
	 android:drawable="@drawable/up_selected" />

    <item android:drawable="@drawable/up" />
</selector>

 

state_ 로 시작하는 속성은 상태를 나타낸다. pressed는 눌린 상태를의미하고 focused는 포커스를 받은 상태를 의미한다.

속성이 지정되지 않으면 drawable 속성에 up이미지가 디폴트 이미지로 보여진다.

<Button
    android:id="@+id/button"
    android:layout_width="80dp"
    android:layout_height="80dp"
    android:background="@drawable/up" />

/res/drawable 폴더 안에 up.xml 을 배경으로 설정하면 적용 된다.


쉐이프 드로어블 (Shape Drawable)

  • 최상위 태그를 <shape>로 바꾸면 도형 하나를 정의할 수 있다.
  • Design탭에서 작성한 모양을 확인할 수 있다.
  • shape태그에 shape속성을 이용해 모양을 설정할 수도 있다.
  • <stroke>는 테두리 선의 속성을 지정하며, width는 선의 굵기, color는 선의 색상을 설정한다.
  • <solid>는 도형의 안쪽을 채울 때 사용한다.
  • <gradient>는 그라데이션을 줄 때 사용한다.
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">

    <size android:width="200dp" android:height="120dp"/>
    <stroke android:width="1dp" android:color="#0000ff"/>
    <solid android:color="#aaddff" />
    <padding android:bottom="1dp" />

</shape>
<shape xmlns:android="http://schemas.android.com/apk/res/android">

    <gradient
        android:startColor="#7288DB"
        android:centerColor="#3250B4"
        android:endColor="#254095"
        android:angle="90"
        android:centerY="0.5"
        />

    <corners android:radius="2dp" />

</shape>

 

테두리만 있는 버튼 배경

  • 최상위 태그는 <layer-list>이며, 여러 그래픽을 하나의 XML 파일에 넣을 수 있다.
  • <layer-list>안에 <item> 태그가 여러개 들어갈 수 있으며, <item>태그 안에는 <shape> 태그가 들어갈 수 있어 각각을 도형으로 정의할 수 있다.
  • 버튼의 테두리만 보이게 하는 드로어블을 만들고 싶다면 도형 안쪽을 투명하게 채우고 테두리 선만 색상을 주면 된다.
  • 여러 개의 그래픽으로 나누면 그래픽을 중첩시켜서 좀 더 예쁜 배경을 만들 수 있다.
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">

    <item>
        <shape android:shape="rectangle">
            <stroke android:width="1dp" android:color="#BE55DA" />
            <solid android:color="#00000000" />
        </shape>
    </item>

    <item android:top="1dp" android:bottom="1dp" 
          android:right="1dp" android:left="1dp">
        <shape android:shape="rectangle">
            <stroke android:width="1dp" android:color="#BE55DA" />
            <solid android:color="#00000000" />
        </shape>
    </item>

</layer-list>

Reference

 

[부스트코스] 안드로이드 프로그래밍 강좌소개 : edwith

- 부스트코스

www.edwith.org

 

 

 

'Android' 카테고리의 다른 글

[안드로이드] 애니메이션  (0) 2019.11.18
[안드로이드] 패키지명, Color 변경  (1) 2019.11.17
[Kotlin] TextWatcher  (0) 2019.10.30
[Kotlin] 안드로이드 권한 - 1  (0) 2019.09.30
[Design] Material Design  (0) 2019.08.18
더보기

작성 중 날라가 다시씀

서버에 EditText에 입력한 값이 유효한지 확인하는 부분을 만들어야하는중에 TextWatcher를 설명하는 글을 보게 되었다. TextWatcher를 통해 입력이 끝났을 때 발생하는 event가 실행된다는 설명들을 볼 수 있었는데, 간단히 설명된 글들도 많고 감이 잘 잡히지 않아, 언제 호출되는지 테스트해보기로 했다.

 

테스트하며 작성한 코드와 주석을 첨부했다.

        /* 1차 테스트
        - 이벤트가 호출되는 시점을 알아보기 위해 println()으로 호출되었음을 확인해보기

        결과
        - 글자 하나를 입력할 때 마다 3개의 이벤트가 모두 호출됨
        - 작성 전, 작성 중, 작성 끝 순으로 키보드 한번 입력마다 3개의 이벤트가 모두 호출됨

        생각했던 예상
        - 입력시작하려할 때 작성 전 이벤트 발생후, 텍스트를 연속으로 작성하는 동안 작성 중, 멈추면 작성 끝이 나올 것이라 생각했음
        */

        /* 2차 테스트
        - 각 단계에서 입력중인 텍스트의 값을 찍어보기

        결과
        - 작성전(before) : 새로운 텍스트가 입력되기 전의 Text값을 가져옴
        - 작성중(on) : 새로운 텍스트가 입력된 값을 가져옴
        - 작성끝(after) : onTextChanged와 같은 값을 가져옴
        - "곡 -> 고기" 로 변할 때 최종적으론 고기가 작성중과 작성끝에서 값을 다 가져오지만
          "고기" 를 가져오기 전
          before: 곡, on : 고, after: 고
          before: 고, on : 고기, after : 고기     이렇게 읽어옴

          생각했던 결과
          before와 on, after에서 읽어올 때 생각했던 부분이 일부 맞았음
          받침있는 글자에서 새로운 글자로 변할 때 위와 같은 순차가 아니라 before: 곡, on,after: 고기 이렇게 한번에 가져올 것이라 생각했던 부분이 다름
        */

        /* 정리
        텍스트 작성이 완료된 시점에 서버의 데이터와 비교하기위해 이벤트 발생 시점과 읽어오는 값을 테스트하게 되었고,
        이벤트 발생이 키입력 한번마다 일어나서 서버쪽 데이터와 비교하는걸 이 부분에 만들게되면 너무 잦은 request를 보내게되어 부적합하다고 생각함.

        작성을 완료하고 해당 값이 정상적인 값인지 확인하는 버튼을 두는 방식으로 만들어야겠음.
         */
        editText.addTextChangedListener(object : TextWatcher {
            override fun afterTextChanged(s: Editable?) {
                showMessage("afterTextChanged", "입력이 완료되었습니다3", editText.text.toString())
                showLine()
            }

            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
                showMessage("beforeTextChanged", "입력하기 전입니다1", editText.text.toString())
            }

            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
                showMessage("onTextChanged", "타이핑 중입니다2", editText.text.toString())
            }
        })

아래는 실행해본 결과이다.

Test

 

간단히 "고기"라고 입력을 하며 확인한 화면 중 일부이다.

입력이 완료되었다는 설명을 읽었을 때 고기라고 멈추지않고 입력했을 때, "고기"의 입력이 끝나고 이벤트가 발생될 것이라 생각했었지만, 키입력 한번이 끝날때마다 입력 완료 이벤트가 발생했다.

 

키 입력마다 이벤트의 발생이 일어나 서버의 데이터와 확인하는 부분을 이곳에 만들면 너무 많은 request가 발생하게 되어 적합하지 않다는 결론을 내리게 됐다.

'Android' 카테고리의 다른 글

[안드로이드] 패키지명, Color 변경  (1) 2019.11.17
[안드로이드] 기본위젯과 드로어블  (0) 2019.11.16
[Kotlin] 안드로이드 권한 - 1  (0) 2019.09.30
[Design] Material Design  (0) 2019.08.18
[Kotlin] Room Library  (0) 2019.08.17

문제


수많은 마라톤 선수들이 마라톤에 참여하였습니다.

단 한 명의 선수를 제외하고는 모든 선수가 마라톤을 완주하였습니다.

마라톤에 참여한 선수들의 이름이 담긴 배열 participant와 완주한 선수들의 이름이 담긴 배열 completion이 주어질 때,

완주하지 못한 선수의 이름을 return 하도록 solution 함수를 작성해주세요.

 

해결 방법 : 배열의 정렬을 활용


 

public static String solution(String[] participant, String[] completion) {
	Arrays.sort(participant);
	Arrays.sort(completion);
	int index = 0;
	for(String c : completion) {
		if(!c.equals(participant[index]))
			return participant[index];
		index++;
	}
	return participant[participant.length-1];
}

참여한 사람들과 완주한 사람들을 담아둔 배열을 정렬시키고,

배열의 처음부터 순차적으로 비교해나가며 완주하지 못한 선수를 찾아내도록 만들었다. 

 

위의 코드는 완주한 사람을 배열에서 값을 순차적으로 가져와 같은 인덱스의 참여한 사람 배열의 값을 비교해 같은 값인지 확인한다.

equals() vs ==

String은 참조변수라서, ==으로 비교할 경우 객체가 같은가를 비교하게 되므로, equals를 사용하여 내용이 같은지 비교하도록 했다.

Arrays.sort() 시간 복잡도 : O(nlogn) or O(n^2) // O(nlogn)

primitive type배열은 Dual Pivot Quick Sort를 하고 nlogn을 기대할 수 있지만, 최악의 경우 n^2있고, primitive type은 comparator를 지정할 수 없다.

 

객체, 제너릭 타입들은 comparator를 지정하거나, null인 경우

Merge sort 또는 TimSort를 이용한다. 이는 최악의 경우에도 nlogn을 기대할 수 있다.

 

 

 

해쉬맵을 활용


public static String solution(String[] participant, String[] completion) {
	String answer = "";
    
	HashMap<String, Integer> prtcpt_map = new HashMap<>();
	for(String name : participant) {
		prtcpt_map.put(name, prtcpt_map.getOrDefault(name, 0)+1);
		// getOrDefault() : 값이 없으면 0으로 초기화하고 있으면 해당 값을 가져온다
	}
	
	for(String name: completion) {
		prtcpt_map.put(name,  prtcpt_map.get(name)-1);
	}
	
	for(String name: prtcpt_map.keySet()) {
		if(prtcpt_map.get(name) != 0) {
			answer = name;
			break;
		}
	}
	
	return answer;
}

동명이인이 있을 수 있어 참여한 사람의 이름과 명수를 K-V의 형태로 Map에 저장하고,

완주한 사람의 이름이 나올때 마다 명수를 줄여준다. 완주하지 못한 사람은 1명이기 때문에,

keySet을 받아와 key의 value가 0이 아닌 이름을 찾아준다.

 

위의 코드는 key의 value가 0인지 아닌지만 확인하면 된다. 

HashMap의 시간복잡도

HashMap은 Dictionary와 같은 역할을 하는 자료구조이다. 

중요한 점은 Hash의 성능을 통해 저장된 Key에 해당하는 Value를 O(1)의 시간복잡도로 검색이 가능하다.

 

HashMap.put(K, V) : O(1)
HashMap.replace(K,V) : 상수기간

자바의 HashMap의 요소에 대한 수정은 생각보다 복잡하다.

replace()와 get()을 통해 접근, 수정해주도록 하자. 말할 필요도 없이 시간복잡도는 상수기간이다.

 

HashMap.containsKey(K), HAshMap.containsValue(V) : O(1), O(n)

Key와 Value를 포함하고 있는지 확인하는 함수이다.

주로 containsKey()를 통해 Key가 있는지 확인하고 없을시 put()해주는 식으로 사용한다.

 

HashMap.keySet() : O(1)

Key를 모아놓은 자료구조를 반환하는 메서드이다. keySet()은 Set<K>를 반환한다.

주로 keySet()을 통해 반환된 Set으로 Map의 요소를 순환하고 싶을 때 사용한다.

 

References


 

 

 

'Algorightm' 카테고리의 다른 글

[Kotlin] 387.First Unique Character in a String [LeetCode]  (0) 2020.05.12
[Kotlin] 344.ReverseString [LeetCode]  (0) 2020.04.28
Hash Algorithm  (0) 2019.10.14
시간복잡도를 알아보자  (0) 2019.07.17

+ Recent posts