반응형
블로그 이미지
개발자로서 현장에서 일하면서 새로 접하는 기술들이나 알게된 정보 등을 정리하기 위한 블로그입니다. 운 좋게 미국에서 큰 회사들의 프로젝트에서 컬설턴트로 일하고 있어서 새로운 기술들을 접할 기회가 많이 있습니다. 미국의 IT 프로젝트에서 사용되는 툴들에 대해 많은 분들과 정보를 공유하고 싶습니다.
솔웅

최근에 올라온 글

최근에 달린 댓글

최근에 받은 트랙백

글 보관함

카테고리


반응형

지금 참여하고 있는 프로젝트에서 TDD 관련 Role 을 맡고 있는데요.

안드로이드 Tablet 용 Native 애플리케이션 개발쪽 Role 을 맡을 수도 있을 것 같아서 얼마전 책 두권을 샀습니다.

그 중 하나가 B.M. Harwani 가 지은 The Android Tablet Developer's Cookbook 입니다.


기왕 샀으니 열심히 공부해야겠죠.


오늘은 책장을 넘기다가 눈에 띄는 부분을 공부하려구요.

Chapter 8에 있는 Tweening Animation 인데요.

이 앱을 공부해 보겠습니다.


이 앱에는 4가지 타입의 애니메이션이 있습니다.


Alpha animation - view 의 투명도를 바꿈

Rotate animation - 주어진 pivot point 나 axis 를 중심으로 특정 각도로 view를 rotate 시킴

Scale animation - X나 Y 축을 중심으로 view 를 축소하거나 확대 함.

Translate animation - X나 Y 축을 따라서 view를 움직임


원래 view 를 flipping 시키는 효과를 어디서 찾아보던 중이었거든요.

Rotate animation 이 바로 제가 원하는 효과인지 한번 봐야겠습니다.


그럼 일단 layout xml인 activity_tweening_anim_app.xml을 보겠습니다.


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    <ImageView android:id="@+id/imgview"
        android:layout_width="@dimen/image_width"
        android:layout_height="@dimen/image_height"
        android:src="@drawable/ic_launcher"
        android:layout_centerInParent="true" />
    <Button
        android:id="@+id/alpha_button"
        android:text="Alpha"
        android:textSize="@dimen/text_size"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"  />
    <Button
        android:id="@+id/rotate_button"
        android:text="Rotate"
        android:textSize="@dimen/text_size"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@id/alpha_button" />
    <Button
        android:id="@+id/scale_button"
        android:text="Scale"
        android:textSize="@dimen/text_size"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
         android:layout_toRightOf="@id/rotate_button" />
    <Button
        android:id="@+id/translate_button"
        android:text="Translate"
        android:textSize="@dimen/text_size"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@id/scale_button"  />
</RelativeLayout>



전체 Layout 은 RelativeLayout 으로 감쌌습니다.

그리고 그 안에 1개의 ImageView와 4개의 Button들이 있습니다.

각 버튼마다 위에 소개한 4개의 효과 중 하나를 동작하도록 할 거 같습니다.

각 view 마다 모두 id 가 있죠? 나중에 java에서 갖다가 사용할 겁니다.

각 뷰마다 size는  @dimen/ 으로 시작하는데 이것은 res-values 폴더 아래에 있는 dimens.xml 안에 설정한 값을 사용하겠다는 겁니다.


dimens.xml


<?xml version="1.0" encoding="utf-8"?>
<resources>
    <dimen name="text_size">14sp</dimen>
        <dimen name="image_width">100dp</dimen>
    <dimen name="image_height">120dp</dimen>
</resources>


이 크기들은 일반 phone 크기에 맞춘 것입니다. 


이 소스를 보면 values-sw600dp 라는 폴더가 있는데요. 이 안에 있는 dimens.xml을 보면 아래와 같습니다.


<?xml version="1.0" encoding="utf-8"?>
<resources>
    <dimen name="text_size">24sp</dimen>
        <dimen name="image_width">140dp</dimen>
    <dimen name="image_height">160dp</dimen>
</resources>


이것은 7인치 타블렛 용입니다.

그리고 values-sw720dp 는 10 인치 이상의 tablet 을 위한 겁니다.


<?xml version="1.0" encoding="utf-8"?>
<resources>
    <dimen name="text_size">32sp</dimen>
        <dimen name="image_width">180dp</dimen>
    <dimen name="image_height">200dp</dimen>
</resources>


크기의 비율을 잘 봐 두면 나중에 실무에 도움을 받을 수 있겠네요.

이렇게 설정을 해 놓으면 각 device 마다 해당 해상도에 맞는 dimens.xml 을 갖다가 쓰게 됩니다. 다양한 크기의 해상도를 가진 안드로이드 앱을 개발할 때는 이런 구성을 미리 생각하고 프로그래밍에 들어가야 겠습니다.


아까 소개했던 4개의 애니메이션 효과들은 각각 해당 class 를 가지고 있습니다.


* AlphaAnimation


먼저 AlphaAnimation 을 보겠습니다.


이 클래스는 view의 투명도를 조절하기 위해 만든 건데요. 그 구성은 아래와 같습니다.


public AlphaAnimation(float from_alpha, float to_alpha)


여기서 첫번째 파라미터인 from_alpha 는 이 애니메이션이 시작할 때의 alpha 값입니다. 값은 0.0에서 1.0까지 설정할 수 있습니다.  1.0은 제일 선명한 거고 0.0은 완전 투명한 겁니다.

두번째 파라미터인 to_alpha 는 이 애니메이션이 끝날 때의 alpha 값입니다.


예를 들어 Animation animation = new AlphaAnimation(1.0f,0.1f) 라고 선언하면 아주 뚜렷한 이미지에서 거의 투명한 이미지로 바뀌게 되겠죠.



* TranslateAnimation


이 클래스는 view를 움직이도록 합니다. syntax는 아래와 같습니다.


public TranslateAnimation (float fromXDelta, float toXDelta, float fromYDelta, float toYDelta)

fromXDelta Change in X coordinate to apply at the start of the animation
toXDelta Change in X coordinate to apply at the end of the animation
fromYDelta Change in Y coordinate to apply at the start of the animation
toYDelta Change in Y coordinate to apply at the end of the animation



* RotateAnimation


public RotateAnimation (float fromDegrees, float toDegrees, int pivotXType, float pivotXValue, int pivotYType, float pivotYValue)

Parameters
fromDegrees Rotation offset to apply at the start of the animation.
toDegrees Rotation offset to apply at the end of the animation.
pivotXType Specifies how pivotXValue should be interpreted. One of Animation.ABSOLUTE, Animation.RELATIVE_TO_SELF, or Animation.RELATIVE_TO_PARENT.
pivotXValue The X coordinate of the point about which the object is being rotated, specified as an absolute number where 0 is the left edge. This value can either be an absolute number if pivotXType is ABSOLUTE, or a percentage (where 1.0 is 100%) otherwise.
pivotYType Specifies how pivotYValue should be interpreted. One of Animation.ABSOLUTE, Animation.RELATIVE_TO_SELF, or Animation.RELATIVE_TO_PARENT.
pivotYValue The Y coordinate of the point about which the object is being rotated, specified as an absolute number where 0 is the top edge. This value can either be an absolute number if pivotYType is ABSOLUTE, or a percentage (where 1.0 is 100%) otherwise.



* ScaleAnimation


public ScaleAnimation (float fromX, float toX, float fromY, float toY, int pivotXType, float pivotXValue, int pivotYType, float pivotYValue)


Parameters
fromX Horizontal scaling factor to apply at the start of the animation
toX Horizontal scaling factor to apply at the end of the animation
fromY Vertical scaling factor to apply at the start of the animation
toY Vertical scaling factor to apply at the end of the animation
pivotXType Specifies how pivotXValue should be interpreted. One of Animation.ABSOLUTE, Animation.RELATIVE_TO_SELF, or Animation.RELATIVE_TO_PARENT.
pivotXValue The X coordinate of the point about which the object is being scaled, specified as an absolute number where 0 is the left edge. (This point remains fixed while the object changes size.) This value can either be an absolute number if pivotXType is ABSOLUTE, or a percentage (where 1.0 is 100%) otherwise.
pivotYType Specifies how pivotYValue should be interpreted. One of Animation.ABSOLUTE, Animation.RELATIVE_TO_SELF, or Animation.RELATIVE_TO_PARENT.
pivotYValue The Y coordinate of the point about which the object is being scaled, specified as an absolute number where 0 is the top edge. (This point remains fixed while the object changes size.) This value can either be an absolute number if pivotYType is ABSOLUTE, or a percentage (where 1.0 is 100%) otherwise.



4개의 애니메이션을 구현하기 위해 따로 코딩을 하지 않고 그냥 안드로이드 API 에서 해당 클래스를 불러다 쓰는 군요.

제가 원하는 flipping 효과를 낼 수 있을 지 어떨지 잘 모르겠네요.


다음 글에서 실제 자바 코드를 분석해 보고 어떻게 실행되는지도 살펴 보겠습니다.

