'분류 전체보기'에 해당되는 글 418건
- 2010.05.07 정규식
- 2010.04.22 back key overriding
- 2010.04.22 SurfaceView
- 2010.04.22 custom popup dialog layout design
- 2010.04.15 Android Location & google maps 탐구 -1-
- 2010.04.15 android gps 관련 소스 7
- 2010.04.13 Android의 9 patch(나인패치) drawable 이란?
- 2010.04.12 안드로이드 010: TableLayout 컨테이너 / ScrollView (Android Container 3: TableLayout / ScrollView) 2
- 2010.04.12 어플리케이션 서명에서 마켓 배포까지, 한눈에 보기
- 2010.04.06 AndroidManifest.xml 10
정규식, 정규표현식 다 같은말이다.
어느 프로그래밍언어든 정규식, 정규표현식 을 다루는것은 비슷하다.
1. 개념잡기
일반화 시킨 표현. 이것을 정규표현이라고 요약할 수 있을 것 같다.
다음의 과정을 너무 쉽다 생각말고 따라오길 바란다.
- 감잡기
"12354" -> 숫자
"asdfasf" -> 알파벳
두 가지의 간단정규표현을 만들었다. 실생활의 보기와 비추어보자.
"길이가 3인 이름!"
위의 표현은 길이를 표시하는 방법이 없다. 조금 더 발전시켜서 "알파벳{3}"이런식
으로 길이를 표현할 수 있도록 한다. 그리고, "알파벳"란 것도 너무 길다 "알"
이라고 한 글자로 표현한다. 그러면 "길이가 3인 이름"은
"알{3}"으로 표시가 가능하다.
길이가 10인 숫자는 "수{10}"
"길이가 1인 알파벳이 나오고 그 다음에 길이가 3인 숫자가 나오는 문자열"! ->
"알{1}수{3}"얼핏이나마 감이 올 것이다.
"첫 글자는A, 그 다음은 아무 알파벳 5글자" -> "A알{5}"
- 조금 더
아이디는 대개 첫 글자는 영문이고 두 번째부터는 영문이나 숫자가 온다. 이것을
표현하기 위해선 이것 들 중에 하나란 의미를 갖는 새로운 표현이 필요하다.
"a,b,c,d 중에 하나" -> [abcd]
응용하면,
"알파벳이나, 숫자중 하나" -> [알수]
"[" 안에 있는 문자들의 순서는 의미가 없으며, 그 표현은 (클래스라고 한다.)
결국 한 글자를 말한다.
위에서 말한 "첫 글자는 영문, 두 번째 부터는 영문이나 숫자가 11자"를
표현하면, "알[알수]{11}".
그런데, 실제로 모든 아이디가 12자인 것은 아니다, 대개 4자부터 12자를 지원한다.
새로운 표현이 등장한다. "몇 자부터 몇 자"
"A가 3글자부터 12자" -> "A{3,12}"
"알파벳이나 숫자가 1자부터 100자" -> "[알수]{1,100}"
이제 아이디를 다시 정의하자.
"첫 글자는 영문, 영문이나 숫자가 3자부터 11자" -> "알[알수]{3,11}"
2. 표현식
지금 까지의 규칙에서 설명한 용어를 실제 정규표현에서 사용하는 표현으로 바꾸고,
다른 세부적인 옵션에 대해 알아보자.
\ : 다음의 글자가 특별한 문자임을 나타낸다. 때론, 그 다음 문자 자체를 의미하기
도 한다.
보기를 들면, "\n"은 문자"\"과 문자"n" 두 글자와 매치되는 것을 의미하는 것이 아
닌,
새줄(New Line)을 의미하며, "\\"은 첫 "\" 다음 문자인 "\" 자체를 의미한다.
즉, "\\"은
"\"과 매칭된다.
^ : 입력문자열의 맨 처음을 의미한다. (맨 첫 글자가 아니라, 맨 처음이란 문맥적 의
미를
말한다. 아주 중요하다) 기본적으로 정규표현은 입력 문자열의 한 줄에만 적용된다.
하지만, 옵션에 따라 여러줄에 적용할 수도 있다. 그럴 경우에는 "^"는 "\n"
나 "\r"
다음의 위치를 의미한다.
$ : "^"는 반대로 입력 문자열의 맨 끝을 의미한다. 역시 여러줄에 정규표현이 적용
될
경우에는 "\n"이나 "\r"의 앞의 위치를 의미한다.
* : 이 문자 앞의 표현이 0번내지 무한번 반복될 수 있음을 말한다.
보기를 들면, /a*/은 "a", "", "aaaa", "aaaaa"와 매칭된다.
(0번이상은 없어도 된다는 것을 의미한다.)
+ : *와 같지만, 0번이상이 아니라 1번이상이라는 점을 제외하곤 /*/와 같다.
? : 앞의 표현이 0번 또는 1번. /do(es)?/는 "do", "does"와 매칭된다.
{n} : 앞의 표현이 n은 음수가 아닌 정수이어야 하며, 앞의 표현이
n번 매치되는 것을 말한다.
{n,} : 앞의 표현이 n은 음수가 아닌 정수이어야 하며, n번 이상
매치되는 것을 말한다.
{n,m} : 앞의 표현이 n번 이상 부터 m번 이하까지 매칭되는 것을
말하며, /*/는 /{0,}/과 같으며, /+/는 /{1,}/과 /?/는 /{0,1}/으로
표현 가능하다.
. : "\n"을 제외한 한 글자를 뜻한다. 만일 모든 글자를 표현하고
싶다면("\n"마저도 합친) /[.\n]/을 사용하면 된다.
x|y : x 또는 y와 매칭된다. 보기를 들면, /z|food/는 "z" 또는
"food"와 매칭된다. /(z|f)ood/는 "zood" 또는 "food"와 매칭된다.
(참고로 괄호는 묶어준 것 이상의 의미가 있다.)
(패턴) : 해당 패턴과 매칭시키고, 그 부분을 특정 변수에 담는다.
그 변수 이름은 JScript는 $0~$9까지의 변수에 저장이 되고(Perl과 같다.),
VBScript에서는 SubMatches 컬렉션에 저장된다.
괄호기호 자체와 매치시키고 싶다면? /\(/와 /\)/를 사용한다.
(?:패턴) : 해당 패턴과 매칭은 시키지만, 그 부분을 특정 변수에
담지 않는다. 왜 이게 필요할까?
위의 보기에서 /(z|f)ood/는 "zood" 또는 "food"와 매칭된다고 했는데,
단순히 매칭의 목적으로 사용했지만, "zood"의 경우 "z"가 $0 이란
변수에 저장이 되고 말았다. 이러한 것을 막기 위해서 사용하는 것이
(?:패턴)이다.
(?=패턴) : (?:패턴)과 동일하지만, 패턴과 일치한 부분이후부터
다음 매치가 일어나지 않고 패턴 앞부터 다시 매칭이 진행된다.
즉, 룩업(lookup, lookahead)을 할 뿐이다. /Windows (?=95|98|NT|2000)/ 은
"Windows 2000"의 "Windows" 부분과 매칭이 되며 다음 매칭은
"2000" 다음 부터가 아닌 "Windows" 다음 부터 진행이 된다.
(?!패턴) : (?=패턴)과 반대다. /Windows (?=95|98|NT|2000)/ 은
"Windows 3.1"의 "Windows" 부분과 매칭이 된다.
[xyz] : "["안에 있는 표현중 하나를 의미한다.
[^xyz] : "["안에 있는 표현을 제외한 것중 하나를 의미한다.
"[^abc]"는 "plain"의 "p"때문에 매칭된다.
[a-z] : "a"부터 "z" 까지의 문자중 하나
[^a-z] : "a"부터 "z" 까지의 문자를 제외한 하나
\b : 단어의 경계(단어와 공백, "\n", "\r"의 사이)와 매칭된다.
보기를 들면, "er\b"는 "never"와는 매칭되지만, "verb"와는 매칭되지 않는다.
\B : 단어의 경계가 아닌 것과 매칭된다. "er\B"는 "verb"와는
매칭되지만, "never"와는 매칭되지 않는다.
\cx : Ctrl+x 키와 매칭된다. "\cc"는 Ctrl+C와 매칭된다. x의 범위는
[a-zA-Z]이며, 만일 이 이외의 문자를 사용한다면 "\c"는 "c"와 동일하다.
\d : [0-9]와 같다.
\D : [^0-9]와 같다. 참고로 대문자는 소문자의 반대 의미를 갖는다.
\f : 폼피드(form-feed) 문자를 의미하며, "\x0c"와 "\cL"과 동일하다.
\n : 새 줄(newline)를 의미하며, "\x0a"와 "\cJ"와 동일하다.
\r : 캐리지 리턴(carriage return)을 의미하며, "\x0d"와 "\cM"과 동일하다.
\t : 탭. "\x09", "\cI"과 동일
\v : 버티컬 탭. "\x0b", "\cK"과 동일
\s : 화이트스페이스를 의미한다. 화이트스페이스란 공백, 탭, 폼피드,
캐리지리턴등을 의미한다. [ \f\n\r\t\v]과 동일("\f"앞에 공백이 있다. 주의!)
\S : "[^ \f\n\r\t\v]"
\w : "_"를 포함한 일반적인 단어에 사용되는 문자를 말한다.
"[A-Za-z0-9_]" 과 동일
\W : "[^A-Za-z0-9_]"
\xn : n은 2자리 16진수이며, 해당 16진수 코드와 매칭된다. "\x412"는 16진수
41은 "A"이기 때문에 "A2"와 매칭된다.
\num : 캡쳐한 매칭을 가리킨다(백레퍼런스, backreference).
"(.)\1"은 연속된 두개의 문자열을 의미한다.
\n : "\1"은 위에서 캡쳐한 매칭(backreference)를 가리킨다고 했는데,
만일 이 패턴앞에 어떠한 n개의 캡쳐한 표현이 있다면 백레퍼런스이지만,
그렇지 않은 경우에는 8진수로 간주하여 해당 코드의 문자와 매칭된다.
\un : n은 4자리 UNICODE 이다. "\u00A9"은 copyright 심볼인 "ⓒ"와 매칭된다.
greedy, non-greedy
? : 앞에서 설명했는데, 왜 또? 라고 생각할 것이다.
?은 문맥에 따라 특별한 의미를 갖는다.
패턴 "o*"는 "foooood"와 매칭된다. 당연하다! 하지만, "f"앞의 "o"와
매칭되는 것이 아니다!! "ooooo"와 매칭된 것이다. 즉, 기본으로
정규표현 매칭은 가장 큰 범위를 선택한다. 이것을 greedy하다고 한다.
하지만, 때론 작은 범위에 매칭시킬 필요가 있을 경우가 있다.
(이의 적절한 보기는 잠시 후에 나온다.) "o*?"가 방금 말한
non-greedy 매칭이다.
수량관련 문자인 "*", "+", "?", "{n}", "{n,}", "{n,m}" 다음에 "?"가
나오면 non-greedy 매칭이된다.
잠시, 위에서 "o*?"가 "o"와 매칭된다고 했는데 이상하게 생각한 분이
있었을 것이다. 맞다. "o*?"는 ""와 매칭되었다. "*"는 0개이상임을
잊어선 안된다. "o+?"가 "o"와 매칭된다.
4. 보기
- 웹 주소
"http://msdn.microsoft.com:80/scripting/default.htm"
위의 주소를 표현할 수 있는 정규표현은 아래와 같다.
/(\w+):\/\/([^/:]+)(:\d*)?([^# ]*)/
$1 : http
$2 : msdn.microsoft.com
$3 : 80
$4 : /scripting/default.htm
- 중복된 단어를 하나로
중복된 영어단어를 하나로 합치기 위해선, 우선 단어를 찾아야한다.
그리고 단어는 앞 뒤가 단어의 경계이어야한다. (말이 참 이상하지만..)
따라서, 아래와 같은 1차 정규표현을 얻을 수 있다.
/\b([a-z]+)\b/
연속해서 동일한 두개의 단어... 앞에서 캡쳐한 표현을 다시 활용하면 된다.
그리고, 단어와 단어 사이엔 화이트스페이스가 있다.
/\b([a-z]+)\s+\1\b/
- HTML 태그 제거
HTML문서에서 태그를 제거한 문서를 추출하고자 한다.
태그는 "<"와 ">"로 감싸여 있다.
/<.*>.*</.*>/
그런데, 위의 정규표현을 HTML문서에 적용하여 해당 패턴을 "",
빈문자열로 바꾸면 문서는 빈 문서가 되고 만다.
<html>
<title>...</title>
<body>
<font>.... </font>
...
</body>
greedy한 매칭이 기본값이라고 위에서 언급을 했다. 따라서,
위의 HTML 문서를 보면, <html>....</body>로 생각할 수 있다.
따라서, 문서 전체가 사라지는 것이다. 이것을 막기 위해선 "*"뒤에 "?"를
추가하면 된다.
/<.*?>.*?</.*?>/
아직 끝나지 않았다. :)
좀더 정제를 한다면, 올바른 HTML 문서는 <태그명>과 </태그명>이
서로 일치한다. 이것도 적용한다면,
/<.(*?)>.(*?)</\1>/
위의 $1에 해당되는 부분을 좀 더 생각해보면, ">"를 제외한 문자로
볼 수 있다. 따라서 최종적으로 아래와 같이 정리된다.
/<(\w+)[^>]*?>(.*?)</\1>/
- URL
/(?:^|")(http|ftp|mailto):(?://)?(\w+(?:[\.:@]\w+)*?)(?:/|@)([^"\?]*?)(?:\?
([^\?"]*?))?(?:$|")/
- float 상수
/^(((+|-)?\d+(\.\d*)?)|((+|-)?(\d*\.)?\d+))$/ -1.1 1.1 .9 .8
정규식 구문
정규식은 일반 문자(예: a에서 z)와 메타문자 로 알려진 특수 문자로 구성된 텍스트 패턴입니다. 패턴은 텍스트 본문을 검색할 때 일치하는 문자열을 하나 이상 설명합니다. 정규식은 검색되는 문자열과 일치하는 문자 패턴을 찾는 템플릿의 역할을 합니다.
일반적으로 볼 수 있는 몇 가지 정규식 예는 다음과 같습니다.
/^\[ \t]*$/ | "^\[ \t]*$" | 빈 줄을 찾습니다. |
/\d{2}-\d{5}/ | "\d{2}-\d{5}" | 2자리, 하이픈 및 5자리로 구성된 ID 번호를 찾습니다. |
/<(.*)>.*<\/\1>/ | "<(.*)>.*<\/\1>" | HTML 태그를 찾습니다. |
아래 표는 정규식 컨텍스트에 사용되는 모든 메타문자와 메타문자의 동작을 보여줍니다.
\ | 그 다음 문자를 특수 문자, 리터럴, 역참조, 또는 8진수 이스케이프로 표시합니다. 예를 들어, "n"은 문자 "n"을 찾고 "\n"은 줄 바꿈 문자를 찾습니다. "\\" 시퀀스는 "\"를 찾고 "\("는 "("를 찾습니다. |
^ | 입력 문자열의 시작 위치를 찾습니다. Multiline 속성이 설정되어 있으면 ^는 '\n' 또는 '\r'앞의 위치를 찾습니다. |
$ | 입력 문자열의 끝 위치를 찾습니다. Multiline 속성이 설정되어 있으면 $는 '\n' 또는 'r'뒤의 위치를 찾습니다. |
* | 부분식의 선행 문자를 0개 이상 찾습니다. 예를 들어, "zo*"는 "z", "zoo" 등입니다. *는 {0,}와 같습니다. |
+ | 부분식의 선행 문자를 한 개 이상 찾습니다. 예를 들어, "zo+"는 "zo", "zoo" 등이지만 "z"는 아닙니다. +는 {1,}와 같습니다. |
? | 부분식의 선행 문자를 0개 또는 한 개 찾습니다. 예를 들어, "do(es)?"는 "do" 또는 "does"의 "do"를 찾습니다. ?는 {0,1}과 같습니다. |
{ n } | n 은 음이 아닌 정수입니다. 정확히 n 개 찾습니다. 예를 들어, "o{2}"는 "Bob"의 "o"는 찾지 않지만 "food"의 o 두 개는 찾습니다. |
{ n ,} | n 은 음이 아닌 정수입니다. 정확히 n 개 찾습니다. 예를 들어, "o{2}"는 "Bob"의 "o"는 찾지 않지만 "foooood"의 모든 o는 찾습니다. "o{1,}"는 "o+"와 같고, "o{0,}"는 "o*"와 같습니다. |
{ n , m } | m 과 n 은 음이 아닌 정수입니다. 여기서 m 은 n 보다 크거나 같습니다. 최소 n 개, 최대 m 개 찾습니다. 예를 들어, "o{1,3}"은 "fooooood"의 처음 세 개의 o를 찾습니다. "o{0,1}"은 "o?"와 같습니다. 쉼표와 숫자 사이에는 공백을 넣을 수 없습니다. |
? | 이 문자가 다른 한정 부호(*, +, ?, { n }, { n ,}, { n , m })의 바로 뒤에 나올 경우 일치 패턴은 제한적입니다. 기본값인 무제한 패턴은 가능한 많은 문자열을 찾는 데 반해 제한적인 패턴은 가능한 적은 문자열을 찾습니다. 예를 들어, "oooo" 문자열에서 "o+?"는 "o" 한 개만 찾고, "o+"는 모든 "o"를 찾습니다. |
. | "\n"을 제외한 모든 단일 문자를 찾습니다. "\n"을 포함한 모든 문자를 찾으려면 '[.\n]' 패턴을 사용하십시오. |
( pattern ) | pattern 을 찾아 검색한 문자열을 캡처합니다. 캡처한 문자열은 VBScript의 경우 SubMatches 컬렉션, Jscript의 경우 $0 ... $9 속성을 이용하여 결과로 나오는 Matches 컬렉션에서 추출할 수 있습니다. 괄호 문자인 ( )를 찾으려면 "\(" 또는 "\)"를 사용하십시오. |
(?: pattern ) | pattern 을 찾지만 검색한 문자열을 캡처하지 않습니다. 즉, 검색한 문자열을 나중에 사용할 수 있도록 저장하지 않는 비캡처 검색입니다. 이것은 패턴의 일부를 "or" 문자(|)로 묶을 때 유용합니다. 예를 들어, 'industr(?:y|ies)는 'industry|industries'보다 더 경제적인 식입니다. |
(?= pattern ) | 포함 예상 검색은 pattern 과 일치하는 문자열이 시작하는 위치에서 검색할 문자열을 찾습니다. 이것은 검색한 문자열을 나중에 사용할 수 있도록 캡처하지 않는 비캡처 검색입니다. 예를 들어, "Windows(?=95|98|NT|2000)"는 "Windows 2000"의 "Windows"는 찾지만 "Windows 3.1"의 "Windows"는 찾지 않습니다. 예상 검색은 검색할 문자열을 찾은 후 예상 검색 문자열을 구성하는 문자 다음부터가 아니라 마지막으로 검색한 문자열 바로 다음부터 찾기 시작합니다. |
(?! pattern ) | 제외 예상 검색은 pattern 과 일치하지 않는 문자열이 시작하는 위치에서 검색할 문자열을 찾습니다. 이것은 검색한 문자열을 나중에 사용할 수 있도록 캡처하지 않는 비캡처 검색입니다. 예를 들어, "Windows(?!95|98|NT|2000)"는 "Windows 3.1"의 "Windows"는 찾지만 "Windows 2000"의 "Windows"는 찾지 않습니다. 예상 검색은 검색할 문자열을 찾은 후 예상 검색 문자열을 구성하는 문자 다음부터가 아니라 마지막으로 검색한 문자열 바로 다음부터 찾기 시작합니다. |
x | y | x 또는 y 를 찾습니다. 예를 들어, "z|food"는 "z" 또는 "food"를 찾습니다. "(z|f)ood"는 "zood" 또는 "food"를 찾습니다. |
[ xyz ] | 문자 집합입니다. 괄호 안의 문자 중 하나를 찾습니다. 예를 들어, "[abc]"는 "plain"의 "a"를 찾습니다. |
[^ xyz ] | 제외 문자 집합입니다. 괄호 밖의 문자 중 하나를 찾습니다. 예를 들어, "[^abc]"는 "plain"의 "p"를 찾습니다. |
[ a-z ] | 문자 범위입니다. 지정한 범위 안의 문자를 찾습니다. 예를 들어, "[a-z]"는 "a"부터 "z" 사이의 모든 소문자를 찾습니다. |
[^ a-z ] | 제외 문자 범위입니다. 지정된 범위 밖의 문자를 찾습니다. 예를 들어, "[^a-z]"는 "a"부터 "z" 사이에 없는 모든 문자를 찾습니다. |
\b | 단어의 경계, 즉 단어와 공백 사이의 위치를 찾습니다. 예를 들어, "er\b"는 "never"의 "er"는 찾지만 "verb"의 "er"는 찾지 않습니다. |
\B | 단어의 비경계를 찾습니다. "er\B"는 "verb"의 "er"는 찾지만 "never"의 "er"는 찾지 않습니다. |
\c x | X 가 나타내는 제어 문자를 찾습니다. 예를 들어, \cM은 Control-M 즉, 캐리지 리턴 문자를 찾습니다. x 값은 A-Z 또는 a-z의 범위 안에 있어야 합니다. 그렇지 않으면 c는 리터럴 "c" 문자로 간주됩니다. |
\d | 숫자 문자를 찾습니다. [0-9]와 같습니다. |
\D | 비숫자 문자를 찾습니다. [^0-9]와 같습니다. |
\f | 폼피드 문자를 찾습니다. \x0c와 \cL과 같습니다. |
\n | 줄 바꿈 문자를 찾습니다. \x0a와 \cJ와 같습니다. |
\r | 캐리지 리턴 문자를 찾습니다. \x0d와 \cM과 같습니다. |
\s | 공백, 탭, 폼피드 등의 공백을 찾습니다. "[ \f\n\r\t\v]"와 같습니다. |
\S | 공백이 아닌 문자를 찾습니다. "[^ \f\n\r\t\v]"와 같습니다. |
\t | 탭 문자를 찾습니다. \x09와 \cI와 같습니다. |
\v | 수직 탭 문자를 찾습니다. \x0b와 \cK와 같습니다. |
\w | 밑줄을 포함한 모든 단어 문자를 찾습니다. "[A-Za-z0-9_]"와 같습니다. |
\W | 모든 비단어 문자를 찾습니다. "[^A-Za-z0-9_]"와 같습니다. |
\x n | n 을 찾습니다. 여기서 n 은 16진수 이스케이프 값입니다. 16진수 이스케이프 값은 정확히 두 자리여야 합니다. 예를 들어, '\x41'은 "A"를 찾고 '\x041'은 '\x04'와 "1"과 같습니다. 정규식에서 ASCII 코드를 사용할 수 있습니다. |
\ num | num 을 찾습니다. 여기서 num 은 양의 정수입니다. 캡처한 문자열에 대한 역참조입니다. 예를 들어, '(.)\1'은 연속적으로 나오는 동일한 문자 두 개를 찾습니다. |
\ n | 8진수 이스케이프 값이나 역참조를 나타냅니다. \ n 앞에 최소한 n개의 캡처된 부분식이 나왔다면 n 은 역참조입니다. 그렇지 않은 경우 n 이 0에서 7 사이의 8진수이면 n 은 8진수 이스케이프 값입니다. |
\ nm | 8진수 이스케이프 값이나 역참조를 나타냅니다. \ nm 앞에 최소한 nm개의 캡처된 부분식이 나왔다면 nm 은 역참조입니다. \ nm 앞에 최소한 n개의 캡처가 나왔다면 n 은 역참조이고 뒤에는 리터럴 m이 옵니다. 이 두 경우가 아닐 때 n과 m이 0에서 7 사이의 8진수이면 \ nm 은 8진수 이스케이프 값 nm을 찾습니다. |
\ nml | n 이 0에서 3 사이의 8진수이고 m 과 l 이 0에서 7 사이의 8진수면 8진수 이스케이프 값 nml 을 찾습니다. |
\u n | n 은 4 자리의 16진수로 표현된 유니코드 문자입니다. 예를 들어, \u00A9는 저작권 기호(©)를 찾습니다. |
--------------------------------------------------------------------------------
Visual Basic Scripting Edition에서 정규 표현식 기능 이용하기
--------------------------------------------------------------------------------
정규 표현식이란 무엇인가요?
정규 표현식이란 무엇일까요? 정규 표현식은 복잡한 패턴 매칭 기능과 텍스트형 검색-대체 알고리즘을 개발할 수 있는 툴을 제공합니다. Perl, egrep, awk, 또는 sed 개발자에게 정규 표현식이 무엇이냐고 물어보면, 정규 표현식은 텍스트와 데이터를 조작할 때 사용할 수 있는 가장 강력한 유틸리티라고 대답할 것입니다. 개발자는 패턴을 만들어 특정 문자열을 매치키시킴으로써 데이터를 검색하거나 추출하거나 교체하는 일을 완벽하게 제어할 수 있습니다. 간단히 말해서, 정규 표현식을 정복하면 데이터도 정복할 수 있는 것입니다.
여기서는, VBScript 정규 표현식과 관련된 모든 개체를 설명하고, 일반적인 정규 표현식 패턴을 간략하게 살펴보고, 실제 코드로 정규 표현식을 사용하는 예를 들어보도록 합시다.
VBScript RegExp 개체
VBScript 5.0 버전은 정규 표현식을 하나의 개체로서 제공합니다. VBScript RegExp 개체는 설계 면에서 JScript의 RegExp 및 String 개체와 비슷하고, 구문 면에서는 Visual Basic과 일치합니다. 먼저, VBScipt RegExp 개체의 속성과 메소드에 관해 알아봅시다. VBScript RegExp 개체는 사용자에게 세 개의 속성과 세 개의 메소드를 제공합니다.
속성 메소드
Pattern Test(검색-문자열)
IgnoreCase Replace (검색-문자열, 대체-문자열)
Global Execute (검색-문자열
Pattern - 정규 표현식을 정의하는 데 사용되는 문자열. 이 속성은 정규 표현식 개체를 사용하기 전에 먼저 설정해야 합니다. Pattern에 관한 내용은 아래에 자세히 설명되어 있습니다.
IgnoreCase - 문자열 안에서 일치하는 문자가 발생할 모든 가능성에 대해 정규 표현식을 테스트해야 하는지를 나타내는 부울 논리 속성입니다. IgnoreCase의 기본 설정 값은 False입니다.
Global - 문자열 안에서 일치하는 문자가 발생할 모든 가능성에 대해 정규 표현식을 테스트해야 하는지 여부를 나타내는 읽기 전용 부울 논리 속성입니다. Global의 기본 설정 값은 False입니다.
Test (문자열) - Test 메소드는 문자열을 매개 변수로 받아 그 문자열이 정규 표현식에 일치하면 True를 반환하고 그렇지 않으면 False를 반환합니다.
Replace (검색-문자열, 대체-문자열) - Replace 메소드는 두 개의 문자열을 매개 변수로 받습니다. 검색-문자열 안에 정규 표현식과 일치하는 문자열이 있으면, 그 문자열을 대체-문자열로 바꾸고, 바뀐 새로운 문자열을 반환합니다. 만일 일치하는 문자열이 없으면, 원래의 검색-문자열을 반환합니다.
Execute (검색-문자열) - Execute 메소드는 Matches 컬렉션 개체를 반환하는 점만 제외하면 Replace 메소드의 작동과 비슷합니다. Matches 컬렉션 개체에는 정규 표현식에 일치하는 각 문자열에 대한 Match 개체가 들어 있습니다. 이 메소드는 원래의 문자열을 변경하지 않습니다.
더 자세한 내용과 예제 코드는,Microsoft Scripting Site 사이트를 참고하시기 바랍니다.
VBScript Matches 컬렉션 개체
앞에서 말했듯이, Matches 컬렉션 개체는 Execute 메소드를 실행한 경우에만 반환됩니다. 이 컬렉션 개체는 0개 이상의 Match 개체를 포함할 수 있으며, 이 개체의 속성은 읽기 전용입니다.
속성
Count
Item
Count -컬렉션 안에 있는 Match 개체의 개수를 나타내는 읽기 전용 값입니다.
Item - Matches 컬렉션 개체에서 Match 개체를 임의로 액세스할 수 있게 만드는 읽기 전용 값입니다. For-Next 루프를 사용하면, Matches 컬렉션 개체에서 Match 개체를 순서대로 액세스할 수도 있습니다.
더 자세한 내용과 예제 코드는, Microsoft Scripting Site 를 참고하시기 바랍니다.
VBScript Match 개체
각 Mathes 개체에는 0개 이상의 Match 개체가 들어 있습니다. 이 Match 개체들은 정규 표현식을 사용했을 때 성공적으로 일치한 문자열을 나타냅니다. 이 개체의 속성은 읽기 전용이며 일치하는 각 문자열에 대한 정보를 저장합니다.
속성
FirstIndex
Length
Value
FirstIndex - 원래 문자열 안에서 정규 표현식에 일치하는 문자열의 위치를 나타내는 읽기 전용 값입니다. 이 색인은 위치를 기록하는데 0 기준 오프셋(문장의 첫 위치가 0번째임을 뜻함)을 사용합니다.
Length - 일치된 문자열의 전체 길이를 나타내는 읽기 전용 값입니다
Value - 일치된 값이나 텍스트를 나타내는 읽기 전용 값입니다. 이 값은Match 개체를 액세스할 때 사용되는 기본 값이기도 합니다.
더 자세한 내용과 예제 코드는, Microsoft Scripting Site 를 참고하시기 바랍니다.
패턴은 어떤 형태인가?
자, 지금까지는 이 모든 것이 지나치게 훌륭하고 환상적인 것으로 느껴지셨겠지만 실제는 어떨까요? 정규 표현식은 그 자체가 하나의 언어라고 할 수 있지만, Perl에 익숙한 사용자들이라면 누구나 쉽게 사용할 수 있습니다. VBScript는 Perl로부터 패턴 셋을 유도하기 때문에, 주요 기능도 Perl과 비슷합니다. 그러면, 정규 표현식을 정의하는 데 사용되는 패턴 셋 몇 가지를 살펴보도록 합시다. 패턴 셋은 여러 범주와 영역으로 분류할 수 있습니다.
포지션 매칭
포지션 매칭은 ^와 $(을)를 사용하여 문자열의 시작이나 끝을 검색합니다. 패턴 속성을 "^VBScript"로 설정할 경우, "VBScript is cool."에는 일치하지만, "I like VBScript."에는 일치하지 않습니다.
기호 기능
^ 문자열의 시작만 비교합니다
"^A"는 "An A+ for Anita."의 첫번째 "A"를 비교합니다.
$ 문자열의 끝을 비교합니다.
"t$"는 "A cat in the hat"의 마지막 "t"를 비교합니다.
\b 임의의 워드 영역을 비교합니다
"ly\B"는 "possibly tomorrow."의 "ly"를 비교합니다
\B Matches any non-word boundary
리터럴
리터럴은 영숫자 문자, ASCII, 8진수 문자, 16진수 문자, UNICODE, 또는 특수 구분 문자 등을 모두 총칭하는 말입니다. 특별한 의미를 갖고 있는 몇몇 문자는 구분해야 합니다. 이들 특수 문자를 비교하려면, 정규 표현식을 문자 앞에 \를 사용해야 합니다.
기호 기능
영숫자 영문자와 숫자를 비교합니다.
\n 새로운 라인을 비교합니다
\f 용지 공급을 비교합니다
\r 캐리지 리턴을 비교합니다.
\t 가로 탭을 비교합니다.
\v 수평 탭을 비교합니다.
\? ?(을)를 비교합니다.
\* *(을)를 비교합니다.
\+ +(을)를 비교합니다.
\. . (을)를 비교합니다.
\| |(을)를 비교합니다.
\{ {(을)를 비교합니다.
\} }(을)를 비교합니다.
\\ \(을)를 비교합니다.
\[ [(을)를 비교합니다.
\] ] (을)를 비교합니다.
\( ((을)를 비교합니다.
\) ) (을)를 비교합니다.
\xxx 8진수 xxx로 표시된 ASCII 문자를 비교합니다.
"\50"은 "(" 또는 chr (40) (을)를 비교합니다.
\xdd 16진수 dd로 표시된 ASCII 문자를 비교합니다.
"\x28"은 "(" 또는 chr (40) (을)를 비교합니다.
\uxxxx UNICODE xxxx로 표시된 ASCII 문자를 비교합니다.
"\u00A3"은 "£"를 비교합니다.
문자 클래스
문자 클래스를 사용하면 괄호 [] 안에 식을 삽입하여 사용자에 의해 정의된 그룹을 만들 수 있습니다. 문자 클래스의 문자들을 제외한 나머지 문자들을 사용하려면 [] 안에 ^(을)를 첫번째 문자로 삽입해야 합니다. 또한, 문자의 범위를 지정할 때는 대시를 사용합니다. 예를 들어, 정규 표현식 "[^a-zA-Z0-9]"(은)는 영문자와 숫자를 제외한 모든 문자를 비교합니다. 추가로 구분 문자와 리터럴로 묶인 문자셋도 있습니다.
기호 기능
[xyz] 문자셋 안에 포함되어 있는 임의의 한 문자를 비교합니다.
"[a-e]" (은)는 "basketball" 안의 "b"를 비교합니다.
[^xyz] 문자 셋 안에 포함되어 있지 않은 임의의 한 문자를 비교합니다.
"[^a-e]"는 "basketball" 안의 "s"를 비교합니다.
. \n을 제외한 임의의 문자를 비교합니다.
\w 임의의 워드 문자를 비교합니다.
[a- zA-Z_0-9]와 동일함.
\W 워드 문자를 제외한 임의의 문자를 비교합니다.
[^a-zA-Z_0-9]와 동일함.
\d 임의의 숫자를 비교합니다. [0-9].
\D 숫자를 제외한 임의의 문자를 비교합니다.
[^0-9]와 동일함.
\s 임의의 공백 문자를 비교합니다.
[ \t\r\n\v\f]와 동일함.
\S 공백 문자가 아닌 임의의 문자를 비교합니다.
[^ \t\r\n\v\f]와 동일함.
반복
반복 매칭을 사용하면 정규 표현식 안에 있는 특정 절에 대한 검색을 여러 번 수행할 수 있습니다. 반복 매칭에서는 어떤 요소가 정규 표현식 안에서 몇 번 반복될 것인지를 지정할 수 있습니다.
기호 기능
{x} {x} 정규 표현식을 x번 비교합니다.
"\d{5}"는 5개의 숫자를 비교합니다.
(x,} 정규 표현식을 x번 이상 비교합니다.
"\s{2,}"는 최소한 두 개의 공백 문자를 비교합니다
{x,y} 정규 표현식을 x부터 y번까지 비교합니다.
"\d{2,3}"는 2개 이상 3개 미만의 숫자를 비교합니다. .
? 0번 또는 한 번 비교합니다. {0,1}와 동일함.
"a\s?b"는 "ab" 또는 "a b"를 비교합니다.
* 0번 이상 비교합니다. {0,}와 동일함.
+ 한번 이상 비교합니다.{1,}과 동일함.
교체와 그룹핑
교체와 그룹핑은 보다 복잡한 정규 표현식을 만들 때 사용합니다. 교체와 그룹핑 기술은 정규 표현식 안에 복잡한 절을 만들고, 보다 많은 융통성과 제어 능력을 제공합니다.
기호 기능
() 절을 그룹핑하여 절을 만듭니다. 중첩하여 사용할 수도 있습니다.
"(ab)?(c)"는 "abc" 또는 "c"를 비교합니다.
| 교체는 여러 절을 하나의 정규 표현식으로 조합한 다음 개별적인 절을 비교합니다.
"(ab)|(cd)|(ef)"는 "ab" 또는 "cd" 또는 "ef"를 비교합니다.
역방향 참조
프로그래머는 역방향 참조를 통해 정규 표현식의 일부를 다시 참조할 수 있습니다. 그 방법은 괄호와 백슬레시(\) 뒤에 한 개의 숫자를 사용하는 것입니다. 첫 번째 괄호 절은 \1로 참조되고 두 번째 괄호 절은 \2로 참조되는 식입니다.
기호 기능
()\n 왼쪽 괄호에 있는 표현식을 n번 반복해서 문장을 비교합니다.
"(\w+)\s+\1"는 "hubba hubba" 같이, 한 열 안에서 두 번 나타나는 임의의 워드를 비교합니다.."
예제로 확인하기!
이 예제는 지금까지 설명한 것을 적용한 것으로, 정규 표현식을 이용하여 유효한 입력 값이 입력되어 있는지 검사하는 간단한 응용 프로그램입니다. 사용자가 유효한 값을 입력할 때까지 사용자에게 입력을 요구하는 프롬프트가 반복적으로 나타납니다. 먼저 초기 패턴을 자세히 설명하겠습니다.
"^\s*((\$\s?)|(£\s?))?((\d+(\.(\d\d)?)?)|(\.\d\d))\s*(UK|GBP|GB|USA|US|USD)?)\s*$"
"^\s*…" 와 "…\s*$" - 앞과 뒤에 몇 개의 공백 문자든지 올 수 있음을 나타내며, 입력은 반드시 라인 자체 위에 있어야 합니다.
"((\$\s?)|(?\s?))?" - 옵션 공백 앞에 오는 옵션 $ 또는 £ 기호를 나타냅니다..
"((\d+(\.(\d\d)?)?)|(\.\d\d))" - 생략 가능한 십진수 소수점 2자리 또는 십진수 소수점 2 자리수 앞에 오는 한 자리 이상의 숫자를 찾습니다. 이 말은 6., 23.33, .88와 같은 숫자는 사용 가능하나 5.5는 사용할 수 없음을 의미합니다.
"\s*(UK|GBP|GB|USA|US|USD)?" - 문자열에 대하여 생략 및 사용이 가능하고 인수 앞에서 유효한 공백 문자의 수를 의미합니다.
본 예제의 경우, 정규 표현식은 사용자의 US 달러 또는 영국 파운드 입력 여부를 결정하는 데 사용됩니다. 필자는 £, UK, GBP, 또는 GB 문자열을 검색하고 있습니다. 정규 표현식 결과가 참이면 사용자는 영국 파운드 단위의 액수를 입력한 것이라고 보면 됩니다. 그렇지 않다면 USD 통화를 사용한 것이겠지요.
이 코드를 사용하려면 코드를 CurrencyEx.vbs로 저장하고 Windows Script Host를 이용해 코드를 실행시킨 다음 VB에 복사하거나(이 경우, Microsoft VBScript 정규 표현식에 참조를 추가할 필요가 있음) HTML 파일에 코드를 포함시킵니다.
Sub CurrencyEx
Dim inputstr, re, amt
Set re = new regexp 'Create the RegExp object
'Ask the user for the appropriate information
inputstr = inputbox("I will help you convert USA and CAN currency. Please enter the amount to convert:")
'Check to see if the input string is a valid one.
re.Pattern = "^\s*((\$\s?)|(£\s?))?((\d+(\.(\d\d)?)?)|(\.\d\d))\s*(UK|GBP|GB|USA|US|USD)?)\s*$"
re.IgnoreCase = true
do while re.Test(inputstr) <> true
'Prompt for another input if inputstr is not valid
inputstr = inputbox("I will help you convert USA and GBP currency. Please enter the amount to(USD or GBP):")
loop
'Determine if we are going from GBP->US or USA->GBP
re.Pattern = "£|UK|GBP|GB"
if re.Test(inputstr) then
'The user wants to go from GBP->USD
re.Pattern = "[a-z$£ ]"
re.Global = True
amt = re.Replace(inputstr, "")
amt = amt * 1.6368
amt = cdbl(cint(amt * 100) / 100)
amt = "$" & amt
else
'The user wants to go from USD->GBP
re.Pattern = "[a-z$£ ]"
re.Global = True
amt = re.Replace(inputstr, "")
amt = amt * 0.609
amt = cdbl(cint(amt * 100) / 100)
amt = "£" & amt
end if
msgbox ("Your amount of: " & vbTab & inputstr & vbCrLf & "is equal to: " & vbTab & amt)
End sub
더욱 강력한 파워를!
Visual Basic 개발자들이 정규 표현식을 사용할 수 있도록 VBScript 정규 표현식 엔진은 COM 개체로 구현되어 왔습니다. 이 경우, 정규 표현식은 보다 강력한 힘을 발휘하게 되는데 즉, Visual Basic 또는 C와 같은 VBScript 외의 다양한 소스로부터 호출이 가능하기 때문입니다. 예컨대, 필자는 Outlook(R) 97, Outlook 98 또는 Outlook 2000의 접속 목록을 통해 내용을 추적하고 특정 도시에 사는 접속자 이름을 반환하는 작은 Visual Basic 응용 프로그램을 만든 경험이 있습니다.
이 프로그램은 매우 간단합니다. 먼저 사용자는 검색할 대상 도시명을 입력하고, 구분 표시에는 쉼표를 사용합니다. 그런 다음, Outlook에 작성할 새 접속 폴더의 이름을 입력합니다. 각 접속이 일치하면 이 내용은 새로 작성된 접속 폴더에 복사됩니다.
Microsoft VBScript 정규 표현식 개체 라이브러리에 참조를 추가할 경우 몇 가지 유용한 조기 바인딩 기능(early binding)을 사용할 수 있습니다. 이 조기 바인딩 개체는 몇 가지 이점을 제공하는데 즉, 속도가 빠르고 코딩 프로그램 사용이 간편하다는 점입니다. "new RegExp"가 즉시 사용되므로 사용자는 개체에 참조를 추가하고 VBScript코드를 오려내어 VB에 그대로 붙일 수 있습니다.
이러한 이유로 필자 또한 정규 표현식과 동일한 방법을 사용하여 Outlook 9.0 개체 라이브러리를 참조한 적이 있습니다. 물론, 여러분은 여전히 CreateObject() (을)를 사용하여 COM 호출을 생성시킬 수도 있으나 상기 방법을 더 간편하게 사용할 수 있을 것입니다. 이 개체들을 작성한 후 간단한 코드를 사용하여 도시명과 일치하는 폴더와 트리를 액세스할 수 있습니다. 본인은 2개의 모음 개체를 가지는 작은 도움 함수 compareCollectionObjects(x,y)(을)를 사용/비교하여 일치 여부를 확인합니다.
이 프로그램을 사용하려면 단순히 코드를 VB(참조 추가에 필요함)에 복사한 다음 FindCityContacts() 함수를 호출하면 됩니다. .
Sub FindCityContacts()
Dim strTemp
Dim index
Dim citySearch
Dim myNameSpace, myContacts, newCityContacts, newCityContactsName
Dim contact
Dim newContact
'Set the early binding objects
Dim re as New RegExp
Dim myApp as New Outlook.Application
re.Global = True
re.IgnoreCase = True
citySearch = InputBox("Please enter the cities of your search, separated by commas.")
newCityContactsName = InputBox("Please enter the new contact folder name")
'Set some of the objects and create the new Contacts folder
Set myNameSpace = myApp.GetNamespace("MAPI")
'olFolderContacts = 10
Set myContacts = myNameSpace.GetDefaultFolder(10)
Set newCityContacts = myContacts.Folders.Add(newCityContactsName)
'Set cities, using regular expressions to contain the city names
re.Pattern = "[^,]+"
Set cities = re.Execute(citySearch)
For Each city In cities
'Set citytokens to be the individual tokens in the city name
'Then we compare them to the address tokens in each contact
re.Pattern = "[^ ]+"
Set citytokens = re.Execute(city)
For i = 1 to myContacts.Items.Count
re.Pattern = "[^ ]+"
Set contact = myContacts.Items.Item(i)
Set HomeAddressCityTokens = re.Execute(contact.HomeAddressCity)
If compareCollectionObjects(HomeAddressCityTokens, citytokens) = 1 Then
Set newContact = contact.Copy
newContact.Move newCityContacts
End If
Set OtherAddressCityTokens = re.Execute(contact.OtherAddressCity)
If compareCollectionObjects(OtherAddressCityTokens, citytokens) = 1 Then
Set newContact = contact.Copy
newContact.Move newCityContacts
End If
Set BusinessAddressCityTokens = re.Execute(contact.BusinessAddressCity)
If compareCollectionObjects(BusinessAddressCityTokens, citytokens) = 1 Then
Set newContact = contact.Copy
newContact.Move newCityContacts
End If
Next
Next
MsgBox "done"
End Sub
'This function is provided as a helper-function
' to compare two collection objects.
Function compareCollectionObjects(x, y)
Dim index
Dim flag
flag = 1
If x.Count <> y.Count Then
flag = 0
Else
index = x.Count
For i = 0 To (index - 1)
If StrComp(x.Item(i), y.Item(i), 1) Then
flag = 0
End If
Next
End If
compareCollectionObjects = flag
End Function
넘치는 정보!
앞에서 보았듯이, Microsoft는 정규 표현식(버전 5.0)을 이용하여 VBSscript를 강화시키는데, 이것은 VBScript와 Jscript 비교에서 가장 중요한 부분이었습니다. 스크립팅 엔진 버전 5.0에서 우리는 VBScript의 기능을 향상시키는 데 특히 비중을 두었습니다. 이제 여러분은 정규 표현식을 추가시킴으로써 데이터를 보다 확실하게 관리하고 그 효과를 높일 수 있게 되었으며, 클라이언트와 서버에서 보다 강력한 웹 응용 프로그램을 만들 수 있게 되었습니다.
OnKeyDown() 함수를 overriding하면 됨
참고해야할 사항은 back key를 눌러서 platform에서 이전 activity로 돌아가는 처리를 하는 이벤트가
ACTION_DOWN이벤트라는 거다. (key down + back key가 들어오면 자동종료되고 이후에 key up등은 안들어옮)
그래서 굳이 UP에서도 처리할 필요없고 아래와 같이 처리를 하면 된다.
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN) {
// Do your job~~
}
return true;
}
위의 경우에는 내가 모든 key를 무조건 다 먹어버리는데 back키만 오버라이드하고 나머지는 platform이 알아서
후처리를 하게 하고 싶다면 아래와 같이 변경
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN) {
// Do your job~~
} else {
super.onKeyDown(keyCode, event);
}
기존에 제공되는 뷰를 이용하지 않고 custom한 ui를 만드는 방법은 여러가지인데
대부분의 case에서는 View를 상속받은 class를 하나 생성하고 onDraw method를 overriding하고
onDraw에 parameter로 넘어오는 canvas를 이용하여 그리면 된다.
좀더 뻘짓을 하기 위해서 이방법을 이용하지 않고 lcd화면과 직접 match가 되는 surface라는 걸 이용하는 방법이다. 이넘은 제공되는 함수도 몇개 더 되며, 물론 이 뷰에 다른 뷰를 박아도 알아서 잘 동작한다.
그리고 opengl es로 화면 출력할려면 이걸 써야된다는듯? (안해봐서 모름 ㅋㅋ)
package com.windweaver;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.SurfaceHolder.Callback;
public class Title extends SurfaceView implements Callback { // 이쉑을 상속받고 저쉑을 구현
Drawable mBlack;
Drawable mRed;
static int mSurfaceWidth;
static int mSurfaceHeight;
Canvas mCanvas;
SurfaceHolder mHolder = getHolder(); // sufaceview에서 화면을 그릴려면 holder라는넘을 가지고 함
public Title(Context context, AttributeSet attr) {
super(context);
mBlack = context.getResources().getDrawable(R.drawable.chip_black);
mRed = context.getResources().getDrawable(R.drawable.chip_red);
mHolder.addCallback(this); // 콜백을 등록하면 surface와 관련된 함수들이 적절하게 호출됨
}
@Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) { // 필수함수1
}
@Override
public void surfaceCreated(SurfaceHolder holder) { // 필수함수2 : surface가 생성될때 호출됨
mSurfaceWidth = this.getWidth();
mSurfaceHeight = this.getHeight();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) { // 필수함수3
}
@Override
public void draw(Canvas canvas) { // 필수함수4 : 이넘은 platform에서 draw호출했을 경우에
// 자동으로 호출되는넘이니 여기서 필요한거 그려주면 됨
super.draw(canvas);
// black
int blackX = logoX-mBlack.getIntrinsicWidth()-10;
int blackY = (mSurfaceHeight - mBlack.getIntrinsicHeight())/2;
mBlack.setBounds(blackX, blackY, blackX+mBlack.getIntrinsicWidth(), blackY+mBlack.getIntrinsicHeight());
mBlack.draw(canvas);
// red
int redX = logoX+mLogo.getIntrinsicWidth()+10;
mRed.setBounds(redX, blackY, redX+mRed.getIntrinsicWidth(), blackY+mRed.getIntrinsicHeight());
mRed.draw(canvas);
}
}
* 사용자가 임의로 표면에 그릴때 사용하는 방법
try {
mCanvas = mHolder.lockCanvas(); // lock을 하면 canvas를 돌려줌
mParent.draw(mCanvas); // 받은 canvas로 그리고 싶은걸 그림
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
if (mCanvas != null) {
mHolder.unlockCanvasAndPost(mCanvas); // canvas를 사용했으면 돌려준다.
}
}
custom popup dialog layout design

만들고나니 열라 허무.. 만들기전엔 졸라 삽질 -_-;
첨에는 relative layout을 이용해서 만들려고 했었으나.. relative layout의 동작방식이 좀 야리꾸리해서
원하는 모양으로 만들기 힘들었음.. 그러다가 걍 linear layout의 weight를 이용해서 해결
title영역의 사이즈는 고정, 버튼의 경우 팝업의 하단에 위치, 그 외의 영역을 body text영역으로
만든거임.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout // 팝업영역을 가운데에 위치시키기 위한 parent layout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center"
>
<LinearLayout // 이게 팝업의 배경영역만큼만 차지하는 layout이다.
android:id="@+id/customdialogpanel"
android:orientation="vertical"
android:layout_width="wrap_content" // wrap_content로 설정하면 팝업이미지 크기만큼 레이아웃이 잡힘
android:layout_height="wrap_content"
android:background="@drawable/bg_popup" // 팝업 배경이미지 지정
android:padding="8px"
android:gravity="center_horizontal"
>
<TextView // 이하 원하는 거 줄줄이 삽입
android:id="@+id/customdialogtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignTop="@id/customdialogpanel"
android:gravity="center"
android:textColor="#ffffff"
android:textSize="30px"
android:text="Title"
/>
<TextView
android:id="@+id/customdialogbody"
android:layout_weight="1" // 이넘만 weight값을 아무거나 집어넣어주면 들어있는 내용의 크기에 상관없이 타이틀과 버튼을 제외한 영역에 꽉참
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/customdialogtitle"
android:gravity="center"
android:textColor="#ffffff"
android:textSize="15px"
android:text="body content1\nbody content2"
/>
<Button
android:id="@+id/customdialogbutton1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:textColor="#ffffff"
android:textSize="20px"
android:text="button1"
android:background="@drawable/menubutton" // http://jjihun.tistory.com/70 참고
android:layout_marginBottom="5px"
/>
<Button
android:id="@+id/customdialogbutton2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:gravity="center"
android:textColor="#ffffff"
android:textSize="20px"
android:text="button2"
android:background="@drawable/menubutton"
/>
</LinearLayout>
</LinearLayout>
* ui를 만들때 보통 많이 쓰는 형태인 가운데에 팝업이 있고 배경이 살짝 어둡게 보이게 만드는 방법
1. activity를 생성
2. manifest.xml에 activity의 theme를 투명으로 지정
<activity
android:name=".CustomDialog"
android:launchMode="standard"
android:theme="@android:style/Theme.Translucent"
></activity>
투명으로 지정하지 않으면 화면을 검은색으로 채워버리기 때문에 theme를 꼭 투명으로 지정
3. 팝업 view의 xml을 생성 :
<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout // 굳이 linear일 필요는 없다.. 원하는 거 쓰면 됨
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent" // 대충 전체화면 차지하게 만들고
android:gravity="center" // 안에 들어가는넘은 가운데에위치시킴
>
<LinearLayout // 굳이 linear일 필요는 없다.. 원하는 거 쓰면 됨
android:id="@+id/customdialogpanel"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/bg_popup" // 팝업의 배경이미지를 지정함
android:gravity="center"
>
...
// 이 부분에 팝업안에 들어갈 각종 뷰들을 정의하면 됨
...
</LinearLayout>
</LinearLayout>
4. activity의 생성자에서 배경을 어둡게 만들고 layout을 inflate하고 애니메이션도 수행해보자
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 이부분이 화면을 dimming시킴
WindowManager.LayoutParams lpWindow = new WindowManager.LayoutParams(); lpWindow.flags = WindowManager.LayoutParams.FLAG_DIM_BEHIND;
lpWindow.dimAmount = 0.75f;
//lpWindow.windowAnimations = android.R.anim.accelerate_interpolator | android.R.anim.fade_in | android.R.anim.fade_out;
getWindow().setAttributes(lpWindow);
// view inflating
// 뷰를 생성함 이거 전에 window관련 동작을 처리해야한다.
// 뷰생성후에 dimming처리하면 안먹음
setContentView(R.layout.customdialog);
// 애니메이션을 수행 왼쪽에서 박스가 나와서 화면의 가운데에 위치하게 됨
TranslateAnimation anim=new TranslateAnimation(
TranslateAnimation.RELATIVE_TO_PARENT, -1.0f,
TranslateAnimation.RELATIVE_TO_SELF, 0.0f,
TranslateAnimation.RELATIVE_TO_SELF, 0.0f,
TranslateAnimation.RELATIVE_TO_SELF, 0.0f);
anim.setDuration(500);
anim.setFillAfter(true);
findViewById(R.id.customdialogpanel).setAnimation(anim);
anim.start();
}
* 배경을 dimming처리하는 방식은 여러가지가 있겠지만 배경을 dimming시키는 팝업 여러개를 겹쳐서 실행시킬 경우에 dimming된걸 다시 dimming시켜서 원하는 것보다 더 어둡게 만들 수가 있기 때문에
dimming에 관련된 처리를 android에서 제공하는 windowmanager를 통해서 하면
android가 알아서 중첩된 dimming처리를 smart하게 수행함 (몇개를 겹쳐서 실행시켜도 정확하게 75%어둡게 배경이 dimming처리됨)
위예제를 실행시켜보면 dimming은 dimming대로 fade-in 되면서 동시에 popup이 애니메이션 되는걸 알 수 있음
dialog를 customize할려고 했던건 삽질이고 이게 가장 적절한 방식인듯
Android Location & google maps 탐구 -1-

