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

최근에 올라온 글

최근에 달린 댓글

최근에 받은 트랙백

글 보관함

카테고리


반응형

그럼 구체적으로 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 예제에 대한 분석이었습니다.

반응형