그리고 실제 코드를 이것 저것 수정해서 어떤 효과들을 낼 수 있는지도 추가적으로 알아보겠습니다.


반응형


반응형

오늘도 Do it 안드로이드 프로그래밍에서 제공하는 예제로 공부를 했습니다.


예제소스는 http://android-town.org/ 로 가면 무료로 제공하고 있으니 필요하신 분들은 받으셔서 보셔도 됩니다.

동영상강좌는 http://www.youtube.com/user/easyspub 에서 제공되고 있습니다.

책을 직접 구입하셔서 보시면 훨씬 더 도움이 될 것 같네요.


이 예제 중 book3 에 있는 SamplePageSliding 을 공부했는데요.

지금 하고 있는 일과 관련해서 화면을 하나 만들어야 되서 이 예제를 바탕으로 좀 수정을 했습니다.


이 예제는 Android 의 Animation 기능을 이용해서 버튼을 누르면 오른쪽에 메뉴화면이 뜨고 또 버튼을 누르면 이 메뉴화면이 부드럽게 사라지는 효과를 주었습니다.


저는 이 메뉴를 오른쪽으로 옮기고 버튼을 없애는 대신 두 손가락으로 sliding을 할 경우 왼쪽에서 메뉴가 부드럽게 나타났다고 다시 두 손가락으로 sliding 하면 부드럽게 사라지는 기능을 만들었습니다.


우선 Layout xml 을 볼께요.


activity_main.xml


<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:background="#ffffffff">
        <TextView 
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="26px"
            android:text="AAA Bank Check - 9513   Available balance $2,354.32"
            android:textColor="#000000"
            android:layout_marginLeft="350dp"
            android:layout_marginTop="100dp"
            />
    </LinearLayout>
   
    <LinearLayout
        android:id="@+id/slidingPage01"
        android:layout_width="250dp"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:layout_gravity="left"
        android:background="#ff888888"
        android:visibility="gone">
        <TextView 
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:textSize="20px"
            android:text="Direct banking  $642.77 "
            android:textColor="#ff000000"
            android:layout_marginLeft="10dp"
            android:layout_marginTop="10dp"
            />
        <TextView 
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:textSize="20px"
            android:text="Money Market - 3670"
            android:textColor="#ff000000"
            android:layout_marginLeft="10dp"
            android:layout_marginTop="10dp"           
            />
                                       
    </LinearLayout>
 
    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:layout_gravity="right|center_vertical"
        android:background="#00000000">
        <Button 
            android:id="@+id/openBtn01"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Open"
            android:visibility="invisible"
            />
    </LinearLayout>

</FrameLayout>



전체 화면은 FrameLayout 을 사용했습니다. Animation 기능을 구현해야 하기 때문에 이 FrameLayout 을 사용했을 겁니다.

FrameLayout 의 특징이 화면에 여러 뷰나 레이아웃을 겹쳐 놓고 한순간에 하나의 레이아웃을 보이도록 할 수 있습니다. 계속 이 레이아웃을 바꾸면 애니메이션 효과가 나올 수 있겠죠.


그 다음엔 LinearLayout 이 있고 orientation은 vertical 로 돼 있습니다.

이 LinearLayout 안에 있는 view들은 위에서 아래로 정렬이 될 겁니다.

그 아래 보니까 그냥 TextView 하나만 있네요.


일단 화면에 이 TextView가 표시 될 겁니다.


다음에 보니까 다시 LinearLayout 이 나왔습니다.

이것도 orientation이 vertical 이네요. view들이 위에서 아래로 배치가 될겁니다.

그런데 그 다음에 layout_gravity 가 left로 돼 있습니다. 이것은 기준이 왼쪽이 된다는 겁니다.

원래 소스에는 이것이 right로 돼 있었습니다.

그런데 저는 메뉴가 왼쪽에서 나오도록 하기 위해 이것을 right으로 바꿨습니다.

다음에는 TextView가 두개가 나오는데요.

이 두개는 아래 위로 배치될 겁니다.

이 두번째 LinearLayout 에 animation 효과가 적용되서 좌우로 sliding 될 겁니다.

이 LinearLayout 의 id 가 slidingPage01 이라는 것을 잘 봐 두세요.


그 다음에 LinearLayout 이 또 나오네요.

orientation은 vertical 이고 gravity 가 right|center_vertical 이네요.

이 의미는 가로로는 오른쪽으로 배치를 하는데 세로로는 가운데에 정렬한다는 뜻입니다.

이 Linear Layout 에는 Button 만 하나 있네요.

그런데 저는 이 버튼을 사용하지 않을거기 때문에 그냥 android:visibility="invisible" 로 해서 화면에서 없앴습니다.


이제 Java 파일을 볼까요?


MainActivity.java


public class MainActivity extends Activity {

    boolean isPageOpen = false;

    Animation translateLeftAnim;
    Animation translateRightAnim;

    LinearLayout slidingPage01;

    Button openBtn01;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        slidingPage01 = (LinearLayout) findViewById(R.id.slidingPage01);

        translateLeftAnim = AnimationUtils.loadAnimation(this, R.anim.translate_left);
        translateRightAnim = AnimationUtils.loadAnimation(this, R.anim.translate_right);

        SlidingPageAnimationListener animListener = new SlidingPageAnimationListener();
        translateLeftAnim.setAnimationListener(animListener);
        translateRightAnim.setAnimationListener(animListener);

        openBtn01 = (Button) findViewById(R.id.openBtn01);
        openBtn01.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                if (isPageOpen) {
                    slidingPage01.startAnimation(translateRightAnim);
                } else {
                    slidingPage01.setVisibility(View.VISIBLE);
                    slidingPage01.startAnimation(translateLeftAnim);
                }
            }
        });

    }

    private class SlidingPageAnimationListener implements AnimationListener {
        public void onAnimationEnd(Animation animation) {
            if (isPageOpen) {
                slidingPage01.setVisibility(View.INVISIBLE);

                openBtn01.setText("Open");
                isPageOpen = false;
            } else {
                openBtn01.setText("Close");
                isPageOpen = true;
            }
        }

        public void onAnimationRepeat(Animation animation) {
        }

        public void onAnimationStart(Animation animation) {
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }
   
    public boolean onTouchEvent(MotionEvent event) {
        if(event.getPointerCount() > 2) {
            return false;
        }
        else if (event.getPointerCount() == 2) {
        int action = event.getAction();
        float downX = 0;
        float upX = 0;

       
        int pureaction = action & MotionEvent.ACTION_MASK;
        if (isPageOpen) {
            slidingPage01.startAnimation(translateRightAnim);
        } else {
            slidingPage01.setVisibility(View.VISIBLE);
            slidingPage01.startAnimation(translateLeftAnim);
        }
      }
      return true;
    }
}



우선 onCreate() 메소드 부터 보겠습니다.

layout xml 로 activity_main 을 세팅했죠.

그 다음에 한 것이 sliding 효과를 줄 LinearLayout 객체에 넣은 겁니다.

아까 봤던 두번째 LinearLayout 인 slidingPage01 을요.


다음엔 animation 효과를 객체에 담은 건데요.

translate_left와 translate_right는 res의 amin 이라는 폴더안에 xml 형태로 있습니다.


translate_left.xml


<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/accelerate_decelerate_interpolator"
    >
    <translate
        android:fromXDelta="-20%p"
        android:toXDelta="0%p"
        android:duration="500"
        android:repeatCount="0"
        android:fillAfter="true"
        />
</set>


translate_right.xml


<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/accelerate_decelerate_interpolator"
    >
    <translate
        android:fromXDelta="0%p"
        android:toXDelta="-20%p"
        android:duration="500"
        android:repeatCount="0"
        android:fillAfter="false"
        />
</set>


저는 메뉴가 좌측에서 나오도록 하기 위해서 from, toXDelta 값들을 바꿨습니다.

애니메이션의 시작점과 끝점을 가리키는 겁니다.


그 다음에는 SlidingPageAnimationListener 의 객체를 만들어서 방금 만들었던 Animation에 이 리스너를 set 해 넣습니다.


그리고 Button 을 만들어서 이 버튼을 클릭하면 좌측 화면이 사라졌다가 나타났다가 하는 동작을 하도록 코딩을 해 줍니다.


사실 이 부분은 원본 소스에서 사용되는 부분이구요.

저는 버튼클릭은 없애고 대신 두손가락으로 sliding 하는 이벤트를 Listening 하다가 그에 반응하는 기능을 넣고 싶었거든요.


그래서 onTouchEvent() 메소드를 구현한 겁니다.


이 메소드를 보죠.


public boolean onTouchEvent(MotionEvent event) {
        if(event.getPointerCount() > 2) {
            return false;
        }
        else if (event.getPointerCount() == 2) {
        int action = event.getAction();
        float downX = 0;
        float upX = 0;

       
        int pureaction = action & MotionEvent.ACTION_MASK;
        if (isPageOpen) {
            slidingPage01.startAnimation(translateRightAnim);
        } else {
            slidingPage01.setVisibility(View.VISIBLE);
            slidingPage01.startAnimation(translateLeftAnim);
        }
      }
      return true;
    }


