Android/View | Posted by 덩치 2014. 4. 3. 16:21

나인패치 (9patch) 이미지 만드는 방법

펌 OK (출처 표시), 상업적 이용 NO, 컨텐츠 변경 NO

나인패치 이미지란


(http://developer.android.com/tools/help/draw9patch.html) <- 디벨로퍼사이트의 나인패치에 대한 설명


해상도가 다른 단말기에서 아이콘 등이 확대 될 때, 확대 되는 영역을 특정지어서 확대되서


픽셀이 깨지는 (라운드,그라데이션) 현상 없이 확대되는 이미지.


확대되도록 설정한 영역 이외의 부분은 확대가 되지 않는다.


쉽게말해 말풍선 같은 이미지를 네 모서리와 하단 꼭짓점 크기는 고정시키고 안의 크기만 늘려주며,


고정된 해상도라기 보다 어떤 해상도로 늘어나더라도 이미지가 깨지지 않도록 하는 방식이다.


다음 이미지를 보자




위 이미지가 나인패치 이미지이다. 확장자가 .9.png로 특이한 형태를 취하고 있으며,


풍선 주위에 검은색 선은 확장 영역과 콘텐츠 영역을 표시하는것으로, 실제 이미지가 적용되면 나타나지 않는다.


나인패치 사용법에 앞서 우선 위의 이미지가 어떻게 확장되는지 설명을 하자면


다음 이미지를 보며 설명해주겠다.




왼쪽변의 검은 선은 세로로 확장되는 영역, 상단변의 짧은 선 두개는 각각 세로로 확장되는 영역이며,


우측변의 검은 선은 콘텐츠(텍스트 등)가 들어가는 세로영역, 하단의 변은 마찬가지 콘텐츠가 들어가는 가로 영역이다.


분홍색 기둥 두개가 보일텐데, 간단히 말해 저 두개의 영역이 확대,축소되며 이미지를 표시한다.


즉, 노란부분과 분홍색 막대 상,하단, 왼쪽분홍막대 좌측, 오른쪽 분홍막대 우측 영역은


이미지 크기가 불변한다. (돼지꼬리)


분홍색 막대만이 가로,세로로 확장되고 축소되며 전체 이미지가 커지거나 작아지는것처럼 표시된다.


그렇기때문에 작은 해상도에서는 라운드가 엄청 커보이지만, 큰 해상도에서는 라운드가 작아보이게 되고


엄청 커지면 라운드는 거의 없는것처럼 보이게 된다.


밑의 말풍선 꼬리 영역도 마찬가지로 크기가 변하지 않는다.


위 이미지처럼 라운드가 있거나, 또는 그라데이션이 있어서 그라데이션 영역은 확장하지 않고, 이외의 부분만


확장될 수 있을 때, 나인패치 이미지를 사용한다.


나인패치의 한계는 하트모양이나 동그라미처럼 특정 영역만 확대하면 모양이 이상해져버리는 


도형에는 사용할 수 없다는것이다.


나인패치를 만드는법을 알아보자. 우선 이미지를 준비한다. 포토샵으로 그려도 되고 기존의 이미지를 사용해도 된다.



나는 간단하게 아래의 이미지로 실습을 해 보겠다.




다음은 나인패치 이미지를 만들 수 있는 툴을 실행시킨다.

(툴은 안드로이드 sdk에 있으며, 툴이 없는 경우 포토샵으로 맨처음 이미지처럼 만들고, 확장자를 name.9.png 식으로 저장하여도 된다.)


나의 경로는

adt-bundle-windows-x86_64-20130522 -> sdk -> tools -> draw9patch.bat


draw9patch.bat 파일을 실행시키면 잠시후 다음과 같은 창이 나타나는데,




이미지를 드래그해서 위 창에 드랍시킨다.




그럼 이렇게 표시된다. 우측은 미리보기이고..


상하좌우 맨 마지막 1픽셀을 마우스로 클릭하여 드래그하면 검은색 선이 생기는데,


이런 방식으로 영역을 설정 해 준다.


일반적으로.콘텐츠영역은 확대되는 영역의 최대 영역으로 설정한다.


영역 취소는 시프트를 누르고 클릭 하여 드래그하면 된다.




(이런식으로 색상이 구분되는것은 하단에 show patches 를 체크해 주면 된다.)


분홍색 부분이 확대되는 영역, 초록색과 붉은부분이 확대되지 않는 영역이며


우측을 보면 확대를 엄청 했을경우 미리보기인데, 라운드부분은 확대되지 않아서 상대적으로 작아보인다.


하지만 이런 특성 덕분에 라운드가 깨져보일 염려는 없다.




나름대로 알아듣기 쉽게 설명하기 위해 노력했는데 잘 전달 되었는지 모르겠습니다.


문의사항은 댓글 남겨주세요



펌 환영. 출처만 남겨주세요



Android/View | Posted by 덩치 2014. 2. 4. 11:50

레이아웃의 종류와 사용법

펌 OK (출처 표시), 상업적 이용 NO, 컨텐츠 변경 NO

자주 사용하게 되는 레이아웃 3가지만 다루겠다.


1. LinearLayout

뷰가 가로 또는 세로로 순차적으로 나열되는 레이아웃.



보는바와 같이 android:orientation 옵션을 통해 가로(horizontal) 또는 세로(vertical)로 설정할 수 있으며

따로 선언하지 않는다면 디폴트로 horizontal이 적용된다.

가장 사용하기 편리한 레이아웃이라고 생각함



2. RelativeLayout

따로 위치를 지정하지 않으면 뷰가 0,0 위치에 계속 쌓이는 레이아웃으로,

최상위 부모 레이아웃 상대위치 또는 id를 참조해 특정 뷰에 대해 상대적인 위치를 지정할 수 있다.

약간 까다로울 수 있는 레이아웃인데 예제를 보자.




위와같이 따로 위치를 지정하지 않으면 저렇게 다 겹쳐서 출력된다.

위치를 지정해 보자.


(클릭해서 보세요)

이런식으로 지정해 줄 수 있다.

RelativeLayout은 사용법이 까다로운만큼 완벽히 이해하고 넘어가길 바란다.



3. FrameLayout

같은 자리의 자식 뷰들을 겹치도록 놓고, VISIBLE, INVISIBLE, GONE 등의 옵션으로 교차하면서 보여줄 수 있음

아래쪽에서 선언된 뷰가 가장 위에 표시



주로 버튼클릭시 기존의 뷰를 숨기고 다른 뷰를 표시하는 탭기능에서 사용된다.

(텝1페이지 레이아웃과 2페이지 레이아웃을 인클루드하여 사용하는 방식 등)


소스코드에서는 View.setVisibility("GONE"); 형식으로 사용한다.


visible = 보이기  invisible = 뷰의 영역은 가지고 숨기기  gone = 뷰를 숨기고 영역도 해제함


직접 사용해보면서 차이점을 느끼기 바란다.


질문사항 있으면 댓글로 남겨주세요

-끝-



펌 OK (출처 표시), 상업적 이용 NO, 컨텐츠 변경 NO

안드로이드에서 데이터 관리를 할 수 있는 방법에는 여러가지가 있다.

SQLite DB를 이용한 데이터 관리, 서버를 거친 DB에 의한 관리, Input,OutputStreamReader를 이용한 관리,

SharedPreferences를 이용한 관리 등이 있으며, 여기서는 SharedPreferences를 이용한 방법에 대해

알아보겠다.


SharedPreferences키와 벨류로 이루어진 파일 형식으로 데이터를 저장하는 방법으로,

Boolean, Float, Int, Long, String 형태로 데이터를 저장할 수 있다.

어플의 설정값, 사용자 설정 정보등을 저장하는데 적합하며 사용법은 다음과 같다.


선언

SharedPreferences mPref = PreferenceManager.getDefaultSharedPreferences(context);


데이터 저장

SharedPreferences.Editor editor = mPref.edit();

editor.putString("key", "value");

editor.commit();


데이터 호출

String callValue = mPref.getString("key", "default value");

*호출하는 키에 대응하는 값이 없을 경우 디폴트로 설정한 데이터가 출력된다.


데이터 삭제

SharedPreferences.Editor editor = mPref.edit();

editor.remove("key"); or editor.clear();

editor.commit();



주의할점은 만약 기존 데이터의 형을 변경시키고싶다면

반드시 클리어를 한 다음 변경사항을 적용시킨다. 그렇지않으면 예외가 발생하게된다.


SharedPreferences의 장점은 심플한 사용과 관리가 아닐까 한다.



'Android > 입/출력' 카테고리의 다른 글

기본적인 JSONObject, JSONArray 사용법  (3) 2014.03.21
Android/센서 | Posted by 덩치 2014. 1. 7. 10:36

기본적인 센서(Sensor) 사용법

펌 OK (출처 표시), 상업적 이용 NO, 컨텐츠 변경 NO

1. 클래스에 SensorEventListener 참조설정

2. onResume에서 센서값 받아오는 딜레이 설정

3. 리스너가 읽어들이는 센서값 판별, 활용


public class MainActivity extends Activity implements SensorEventListener {

SensorManager sm;

Sensor gyroSensor;

@Override

protected void onCreate(Bundle saveInstanceState) {

sm =  = (SensorManager) getSystemService(SENSOR_SERVICE);

//4가지 센서 설정

gyroSensor = sm.getDefaultSensor(Sensor.TYPE_GYROSCOPE);

accSensor = sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);

magSensor = sm.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);

oriSensor = sm.getDefaultSensor(Sensor.TYPE_ORIENTATION);

}