Android Location & google maps 탐구 -1부- 입니다. 3부 까지는 가지 않을까 합니다.
<본<본 게시물에 내용은 제 학습을 목적으로 정리한 글입니다. 그러므로 내용이 틀릴 가능성이가능성이 꾀 큽니다.>
<참고 문헌 wrox:Professional Android Application Development, Apress: ProPro Android>
LocationManager : Provides hooks to the location-based services.라고 나와나와 있고 번역서에는 위치기반 서비스에 대한 고리를 제공한다........라고 그대로 번역 되어 있더군요..있더군요..
설명 되로 LocationManager 은 위치기반 서비스의 '연결'고리 역활을 합니다.
LocationManager을 이용하여이용하여 위치를 나타내는 Location과 LocationProvider를 얻을 수 있지요.
아래 코드는 LocationManager를 얻는얻는 코드 입니다.
LocationManager locationManager;
locationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);(LocationManager)getSystemService(Context.LOCATION_SERVICE);
LocationProvider는 위치 정보 공급자이며 위치정보를 담고있는 Location을 얻기위해 필요필요 하지요
LocationProvider 얻는 방법은 ..
String provider = LocationManager.GSP_PROVIDER;//제공되는LocationManager.GSP_PROVIDER;//제공되는 공급자를 직접 명시하는...(없으면..?)
List<String> providers = locationManager.getProviders(true); //사용//사용 가능한 모든 공급자를 얻음
그리고 Criteria클래스를 이용하여 이용가능한 공급자공급자 중에서 가장 적당한 것을 고르는 방법이 있습니다.
Criteria criteriacriteria = new Criteria();
criteria.setAccuracy(Criteria.ACCURACY_COARSE); //정확도
criteria.setPowerRequirement(Criteria.POWER_LOW); //전원//전원 소리량
criteria.setAltitudeRequired(false); // 고도, 높이 값을 얻어 올지를 결정결정 하는듯 합니다..;;
criteria.setBearingRequired(false);//뭘까요..
criteria.setSpeedRequired(false);//속도
criteria.setCostAllowed(true);//위치criteria.setCostAllowed(true);//위치 정보를 얻어 오는데 들어가는 금전적 비용
위 코드에서 보이는보이는 것처럼 Criteria를 설정 한 후 locationManager.getBestProvider()메소드에 인자로 넘기면... 조건에 맞는 공급자를공급자를 얻을 수 있습니다.
String bestProvider = locationManager.getBestProvider(criteria, true); //가장//가장 좋은 하나의 공급자
List<String> matchingProviders = locationManager.getProviders(criteria,false);//조건에 맞는 모든모든 공급자
Criteria클래스에 정의된 조건들은 Cost에 대한 부분을 제외 하고는 해당해당 사항이 없을 경우 그 값을 사용자 몰래~낮추어 버립니다..
Criteria클래스의 설정설정 부분은 SharedPreferences클래스를 이용하여 저장 하면 좋을 듯 합니다.
(혹시 ...PreferencesActivity에 관한관한 정보 있으신분....지식 좀 나누워 주세요 ㅠㅠ)
이제 LocationManager와 LocationProvider까지 얻었으니얻었으니 이제 Location 클래스를 얻을 차례입니다.
Location location = locationManager.getLastKnownLocation(provider);//끝......locationManager.getLastKnownLocation(provider);//끝......
getLastKnownLocation메소드에 이용 가능한 공급자를 넘겨주면 Location션을 리턴 하십니다..
그럼그럼 Location의 get메소드를 이용 하여 위치 정보를 얻으면 되지요..
doubledouble lat = location.getLatitude();
double lng = location.getLongitude();//참 쉽지요..
--------------------------------------숨 쉬 기------------------------------------------------
이제 위치 정보를 업데이트 하는 방법방법 입니다... 짧은 설명과 크드만 쓱~~
위치정보 업데이트는 아래 메소드를 call해서 이루어이루어 집니다.
locationManager.requestLocationUpdates(provider, 2000, 10,locationListener);
전달되되는 값을 한번한번 살펴 보겠습니다. (provider, 1000, 10,locationListener)
(공급자, 업데이트 시간간격, 업데이트 거리m,리스너)
요말은 .....2초마다 업데이트 또는 거리다 10m10m 이상 바뀌었을 때~업데이트...한다는 소리죠..
누가~? LocationListener가...
private fi nalnal LocationListener locationListener = new LocationListener() {
publicpublic void onLocationChanged(Location location) {
//업데이트...
}
publicpublic void onProviderDisabled(String provider){
}
public void onProviderEnabled(String provider){ }
publicpublic void onStatusChanged(String provider, int status,Bundle extras){ }
};
--------------------------------------숨 쉬 기 2 -----------------------------------------------
이제 Geocoder에 대해 알아 정리를정리를 한번 해보겠습니다.
Geocoder는 위도/경도 값을 이용하여 주소값을 얻어 오거나 반대로 주소값를 이용하여 위도/경도를 얻을 수 있는 신기한 녀석 입니다.
Geocoder는 아래와 같이 얻어지며
Geocoder geocodergeocoder = new Geocoder(Context, Locale.default);
Locale은 지오코딩을 하기 위한위한 '지역'정보 입니다..Locale.US, Locale.KOREA 등등.....
geocoding에는 Forward Geocoding 과 Reverse GeocodingGeocoding 이 있고
두 가지 모두 Address 리스트를 리턴 합니다.
List<Address> addresses = null;
List<Address> locations = null;null;
addresses = gc.getFromLocation(latitude, longitude, 10);//위도와 경도값을~
locationslocations = fwdGeocoder.getFromLocationName("Seoul", 10); //주소값을~
Address클래스는 위도, 경도, 주소, 전화번호,전화번호, 등등...많은 위치정보를 저장 하는 클래스이며
address.getXxx() 메소드를 이용 하여 정보를 얻을얻을 수 있습니다. 자세한 내용은 레퍼런스를...보세요.;;
ps. 위치기반 서비스를 이용 하기하기 위하서는...
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
권한을 추가 하셔야 합니다.....권한에 대한 자세한 내용은 "Apress: Pro Android"의 7장에7장에 잘 나오더군요..;;
전 저질 영어 실력이라..OTL...
2부에는..Google Maps API에 대한대한 내용을 정리 해야 겠습니다..
<본 게시물에 내용은 제 학습을 목적으로 목적으로 정리한 글입니다. 그러므로 내용이 틀릴 가능성이 꾀 큽니다.>
import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import android.app.PendingIntent; import android.app.Service; import android.content.Context; import android.content.Intent; import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; import android.location.LocationProvider; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.util.Log; public class ContentCreationService extends Service { /** Debugging Tag*/ private static final String TAG = "SERVICE"; private Bundle bundle = new Bundle(); private String errorMessage; private String infoMessage = ""; private Context context; private String[] location; private LocationManager lM; private LocationListener mLocationListener; private Condition condition; private final Lock lock = new ReentrantLock(); // Get the Monitor Lock private final IContent.Stub binder=new IContent.Stub() { /// Here are the methods you can use after binding the service }; @Override public void onCreate() { super.onCreate(); nm = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); Log.e(TAG,"Service onCreate done"); context = this; } public void onStart(Intent intent,int startId) { Thread background = new Thread(new Runnable(){ public void run(){ // Submit a message to the other threads handler in order to start the method "getLocation()" handler.sendEmptyMessage(1); // Initalizing the condition. (get it from the monitor) condition = lock.newCondition(); // Lock this part lock.lock(); try { Log.e(TAG,"Waiting for Location"); // Thread waits untill he gets the condition.signal() from the other thread condition.await(); } catch ( InterruptedException e ) { Log.e(TAG,"Thread got interrupted..."); } finally { // Unlock this part lock.unlock(); } // Go on working .... } }); background.start(); } Handler handler = new Handler(){ /** Ueberschreibt die handleMessage() des Handlers um Nachrichten die ankommen * selbst zu verwalten. Wenn eine Nachricht angekommen ist wertet er den aktuellen Status, * des Service aus und zeigt eine Notification an. */ @Override public void handleMessage(Message msg) { if(msg.what == 1){ getLocation(); } } }; @Override public IBinder onBind(Intent intent) { return(binder); } @Override public void onDestroy() { super.onDestroy(); Log.e(TAG,"Service onDestroy done"); } public void getLocation(){ Log.e(TAG,"Started Location Search"); lM = (LocationManager)context.getSystemService(context.LOCATION_SERVICE); lM.setTestProviderStatus(lM.GPS_PROVIDER,LocationProvider.AVAILABLE, null, System.currentTimeMillis()); lM.setTestProviderEnabled(lM.GPS_PROVIDER,true); mLocationListener = new MyLocationListener(); lM.requestLocationUpdates(lM.GPS_PROVIDER, 0, 0, mLocationListener); } private class MyLocationListener implements LocationListener { public void onLocationChanged(Location loc) { if (loc == null) { Log.e(TAG, "location changed to null"); } else { Log.e(TAG,"Location -> Lon: "+loc.getLongitude()+" Lat: "+loc.getLatitude()); location = new String[2]; location[0] = String.valueOf(loc.getLongitude()); location[1] = String.valueOf(loc.getLatitude()); Log.e(TAG, "location changed : " + loc.toString()); // Lock this part lock.lock(); try { // Send the signal to the other thread to go on with its work, the location is now available condition.signal(); } finally { // Unlock this part lock.unlock(); } lM.removeUpdates(mLocationListener); } } public void onStatusChanged(java.lang.String arg0, int arg1, Bundle extras) { // ignore } public void onProviderEnabled(java.lang.String arg0) { // ignore } public void onProviderDisabled(java.lang.String arg0) { // ignore } } }
Android의 9 patch(나인패치) drawable 이란?

일반 PNG 이미지에서 1pixel의 보더를 가지는 형태로 구성되어있습니다. 이 보더가 늘어나는 영역과 늘어나지 않는 영역을 정의하게 됩니다. 왼쪽과 위쪽의 1 pixel 검은색 선은 늘어날 수 있는 부분을 정의합니다. 늘어날 수 있는 부분은 여러개가 될 수 있습니다.
오른쪽과 아래쪽의 1 pixel 검은색 선은 뷰가 그려질 영역을 정하는 일을 합니다. 다시 말해 패딩 영역을 결정합니다. 만약 이 선을 그리지 않는다면 왼쪽과 위쪽의 선이 사용됩니다. 예를 들어 텍스트뷰의 경우 그려질 텍스트가 이 선이 그려진 영역안에서 표시됩니다.
나인패치 이미지를 쉽게 만들기 위해서 SDK의 Tools디렉토리에 draw9patch라고 하는 이미지 에디터가 들어있습니다. 아니면 그냥 일반적인 그래픽 에디터에서 그려도 상관없습니다.

파일이름은 반드시 .9.png라고 끝나도록 저장해주어야 합니다. res/drawable/some_name.9.png 와 같은 형태가 되겠지요. 만약 그냥 png라고 끝난다면 일반 이미지 파일로 처리가 됩니다.

예제를 한번 확인해보시지요. 왼쪽의 버튼과 오른쪽의 버튼은 모두 같은 나인패치 Drawable을 백그라운드 이미지로 사용하고 있습니다. 이미지 파일 하나로 다양한 크기의 버튼의 백그라운드로 사용될 수 있다는 것은 정말 편리하고 UI작업을 할 때 항상 사용하는 것이니 알아두시면 좋습니다.
http://www.androidpub.com/2096
안드로이드 010: TableLayout 컨테이너 / ScrollView (Android Container 3: TableLayout / ScrollView)

이번에는 위젯들을 화면에 배치 하는데 필요한 container에 관한 내용입니다.
다음과 같이 3부분으로 나누어서 포스팅 하려고 합니다.
Part 3. TableLayout + ScrollView
그중 Part 3. TableLayout에 대한 정리 입니다.
3. TableLayout (Grid Model)
TableLayout 컨테이너는 HTML과 같이 방식으로 쓰인다.
즉, 위젯을 테이블에 배치하고, 테이블의 행과 열의 간격을 조정하여 위젯의 크기를 결정하는 방식이다.
Table 구성하기
TableLayout은 TableRow와 같이 사용된다.
TableLayout은 테이블의 전반적인 사항을 관리하고, TableRow로 테이블에 행을 하나씩 추가하고, 추가한 행에 위젯(들)을 배치하는 한다.
TableLayout 예제 (main.xml) *속성 적용 전
01 |
<? xml version = "1.0" encoding = "utf-8" ?> |
02 |
< TableLayout xmlns:android = "http://schemas.android.com/apk/res/android" |
03 |
android:layout_width = "fill_parent" |
04 |
android:layout_height = "fill_parent" > |
05 |
|
06 |
<!-- Row 0 --> |
07 |
< TableRow > |
08 |
< TextView |
09 |
android:id = "@+id/textview1" |
10 |
android:text = "Row0 : Column0" |
11 |
android:textColor = "#000000" |
12 |
android:background = "#FFFFFF" /> |
13 |
< TextView |
14 |
android:id = "@+id/textview2" |
15 |
android:text = "Row0 : Column1" |
16 |
android:textColor = "#000000" |
17 |
android:background = "#FF0000" /> |
18 |
< TextView |
19 |
android:id = "@+id/textview3" |
20 |
android:text = "Row0 : Column2" |
21 |
android:textColor = "#000000" |
22 |
android:background = "#FFFFFF" /> |
23 |
< TextView |
24 |
android:id = "@+id/textview4" |
25 |
android:text = "Row0 : Column3" |
26 |
android:textColor = "#000000" |
27 |
android:background = "#FF0000" /> |
28 |
</ TableRow > |
29 |
|
30 |
<!-- Row 1 --> |
31 |
< TableRow > |
32 |
< TextView |
33 |
android:id = "@+id/textview5" |
34 |
android:text = "Row1 : Column0" |
35 |
android:textColor = "#000000" |
36 |
android:background = "#FFFF00" /> |
37 |
< TextView |
38 |
android:id = "@+id/textview6" |
39 |
android:text = "Row1 : Column1" |
40 |
android:textColor = "#000000" |
41 |
android:background = "#00FF00" /> |
42 |
< TextView |
43 |
android:id = "@+id/textview7" |
44 |
android:text = "Row1 : Column2" |
45 |
android:textColor = "#000000" |
46 |
android:background = "#FFFF00" /> |
47 |
< TextView |
48 |
android:id = "@+id/textview8" |
49 |
android:text = "Row1 : Column4" |
50 |
android:textColor = "#000000" |
51 |
android:layout_column = "4" |
52 |
android:background = "#00FF00" /> |
53 |
</ TableRow > |
54 |
</ TableLayout > |
위의 예제의 경우, 테이블은 2개의 행으로 이루어져 있으며
첫 번째 행과 두 번째 행 모두 4개의 TextView로 이루어져 있다.
위의 XML Layout을 일반적으로 사용하는 테이블로 시각화 시킨다면 다음과 같다.
Row1 : Column4 처럼 위젯을 특정 column에 배치하는 TableRow.LayoutParams 의 속성은 다음과 같다.
또, 테이블의 전체 column 수는 column수가 가장 많은 row에 따른다.
위의 경우 Row0은 순차적으로 4개의 cell을 소모하여 4개의 column이면 충분히 표현 가능하지만,
Row1은 마지막 위젯이 cell 하나를 건너뛰어 배치되어서 총 5개의cell이 사용되었다.
그럼으로 테이블 전체 column수는 row1의 column수에 따라 5 column 테이블이 된다.
다음은 예제를 실행한 화면이다. cell들의 너비가 넓어 테이블이 화면을 벋어났지만 다음에서 해결한다.
셀(Cell)의 너비 줄이기(shrink) *참고: 테이블 좌우 폭이 컨테이너 폭보다 넓은 경우에만 효과 있음.
위 실행 화면에서 보면, 테이블의 전체 너비가 컨테이너 너비보다 넓어 컨테이너 밖으로 삐쳐 나간 것을 볼 수 있다.
경우에 따라서는 테이블의 column(들)의 너비를 인위적으로 줄여 테이블 전체가 보이도록 할 필요가 있다.
column(들)의 너비가 화면에 적당하도록 줄이려면 TableLayout의 다음 속성을 사용한다.
1~n 개의 column에 적용 가능하며 복수의 column은 쉼표 (,) 로 구분하며 전체 column을 줄이려면 아스테리스크(*)를 사용한다.
또, column의 너비가 줄어들면서 위젯이 표현하는 컨텐트(예. string object)의 너비가 위젯의 view 너비 보다 커서 하나의 라인에 정상적으로 표현할 수 없게 되면 자동으로 줄 바꿈이 일어난다.
Java 코드에서는 setColumnShrinkable 또는 setShrinkAllColumns 메소드를 사용.
다음은 예제에 android:shrinkColumns="*"를 적용한 화면. 모든 cell들이 정상적으로 보인 반면 줄 바꿈이 일어났다.
셀(Cell) 숨기기(collapse)
필요에 따라서 테이블의 특정 셀이 존재는 하지만 보이지 않게 숨겨야 할 경우도 있다.
역시 TableLayout의 속성이며 1~n 개의 column에 적용가능 하다. 복수의 column은 쉼표 (,) 로 구분하며 전체 column을 숨기려면 아스테리스크(*)를 사용한다.
자바 코드에서는 setColumnCollapsed 메소드를 사용.
다음은 예제에 android:collapseColumns="0, 1"를 적용한 화면이다. column 0, 1이 보이지 않는 것을 확인할 수 있다.
셀(Cell) 합치기
위젯이 2개이상의 column에 걸쳐 나타나게 할 수 있는데 이를 결정하는 TableRow.LayoutParams 의 속성은 다음과 같다.
예제 중 Row1 : Column 2 에 위치한 EditText 위젯에 android:layout_span="2" 속성을 적용하면 테이블이 다음과 같아진다.
셀(Cell) 늘리기(stretch) *참고: 테이블 좌우 폭이 컨테이너 폭보다 좁을 경우에만 효과 있음.
TableLayout 컨테이너에 배치된 위젯의 넓이는 그 위젯이 속한 컬럼에서 가장 넓은 위젯의 크기를 따른다.
하지만 필요에 따라 특정 위젯이 속한 column의 너비를 인위적으로 늘릴 필요가 있다.
이럴경우 TableLayout의 다음 속성을 사용한다.
속성에 지정된 column외의 column들이 소비하고 남은 모든 여유공간을 지정된 column(들)이 차지하게 된다.
Java 코드에서는 TableLayout의 setColumnStretchable 이나 setStretchAllColumns 메소드를 이용.
예제에서 column4를 늘리면 다음과 같이 테이블 형태가 변한다. 이전 그림과 비교해 보면 Row1 : Column4 가 화면 끝까지 확장 된 것을 볼 수 있다.
TableLayout 중간에 TableRow가 아닌 위젯 삽입하기
TableLayout의 중간에 TableRow가 아닌 위젯이 올 수도 있다.
단, 그런 요소의의 경우 다음과 같은 특징을 갖는다.
- TableLayout은 orientation이 vertical로 지정된LinearLayout 처럼 작동함.
- android:layout_width속성이 무조건 "fill_parent"로 고정됨.
예제의 두 TableRow 사이에 다음과 같은 코드를 삽입 한다면,
TableLayout 내부의 TableRow가 아닌 요소 예제 (main.xml 의 일부)
1 |
< View |
2 |
android:layout_height = "4px" |
3 |
android:background = "#FF00FF" /> |
실행 화면은 다음과 같이 된다. Row 0과 Row 1사이의 핑크색 경계선을 볼 수 있다.
다음은 위 실행화면에 대한 소스코드이다. 지금까지 정리한 여러 속성들이 사용된 것을 확인할 수 있다.
TableLayout 예제 코드 (main.xml) *여러 속성 적용 후
01 |
<? xml version = "1.0" encoding = "utf-8" ?> |
02 |
< TableLayout xmlns:android = "http://schemas.android.com/apk/res/android" |
03 |
android:layout_width = "fill_parent" |
04 |
android:layout_height = "fill_parent" |
05 |
android:shrinkColumns = "*" |
06 |
android:collapseColumns = "0, 1" |
07 |
android:stretchColumns = "4" > |
08 |
|
09 |
<!-- Row 0 --> |
10 |
< TableRow > |
11 |
< TextView |
12 |
android:id = "@+id/textview1" |
13 |
android:text = "Row0 : Column0" |
14 |
android:textColor = "#000000" |
15 |
android:background = "#FFFFFF" /> |
16 |
< TextView |
17 |
android:id = "@+id/textview2" |
18 |
android:text = "Row0 : Column1" |
19 |
android:textColor = "#000000" |
20 |
android:background = "#FF0000" /> |
21 |
< TextView |
22 |
android:id = "@+id/textview3" |
23 |
android:text = "Row0 : Column2" |
24 |
android:textColor = "#000000" |
25 |
android:background = "#FFFFFF" /> |
26 |
< TextView |
27 |
android:id = "@+id/textview4" |
28 |
android:text = "Row0 : Column3" |
29 |
android:textColor = "#000000" |
30 |
android:background = "#FF0000" /> |
31 |
</ TableRow > |
32 |
|
33 |
<!-- TableLayout 내부의 TableRow가 아닌 요소 --> |
34 |
< View |
35 |
android:layout_height = "4px" |
36 |
android:background = "#FF00FF" /> |
37 |
|
38 |
<!-- Row 1 --> |
39 |
< TableRow > |
40 |
< TextView |
41 |
android:id = "@+id/textview5" |
42 |
android:text = "Row1 : Column0" |
43 |
android:textColor = "#000000" |
44 |
android:background = "#FFFF00" /> |
45 |
< TextView |
46 |
android:id = "@+id/textview6" |
47 |
android:text = "Row1 : Column1" |
48 |
android:textColor = "#000000" |
49 |
android:background = "#00FF00" /> |
50 |
< TextView |
51 |
android:id = "@+id/textview7" |
52 |
android:text = "Row1 : Column2" |
53 |
android:textColor = "#000000" |
54 |
android:background = "#FFFF00" |
55 |
android:layout_span = "2" /> |
56 |
< TextView |
57 |
android:id = "@+id/textview8" |
58 |
android:text = "Row1 : Column4" |
59 |
android:textColor = "#000000" |
60 |
android:layout_column = "4" |
61 |
android:background = "#00FF00" /> |
62 |
</ TableRow > |
63 |
</ TableLayout > |
4. Container Scroll 하기
스마트폰의 화면은 크기가 제한적 임으로 스크롤의 사용이 중요하다.
스크롤 구현 방법은 다음과 같이 스크롤 시키고 싶은 container를 ScrollView elememt내부에 nest 시키면 된다.
ScrollView 예제 (main.xml)
01 |
<? xml version = "1.0" encoding = "utf-8" ?> |
02 |
< ScrollView xmlns:android = "http://schemas.android.com/apk/res/android" |
03 |
android:layout_height = "fill_parent" |
04 |
android:layout_width = "fill_parent" > |
05 |
|
06 |
<!-- 어떤 Layout을 사용해도 상관없음 --> |
07 |
<!-- 스크롤 바를 위한 공간 확보용 paddingRight="5px" 주목 --> |
08 |
< LinearLayout |
09 |
android:orientation = "vertical" |
10 |
android:layout_width = "fill_parent" |
11 |
android:layout_height = "fill_parent" |
12 |
android:paddingRight = "5px" > |
13 |
< TextView |
14 |
android:layout_width = "fill_parent" |
15 |
android:layout_height = "300px" |
16 |
android:background = "#FF0000" |
17 |
android:text = "TextView 1" /> |
18 |
< TextView |
19 |
android:layout_width = "fill_parent" |
20 |
android:layout_height = "300px" |
21 |
android:background = "#00FF00" |
22 |
android:text = "TextView 2" /> |
23 |
< TextView |
24 |
android:layout_width = "fill_parent" |
25 |
android:layout_height = "300px" |
26 |
android:background = "#0000FF" |
27 |
android:text = "TextView 3" /> |
28 |
</ LinearLayout > |
29 |
</ ScrollView > |
다음은 실행 화면이다.
완전한 TableLayout API Reference는 다음을 참조.
최근 마켓에 어플 올리면서 한번 정리해보았습니다 :)
- Application .apk file : 어플리케이션 파일입니다.
- Screenshots : 스크린샷입니다. 최대 2장까지 등록 가능하며, Portrait 형태의 사진으로 등록해야 잘리지 않습니다.
- Promotional Graphic : 아마도 마켓 첫화면에 소개될 때(?) 표시할 그림 같습니다. 선택사항입니다.
<?xml version=”1.0” encoding=”utf-8”?>
<manifest>
<uses-permission />
<permission />
<permission-tree />
<permission-group />
<instrumentation />
<uses-sdk />
<uses-configuration />
<uses-feature />
<supports-screens />
<activity>
<intent-filter>
<action />
<category />
<data />
</intent-filter>
<meta-data />
</activity>
<activity-alias>
<intent-filter> . . . </intent-filter>
<meta-data />
</activity-alias>
<intent-filter> . . . </intent-filter>
<meta-data/>
</service>
<receiver>
<intent-filter> . . . </intent-filter>
<meta-data />
</receiver>
<provider>
<grant-uri-permission />
<path-permission />
<meta-data />
</provider>
<uses-library />
</application>
</manifest>
매니패스트 파일은 어플리케이션에 대한 전반적인 정보를 담고 있는 파일로, 어플리케이션이 실행되기 전에 시스템이 알고 있어야 하는 파일이다. 이 매니페스트 파일 안에는 어플리케이션 컴포넌트(Activity, Service, intents, Content provider, Broadcast Receivers)에 대한 노드를 포함하고 있고 Intent filter와 같이 permissions을 사용해 다른 컴포넌트와 어플리케이션이 어떻게 상호 작용을 하는지를 결정한다.
</receiver>
<provider>
<grant-uri-permission />
<path-permission />
<meta-data />
</provider>
<uses-library />
</application>
</manifest>
<manifest>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.android.notepad"
android:versionCode="1"
android:versionName="1.0">
[어플리케이션 태그 및 Permission 태그들]
</manifest>
AndroidManifest.xml의 root element로써 <manifest> 태그가 전체를 감싸는 구조를 하고 있으며 package attribute의 값으로는 어플리케이션의 base를 지정하는 Java package 이름이 온다.
<uses-permission>
<uses-permission android:name="string" />
어플리케이션의 필요한 기능의 권한을 정의해준다. 여기에 정의된 권한은 설치 과정 중 사용자에게 보여주고 권한부여 혹은 거절이 결정된다.
android:name – 애플리케이션 안에 <permission>엘리먼트를 사용해서 정의된 퍼미션의 이름
다른 애플리케이션에 의해 정의된 퍼미션의 이름
표준 시스템 퍼미션의 이름(예 - “android.permission.INTERNET”)
<permission>
<permission android:description="string resource"
android:icon="drawable resource"
android:label="string resource"
android:name="string"
android:permissionGroup="string"
android:protectionLevel=["normal" | "dangerous" | "signature" | "signatureOrSystem"]
/>
컴포넌트를 사용하기 위한 권한 중에 안드로이드가 제공하는 권한 이외에 다른 권한이 필요할 때 정의한다. 다른 어플리케이션이 이 컴포넌트를 사용하려면 자신의 매니페스트에 uses-permission 태그를 설정해 주거나<activity android:permission>속성에 권한을 추가해 주면 된다.
android:description – 퍼미션의 설명으로 사용자에게 퍼미션을 설명하기 위해 사용 될 수도 있다.
android:icon – 퍼미션을 의미하는 아이콘의 리소스의 레퍼런스로 예를 들어 res/drawable/app_note.png라는 파일이 있다면 “@drawable/app_note”라고 쓴다.
android:label – 사용자에게 보여질 수 있는 퍼미션의 이름이다. 배포가 될때는 string.xml에 정의하고 @string/app_name 같이 사용하여야 한다.
android:name – 코드에서 사용되는 퍼미션의 이름이다. “com.example.project.PERMITTED_ACTION”과 같이 고유한 이름을 사용해야 한다.
android:permissionGroup – 그룹에 퍼미션을 할당한다. <permission-group>으로 선언되어진 그룹의 이름을 지정한다.
android:protectionLevel – 이 레벨 설정에 따라서 사용자가 퍼미션을 요구하는 애플리케이션을 알 수 있거나 해당 퍼미션을 누가 사용하는지를 알 수 있다.
normal : 디폴트 값으로 낮은 수위의 위험을 갖는다. 최소한의 위험요소를 가진 애플리케이션이 다른 애플리케이션 레벨의 기능들에 대해 접접근하는 것 부여한다.
dangerous : 높은 수위의 위험을 갖는다. 사용자의 사적 데이터 접근이나 디바이스에 대한 제어를 허용한다.
signature : 애플리케이션이 다른 애플리케이션과 같은 인증서를 가지고 사인되었을때에 한하여 시스템이 퍼미션을 부여한다.
signatureOrSystem : 시스템이 안드로이드 시스템 이미지 안에 있거나 시스템 이미지 안에 있는 것들과 같은 인증서로 사인된 애플리케이션에 한하여 부여한다.
<permission-tree>
<permission-tree android:icon="drawable resource"
android:label="string resource"
android:name="string" />
퍼미션 트리에 대한 기본적인 이름을 선언한다. 이 애플리케이션은 트리 내의 모든 이름들에 대한 소유권을 갖는다.
<permission-group>
<permission-group android:description="string resource"
android:icon="drawable resource"
android:label="string resource"
android:name="string" />
퍼미션 그룹의 이름을 선언한다.
<instrumentation>
실행 시 액티비티와 서비스를 테스트 하기 위한 프레임워크롤 제공하며, 선언된 클래스는 시스템리소스와 상호작용을 모니터링하기 위한 연결 고리를 제공한다.
Jfeature를 설치해 Test를 사용할 경우
<instrumentation android:targetPackage="com.jfeature" android:name="android.test.InstrumentationTestRunner" />
<instrumentation android:functionalTest=["true" | "false"]
android:handleProfiling=["true" | "false"]
android:icon="drawable resource"
android:label="string resource"
android:name="string"
android:targetPackage="string" />
이 엘리먼트가 매니페스트에 자동으로 생성된다.
android:functionalTest – 기능적 테스트를 위해 수행되어야 하는지 여부를 표시한다. 디폴트 값은 “false”이다.
android:handleProfiling – 프로파일링을 on, off 할 것인지의 여부를 표시한다. 프로파일링을 시작할 때와 멈출때는 결정하려면 “ture”, 프로파일링이 시행되는 모든 시간 동안 계속 하려면 false로 표시한다. 디폴트는 “false”이다.
android:targetPackage – 타겟으로 정할 패키지 주소를 입력한다.
<uses-sdk android:minSdkVersion="integer"
android:maxSdkVersion="integer"
amdroid:targetSdkVersion="integer" />
Android Version이 아닌 API 레벨을 설정한다.
android:minSdkVersion – API의 최소레벨을 지정하는 함수로 Default값은 1이다.
시스템이 지정한 값보다 낮은 버전 이라면 시스템에 설치 되지 않는다.
android:maxSdkVersion – API의 최소레벨을 지정하는 함수이다. 시스템이 지정한 값보다 높은 버전이라면 시스템에 설치 되지 않는다. 이 애트리뷰트를 사용하는 것을 권장하지 않는다. 왜냐하면 신규 버전의 안드로이드 플렛폼 배치가 차단되고 더 높은 API 레벨로 시스템이 업데이트 된 이후 사용자의 디바이스에서 maxSdkVersion이 시스템보다 낮은 값으로 설정된 애플리케이션이 제거된다.
android:targetSdkVersion - 애플리케이션이 타겟으로 하고 있는 API 레벨을 지정하는 함수이다.
<uses-feature>
<uses-feature android:glEsVersion="integer"
android:name="string" />
SDK버전을 선언하는 것과 비슷하게 기능을 지원하지 않는 디바이스 상에는 설치가 되지 않도록 하는 옵션이다. 예를 들어 디바이스가 카메라를 지원하지 않으면 어플리케이션이 설치 되지 않는다. 애플리케이션이 특정 디바이스를 사용해야 한다면 이 옵션을 추가해야 한다.
android:glEsVersion – 애플리케이션이 필요로 하는 GLES 버전이다.
android:name – 애플리케이션이 필요로 하는 기능의 이름으로써 예로 “android.hardware.camera”와 같이 쓰이는데 이것은 애플리케이션이 카메라를 필요로 한다는 의미이다.
<supports-screens android:smallScreens=["true" | "false"]
android:normalScreens=["true" | "false"]
android:largeScreens=["true" | "false"]
android:anyDensity=["true" | "false"] />
애플리케이션이 지원하는 스크린 크기를 지정하는 옵션이다.(멀티해상도 관련)
android:smallScreens – 애플리케이션이 “normal”보다 더 작은 스크린을 지원하는지 여부이다. API 레벨 4이상에서는 디폴트 값이 “ture”이고 다른 레벨에서는 “false”이다.
android:normalScreens – 애플리케이션이 “normal” 스크린을 지원하는지 여부이다. 디폴트 값은 “true”이다.
android:largeScreens – 애플리케이션이 “normal”보다 더 큰 스크린을 지원하는지 여부이다. API 레벨 4이상에서는 디폴트 값이 “ture”이고 다른 레벨에서는 “false”이다.
android:anyDensity – 애플리케이션이 임의의 스크린 밀도를 수용할 수 있는 지에 대한 옵션이다. API레벨 4이상에서는 디폴트 값이 “true”이고 다른 레벨에서는 “false”이다.
<application>
<application android:allowClearUserData=["true" | "false”]
android:allowTaskReparenting=["true" | "false"]
android:debuggable=["true" | "false"]
android:description="string resource"
android:enabled=["true" | "false"]
android:hasCode=["true" | "false"]
android:icon="drawable resource"
android:label="string resource"
android:manageSpaceActivity="string"
android:name="string"
android:permission="string"
android:persistent=["true" | "false"]
android:process="string"
android:task="string"
android:theme="resource or theme" >
. . .
</application>
이 엘리먼트는 반드시 한번 사용되어야 한다. Application 아래에 있는 서브 엘리먼트는 없거나 순서가 바뀌어도 문제되지 않는다. 애플리케이션의 메타데이타(타이틀, 아이콘, 테마 등)을 지정한다.
android:allowClearUserData – 사용자들에게 사용자 데이터를 제거할 수 있는 옵션을 부여할 것인가에 대한 애트리뷰트이다.
android:allowTaskReparenting – 이 애트리뷰트가 “true”로 설정되어 있다면 액티비티는 시작된 태스크부터 affinity를 갖는 태스크가 된다.
예를 들어 e-mail Activity에서 web page링크를 클릭하게 되면 해당 페이지가 보여지는 브라우저가 시작되게 된다. 이 Activity는 Browser Application에 정의 되어 있지만 e-mail Task의 일부로 실행된 상태이다. 만약 android:allowTaskReparenting이 true로 되어있고 Browser Task로 Reparenting되면 Browser어플리케이션에서 그 페이지가 보여질 것이고 다시 e-mail Task가 보여지면 그 Activity는 보이지 않게 된다. 디폴트 값은 false이다.
android:debuggable – 사용자모드로 실행중일 때 디버그 될수 있는지를 설정한다. 디폴트 값은 ”false”이다. “false”로 설정한다면 Wating for Debugger화면에서 더 이상 진행되지 않는다.
android:enable – 애플리케이션의 컴포넌트를 인스턴스화 할 수 있는지를 설정한다. 디폴트 값은 “true”이다. “true”라면 각 컴포넌트의 enabled 애트리뷰트가 그 컴포넌트의 활성화 여부를 결정하고 “false”라면 모든 컴포넌트들은 비활성화 된다.
android:hasCode – 시스템 코드가 아닌 다른 코드를 포함하고 있는지를 설정한다. 디폴트 값은 “true”이다.
android:manageSpaceActivity – 디바이스상에서 애플리케이션이 점유하는 메모리를 사용자가 관리 할 수 있도록 하는 액티비티 이름이다.
adroid:permission – 클라이언트와 애플리케이션이 상호작용하기 위해 필요한 퍼미션 이름이다. 이 애트리뷰트는 애플리케이션 안의 모든 컴포넌트에 퍼미션을 적용한다.
android:persistent – 애플리케이션이 항상 실행 상태로 있는지의 설정값이다. 디폴트는 “false”이다.
android:process – 애플리케이션 프로세스의 이름이다. 애플리케이션 안에 모든 컴포넌트는 이 애트리뷰트의 프로세스로 실행이 되고 각 컴포넌트에 process 애트리뷰트를 설정 함으로써 오버라이드 할 수 있다. 디폴트로 <manifest>엘리먼트의 package이름이다. 이 애트리뷰트의 이름이 콜론(:)으로 시작되면 private하고 소문자로 시작한다면 그 이름을 가진 글로벌 프로세스가 만들어진다. 글로벌 프로세스는 공유될 수 있어 리소스 사용을 감소시킨다.
android:taskAffinity – 애플리케이션 안의 모든 액티비티에 적용되는 affinity이름이다. 액티비티 내에 taskAffinity를 설정했다면 적용되지 않는다. 디폴트로 <manifest>엘리먼트의 package 이름을 가지고 어플리케이션내에 액티비티는 동일 Affinity를 공유한다.
android:theme – 애플리케이션 안의 모든 액티비티에 적용되는 스타일 리소스에 대한 레퍼런스 이다. 각각의 액티비티는 이 설정을 override 할 수 있다.
<activity>
<activity android:allowTaskReparenting=["true" | "false"]
android:alwaysRetainTaskState=["true" | "false"]
android:clearTaskOnLaunch=["true" | "false"]
android:configChanges=[one or more of: "mcc" "mnc" "locale"
"touchscreen" "keyboard" "keyboardHidden" "navigation" "orientation" "fontScale"]
android:enabled=["true" | "false"]
android:excludeFromRecents=["true" | "false"]
android:exported=["true" | "false"]
android:finishOnTaskLaunch=["true" | "false"]
android:icon="drawable resource"
android:label="string resource"
android:launchMode=["multiple" | "singleTop" | "singleTask" | "singleInstance"]
android:multiprocess=["true" | "false"]
android:name="string"
android:permission="string"
android:process="string"
android:screenOrientation=["unspecified" | "user" | "behind" | "landscape" | "portrait" | "sensor" | "nonsensor"]
android:stateNotNeeded=["true" | "false"]
android:taskAffinity="string"
android:theme="resource or theme"
android:windowSoftInputMode=[one or more of: "stateUnspecified"
"stateUnchanged" "stateHidden"
"stateAlwaysHidden" "stateVisible"
"stateAlwaysVisible" "adjustUnspecified"
"adjustResize" "adjustPan"] >
. . .
</activity>
각각의 액티비티마다 <activity>태그가 필요하다. 매니페스트 파일에 액티비티가 정의되어 있지 않다면 해당 액티비티를 실행시킬 수 없다.(런타임 오류가 발생)
android:allowTaskReparenting – 친화력 있는 태스크 설정 애트리뷰트이다. 이 애트리뷰트가 설정되지 않으면 <application>엘리먼트의 allowTaskReparenting에 설정된 값이 액티비티에 적용된다. 디폴트 값은 “false”이다.
android:alwaysRetainTaskState – 사용자가 Task를 오랫동안 방치하면 시스템은 Root Activity를 제외한 모든 Activities의 Task를 Clear 시킨다. 이 애트리뷰트가 “true”로 설정 되어 있다면 Task는 오랜 시간이 지나도 Stack에 있는 모든 Activity를 유지한다. 디폴트 값은 “false”이다.
android:clearTaskOnLaunch – 이 속성이 “true”로 설정되어 있으면 사용자가 Task를 떠났다가 다시 돌아 올 때마다 Stack은 Root Activity로 정리된다. 디폴트 값은 “false”이다.
Android:configChanges – 시스템은 각 어플리케이션을 종료하고 재시작한 뒤 리소스 값을 다시 읽어 들임으로써 언어, 위치, 하드웨어에 대한 런타임 변경을 지원한다. 런타임 구성 변경을 감지하는 activity를 가지려면 Manifest 노드에 android: configChanges 속성을 추가 한 뒤 변경을 하고자 하는 구성 변경을 지정한다. 여러 값을 사용할 때는 ‘|’에 의해 구분된다.
mcc : IMSI 모바일 국가 코드가 변경되었다.
mnc : IMSI 모바일 네트워크 코드가 변경되었다.
locale : 사용자가 다른 언어 설정을 선택했다.
touchscreen : 터치스크린이 변경되었다.
keyboard : 키보드 종류가 바뀌었다.
keyboardHidden : 키보드가 보여졌거나 숨겨졌다.
navigation : 네비게이션 타입이 변경 되었다.
origentation : 화면이 세로 방향이나 가로 방향으로 회전됐다.
fontScale : 사용자가 선호하는 글꼴 크기를 변경했다.
/// Configuraion 객체를 사용해 새로운 구성 값을 결정하도록
/// OnConfigurationChnaged 메서드를 재정의 한다.
@Override
public void onConfigurationChanged(Configuration _newConfig) {
super.onConfigurationChanged(_newConfig);
// resource 값에 기반을 두고 있는 모든 GUI를 update를 한다.
// ....
if (_newConfig.orientation == Configuration.OPRIENTATION_LANDSCAPE)
{
// 방향이 landscape로 변경되면 해당 방향으로 반응을 한다.
}
if (_newConfig.keyboardHidden == Configuration.KEYBOARDHIDDEN_NO)
{
// 변경된 키보드의 유무에 반응을 한다.
}
}
시스템이 재시작 되지 않을 경우 다음과 같이한다.
android:excludeFromRecents – “true”이면 사용자가 볼 수 있는 최근 런치된 액티비티 리스트에서 제외되고 “false”이면 리스트에 포함된다. 디폴트 값은 “false”이다.
android:exported – 다른 애플리케이션의 컴포넌트에서 이 액티비티를 런치 할 수 있는지를 설정한다. “false”라면 이 액티비티는 같은 애플리케이션 혹은 같은 유저 ID를 가진 애플리케이션 컴포넌트만 런치 할 수 있다. 디폴트는 액티비티가 인텐트 필터를 포함하는지에 달려있다. 필터가 없다면 디폴트 값이 “false”이고 필터가 있다면 “true”이다.
MAIN/LAUNCHER 액티비티에는 절대로 “false”값을 주면 안 된다. “false”값을 주게 되면 SecurityException이 발생하고 exported 속성을 true로 설정해 달라는 메시지가 출력된다.
android:finishOnTaskLaunch – 사용자가 태스크를 런치 할 때 마다 액티비티의 기존 인스턴스가 종료 되어야 하는지의 여부를 설정한다. 종료되어야 한다면 “true”이고 종료되지 않아야 한다면 “false”이다. 디폴트 값은 “false”이다. 만약 이 애트리뷰트와 allowTaskReparenting이 모두 “true”라면 액티비티 친화력은 무시되어 액티비티는 부모를 바꾸지 않고 파괴된다.
android:launchMode – 액티비티가 어떻게 런치되어야 하는지에 대한 명령이다. 4가지 런치모드(“standard” “singleTop” “singleTask” “singleInstance” )가 있고 디폴트는 “standard”이다.
모드는 두개의 main Group으로 나뉜다(standard, singleTop / singleTask, singleInstance). “standard”, “singleTop”모드를 가지는 액티비티는 여러 번 인스턴스화 될 수 있으나(Intent Object가 “FLAG_ACTIVITY_NEW_TASK” flag를 가지고 있지 않을 경우에 해당) “singleInstance” 액티비티는 하나의 Task만 시작 할 수 있다.
“standard” vs “singleTop” : “standard” 액티비티에 대한 새로운 Intent가 발생하면 언제나 해당 Class의 Instance가 만들어 지지만 “singleTop” 액티비티의 새로운 Instance는 생성 될 수도 있다. 즉, Target Task에 이미 해당 액티비티의 인스턴스가 존재하면 새로 만들어지지 않고 기존 인스턴스가 새로운 Intent를 받게 된다.
“singleTask” vs “singleInstance” : “singleTask” 액티비티는 다른 액티비티들이 해당 Task의 일부가 되는 것을 허락하여 “singleTask” 액티비티는 액티비티 스택의 root에 존재하게 되고 다른 액티비티들은 동일한 Task에서 시작 될 수 있다. 이와 달리 “singleInstance” 액티비티는 어떤 다른 액티비티들도 해당 Task의 일부가 될 수 없다. 이로 인해 해당 Task에는 유일한 Activity만 존재하고 또 다른 Activity를 실행하려고 하면 새로운 Task로 할당이 된다.
android:multiprocess – 이 플래그가 “true”이면 액티비티 인스턴스가 다양한 프로세스에서 실행 될 수 있다. 디폴트 값은 “false”이고 “true”값은 지양한다.
android:noHistory – “true”라면 사용자가 액티비티를 떠나 화면에 보이지 않았을 때 스택에서 제거되고 종료(finish()메소드가 호출됨)된다. 기본값은 “false”이다.
android:permission – 액티비티를 런치하기 위해 혹은 인텐트에 응답하기 위해 얻어야 하는 퍼미션 이름이다. 만약 startActivity() 또는 startActivityForResult()의 호출자가 퍼미션을 부여받지 않으면 인텐트는 해당 액티비티에 전달 되지 않는다.
애트리뷰트가 설정되지 않으면 <application>엘리먼트의 퍼미션이 적용되고 <application>엘리먼트 퍼미션이 없다면 이 액티비티는 퍼미션에 의해 보호되지 않는다.
android:process – 액티비티가 실행되어야 하는 프로세스의 이름이다. 디폴트 프로세스 이름은 어플리케이션 패키지 이름이다.
android:screenOrientation – 액티비티의 방향을 설정한다.
unspecified : 시스템에서 디바이스에 따라 방향을 결정
landscape : 가로방향
portrait : 세로방향
behind : 이전 액티비티의 스택에 따라 결정
user : 사용자 설정
sensor : 가속 센서의 방향에 따라 결정
nosensor : 가속 센서를 사용하지 않음, “unspecified”와 비슷
android:stateNotNeeded – 액티비티가 임시로 종료되기 전에 리소스를 저장하기 위해 onSaveInstanceState() 메쏘드가 호출된다. 이 메쏘드는 액티비티가 재시작될 때, onCreate()에 전달되는 Bundle에 액티비티의 현재 상태를 저장한다. 만약 이 애트리뷰트가 “true”로 설정되다면 onSaveInstanceState()는 호출되지 않고 onCreate()는 bundle 대신에 null을 전달받는다. 디폴트 값은 “false”이다.
android:taskAffinity – 이곳에 다른 task name을 설정해 주면 이 액티비티는 해당 task에서 실행된다. 하나의 어플리케이션에서 실행되는 아이콘을 여러 개 만드는데 사용된다. 기본적으로 액티비티는 애플리케이션의 친화력을 상속한다. 애플리케이션의 디폴트 친화력 이름은 <manifest>엘리먼트의 패키지 이름이다.
android:theme – 액티비티의 테마를 정의하는 스타일 리소스에 대한 레퍼런스이다. 기본적으로 <application>엘리먼트의 테마를 사용하고 테마가 없으면 시스템 테마가 사용된다.
android:windowSoftInputMode – 소프트 키보드 상태 : 액티비티가 사용자 관심의 포커스를 받을 때 소프트 키보드가 보여지는지 여부를 설정한다.
액티비티 메인 윈도우에 대한 조정 : 소프트 키보드를 위한 공간을 만들기 위해 액티비티 메인 윈도우를 작게 줄일 지의 여부 또는 메인 윈도우 일부가 소프트 키보드에 의해 가려질 때 현재 포커스를 보이도록 하기 위해 메인 윈도우의 컨텐트가 상하로 움직일 지의 여부를 설정한다.
stateUnspecified : 소프트 키보드 상태에 대해 시스템이 적절한상태를 선택하거나 테마 설정값을 따른다. 소프트 키보드의 디폴트 설정 값.
stateUnchanged : 소프트 키보드는 마지막 상태로 유지
stateHidden : 사용자 액티비티를 선택할 때 소프트 키보드는 숨겨짐
stateAlwaysHidden : 액티비티의 메인 위도우가 입력 포커스를 가질 때 소프트 키보드는 항상 숨겨짐
stateVisible : 사용자가 액티비티 메인 위도우 앞으로 갈 때 소프트 키보드 보여짐
stateAlwaysVisible : 사용자가 액티비티를 선택할 때 소프트 키보드 보여짐
adjustUnspecified : 스크롤 할 수 잇는 레이아웃 뷰들을 가지고 있다면 윈도우 크기 재조정. 메인 윈도우의 디폴트 값
adjustResize : 스크린에 소프트 키보드 공간을 만들기 위해 메인 윈도우 크기가 항상 재조정 됨
adjustPan : 소프트 키보드 공간을 만들기 위해 메인 윈도우 크기가 재조정 되지 않음
<intent-filter>
수행되어야 할 Action을 서술해 놓은 정보의 묶음이다. 이 정보에는 수행되었을 때의 데이터, Action을 수행하기 위한 구성 요소의 Category, 그리고 또 다른 적절한 지시 등이 포함된다.
Android System은 Component를 구동하기 전에 Component가 다루려 하는 의도를 파악해야 하기 때문에 Intent Filters은 <intent-filter> 요소로 Manifest에 규정되어 있어야 한다. 하나의 Component는 여러 개의 Filters을 가질 수 있고 각각은 서로 다른 Capabilities를 나타내게 된다.
<intent-filter android:icon="drawable resource"
android:label="string resource"
android:priority="integer" >
. . .
</intent-filter>
Target Component를 명시적으로 명명한 Intent는 해당 Component를 활성화 시키게 되는데 이 때는 filter가 사용되지 않는다. 그러나 명시적으로 Target을 정하지 않게 되면 Component's Filters 중 하나를 통해 전달하게 된다.
android:priority – 부모 컴포넌트가 필터에 따른 인텐트 처리의 우선순위이다. 액티비티와 브로드캐스드의 경우에 해당한다.
필터와 일치하는 인텐트에 대해 응답 방법에 대한 정보를 제공하고 인텐트에 대한 잠재적 타겟으로 높은 우선순위인 액티비티만을 고려한다.
높은 우선순위의 값을 가지는 브로트캐스트 리시버가 먼저 호출된다.
<action>
<action android:name="string" />
<intent-filter>엘리먼트는 반드시 하나이상의 <action>엘리먼트를 포함해야 한다.
android:name – 액선의 이름으로써 ACTION_문자열 상수이다. 예를들어 ACTION_MAIN에 대해서는android.intent.action.MAIN, ACTION_WEB_SEARCH에 대해서는 anroid.intent.action.WEB_SEARCH를 사용한다.
안드로이드 패키지가 아닌 직접 정의한 액션에 대해서는 접두어로 패키지 이름을 사용하는 것이 좋다. 예를들어 TRANSMOGRIFY액션은 com.example.project.TRANSMOGRIFY 처럼 사용한다.
<category android:name="string" />
인텐트가 카테고리 테스트를 통과하기 위해서는 인텐트 오브젝트 안의 모든 카테고리가 필터에 있는 카테고리와 일치해야 한다.
android:name – 카테고리의 이름으로써 CATEGORY_name 상수이다. 예를들어 CATEGORY_LAUNCHER에 대한 문자열 값은 android.intent.category.LAUNCHER이다.
<data>
URI와 데이터 타입(MIME 미디어 타입)을 지정 할 수 있다. schema, host, port, path와 같은 URI 애트리뷰트들에 의해 지정된다.
scheme://host:port/path 또는 pathPrefix 또는 pathPattern
예를들어 content://com.example.project:200/folder/subfolder/etc이다.
<data android:scheme=”something” android:host=”project.example.com” />과
<data android:host="string"
android:mimeType="string"
android:path="string"
android:pathPattern="string"
android:pathPrefix="string"
android:port="string"
android:scheme="string" />
<data android:scheme=”something” /><data android:host=”project.example.com” />은 동일하다.
android:host – URI authority의 host영역이다. scheme가 없으면 이 애트리뷰트는 의미가 없다. 호스트 이름은 항상 소문자로 지정해야 한다.
android:mimType – image/jpeg 또는 audio/mpeg4-generic과 같은 MIME 미디어 타입이다. 하위타입에 대해 와일드카드(*)를 사용할수 있으면 항상 소문자를 사용해서 지정해야 한다.
android:path
android:pathPrefix
android:pathPattern – URI authority의 path영역이다. path 애트리뷰트는 인텐트 오브젝트 내의 전체 path와 일치하는 path를 지정한다. pathPrefix 애트리뷰트는 인텐트 오브젝트 내 path의 첫 머리만 일치하는 부분적인 path를 지정한다. pathPattern 애트리뷰트는 인텐트 오브젝트 내의 전체 path와 일치하는 path를 지정하지만 다음과 같은 와일드카드를 포함할 수 있다. 첫째로 별표(*)는 바로 앞에 나오는 문자가 0번 이상 발생하는 것을 나타내고 둘째로는 마침표 뒤에 별표가 나오는 것(.*)은 어떤 문자든 0번 이상 발생하는 것을 나타낸다.
XML에서 “\”은 이스케이프 문자로써 사용된다.
scheme와 host 애트리뷰트가 필터에 없으면 이 애트리뷰트는 의미가 없다.
android:port - URI authority의 port영역이다. scheme와 host 애트리뷰트가 지정될 때에만 의미를 같는다.
android:scheme – URI authority의 scheme영역이다. Scheme이 없다면 나머지 애트리뷰트는 의미가 없다. 스키마는 항상 소문자를 사용해야 한다.
<meta-data>
데이터에 대한 정의나 설명이다. 컴포넌트 엘리먼트는 <meta-data> 서브엘리먼트를 포함할 수 있다. <meta-data>의 모든 값은 하나의 Bundle로 모아지고 PackageItemInfo.metaData 필드로써 컴포넌트에서 사용할 수 있다.
<meta-data android:name="string"
android:resource="resource specification"
android:value="string" />
android:name – 아이템에 대한 고유한 이름이다. 예를들어 com.example.project.activity.fred처럼 Java 스타일 naming 규약을 사용해야 한다.
android:resource – 리소스에 대한 레퍼런스 이다. ID는 Bundle.getInt() 메쏘드에 의해 meta-data Bundle로부터 얻을수 있다.
android:value – 아이템에 할당된 값이다. 아래는 값으로 할당 할수 있는 데이터 타입과 값을 얻기 위해 사용하는 메쏘드들이다.
타입 |
Bundle 메쏘드 |
유니코드 문자를 위한 “\\n” 와 “\\uxxxxx” 같은 이스케이프(escape) 캐릭터에 더블 백슬래시(\\)를 사용하는 문자열 값 |
getString() |
“100”같은 정수(integer) 값 |
getInt() |
“참(true)” 또는 “거짓(false)” 중 하나인 boolean 값 |
getBoolean() |
“#rgb“,#”argb“,#”rrggbb” 또는 “#aarrggbb”형식의 컬러 값 |
getString() |
“1.23” 같은 부동소수점 값 |
getFloat() |
<activity-alias>
<activity-alias android:enabled=["true" | "false"]
android:exported=["true" | "false"]
android:icon="drawable resource"
android:label="string resource"
android:name="string"
android:permission="string"
android:targetActivity="string" >
. . .
</activity-alias>
<activity>를 타겟으로 지정해 그 타겟과 다른 속성으로 <activity>를 호출한다. targetActivity는 같은 <application>안에 있어야 하고 <activity-alias>보다 먼저 선언 되어 있어야 한다. targetActivity는 Activity-alias의 부모 엘리먼트이고 activity-alias는 targetActivity의 애트리뷰트를 따르지만 activity-alias안에 같은 애트리뷰트가 선언되면 activity-alias 애트리뷰트 값을 따른다.
android:exported – 다른 애플리케이션의 컴포넌트들이 이 앨리어스를 통해 타겟 액티비티를 런치할 수 있는지를 설정한다. 런치할 수 있다면 “true”이다. 인텐트 필터가 없으면 디폴트 값은 “false”이고 인텐트 필터가 있다면 디폴트 값은 “true”이다.
android:name – 앨리어스의 이름을 지정한다. 이름은 전체 클래스 이름과 비슷해야 하고 실제 클래스 이름을 참조하지 않는다.
android:permission – 이것이 설정된다면 targetActivity 퍼미션을 대체한다. 설정이 되지 않는다면 앨리어스를 통해 타겟을 활성화 하기 위한 퍼미션은 필요하지 않다.
android:targetActivity – 앨리어스를 통해 활성화 될 수 있는 액티비티의 이름을 지정한다.
<service>
<service android:enabled=["true" | "false"]
android:exported=["true" | "false"]
android:icon="drawable resource"
android:label="string resource"
android:name="string"
android:permission="string"
android:process="string" >
. . .
</service>
각 서비스마다 <service>태그가 필요하다. 서비스는 백그라운드 오퍼레이션이나 다른 애플리케이션이 호출 할 수 있는 커뮤니케이션 API를 구현하기 위해 사용된다.
android:icon – 서비스 아이콘은 이곳에서 설정하던 <application>엘리먼트에서 설정하던 모든 서비스의 인텐트 필터에 대한 디폴트 아이콘이다.
android:label – 서비스 아이콘은 이곳에서 설정하던 <application>엘리먼트에서 설정하던 모든 서비스의 인텐트 필터에 대한 디폴트 라벨이다.
android:name – 서비스를 구현하는 Service 서브클래스의 이름이다. com.example.project.RoomService 처럼 전체 클래스 이름이어야 한다. 하지만 .RoomService와 같이 단축형 이름이라면 <manifest>엘리먼트에 지정된 패키지 이름 끝에 붙여진다.
android:permission – 서비스를 런치하거나 바인드를 하기 위해 가져야 하는 퍼미션 이름이다. 만약 startsService(), bindService(), stopService()의 호출자가 이 퍼미션을 부여받지 않는다면 이 메쏘느는 작동하지 않으며 인턴트 오브젝트는 서비스에 전달되지 않는다. 이 퍼미션을 설정하지 않으면 <application>퍼미션이 적용되고 <application>퍼미션이 없다면 퍼미션이 적용되지 않는다.
<receiver>
<receiver android:enabled=["true" | "false"]
android:exported=["true" | "false"]
android:icon="drawable resource"
android:label="string resource"
android:name="string"
android:permission="string"
android:process="string" >
. . .
</receiver>
어플리케이션이 브로드캐스트 메시지를 수신할수 있도록 한다. 브로드캐스트 리시버는 애플리케이션의 다른 컴포넌트들이 실행되지 않아도 다른 애플리케이션 또는 시스템에 의해 브로드캐스트 되는 인텐트를 받기 위해 애플리케이션을 활성화 한다.
시스템에게 브로드캐스트 리시버를 알기기 위한 방법으로는 이 엘리먼트를 가지고 매니페스트 파일 안에 선언하는 것과 코드 안에서 동적으로 리시버를 만들어서 Context.registerReceiver() 메쏘드를 사용해서 등록한다.
android:exported – 브로드캐스트 리시버가 다른 애플리케이션 소스로부터 메시지를 받을수 있는지를 설정한다. 받을수 있으면 “true”이고 아니면 “false”이다. 인텐트 필터가 없으면 디폴트 값은 “false”이고 인텐트 필터가 있다면 디폴트 값은 “true”이다.
<provider>
<provider android:authorities="list"
android:enabled=["true" | "false"]
android:exported=["true" | "false"]
android:grantUriPermissions=["true" | "false"]
android:icon="drawable resource"
android:initOrder="integer"
android:label="string resource"
android:multiprocess=["true" | "false"]
android:name="string"
android:permission="string"
android:process="string"
android:readPermission="string"
android:syncable=["true" | "false"]
android:writePermission="string" >
. . .
</provider>
애플리케이션의 일부가 되는 모든 컨텐트 프로바이더를 선언해야 한다. 컨텐트 프로바이더 서브클래스에 대한 이름은 URI authority이다.
android:authorities – 데이터를 구분하는 URI authority 목록이다. Authority가 여러 개이면 세미콜론(;)으로 이름을 구분한다. 최소한 하나의 authority가 지정되어야 한다.
android:grantUriPermissions – 일시적으로 radPermission, writePermission, 데이터 접근 할수 있게 하려면 “ture”로 설정하거나 <grant-uri-permission>서브엘리먼트를 정의함으로써 이 기능을 활성화 한다. 퍼미션을 설정하지 않으려면 “false”로 한다.
android:initOrder – 컨텐트 프로바이더가 인스턴스화되어야 하는 순서를 설정한다. 높은 숫자들이 먼저 초기화 된다.
android:permission – 클라이언트가 컨텐트 프로바이더의 데이터를 읽거나 쓰기 위해 가져야 하는 퍼미션의 이름이다. 이 애트리뷰트는 읽기와 쓰기 모두에게 하나의 퍼미션을 설정한다. 하지만 readPermission과 writePermission 애트리뷰트가 이것보다 우선순위이다.
android:readPermission – 클라이언트가 컨텐트 프로바이더에 쿼리하기 위해 가져야 하는 퍼미션이다.
android:syncable – 컨텐트 프로바이더의 제어하에 있는 데이터가 서버 상의 데이터와 동기화되어져야 한다면 “true” 아니면 “false”이다.
android:writePermission – 클라이언트가 컨텐트 프로바이더에 의해 제어되는 데이터를 변경하기 위해 가져야 하는 퍼미션이다.
<uses-permission android:name="string" />
어플리케이션에 링크 되어야 하는 외부 라이브러리를 지정한다.
android:name – 라이브러리 이름
디폴트 값
Element |
Atrribute |
디폴트 값 |
false | ||
|
android:handleProfiling |
false |
<uses-sdk> |
android:minSdkVersion |
1 |
|
android:maxSdkVersion |
없음 |
<supports-screens> |
android:smallScreens |
true(API Level 7 기준) |
|
android:normalScreens |
true(API Level 7 기준) |
|
android:largeScreens |
true(API Level 7 기준) |
|
android:anyDensity |
true(API Level 7 기준) |
<application> |
android:allowClearUserData |
|
|
android:allowTaskReparenting |
false |
|
android:debuggable |
false |
|
android:enable |
true |
|
android:hasCode |
true |
|
android:persistent |
false |
|
android:process |
<manifest>엘리먼트의 package 이름 |
|
android:taskAffinity |
<manifest>엘리먼트의 package 이름 |
<activity> |
android:alwaysRetainTaskState |
false |
|
android:clearTskOnLaunch |
false |
|
android:enabled |
true |
|
android:excludeFromRecents |
false |
|
android:exported |
Intent 필터가 없다면 false Intent 필터가 있다면 true |
|
android:finishOnTaskLaunch |
false |
|
android:launchMode |
standard |
|
android:multiprocess |
false |
|
android:noHistory |
false |
|
android:permission |
<application>엘리먼트의 퍼미션 <application>퍼미션이 없다면 퍼미션에 의해 보호 되지 않음 |
|
android:process |
애플리케이션의 패키지 이름 |
|
android:stateNotNeeded |
false |
|
android:taskAffinity |
어플리케이션의 친화력을 상속. 어플리케이션의 디폴트 친화력 이름은 <manifest>엘리먼트의 패키지 이름이다. |
|
android:theme |
<application>테마 <application>테마가 없다면 시스템 테마 |
|
android:windowSoftInputMode |
소프트 키보드 : stateUnspecified 메인 윈도우 : adjustUnspecified |
<intent-filter> |
android:label |
부모 컴포넌트에 설정된 라벨 부모가 라벨을 설정하지 않으면 <application>라벨 |
<activity-alias> |
android:enabled |
true |
|
android:exported |
인텐트 필터가 있으면 true |
|
android:permission |
targetActivity의 퍼미션 targetActivity의 퍼미션이 없다면 퍼미션에 의해 보호되지 않음 |
<service> |
android:enabled |
true |
|
android:exported |
인텐트 필터가 없으면 false 인텐트 필터가 있으면 true |
|
android:permission |
<application>엘리먼트의 퍼미션 <application>퍼미션이 없다면 퍼미션에 의해 보호되지 않음 |
<receiver> |
android:enabled |
true |
|
android:exported |
인텐트 필터가 없으면 false 인텐트 필터가 있으면 true |
|
android:permission |
<application>엘리먼트의 퍼미션 <application>퍼미션이 없다면 퍼미션에 의해 보호되지 않음 |
<provider> |
android:enabled |
true |
|
android:exported |
인텐트 필터가 없으면 false 인텐트 필터가 있으면 true |
|
android:multiprocess |
false |
|
android:process |
<application>엘리먼트의 프로세스 |
|
|
|