화면에서 일어나는 이벤트를 감지해서 어떤 동작을 하고 싶으면 이 메소드를 구현하면 됩니다.


getPointerCount()는 화면에 닿은 손가락 갯수를 받는 거구요.

화면에 2개의 손가락이 닿았을 공우 isPageOpen 이 true 이면 translateRightAmin 이 실행되고 false 이면 translateLeftAnim 이 실행 되도록 만든 겁니다.


원본 샘플 파일을 받아서 실행해 보시고 위에서 제가 바꾼 것들을 따라서 바꿔가면서 결과를 단계별로 확인하시면 쉽게 이해하실 수 있을 겁니다.


그리고 이 두 소스를 기반으로 본인이 구현하고 싶은 기능을 나름대로 생각해서 구현하면 공부하는데 훨씬 도움이 될 겁니다.



반응형


반응형

그럼 구체적으로 sliding 되는 화면들은 어떤 구성을 갖게 될지 PersonPage.java를 분석하면서 공부해 보도록 하겠습니다.

일단 화면 구성을 할 layout xml 을 보도록 하죠.
슬라이딩으로 넘어갈 화면들은 여기서 정한 Layout 을 사용할 겁니다.





person_page.xml



<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
    <TextView
        android:id="@+id/nameText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="30dp"
        />
    <Button
        android:id="@+id/callButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="20dp"
        android:text="전화걸기"
        android:focusable="false"
        />
    <ImageView
        android:id="@+id/iconImage"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />
</LinearLayout>



일단 전체 구조는 LinearLayout 으로 잡아놨고 그 안에 TextView, Button, ImageView를 배치 했습니다.

그러면 이제 PersonPage.java를 보겠습니다.



public class PersonPage extends LinearLayout {
    Context mContext;

    TextView nameText;
    Button callButton;
    ImageView iconImage;

    public static final int CALL_NUMBER = 1001;

    public PersonPage(Context context) {
        super(context);
        init(context);
    }

    public PersonPage(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    private void init(Context context) {
        mContext = context;

        // inflate XML layout
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
        inflater.inflate(R.layout.person_page, this, true);

        iconImage = (ImageView) findViewById(R.id.iconImage);
        nameText = (TextView) findViewById(R.id.nameText);
        callButton = (Button) findViewById(R.id.callButton);
        callButton.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                String callNumber = (String) callButton.getTag();
                Toast.makeText(mContext, "전화번호 : " + callNumber, Toast.LENGTH_LONG).show();
            }
        });
    }
    public void setImage(int resId) {
        iconImage.setImageResource(resId);
    }
    public void setCallNumber(String number) {
        callButton.setTag(number);
    }
    public String getNameText() {
        return nameText.getText().toString();
    }
    public void setNameText(String nameStr) {
        nameText.setText(nameStr);
    }
}



먼저 선언된 인스턴스들을 보면 Context, TextView, Button, ImageView 이런 것들이 있네요.
Context는 당연한거고 나머지는 Layout xml에서 선언된 view들인데요. 이걸 불러내서 이런 저런 처리를 하려고 하나 봅니다.
그 다음에 CALL_NUMBER라는 int 형이 final 로 1001이란 값을 받았네요.
이건 왜 이런지 소스를 보면서 알아가 보도록 하겠습니다.

일단 생성자인 PersonPage() 메소드에서는 init()메소드를 call 하고 있습니다.
그러니까 가장 먼저 init() 메소드가 실행이 될 겁니다.

init() 메소드에서는 다시 inflater 가 나오네요. 이것은 xml 문서의 리소스들을 받아 객체로 만들어 줘서 control할 수 있도록 만들어 주는 놈 입니다.
inflater 에 person_page.xml 을 세팅했습니다.

그러면 이제 person_page.xml 파일 안에 있는 리소스들에 대한 객체를 만들 수가 있는데요.
처음에 선언했던 객체를 사용해서 iconImage, nameText, callButton 에 대한 객체를 만들었습니다.
그리고 그 다음에는 callButton 에 onClickListener를 세팅해서 이 버튼이 눌려지면 전화면호가 화면에 표시되도록 (Toast) 만들어 놨군요.

그 다음에 나오는 메소드들은 setter와 getter 메소드들 입니다.
바로 MainActivity 에서 배열에 있는 이름, 전화번호, 이미지 파일들을 이 setter들을 사용해서 세팅을 했었죠?

PersonPage.java 에서는 MainActivity.java에서 받은 내용을 가지고 person_page.xml에 정의된 Layout 에 그 내용들을 넣고 그 view들에게 리스너등을 넣어서 어떤 이벤트 등에 반응 할 수 있도록 하는 클래스 입니다.
MainActivity 는 ViewPager를 사용할 수 있도록 세팅하고 각 페이지에 들어갈 내용들을 PersonPage에 보내서 페이지를 구성할 수 있도록 하고 있구요.


여기까지 ViewPager에 대해 알아 봤습니다.



반응형


반응형

이번에 POC 작업을 하면서 좀 자세히 알아야 되겠다라고 생각한게 ViewPager 기능입니다.
슬라이드 형식으로 좌우로 페이지를 넘기는 건데요.
ViewFlipper가 미리 여러개의 페이지를 ViewFlipper 에 넣은 다음에 페이지 넘김 효과를 주는 것처럼 이 ViewPager도 여러개의 페이지를 ViewPager에 넣어서 페이지 넘김 효과를 줍니다.


다른점은 ViewFlipper는 안드로이드에서 기본적으로 제공하는 API 이고 ViewPager는 기본 API 에 속하지 않은 부속 기능이라서 해당 jar 파일을 이클립스에 plug-in 한 다음에 사용한다는 겁니다.


Java Build Path - Libraries - android-support-v4.jar 등록

그리고 예제를 봤더니 ViewFlipper는 animation xml을 통해서 여러 페이지 넘김 효과를 주는 데 반해 ViewPager는 슬라이드 효과만 주고 있네요.
ViewFlipper가 더 많은 기능을 가지고 있는거 같긴한데.. 


그래도 일단 ViewPager에 대해서 한번 분석해 들어가 보겠습니다.


예제소스는 http://android-town.org/ 로 가면 무료로 제공하고 있으니 필요하신 분들은 받으셔서 보셔도 됩니다.

동영상강좌는 http://www.youtube.com/user/easyspub 에서 제공되고 있습니다.

책을 직접 구입하셔서 보시면 훨씬 더 도움이 될 것 같네요.




ViewPager

안드로이드 개발자 사이트에 소개된 ViewPager 관련 설명은 아래와 같습니다.

안드로이드 Developer 사이트 (API)
   
유저가 페이지를 오른쪽 왼쪽으로 flip 하도록 해 주는 Layout manager. 보여질 view를 generate 하기 위해 PagerAdapter를 import 해 사용해야 한다.
현재 버전은 초기 버전이고 이 후 업데이트에서는 새로운 버전에 맞게 변화가 있게 될 것이다.
viewPager는 Fragment 와 같이 어우러져서 사용된다. 이 Fragment는 각 페이지의 lifecycle을 관리하기 편리하도록 돼 있다.
ViewPager 와 함께 fragment들을 사용하기 위해 standard adapter들이 implement 돼 있다.
FragmentPagerAdaper와 FragmentStatePagerAdapter 클래스들은 full user interface를 아주 간단하게 만들 수 있도록 도와 준다.

그리고 아래 예제를 다룰 때도 설명이 될 텐데요.
ViewPager와 같이 사용되야 할 PagerAdapter 의 주요 메소드를 간단히 살펴 보겠습니다.
   
PagerAdapter API

getCount() : 현재 PagerAdapter 에서 관리할 갯수
instantiateItem() : ViewPager에서 사용할 뷰객체 생성 및 등록
destroyItem() : View 객체를 삭제 한다.
isViewFromObject() :instantiateItem 메소드에서 생성한 객체를 이용할 것인지 여부를 반환한다.
restoreState() : saveState() 상태에서 저장했던 Adapter와 page를 복구한다.
saveState() : 현재 UI 상태를 저장하기 위해 Adapter와 Page 관련 인스턴스 상태를 저장한다.
startUpdate() : 페이지 변경이 시작될 때 호출 된다.
finishUpdate() : 페이지 변경이 완료 됐을 때 호출 된다.


이제 Do it 안드로이드 앱 프로그래밍 책에서 제공하는 SampleViewPager라는 소스를 분석해 보도록 하겠습니다.
먼저 layout xml 파일 부터 분석하겠습니다.

activity_main.xml


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="ViewPager 사용하기"
        />

    <android.support.v4.view.ViewPager
        android:id="@+id/pager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#ffffffff"
        />
</LinearLayout>



앱을 시작하면 화면을 구성할 첫번째 Layout xml 파일 입니다.
LinearLayout 으로 전체 구성을 잡았고 그 안에 TextView와 ViewPager 를 넣었습니다.
TextView는 좌우로는 화면을 꽉 채우고 높이는 내용만큼만 자리를 차지하도록 했네요.
그 이하 공간은 모두 ViewPager 가 차지할 겁니다.
아마 ViewPager 사용하기라는 글자는 그대로 있으면서 그 아래 ViewPager 공간만 slide 될 것 같습니다.