//액티비티에 SensorEventListener를 참조하게 되면 Add unimplemented methods를 통해 밑의 항목을 오버라이드한다.

@Override

protected void onResume() {

super.onResume();

//4가지 센서에 대한 딜레이 설정. 이걸 해 줘야 리스너로 값이 떨어짐

sm.registerListener(this, gyroSensor, SensorManager.SENSOR_DELAY_UI);

sm.registerListener(this, accSensor , SensorManager.SENSOR_DELAY_UI);

sm.registerListener(this, magSensor, SensorManager.SENSOR_DELAY_UI);

sm.registerListener(this, oriSensor , SensorManager.SENSOR_DELAY_UI);

}

@Override

public void onAccuracyChanged(Sensor sensor, int accuracy) {

//정확도 변경시 사용된다는것 같은데 정확한 용도는 잘 모르겠다. 사용되는건 한번도 못 본듯 하다.

}

@Override

public void onSensorChanged(SensorEvent event) {

//여기서 센서값이 변하는걸 체크한다.

switch (event.sensor.getType()) {

case Sensor.TYPE_GYROSCOPE :

Log.d("tag", "TYPE_GYROSCOPE");

break;

case Sensor.TYPE_ACCELEROMETER :

Log.d("tag", "TYPE_ACCELEROMETER");

break;

//등등으로 쭉 나간다.

}

}

}


