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

최근에 올라온 글

최근에 달린 댓글

최근에 받은 트랙백

글 보관함

카테고리


반응형

지난 월요일 화요일 이틀동안 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 이고 정수형입니다.


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

반응형