다음은 자바 파일을 보죠.



public class MainActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // get a ViewPager reference and set adapter for it
        ViewPager pager = (ViewPager) findViewById(R.id.pager);
        ViewPagerAdapter adapter = new ViewPagerAdapter(this);
        pager.setAdapter(adapter);
    }

    public class ViewPagerAdapter extends PagerAdapter {
        // sample names
        private String[] names = { "John", "Mike", "Sean" };
        // sample image resource ids
        private int[] resIds = {R.drawable.dream01, R.drawable.dream02, R.drawable.dream03};
        // sample call numbers
        private String[] callNumbers = {"010-7777-1234", "010-7788-1234", "010-7799-1234"};

        /**
         * Context
         */
        private Context mContext;

        /**
         * Initialize
         *
         * @param context
         */
        public ViewPagerAdapter( Context context ) {
            mContext = context;
        }
        /**
         * Count of pages
         */
        public int getCount() {
            return names.length;
        }
        /**
         * Called before a page is created
         */
        public Object instantiateItem(View pager, int position) {
            // create a instance of the page and set data
            PersonPage page = new PersonPage(mContext);
            page.setNameText(names[position]);
            page.setImage(resIds[position]);
            page.setCallNumber(callNumbers[position]);

            // add to the ViewPager
            ViewPager curPager = (ViewPager) pager;
            curPager.addView(page, position);

            return page;
        }

        /**
         * Called to remove the page
         */
        public void destroyItem(View pager, int position, Object view) {
            ((ViewPager)pager).removeView((PersonPage)view);
        }
        public boolean isViewFromObject(View view, Object object) {
            return view.equals(object);
        }
        public void finishUpdate( View view ) {
        }
        public void restoreState( Parcelable p, ClassLoader c ) {
        }
        public Parcelable saveState() {
            return null;
        }
        public void startUpdate( View view ) {
        }
    }
}


위 이미지는 여기에서 다운 받은 이미지 입니다.


제 Laptop 에 영문 윈도우가 깔려 있어서 한글이 깨지네요.
그래서 한글로 된 주석은 지웠습니다. 이전 글에 있는 링크에서 소스파일을 다운 받아 보시면 한글 주석을 보실 수 있을 겁니다.

우선 맨 먼저 실행될 onCreate() 메소드를 보겠습니다.
activity_main.xml 을 layout을 구성하는 xml로 사용하겠다고 세팅한 라인이 있구요.
바로 그 밑에 ViewPager의 instance를 만들고 거기에 activity_main.xml 에 선언한 id가 pager 인 ViewPager를 대입했습니다.
그리고 ViewPagerAdapter 에 대한 인스턴스도 만들어서 방금전 만들었던 ViewPager 에 이 adapter를 세팅했습니다.

이 ViewPagerAdapter 는 어디서 왔을 까요? 안드로이드에서 제공하는 함수는 아니고 개발자가 만든 클래스 입니다.
바로 아래에 그 클래스가 있습니다.

ViewPagerAdater 클래스는 PagerAdapter를 extends 하네요.
이 PagerAdapter 는 안드로이드에서 제공하는 API 입니다.

이 PagerAdapter에 대해 안드로이드 개발자 페이지 (API) 에서는 아래와 같이 설명했네요.


ViewPager안에 페이지들을 생성하기 위해 Base Class 는 이 adapter를 제공한다. 이것과 관련해 좀 더 특정 implementation을 사용하고 싶어 할 것이다.
예를 들어 FragmentPagerAdapter 나 FragmentStatePagerAdapter 같은....

PagerAdapter를 implement 하면 최소한 다음과 같은 메소드들을 override 해야 한다.



그 다음에도 계속 설명이 나오는데요.
너무 길고.. 나중에 필요하면 따로 정리를 해야겠습니다.

일단 이 PagerAdapter에는 ViewPager에서 사용할 페이지들이 들어가는군요.
이 예제에서는 이 PagerAdapter를 extends 한 ViewPagerAdapter인 클래스를 만들었구요. 여기다가 보일 페이지들을 넣을건가 봅니다.

그러면 이 ViewPagerAdapter 클래스를 살펴 보겠습니다.

처음에는 names, resIds, callNumbers라고 하는 배열들을 만들었습니다.
names에는 사람 이름이 그리고 resIds에는 이미지 resource들이 마지막으로 callNumbers 에는 전화번호들이 들어가는군요.

그 다음에는 Context를 초기화 했습니다.

다음 생성자에서는 Context를 파라미터로 받아서 mContext에 대입했네요.
이 클래스가 호출이 되면 가장 먼저 이 생성자가 실행이 될 겁니다.
그러니까 가장 먼저 일단 context를 세팅한다는 얘기죠.

이 Context는 어플리케이션이 실행되기 위해 기본적으로 필요한 정보나 환경들에 대한 내용인데 안드로이드에서 제공하는 겁니다.
getSystemService() 메소드를 통해서 여러 많은 정보들을 가져다 쓸 수도 있죠.
그리고 Activity가 이 Context를 상속 받았습니다.
그러니까 Activity 를 상속받은 클래스에서는 이 Context를 그냥 this 라는 구문으로 사용할 수 있는 겁니다.
하지만 Activity 가 아닌 다른 Context를 상속받지 않은 클래스에서는 this 라는 것으로 Context를 사용하도록 할 수 없겠죠.
제 기억엔 별도로 만든 클래스에서  Intent 나 뭐 이런걸로 Page 전환 할 때 문제가 발생할 수 있습니다.
모르면 당황할 텐데요. 그냥 View의 객체가 있으면 그 View의 getContext() 를 사용해서 처리하시면 됩니다.
혹은 getApplicationContext() 를 사용하셔도 되구요.
저는 대부분 getApplicationContext()를 사용했던 것 같습니다.

그 다음에는 위에서 설명했던 PagerAdapter API 에 있던 메소드들이 있네요.
getCount() 메소드에는 페이지 수가 들어간다는데 이 예제에서는 names 배열내의 아이템 갯수가 페이지 수가 되도록 했습니다.

그 다음 메소드가 ViewPager에서 사용할 View 객체를 생성하고 등록한다는 instantiateItem() 메소드 입니다.

이 메소드는 View 와 int 형의 position을 파라미터로 받습니다.
그 내용은 우선 PersonPage라는 클래스의 인스턴스를 만드네요. 여기에 mContext를 파라미터로 던지구요.
이 PersonPage는 안드로이드에서 제공하는 API 클래스가 아니니까 아마 개발자가 따로 만들었을 겁니다.
나중에 그 클래스도 분석해 보게 되겠네요.
일단 뭔지는 모르지만 PersonPage의 인스턴스를 만들었고 여기에 names와 resIds와 callNumbers 에 있는 아이템들을 세팅합니다.
보니까 PersonPage 클래스에는 setNameText(), setImage(), setCallNumber() 라는 메소드들이 작성 돼 있나 봅니다.

그 다음에는 ViewPager의 인스턴스를 만들고 이 ViewPager에 이 PersonPage (page)와 position (페이지 번호)를 add 해 줍니다.
그러면 ViewPager에는 해당 페이지의 name과 image와 callNumber들이 들어있을 테고 즉 화면에 그게 display 되겠네요.




다음은 view 객체를 삭제하는 destroyItem() 메소드가 있습니다.
View와 int 형으로 페이지번호와 Object 를 파라미터로 봤습니다.
그리고 그 내용은 해당 view를 remove 합니다.
그 다음 finishUpdate(), restoreState(),startUpdate() 는 모두 내용이 없는 껍데기 메소드들이구요.
즉 다른 특별한 코딩을 하지 않아서 어떤 기능 추가나 변경 없이 그냥 override 만 했을 뿐이네요.
saveState() 메소드에서도 그냥 null을 반환할 뿐입니다.

이렇게 되면 MainActivity.java는 모두 분석했습니다.

ViewPager 를 사용하도록 레이아웃 xml 과 onCreate() 에서 선언을 해주고 ViewPager의 페이지들은 ViewPagerAdapter 클래스에서 만들었습니다.
이 ViewPagerAdapter에는 각 화면들에 들어갈 내용들을 배열에 넣었구요.
그 화면들을 어떻게 구성할 것인지는 PersonPage라는 클래스를 외부에 따로 만들어서 사용하고 있습니다.

반응형