센서의 값을 확인하는 방법은 case절 안에서

event.values[0] , event.values[1] , event.values[2] 를 출력하면 x,y,z축의 값이 출력된다.

Log.d("tag", "" + event.values[0]); 이런식으로 ..


이상으로 간단한 센서 사용법을 알아보았다.

문의사항이나 태클걸만한게 있다면 언제든지 댓글 남겨주시길.

Android/기본스킬 | Posted by 덩치 2013. 12. 31. 11:19

핸들러(Handler) 사용하기

펌 OK (출처 표시), 상업적 이용 NO, 컨텐츠 변경 NO


기본적이지만 아주 중요한 Handler

주로 Thread와 함께 사용된다.

안드로이드는 Thread 내에서 UI작업이 불가능하다.

 만약 Thread 내에서 UI작업을 하게되면

CalledFromWrongThreadException 예외가 발생하게된다.

이를 해결하기 위해 핸들러를 이용해 다른 스레드에서 UI에 직접 접근하지 않고

핸들러를 거쳐 접근하여 UI작업을 처리해야한다.


두가지 사용법을 알아보자

1. post로 호출하여 사용하기

Handler handle = new Handler();
public Runnable callback = new Runnable() {
public void run() {
// 실행
}
};

호출하는법은
스래드 내에서 callback 안의 내용을 실행하고싶을 때 
handle.post(callback);
딜레이를 주고싶을 때는 handle.postDelayed(callback, 1000); (1초 뒤 실행)


2. message를 보내 호출하기

Handler handle = new Handler() {

public void handleMessage(Message msg) {

if (msg.waht==0x0001) {


}

else if (msg.what==1) {


}

}

};


호출은 handle.sendEmptyMessage(0x0001);  등으로 한다.

Android/기본스킬 | Posted by 덩치 2013. 12. 31. 10:33

