Dev./Android

동적으로 아이템이 추가되는 ViewPager

like miller 2012. 5. 18. 16:48

같은 질문을 올리신 분들이 계셔서 샘플을 만들어 올립니다.

현재 제가 바빠서 자세한 설명은 다음주에 올리고 소스를 먼저 올립니다.


실행시키면 맨 마지막에 있는 Dynamic Add Item을 보시면 되고

소스는 OtherViewPagerSampeActivity2.java 파일과

etc 패키지에 있는 BkUtils.java파일을 보시면 됩니다.


1. 동적으로 페이지 추가 개념

동적(dynamic)이라는 뜻은 고정되어 있지 않고 특정 상황, 이벤트 등에 의해서 변경될 수 있음을 뜻한다. 뷰페이저에서 미리 정해놓은 페이지말고 앱이 실행되고 나서 동적으로 페이지를 추가 하는 방법을 묻는 질문이 올라와서 샘플을 만듭니다.


안드로이드의 리스트 뷰, 갤러리, 그리드 뷰, 스피너 같이 여러 아이템들을 보여주는 뷰에서 아이템이 동적으로 추가 / 삭제되었을 경우 아답터의 notifyDataSetChanged(); 메소드를 실행하여 갱신할 수 있다.

뷰 페이저도 마찬가지이다. 뷰페이저의 PagerAdapter, FragmentAdapter 무엇을 사용하던지 뷰 페이저의 페이지를 추가 / 삭제를 동적으로 해주고 싶으면 아답터가 가지고 있는 페이지 리스트에 페이지를 추가 / 삭제 후 아답터의 notifyDataSetChanged(); 메소드를 실행시키면 뷰 페이저가 업데이트 된다.


즉, 구글에서 뷰 페이저를 기존 리스트 뷰, 갤러리와 같은 방식으로 만들어서 개발자가 하나의 뷰만 이해하면 나머지 뷰도 사용할 수 있도록 하였다.


다시 한번 강조하지만 뷰 페이저라고 사용이 어렵거나 복잡하지 않다. 뷰 페이저는 리스트 뷰, 갤러리와 같다. 아답터만 잘 이해하면 비슷하다.


2. 뷰 페이저에 동적으로 페이지 추가하기(화면 구성)

기본 화면 구성은 다음 그림과 같다.

1. 현재 페이지 표시 레이아웃

2. 동적으로 추가할 뷰를 선택하는 스피너와 실제 추가하는 버튼

3. 뷰페이저



추가할 뷰이 타입을 3가지로 하였음.

1. 텍스트 뷰 (배경색과 글자색은 랜덤)

2. 스크롤 뷰 (텍스트 뷰, 아날로그 시계, 디지턹 시계, 이미지 뷰가 있다)

3. 리스트 뷰 (어벤져스 캐릭터들의 각각의 영화를 리스트 뷰로 출력)





3. 뷰 페이저에 동적으로 페이지 추가하기(기본 소스 구현)

기본 소스는 OtherViewPagerSampeActivity.java를 바탕으로 만들었습니다.


* 멤버 필드

private final int MAX = 10;                     //뷰 페이저가 가질 페이지 최고 갯수.
private int mPrevPosition;                     //이전에 선택되었던 포지션 값. 현재 페이지 표시 위한 변수

private Button mAddView;                     //뷰 페이저에 아이템 추가하는 버튼
private Spinner mViewTypeSpinner;       //뷰 페이저에 추가할 아이템의 타입을 고르는 스피너
private ViewPager mPager;                   //뷰 페이저
private LinearLayout mPageMark;          //현재 몇 페이지 인지 나타내는 뷰
private BkPagerAdapter mAdapter;         //아답터 객체. 아이템을 추가 하기 위해 변수 선언


*onCreate()메소드 - UI를 초기화 한다.

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.other2);

    mAddView = (Button)findViewById(R.id.btn_add);        //추가 버튼
    mAddView.setOnClickListener(this);                        //클릭 리스너 등록
   
    mViewTypeSpinner = (Spinner)findViewById(R.id.spinner_view_type); //아이템 타입 선택하는 스피너
   
    mPageMark = (LinearLayout)findViewById(R.id.page_mark);    //상단의 현재 페이지 나타내는 뷰

    mPager = (ViewPager)findViewById(R.id.pager);                        //뷰 페이저
    mAdapter = new BkPagerAdapter(getApplicationContext());
    mPager.setAdapter(mAdapter);                                            //PagerAdapter로 설정
}


*뷰 페이저 아답터 - PagerAdapter기반으로 페이지는 뷰로 구성된다.

아답터에서는 뷰 페이저의 페이지들을 가지고 있지 않고 각 페이지의 타입값(int형)만 가지고 있는다.