반응형

    지난 글에서 display 하는 것은 모두 완료 됐습니다.
   
    이제 볼 것은 뭘까요?
    아까 ViewFlipper에 touch 리스너를 달았습니다.
   


    그러면 ViewFlipper에 어떤 touch 이벤트가 발생했을 때 다른 동작을 할 수 있도록 코딩을 할 수 있는데요.
    바로 그 코딩을 하는 onTouch() 메소드를 분석해 봐야 할 차례입니다.
   


        public boolean onTouch(View v, MotionEvent event) {
        if(v != flipper) return false;

        if(event.getAction() == MotionEvent.ACTION_DOWN) {
            downX = event.getX();
        }
        else if(event.getAction() == MotionEvent.ACTION_UP){
            upX = event.getX();

            if( upX < downX ) {  // in case of right direction
 
                flipper.setInAnimation(AnimationUtils.loadAnimation(getContext(),
                        R.anim.wallpaper_open_enter));
                flipper.setOutAnimation(AnimationUtils.loadAnimation(getContext(),
                        R.anim.wallpaper_open_exit));

                if (currentIndex < (countIndexes-1)) {
                    flipper.showNext();

                    // update index buttons
                    currentIndex++;
                    updateIndexes();
                }
            } else if (upX > downX){ // in case of left direction

                flipper.setInAnimation(AnimationUtils.loadAnimation(getContext(),
                        R.anim.push_right_in));
                flipper.setOutAnimation(AnimationUtils.loadAnimation(getContext(),
                        R.anim.push_right_out));

                if (currentIndex > 0) {
                    flipper.showPrevious();

                    // update index buttons
                    currentIndex--;
                    updateIndexes();
                }
            }
        }
        return true;
    }
   


    이 메소드는 View 와 MotionEvent를 파라미터로 받습니다.
    첫번째 줄에는 전달 받은 View 가 flipper 가 아니면 false를 return 하라고 돼 있네요.
    여기서 다루는 view 는 flipper 이니까 이 라인은 건너 뛰고 다음 라인이 실행 될 겁니다.
   
    다음 if 문을 보면 해당 Action 이 Down 일 경우 downX에 touch 점의 x 좌표를 대입합니다.
    다음 else if 문은 action 이 up 인 경우 입니다.
   
    우선 upX에 현재의 x 좌표를 대입시키구요.
    upX 가 downX 보다 작으면 그러니까 사용자가 오른쪽으로 손가락을 slide 할 경우가 되겠네요.
    그런 경우 flipper에 세팅하는 애니메이션을 wallPaper_open_enter 를 선택합니다.
    이 애니메이션은 res 폴더 밑의 anim 폴더 밑에 xml 형태로 저장돼 있습니다. 그 내용은 아래와 같습니다.
   


    <?xml version="1.0" encoding="utf-8"?>
    <set xmlns:android="http://schemas.android.com/apk/res/android"
        android:interpolator="@anim/decelerate_interpolator"
        android:detachWallpaper="true">
    <scale android:fromXScale="2.0" android:toXScale="1.0"
           android:fromYScale="2.0" android:toYScale="1.0"
           android:pivotX="50%p" android:pivotY="50%p"
           android:duration="@android:integer/config_mediumAnimTime" />
    </set>



    일단 Scale이 2.0에서 1.0 바뀌네요. X,Y 모두 다요.
    그 다음엔 pivotX와 pivotY 가 각각 50%p 의 값을 가집니다.
    그리고 duration은 android의 config.xml에 정의 된 config_mediumAnimTime 를 가져옵니다.
    그 값은 400 이구요. 주석을 보면 medium-length animation을 위한 값(milliseconds)라고 돼 있네요.
    pivot은 회전축이라는 뜻으로 애니메이션 효과에 사용됩니다. 여기서는 flip 효과에 사용되나 보네요.
   
    다시 자바로 돌아가면 그 다음에는 wallpaper_open_exit 애니메이션이 실행되네요.
   


    <set xmlns:android="http://schemas.android.com/apk/res/android"
        android:interpolator="@anim/decelerate_interpolator"
        android:zAdjustment="top">
    <scale android:fromXScale="1.0" android:toXScale=".5"
           android:fromYScale="1.0" android:toYScale=".5"
           android:pivotX="50%p" android:pivotY="50%p"
           android:duration="@android:integer/config_mediumAnimTime" />
    <alpha android:fromAlpha="1.0" android:toAlpha="0"
            android:duration="@android:integer/config_mediumAnimTime"/>
    </set>



    여기엔 alpha 값도 설정이 됐군요. 선명한 상태에서 완전 투명해 져서 안보이는 상태로 갑니다.
   
    그리고 나서 currnetIndex 가 currentIndexes-1 보다 적을 경우 는 flipper에 있는 next 를 보여 줍니다.
    그리고 currntIndex 에 1을 더해주고 updateIndexes()를 호출 합니다.
   
    그럼 updateIndexes() 를 보죠.
   


    private void updateIndexes() {
        for(int i = 0; i < countIndexes; i++) {
            if (i == currentIndex) {
                indexButtons[i].setImageResource(R.drawable.green);
            } else {
                indexButtons[i].setImageResource(R.drawable.white);
            }
        }
    }



    countIdexes (3) 만큼 for 문을 돌리구요. i 가 currentIndex 일 경우 indexButtons 의 리소스 이미지를 바꿔 줍니다.
    즉 현재 내용이 몇번째인지 그것을 알아내서 해당 버튼 이미지도 녹색으로 바꾸고 나머지는 흰색으로 보여지게 하는 부분 입니다.
   
    다시 onTouch() 메소드의 다음 부분을 이어서 보면요.
   
    else if (upX > downX) 일 경우 이 경우는 왼쪽방향일 경우라고 주석에 쓰여져 있네요.
    이럴 경우 애니메이션으로 push_right_in.xml와 push_right_out 을 실행 하라고 돼 있습니다.
   
    push_right_in.xml
   

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate android:fromXDelta="-100%p" android:toXDelta="0%p" android:duration="300"/>
    <alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="300" />
</set>

    push_right_out
    <?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate android:fromXDelta="0%p" android:toXDelta="100%p" android:duration="300"/>
    <alpha android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="300" />
</set>



    그리고 currentIndex가 0 보다 크면 flipper의 이전 내용을 보여 줍니다.
    currentIndex에는 -1을 해 주고요.
    그 다음에 updateIndexes() 메소드를 실행해서 이미지 버튼의 색을 바꿔주고요.
   
   
    여기까지가 viewFlipper 예제에 대한 분석이었습니다.

반응형


반응형

이제 실제 메소드들을 보면서 분석해 보겠습니다.
일단 제일 먼저 실행 될 것 같은 init() 메소드를 보죠. 주석에도 Initialize (초기화)라고 돼 있으니까 왠지 이게 제일 먼저 실행 될 것 같네요.
(오버로딩 된 ScreenViewFlipper 메소드를 봐도 이 init() 메소드를 불러오는 것 만 있습니다.)


이 그림은 viewFlipper를 잘 보여주는 것 같아 구글에서 갖다 썼습니다.