자바/안드로이드 HashMap 사용법

펌 OK (출처 표시), 상업적 이용 NO, 컨텐츠 변경 NO

HashMap은 Map인터페이스의 한 종류로, key와 value 한 쌍을 데이터로 가진다.

쉽게 이해하려면 리스트 형태에 값을 키와 벨류로 가지고 있다고 생각하면 된다.

리스트와의 큰 차이점은 위에처럼 키값을 가진다는것이고, 또 순서를 보장하지 않는다는점이다.

순서대로 입,출력이 되고 순서에 의해 자료를 처리하는 작업에는 알맞지 않다.

입력된 key값을 이용해 value를 구하며(리스트에서 인덱스를 이용해 벨류를 구하는 이치)

key값은 중복되지 않으며 value는 중복 가능하다.


즉, key값으로 1을 5번 입력한다면 맨 처음의 key,value만 입력되고 나머지는 입력되지 않아

이 특성을 잘 이용하면 중복검사를 매우 편하게 할 수 있다.


HashMap의 기본적인 사용법을 알아보겠다.


HashMap<Integer, String> map = new HashMap<Integer, String>();


입력 -

map.put(1, "치킨");

map.put(2, "피자");

map.put(3, "탕수육");


출력 -

Iterator<Integer> iter = map.keySet().iterator();

while(iter.hasNext()) {

int key = iter.next();

String value = map.get(key);

Log.d("fureun", "key : " + key + ", value : " + value);

}

이렇게 하면 모든 키와 벨류 쌍이 다 출력된다.


다른 사용법으로는 map.get(1);을 하면 키 1에 대응하는 value "치킨"이 반환된다.


if(map.containsKey(1)) {


}

이렇게 하면 키값 1이 존재할 경우 true가 반환된다.


이외에도 활용법은 엄청 많으니, 공부를 통해 자신이 원하는 형태로 사용 할 수 있도록 노력하자.


Android/View | Posted by 덩치 2013. 12. 24. 14:56

SurfaceView 구현 / 사용법

펌 OK (출처 표시), 상업적 이용 NO, 컨텐츠 변경 NO

SurfaceViewView를 상속받은 클래스로 Video Memory로 바로 접근하기 때문에 일반 View에서의 랜더링 

속도보다 빠르다.

일반 View는 많은 그리기 작업을 하면 메인 스레드의 자원을 다 잡아먹어버리기때문에 상당히 느려지게 되는데

이러한 단점을 보완하기 위한 클래스라고 보면 된다


우선 액티비티에 SurfaceHolder.Callback을 해 주고, add unimplemented methods를 해 준다.


public class DrawClass implements SurfaceHolder.Callback{


@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

}


@Override

public boolean onCreateOptionsMenu(Menu menu) {

getMenuInflater().inflate(R.menu.main, menu);

return true;

}


@Override

public void surfaceChanged(SurfaceHolder holder, int format, int width,

int height) {

}


@Override

public void surfaceCreated(SurfaceHolder holder) {

}


@Override

public void surfaceDestroyed(SurfaceHolder holder) {

}

}


그럼 셋팅은 끝. 사용되는건 surfaceCreatedsurfaceDestoryed 정도가 되겠다.

surfaceCreated는 처음 서피스뷰가 생성될 때 호출되는데, 주의할점은 백그라운드 상태로 내려갔다가, 다시 올라오게 되면

surfaceview가 다시 created된다는점이다. created에서 thread를 실행시키는 작업을 할 경우

반드시 스레드가 동작중인지 여부를 먼저 확인해야한다. 그렇지않으면 익셉션 발생


surfaceChanged는 업데이트를 대비해 만들었다, 뭐라뭐라 하던데 잘 모르겠다. 사용하지않는듯하다.


이제 SurfaceView 구성은 하였고, 실시간으로 그리기를 실행하려면 Thread를 구동해야한다.


private Class PaintThread extends Thread {

public void run() {

while(!this.isInterrupted()){    //스레드가 인터럽트 될 때까지 반복 실행.

if (그리기 실행조건) {

//그리기 실행

doDraw();

}

}

}

}


나는 주로 드로우 관련부를 따로 만들어서 호출하는방식으로 사용한다.

비트맵을 그려보겠다. surfaceCreated에 다음과 같이 선언한다. (그 위에 Bitmap img, tempBitmap 전역변수로 선언해둔다)