아답터는 뷰 페이저의 페이지 갯수를 알려주고 실제 해당 페이지의 뷰를 반환한다.

실제로 뷰를 만드는 역할은 BkUtils 클래스의 getView 메소드가 담당한다.


//Pager 아답터 구현
private class BkPagerAdapter extends PagerAdapter{
    private Context mContext;
    private ArrayList<Integer> mItems;            //아이템 뷰의 타입. 아이템 갯수 만큼
    public BkPagerAdapter( Context con) {
        super(); mContext = con;
        mItems = new ArrayList<Integer>();             //아답터 생성시 리스트 생성
        mItems.add(BkUtils.TYPE_TEXTVIEW);        //최초 1개의 아이템은 기본으로 생성한다
    }

    //뷰 페이저의 아이템 갯수는 리스트의 갯수
    //나중에 뷰 페이저에 아이템을 추가하면 리스트에 아이템의 타입을 추가 후 새로 고침하게 되면
    //자동으로 뷰 페이저의 갯수도 늘어난다.
    @Override public int getCount() { return mItems == null ? 0:mItems.size(); }

    //뷰페이저에서 사용할 뷰객체 생성/등록
    @Override public Object instantiateItem(View pager, int position)
    {  

        //해당 포지션의 아이템 뷰를 생성한다
        View v = BkUtils.getView(mItems.get(position), mContext);   
        ((ViewPager)pager).addView(v);
        return v;
    }

    //뷰 객체 삭제.
    @Override public void destroyItem(View pager, int position, Object view) {
        ((ViewPager)pager).removeView((View)view);
    }

    // instantiateItem메소드에서 생성한 객체를 이용할 것인지
    @Override public boolean isViewFromObject(View view, Object obj) { return view == obj; }

    @Override public void finishUpdate(View arg0) {}
    @Override public void restoreState(Parcelable arg0, ClassLoader arg1) {}
    @Override public Parcelable saveState() { return null; }
    @Override public void startUpdate(View arg0) {}
}


4. 뷰 페이저에 동적으로 페이지 추가하기(추가하는 소스 구현)

페이지추가는 아답터의 mItems에 뷰 타입을 추가함으로 써 끝나게 된다. 정말 간단하다.


*뷰 페이저 아답터에 페이지 추가하는 메소드 추가

/**
 * 동적으로 아이템을 추가하는 메소드
 * @param type - 아이템 타입
 */
public void addItem(int type){
    mItems.add(type);                //아이템 목록에 추가
    notifyDataSetChanged();        //아답터에 데이터 변경되었다고 알림. 알아서 새로고침
}


*버튼 클릭 시 페이지 추가하는 코드

@Override
public void onClick(View v) {
    //뷰 페이저에 아이템 추가
    if(v == mAddView) {
        if(mAdapter.getCount() <= MAX) {       //최대 갯수 이하이면
            int type = mViewTypeSpinner.getSelectedItemPosition();    //아이템 타입을 가져와
            mAdapter.addItem(type);        //해당 타입의 아이템을 추가한다. 뷰 페이져 새로고침
            addPageMark();                           //페이지 표시 뷰도 추가
        }
        else
            Toast.makeText(getApplicationContext(), "최대 10개의 아이템만 등록 가능합니다. 소스를 수정하세요.", Toast.LENGTH_SHORT).show();
    }
}






5. 뷰를 만드는 BkUtils클래스

뷰 페이저 아답터에서 호출하는 getView 메소드는 내부적으로 추가할 페이지의 타입에 따라서 각각의 내부 메소드를 실행한다. 실제 내부 메소드는 예제 소스를 다운받아서 보기 바란다. 이클립스에 보는게 훨씬 가독성이 좋기 때문이다.


* public static View getView(int type, Context con) 메소드


/**
 * 뷰 페이저에 추가할 뷰를 생성하여 반환한다
 * @param type - 추가할 뷰 타입
 * @param con - 뷰 생성에 사용할 Context
 * @return 뷰 객체
 */
public static View getView(int type, Context con) {
    if(type == TYPE_TEXTVIEW)
        return getTextView(con);
    else if(type == TYPE_SCROLLVIEW)
        return getScrollView(con);
    else if(type == TYPE_LISTVIEW)
        return getListView(con);
    else
        return getDigitalClock(con);
}


예제를 실행시키면 맨 마지막에 있는 Dynamic Add Item을 보시면 되고

실제 소스는 OtherViewPagerSampeActivity2.java 파일과

etc 패키지에 있는 BkUtils.java파일을 보시면 됩니다.


전체 샘플 코드 첨부하였습니다.

*글과 자료는 출처만 밝히시면 얼마든지 가져다 쓰셔도 됩니다.

ViewPagerSampe.zip


ViewPagerSampe.zip
0.93MB