이 화면에 대한 소스나 설명은 여기로 가시면 보실 수 있습니다.



    public void init(Context context) {
        setBackgroundColor(0xffbfbfbf);

        // Layout inflation
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        inflater.inflate(R.layout.screenview, this, true);

        buttonLayout = (LinearLayout) findViewById(R.id.buttonLayout);
        flipper = (ViewFlipper) findViewById(R.id.flipper);
        flipper.setOnTouchListener(this);

        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
                LinearLayout.LayoutParams.WRAP_CONTENT,
                LinearLayout.LayoutParams.WRAP_CONTENT);
        params.leftMargin = 50;

        indexButtons = new ImageView[countIndexes];
        views = new TextView[countIndexes];
        for(int i = 0; i < countIndexes; i++) {
            indexButtons[i] = new ImageView(context);

            if (i == currentIndex) {
                indexButtons[i].setImageResource(R.drawable.green);
            } else {
                indexButtons[i].setImageResource(R.drawable.white);
            }

            indexButtons[i].setPadding(10, 10, 10, 10);
            buttonLayout.addView(indexButtons[i], params);

            TextView curView = new TextView(context);
            curView.setText("View #" + i);
            curView.setTextColor(Color.RED);
            curView.setTextSize(32);
            views[i] = curView;

            flipper.addView(views[i]);
        }
    }



    우선 화면의 배경색을 세팅했네요. 0xffbfbfbf 이게 무슨 색인지는 잘 모르겠습니다. 나중에 실행 시켜보면 알겠죠.
    그 다음 LayoutInflater 의 instance를 만들고 여기에 context의 SystemService 에서 layout inflater를 대입했습니다.
   
    이 LayoutInflater에 대해 google developer 사이트에서는 아래와 같이 설명해 놓았습니다.
    layout XML 파일을 해당하는 View object로 초기화 하는 것. getLayoutInflater()나 getSystemService(String)을 가지고 standard LayoutInflater 인스턴스를 가져옴.
    이 standard LayoutInflater 인스턴스는 현재의 context에 이미 있고 디바이스에 맞게 configure 된 것들 입니다.
   
    즉 XML에서 선언된 어떤 view를 가져와서 그 위에 object들을 배열할 때 사용되는가 봅니다.
   
    그 아래 줄을 보시면 이 inflater에 아까 봤던 screenview.xml을 넣었습니다.
    이 xml 에는 <LinearLayout> (id=buttonLayout)과 <ViewFlipper> (id=flipper)가 들어 있었죠.
    이제 이 inflater가 이것들을 구체적으로 어떻게 사용하는지 볼까요?
   
    아까 예상했던 대로 buttonLayout 에는 screenview.xml에 있는 id가 buttonLayout 이라는 LinearLayout 을 세팅합니다.
    다음줄엔 flipper 에 id가 flipper 인 ViewFlipper를 세팅하구요. 이 flipper에는 touchListener를 세팅합니다.
   
    예상컨데 이 buttonLayout에는 button들 (3개로 선언했었죠?)이 배치되겠고 flipper에는 표시될 screen들이 들어가겠네요.
    이 screen을 손가락으로 touch(slide) 하면 화면이 바뀌겠구요.
   
    이것을 구체적으로 어떻게 코딩하는지 계속 알아 보겠습니다.



   
    LinearLayout.LayoutParams 인스턴스를 만들고 여기에 이 view에 대한 width와 height 가 Wrap_content 인 LayoutParams를 대입시킵니다.
    그리고 이 params 에 leftMargin을 50으로 세팅하구요.
   
    이 값은 나중에 아까 선언했던 buttonLayout 에 적용이 되겠죠.
   
    다음에는 indexButtons에 new ImageView[countIndexes]를 대입합니다. countIndexes는 제일 처음에 3으로 선언했었죠?
   
    그리고나서 이 countIndexes 만큼 for문을 돌립니다.
    그 for문을 돌고 나면 3개의 ImageView 가 만들어 질 거고 이 이미지 뷰들은 indexButtons 배열에 담길겁니다.
    만약 i가 0이면 즉 제일 첫번째 것이면 그 ImageView에는 green.png 가 대입 되겠고 그렇지 않으면 white.png가 대입이 될 겁니다.
    그러니까 첫번째는 초록색 버튼이 되고 나머지 두 버튼은 흰색이 되겠네요.
    이 ImageView에 padding 값을 주고 buttonLayout에 지금까지 세팅한 ImageView(indexButtons)를 넣습니다.
    buttonLayout.addView(indexButtons[i], params);
    보시면 params 도 pass 하죠? 이 params는 아까 leftMargin을 50으로 세팅한 겁니다.
   
    그 다음엔 TextView 를 하나 만드네요.
    이 텍스트 뷰에는 View # = i 라는 텍스트가 있고 색은 빨간색이고 size는 32 라고 세팅이 돼 있습니다.
    이 값을 views 배열에 넣는데요.
   
    저 for 문 바로 위에 보니까 vews 라는 TextView 배열이 선언돼 있네요. 배열 크기도 countIndexes 즉 3개로 선언돼 있구요.
    이 부분을 보지 못하고 그냥 넘어갔네요.
   
    이 text를 가진 views 배열을 flipper에 넣는 것이 이 for 문의 마지막이자 이 init메소드의 마지막 입니다.
   
    자 여기까지가 바로 screenview.xml에서 그냥 내용 없이 선언된 LinearLayout 과 ViewFlipper에 내용을 채워 넣은 겁니다.
    LinearLayout 에는 세개의 버튼이 놓여지게 되고 버튼 색은 녹색, 흰색, 흰색이 세팅됐습니다.
    그리고 ViewFlipper 에도 3개의 내용이 들어가 있는데 View #1, View #2, View #3 이라는 텍스트가 있습니다.
    그 텍스트들은 빨간색이고 크기가 32입니다.
   
    이제 display 하는 것은 모두 완료 됐습니다.
   
    이제 볼 것은 뭘까요?
    아까 ViewFlipper에 touch 리스너를 달았습니다.
   
    그러면 ViewFlipper에 어떤 touch 이벤트가 발생했을 때 다른 동작을 할 수 있도록 코딩을 할 수 있는데요.
    바로 그 코딩을 하는 onTouch() 메소드를 분석해 봐야 할 차례입니다.

반응형


반응형

지난 월요일 화요일 이틀동안 POC (Proof of Concept)용으로 안드로이드 Native App 을 하나 개발 했습니다.

Native App 은 거의 2년만에 개발하는 것 같은데..

이번에 새로운 개념들도 여러개 배웠습니다.

그 내용들을 정리해 볼까 하는데요.


오늘은 그 중에 ViewFlipper 에 대해 정리해 보겠습니다.


공부하는 방법은 제가 Do It 안드로이드 앱 프로그래밍이라는 책에서 제공하는 동영상을 보고 개념도 다시 잡고 거기서 제공하는 소스를 다운받아서 보기도 하고 했는데요.


그 책에서 제공하는 viewFlipper 관련 예제 소스를 자세히 분석하면서 공부를 하겠습니다.


예제소스는 http://android-town.org/ 로 가면 무료로 제공하고 있으니 필요하신 분들은 받으셔서 보셔도 됩니다.

동영상강좌는 http://www.youtube.com/user/easyspub 에서 제공되고 있습니다.

책을 직접 구입하셔서 보시면 훨씬 더 도움이 될 것 같네요.


그럼 그 책에서 제공하고 있는 SampleViewFlipper 를 보겠습니다.


우선 첫번째 실행되는 layout xml을 보겠습니다.


activity_main.xml


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <org.androidtown.ui.flipper.ScreenViewFlipper
        android:id="@+id/screen"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_margin="10dp" />
</RelativeLayout>


Launcher Activity 의 Layout xml 은 위와 같이 돼 있습니다.
이 RelitiveLayout 의 대상 공간은 화면 전체이구요.
RelativeLayout 으로 세팅하고 그 내부에는 ScreenViewFlipper 클래스를 import 하는 태그만 있습니다.
이 flipper의 id 는 screen 이고 margin 10dp 로 한채로 대상 공간이 그 parent 인 RelativeLayout 을 꽉 채웁니다.


이클립스에 있는 Graphical Layout 을 통해 보면 아래와 같은 화면이 나옵니다.




이제 JAVA 소스코드를 봐야겠네요.


public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }
}


바로 이 MainActivity 가 첫번째 화면인데요. onCreate() 메소드내에 위에서 본 activity_main.xml 을 Content View로 세팅을 했습니다.
그게 다 입니다.

밑에 있는 onCreateOptionMenu() 메소드는 override 한 것인데 안드로이드 디바이스 밑의 menu 버튼을 누르면 나오는 메뉴들을 세팅하는 메소드 입니다.
실제 이 앱과는 관련이 없으니까 무시하셔도 됩니다.

결국은 앱을 실행하는 첫번째 Activity에는 아무론 것도 화면에 표시를 하지 않네요.
이제 activity_main.xml에서 import한 ScreenViewFlipper.java 를 봐야겠습니다.




그럼 우선 이 ScreenViewFlipper에서 사용하는 layout 파일인 screenview.xml을 보겠습니다.


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >
    <LinearLayout
        android:id="@+id/buttonLayout" 
        android:orientation="horizontal"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        >
    </LinearLayout>   
    <ViewFlipper
        android:id="@+id/flipper" 
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        >   
    </ViewFlipper>
</LinearLayout>


일단 LinearLayout 을 사용했습니다. width와 height가 match_parant니까 위의 xml 파일에서 세팅된 <org.androidtown.ui.flipper.ScreenViewFlipper ...... />의 크기 만큼 그 대상 공간이 됩니다.
여기서는 계속 화면 전체가 되겠죠.

그 다음 LinearLayout 내부에 또 LinearLayout이 있습니다. 그 크기는 wrap_content 로 돼 있는데 그것은 이 LinearLayout에 들어가는 내용의 크기 만큼 설정을 하겠다고 세팅돼 있습니다.
그런데 그 안에 아무것도 없네요. 즉 화면에 표시할 게 아무것도 없습니다. 나중에 혹시 java 파일에서 이 LinearLayout을 불러내서 다른 object를 setting 하면 그 때 화면에 뭔가가 표시 될 수는 있을 겁니다.
(id가 buttonLayout 이니까 이 id로 불러낼겁니다.)

그 아래는 <ViewFlipper> 태그가 있습니다. 여기에 오늘 공부하는 ViewFlipper를 표시할 겁니다.

여기까지 보니까 위에는 버튼이 달릴거고 (내부 LinearLayout id 가 buttonLayout인것을 가지고 아직까지는 그냥 추정해 보는 겁니다.) 그 아래에 ViewFlipper 가 달려서 페이지 전환이 이뤄질 것 같습니다.


아직까지는 이 Layout에 어떤 VIew나 Widget이 표시되지는 않습니다.




ViewFlipper에 대한 Android Developer 싸이트의 설명은 이렇습니다.
두개 이상의 View들이 add돼 있고 이 view들이 animate 될 간단한 ViewAnimator. 한번에 한 child만 보인다. 설정을 한다면 일정한 interval을 두고 각각의 child 를 자동으로 flip 되도록 할 수 있다.

flip이라는 의미가 뒤집다라는 거니까 페이지들을 child로 설정했다면 이 페이지가 뒤집히는 효과를 주면서 화면이 전환되게 할 수 있겠네요.
또 view에는 여러개가 해당 될 수 있으니까 다른 object 별로도 이런 flip 효과를 줄 수 있겠습니다.