팁 하나, 비트맵 이미지가 큰 경우 메모리를 상당히 많이 잡아먹어 종종 익셉션이 발생하게 되는데,

BitmapFactory.Options option = new BitmapFactory.Options();

option.inSampleSize = 1;

option.inPurgeable = true;

option.inDither = true;

이렇게 해 주면 비트맵이 먹는 메모리를 줄일 수 있다. 리사이클만으로는 감당이 안되는 경우가 생겨 찾다보니 이렇게 해주니 해결되더라. 이렇게 했을경우 단점은 잘 모르겠다. 고퀄리티를 요하는 작업이 아니었기때문에..

그리고 

tempBitmap = BitmapFactory.decodeResource(res, R.drawable.img30x30, option);

img = Bitmap.createScaledBitmap(tempBitmap, imgWidth, imgHeight, true);


private void doDraw() {

try {

canvas = mHolder.lockCanvas(); //그리기 준비

     int size = MainActivity.ARR_X.size();

     canvas.drawColor(Color.GRAY);  //배경색 설정

Paint p = new Paint();

p.setAntiAlias(true);

     canvas.drawBitmap(img, imgX, imgY, p);  //이미지를 X,Y위치에 그리기

catch (Exception e) {

}

finally {

mHolder.unlockCanvasAndPost(canvas); //그리기 종료

}

}


그리고 MainActivityxml에서


<패키지명.DrawClass

android:layout_width="500px"

android:layout_height="500px" />

와 같은식으로 호출한다.


여기까지가 SurfaceView 사용 방법이다.


참고로 위의 소스는 새로운 클래스를 만들어서 기존 액티비티에 영역추가하는식으로 사용한것이고

뷰와 마찬가지로 액티비티에서 바로 setContentView하여 적용 할 수도 있다.

문의점은 댓글 남겨주기바람


Android/Adb | Posted by 덩치 2013. 10. 22. 13:58

자주 사용하는 ADB 명령어

펌 OK (출처 표시), 상업적 이용 NO, 컨텐츠 변경 NO

Adb의 개념에 대해서는 이 전 글에서 알아봤으니, 이번에는 명령어에 대해 알아보자


다음 명령어들은 Path설정이 돼 있다면(이전 글 참조) 다른 준비작업 없이

커맨드라인에 그냥 입력하면 된다.


adb devices

현재 컴퓨터에서 인식하고 있는 Device 또는 Emulator 목록을 출력한다.

다른 작업을 하기 전 우선 단말이나 에뮬이 제대로 인식되었는지 확인차 사용한다.


adb install filename

filename은 apk파일의 이름이다. Device나 Emulator에 filename에 해당하는 어플을 설치하라는 

명령이다. 추가옵션으로 -r과 -l을 설정해 줄 수 있다.

-l은 어플이 다른 장치로 복사되는것을 막는 옵션, -r은 이미 존재하는 어플을 삭제하지 않고 설치


adb uninstall 패키지경로

ex ) com.android.test  (.apk를 제외한 패키지 전체경로 입력)

해당하는 어플이 삭제된다


adb push local_파일명 remote_파일명

개발자 컴퓨터의 파일을 타겟에 복사한다.


adb pull remote_파일명 local_파일명

타겟의 파일을 개발자 컴퓨터로 복사한다.


adb shell

Device에 직접 접속하는 명령어. 이 명령어를 통해 android console에 직접 접속할 수 있다.

디바이스를 루팅하지 않으면 리눅스에서는 먹히는 명령이 먹히지않는경우가 많다.


adb kill-server

adb에 문제가 있을 경우, adb를 종료시킨다. (단말기와 노트북의 케이블을 뺏다꽂아도된다)


adb start-server

종료된 adb를 실행시킨다.


adb reboot

Device를 재시작한다. (리부팅)


이정도가 자주사용되는 명령어들이고,


그 외 명령어들이 궁금하다면 그냥 adb 만 입력하면 도움말이 나온다.


디벨로퍼 사이트에서 좀 더 자세한 사항을 알아보고싶다면

http://developer.android.com/tools/help/adb.html 로 이동하면 된다.


-끝-




'Android > Adb' 카테고리의 다른 글

Adb에 대해 알아보자  (1) 2013.10.22