그럼 이제 본격적인 내용이 있는 ScreenViewFlipper를 한번 분석해 보죠.



public class ScreenViewFlipper extends LinearLayout implements OnTouchListener {

    /**
     * Count of index buttons. Default is 3
     */
    public static int countIndexes = 3;

    /**
     * Button Layout
     */
    LinearLayout buttonLayout;

    /**
     * Index button images
     */
    ImageView[] indexButtons;

    /**
     * Views for the Flipper
     */
    View[] views;

    /**
     * Flipper instance
     */
    ViewFlipper flipper;

    /**
     * X coordinate for touch down
     */
    float downX;

    /**
     * X coordinate for touch up
     */
    float upX;

    /**
     * Current index
     */
    int currentIndex = 0;


    public ScreenViewFlipper(Context context) {
        super(context);
       
        init(context);
    }

    public ScreenViewFlipper(Context context, AttributeSet attrs) {
        super(context, attrs);
       
        init(context);
    }

    /**
     * Initialize
     *
     * @param context
     */
    public void init(Context context) {
        setBackgroundColor(0xffbfbfbf);

        // Layout inflation
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        inflater.inflate(R.layout.screenview, this, true);

        buttonLayout = (LinearLayout) findViewById(R.id.buttonLayout);
        flipper = (ViewFlipper) findViewById(R.id.flipper);
        flipper.setOnTouchListener(this);

        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
                LinearLayout.LayoutParams.WRAP_CONTENT,
                LinearLayout.LayoutParams.WRAP_CONTENT);
        params.leftMargin = 50;

        indexButtons = new ImageView[countIndexes];
        views = new TextView[countIndexes];
        for(int i = 0; i < countIndexes; i++) {
            indexButtons[i] = new ImageView(context);

            if (i == currentIndex) {
                indexButtons[i].setImageResource(R.drawable.green);
            } else {
                indexButtons[i].setImageResource(R.drawable.white);
            }

            indexButtons[i].setPadding(10, 10, 10, 10);
            buttonLayout.addView(indexButtons[i], params);

            TextView curView = new TextView(context);
            curView.setText("View #" + i);
            curView.setTextColor(Color.RED);
            curView.setTextSize(32);
            views[i] = curView;

            flipper.addView(views[i]);
        }
    }
   
    /**
     * Update the display of index buttons
     */
    private void updateIndexes() {
        for(int i = 0; i < countIndexes; i++) {
            if (i == currentIndex) {
                indexButtons[i].setImageResource(R.drawable.green);
            } else {
                indexButtons[i].setImageResource(R.drawable.white);
            }
        }
    }

    /**
     * onTouch event handling
     */
    public boolean onTouch(View v, MotionEvent event) {
        if(v != flipper) return false;

        if(event.getAction() == MotionEvent.ACTION_DOWN) {
            downX = event.getX();
        }
        else if(event.getAction() == MotionEvent.ACTION_UP){
            upX = event.getX();

            if( upX < downX ) {  // in case of right direction
 
                flipper.setInAnimation(AnimationUtils.loadAnimation(getContext(),
                        R.anim.wallpaper_open_enter));
                flipper.setOutAnimation(AnimationUtils.loadAnimation(getContext(),
                        R.anim.wallpaper_open_exit));

                if (currentIndex < (countIndexes-1)) {
                    flipper.showNext();

                    // update index buttons
                    currentIndex++;
                    updateIndexes();
                }
            } else if (upX > downX){ // in case of left direction

                flipper.setInAnimation(AnimationUtils.loadAnimation(getContext(),
                        R.anim.push_right_in));
                flipper.setOutAnimation(AnimationUtils.loadAnimation(getContext(),
                        R.anim.push_right_out));

                if (currentIndex > 0) {
                    flipper.showPrevious();

                    // update index buttons
                    currentIndex--;
                    updateIndexes();
                }
            }
        }
        return true;
    }
}



우선 메소드들을 선언하기 전에 나오는 object들을 선언하는 것부터 보겠습니다.
첫번째는 countIndexes=3; 인데 주석을 보니까 index 버튼들의 숫자라고 하네요. 디폴트는 3이구요.
그 다음 LinearLayout을 buttonLayout 이라는 이름으로 하나의 객체를 만들어 놨습니다.
아직 정확하게는 모르지만 이 객체에 screenview.xml 에 있었던 buttonLayout 이라는 id를 가진 LinearLayout 을 세팅할 것 같네요.
그리고 indexButtons 라는 이름으로 ImageView 배열을 선언했구요. 여기에는 위에서 3개로 선언된 index button 이미지가 세팅될것 같습니다.
그 다음에는 views라는 이름으로 View 배열이 있습니다. 주석에는 Flipper들을 위한 View들이라고 돼 있네요.
다음줄에서 ViewFlipper의 instance를 만들었습니다. 그 이름은 flipper 이구요.
그 다음은 down시 x 좌표를 받을 downX라는 이름으로 float 객체를 만들었고 up시 x 좌표를 받을 upX도 있습니다.
그리고 현재의 index는 0이라고 선언한 줄이 나옵니다. 이름은 currentIndex 이고 정수형입니다.


메소드에 대한 분석들은 다음 글에서 이어나가겠습니다.

반응형


반응형

이번 주말은 안드로이드 동영상 강좌만 들으면서 보냈습니다.

이지스퍼블리싱 출판사에서 만든 Do it 안드로이드 앱 프로그래밍이란 책을 바탕으로 제공하는 동영상 강좌 입니다.


카페 주소는 http://cafe.naver.com/easyispub/945 이고

유투브 주소는 http://www.youtube.com/watch?v=Xb9300qU52Y&list=PL5C6E85EFC6E406EF 입니다.





금요일에 안드로이드 관련 업무를 하나 받았거든요.

기존에 개발된 앱을 보여주면서 안드로이드 태블릿 버전으로 POC (Proof of Concept)를 하나 만들어 보라고요. 수요일 오전까지요.


Android Native App Programming 을 잠시 떠나 있어서 예전에 했던것을 다시 떠올리기 위해 자료를 찾다가 이 동영상 강좌를 보게 됐습니다.


1편부터 10편까지 봤습니다. 개념정리에 아주 도움이 됐습니다.

안드로이드 앱 프로그래밍에 관심 있으신 분들께 적극 추천 합니다.


한국에 있다면 당장에 저 책 사서 활용했을 텐데 여기서는 그 책을 구할 수가 없어서... ;;


거의 토요일 하루 종일 봤는데요. 아마 10시간 가까이 봤을 것 같습니다.

오늘 (일요일)에는 법륜 스님이 이 먼 미국까지 오셔서 더군다나 제가 사는 지역까지 오셔서 즉문즉설을 해 주신다고 해서 거기 갈 계획입니다.


그 즉문즉설 다녀온 다음 화요일까지 빡세게 해서 POC를 위한 안드로이드 태블릿 앱을 하나 만들겁니다.


살짝 긴장되는데 기분 좋은 긴장이네요.


아래 글은 동영강강좌 10편을 들으면서 그냥 끄적거린 메모 입니다.

나중에 다시 기억 떠올리는데 도움이 될 것 같아서 이 블로그에 정리해 둡니다.



* 안드로이드 태블릿

허니컴 부터 시작 : 안드로이드 3.0 (Level 11,12,13)
아이스크림 샌드위치부터 phone + Tablet 시작 : 안드로이드 4.0 (Level 14,15)
현재는 젤리빈 : 안드로이드 4.1,4.2,4.3 (Level 16,17,18)
차후 KitKat 예정 : 안드로이드 4.4 (Level 19)

* 기억해야 할 것들


리스너 달기 : setOnClickListener
intent
화면 전환하기 : intent(intent.ACTION_VIEW,Uri.parse("웹사이트 주소 or tel:전화번호 etc."));

layout 에 있는 객체 불러오기 : (Button) findViewById(R.id.buttonname);

* Activity 간 전환
- layout 에 xml 하나 더 만듬
- Intent myIntent = new Intent(getApplicationContext(), NewActivity.class);
- startActivity(myIntent)
- Manifest 파일에 새로운 Activity 등록
=> 이러면 NewActivity.class 액티비티가 호출 됨

* 안드로이드 버전별 주요 기능

Proyo (2.2) : Flash, SD 카드에 설치, Backup API, Push Message 지원
GengerBread (2.3) : NFC (전자 결재), front Camera, 자이로스코프 센서, Internet 전화(SIP) 지원
HoneyComb (3.0) : Tablet UI, 화면 분할, HTTP Live Streming 지원
Icecream Sandwich (4.0) : 홀로그래픽 UI 와 버추얼 키, 얼굴인식과 음성인식 텍스트 입력, NFC 빔 공유와 WiFi 다이렉트 지원

* Structure of Android Project folder
/src
/Android <version>
/res
/gen
/assets
AndroidManifest.xml
default.properties


sdk/tools/hierarchyviewer.bat - 해당 액티비티의 구조도를 볼 수 있음

* apk 만들기
Android tools - export signed application - keystore 제공 - ....

* 화면구성 - View,Layout,Widget

* Widget - fill_parent, wrap_content etc.

* Layout 종류
LinearLayout : android:orientation = vertical, horizontal
Releative Layout
Frame Layout : 여러개의 View를 중첩시킨 후 각각의 뷰에 대해 보이거나 보이지 않게 하면 뷰 전환 가능. object.setVisibility(View.)
Table Layout
Scroll View

* setContentView(R.Layout.main);

* DDMS - LogCat 로그 보기

* startActivityForResult(intent,constant)
  - 다른 액티비티에서 데이터를 받기 위해 사용. (onActivityResult())
  setResult(code,resultIntent), resultIntent.putExtra("name","john");

* parent class 의 method override 하기
  - right mouse button - source - override/Implement method - select method

* Toast.makeText(context,text,duration);

* startActivity(), startService(), bindService(), broadcastIntent()

* ACTION_DIAL tel:1111111, ACTION_VIEW tel:1111, ACTION_EDIT content://contacts/people/2, ACTION_VIEW

content://contacts/people

* Implicit Intent : Intent myIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://m.yahoo.com");
* Explicit Intent : Intent myIntent = new Intent(getApplicationContext(),NewActivity.class);

* FLAG_ACTIVITY_SINGLE_TOP, FLAG_ACTIVITY_CLEAR_TOP, FLAG_ACTIVITY_NO_HISTORY

* Parcelable : 전달하는 데이터가 선언한 객체일 경우, bundle.getParcelable();




* Shared Preference : 간단한 정보 저장했다 불러올 때 사용. Cache 같은 것 (onPause())
  SharedPreference myPref = getSharedPreferences("myPref",Activity_MODE_WORLD_WRITEABLE);
  SharedPreferences.Editor myEditor = myPref.edit();
  myEditor.putString("name","Tom");
  myEditor.commit();
* onResume()
  SharedPreferences myPref = getSharedPreference("myPref",Activity.MODE_WORLD_WRITEABLE);
  if(myPref != null && myPref.contains("name")){
    String name = myPref.getString("name");
  }

* 로그 출력 : Log.d("tag","Message");

* Service : startService(), stopService()
            android:process=":remote" - Manifesto 에 별도의 프로세스를 선언할 수 있음 -> 앱이 Destroy 되도 계속 동작함

* Content Provider
  CONTENT_URI , content://... 로 접근., http:// 로 웹사이트 접근
  Cursor를 이용해 결과 데이터 확인 (Database)
  ContentResolver : getContentResolver(), query()

  ex) ContentResolver resolver = getContentResolver();
      resolver.query(uri,projection,selection,selectionArgs,sortOrder);
      Cursor cursor = resolver.query(ContactsContract.Contacts.CONTENT_URI,null,null.null.null);
      int count = cursor.getCount();
      Toast.makeText(this,"text",duration);
      => add permissions : READ_CONTACTS
      for(int i = 0; i<count; i++){
        cursor.moveToNext();
        String name = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME);
        Toast.makeText(this,"name " + i + name,duration);
    }

* Manifest
  <activity>,<intent-filter><action android:name = ".... .MAIN"> <category android:name = "......LAUNCHER>,

<style ....>

* AlertDialog
  AlertDialog dialog = null;
  switch(id){
      case 1:
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setMessage("");
         builder.setPositiveButton("",new DialogInterface.OnClickListener())
        
        public void onClick(DialogInterface dialog, int which) {
            Toast.makeText.....
        }
        });
        builder.create();
  }

* AlertDialog 를 Activity 로 만들기 (로그인 화면??)
  AlertDialog가 떠야 되는 장소에 코딩
  setContentView(R.layout.dialog); // dialog.xml 만들기 (바탕화면,로그인 창 - 바탕화면은 이미지를 매번 바꿀 것)
  Manifest - <activity android:name="DialogActivity" android:theme="@android.style/Theme.Dialog"></activity>
  => AlertDialog box 디자인 하는 방법
 


반응형

안드로이드 개발 환경 구축하기

2013. 9. 6. 21:32 | Posted by 솔웅


반응형

안드로이드 개발 환경 구축



오랜만에 다시 안드로이드 애플리케이션 개발을 위한 글을 올리기로 했습니다.


지금 하는 TDD 일을 계속 할 지 아니면 Android App 개발 팀으로 옮길지 아직 모르는데요.

다시 Android 개발 관련해서 이야기가 나오니까 준비도 하고 싶고 또 개발도 하고 싶고 하네요.


당분간 Native Android App 개발 관련해서 공부를 할 것 같습니다.


우선 개발 환경부터 구축을 해 보겠습니다.


아래 싸이트로 가서 Android SDK 툴을 다운 받으세요.


http://developer.android.com/sdk/index.html




32bit 64bit 둘 중 하나 선택해서 다운 받으시면 됩니다.


다운 다 받은 후 적당한 곳에 압축을 풀어 주세요.




압축 푼 다음에 SDK Manager 실행을 하세요.




저는 모든 것 다 선택하고 Install Package 했어요. 그거 누르면 License 에 동의하겠느냐고 물어오는데 동의 한다고 한 다음에 Install 버튼 누르시면 됩니다.




Install 이 다 됐으면 이제 eclips 를 실행하시면 됩니다.



이제 HelloWorld 앱을 하나 만들어 보겠습니다.




New - New Android Application을 선택하시고 Application Name 에는 아무 이름이나 넣으세요. 그리고 Next 버튼을 누르세요.

다음 나오는 화면에서도 계속 Next 버튼을 누르세요.


Configure Project - Next
Configure Launcher Icon - Next
Create Activity - Next




그러면 이와 같이 애플리케이션이 만들어 집니다.


이 앱은 화면에 HelloWorld 를 display 해 주는 앱입니다.


이제 이 앱을 한번 실행해 봐야 할 텐데요.

에뮬레이션을 실행하도록 하겠습니다.




우선 에뮬레이터인 Android Vertual Device를 만들어야 하는데요.

메뉴바 밑에 있는 아이콘들 중 핸드폰 모양의 아이콘을 클릭하시면 위 화면이 나옵니다.

여기서 New를 누르시고 적당한 모델을 선택하시면 됩니다.


그리고 나서 Cntl-11 을 누르거나 Run을 누르시면 되는데요.


저는 Failed to allocate memory: 8 이런 메세지가 뜨네요.


이런 경우 해당 avd 폴더로 가서 config.ini 파일을 열어보세요.



이 파일은 C:\Users\본인\.android\avd\test.avd 경로에 있습니다.




빨간 줄 있는 부분이 1024MB가 아니라 1024로 돼 있을 겁니다.

만역 그렇다면 위에 보이는 것 처럼 고쳐 주세요.


그리고 나서 Run 을 실행하시면 됩니다.


에뮬레이터로 하면 시간이 조금 걸리는데요.

실제 개발 하실 때는 에뮬레이터 보다는 디바이스로 실행시켜서 테스트 해 보시는게 좋을 겁니다.





반응형


반응형

요즘 Phonegap 을 이용한 프로젝트를 하나 시작하기 위해 Research 를 하고 있습니다.

샘플을 하나 구해서 이걸 이클립스에 설치 한 다음에 시뮬레이터로 동작하는건 완료 했는데요.


갑자기 이걸 apk 로 만들려고 하니까 생각이 하나도 안 나네요.


뭐든지 다 정리 해 놔야 될 것 같습니다.


첫번째 단계만 보니까 알겠던데... ;;


어쨌든 제일 처음으로 이클립스에서 File > Export 를 선택합니다.



그러면 아래와 같은 화면이 나오는데요. Android > Export Android Application 을 선택하신 후 Next 버튼을 누르세요.


다음엔 Export 할 프로젝트를 선택하시면 됩니다. 프로젝트 이름을 직접 Type 해 넣으셔도 되구요.



다음엔 자기가 사용하는 안드로이드 빌드용 key 를 선택하시면 됩니다. 없으신 분은 Create new keystore 를 선택하셔서 다음 단계 진행하시면 됩니다. 이 새로운 keystore를 만드는 방법은 구글링해서 찾으셔도 되구요. 아니면 그냥 이클립스에서 시키는 대로 따라 하시면 될 겁니다.

해당 key를 선택하신 후 비밀번호를 넣고 Next 버튼을 누르세요.


그러면 아래와 같이 Alias 를 넣는 칸이 나올 텐데요. keystore 생성할 때 만들었던 Alias 선택하고 비밀번호 넣고 다음 버튼 누르시면 됩니다.



그러면 마지막 단계로 apk 파일을 생성할 폴더만 선택하시면 됩니다. 선택하신 후 Finish 버튼을 누르세요.




그러면 위에서 지정한 경로에 apk 파일이 생겼을 겁니다.

이걸 안드로이드폰에 복사해서 인스톨 하셔도 되구요.

안드로이드 마켓에 올리셔도 됩니다.


간단하게 이클립스에서 안드로이드 용 apk 파일 만드는 방법 정리했습니다.


반응형
이전 1 2 3 4 5 6 7 8 ··· 18 다음