출처: http://blog.chopestory.net/201
이런 저런 앱을 만들다 보니 activity전환 속도나 광고 노출 유지를 위해서 하나의 Activity에서 여러개의 다른 뷰를 보여줄 필요가 있었습니다.
기존에 제공되던 ViewFlipper를 관리할 수 있는 Manager를 제작하였습니다. ViewFlipper가 순서대로 동작되는 단점이 있습니다. 이 점을 극복하기 위해 Manager는 지정된 View로 이동시 필요한 만큼의 이동을 하게 됩니다.
사용하는 방법은 간단 합니다. ViewFlipper 안에 어떤 뷰가 순서대로 적용되어 있는지 알아야 합니다. 그리고 그 순서에 맞게 type을 등록하면 됩니다.
간단한 예제로 보는게 빠를 것 입니다. 간단하게 TabView형식으로 구현한 예제입니다.
main.xml
1 2 3 4 5 6 7 8 9 10 11 | <!--?xml version="1.0" encoding="utf-8"?--> < relativelayout xmlns:android = "http://schemas.android.com/apk/res/android" android:layout_width = "fill_parent" android:layout_height = "fill_parent" android:orientation = "vertical" > < linearlayout android:id = "@+id/bottomMenu" android:layout_width = "fill_parent" android:layout_height = "80dp" android:layout_alignparentbottom = "true" > < textview android:id = "@+id/menuA" android:layout_width = "fill_parent" android:layout_height = "fill_parent" android:layout_weight = "1" android:layout_gravity = "center" android:background = "#FF0000" android:textcolor = "#000000" android:textsize = "50dp" android:text = "View 1" > < textview android:id = "@+id/menuB" android:layout_width = "fill_parent" android:layout_height = "fill_parent" android:layout_weight = "1" android:layout_gravity = "center" android:background = "#00FF00" android:textcolor = "#000000" android:textsize = "50dp" android:text = "View 2" > </ textview ></ textview ></ linearlayout > < viewflipper android:id = "@+id/viewFlipper" android:layout_width = "fill_parent" android:layout_height = "fill_parent" android:layout_alignparenttop = "true" android:layout_above = "@id/bottomMenu" > < textview android:layout_width = "fill_parent" android:layout_height = "fill_parent" android:background = "#FFFF00" android:textcolor = "#000000" android:textsize = "50dp" android:text = "View 1" > < textview android:layout_width = "fill_parent" android:layout_height = "fill_parent" android:background = "#00FFFF" android:textcolor = "#000000" android:textsize = "50dp" android:text = "View 2" > </ textview ></ textview ></ viewflipper > </ relativelayout > |
TypeManagerTestActivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | package com.yhg.test.typemanager; import yhg.library.view.manager.TypeViewManager; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.ViewFlipper; public class TypeManagerTestActivity extends Activity { public static final String TYPE_A = "a" ; public static final String TYPE_B = "b" ; protected TypeViewManager mManager; @Override public void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.main); ViewFlipper viewFlipper = (ViewFlipper) findViewById(R.id.viewFlipper); mManager = new TypeViewManager(viewFlipper); mManager.addType(TYPE_A); mManager.addType(TYPE_B); mManager.setStartType(TYPE_A); View menuA = findViewById(R.id.menuA); View menuB = findViewById(R.id.menuB); menuA.setOnClickListener( new OnClickListener(){ @Override public void onClick(View v) { mManager.showTypeView(TYPE_A); } }); menuB.setOnClickListener( new OnClickListener(){ @Override public void onClick(View v) { mManager.showTypeView(TYPE_B); } }); } } |
사용법은 위와 같습니다. 간단합니다. 실제로 어떻게 구동되는지는 아래 동영상을 참고하세요.
데모 동영상을 한번에 찍다 보니.... 약간 엉성하네요 하하하하
정말 간단한 기능이고 TypeViewManager에도 별로 대단할 것 없습니다. 내부 코드는 다음과 같습니다.
[TypeViewDistance.java]
package yhg.library.view.manager; /** * Type끼리의 거리를 저장 * @author yoonhg84 */ public class TypeViewDistance { /** * 왼쪽 방향을 나타내는 상수 */ public final static int LEFT = - 1 ; /** * 방향이 설정되어 있지 않은 상태 */ public final static int NONE = 0 ; /** * 오른쪽 방향을 나타내는 상수 */ public final static int RIGHT = 1 ; /** * 현재의 방향 */ private int direction; /** * Type에서 Type까지의 거리 */ private int distance; /** * 생성자로 기본 정보를 설정한다 * @param dir 방향 상수 * @param dis 거리 */ public TypeViewDistance( int dir, int dis){ this .direction = dir; this .distance = dis; } /** * 방향 정보를 얻는다. * @return 방향 상수 */ public int getDirection(){ return direction; } /** * Type에서 Type까지의 거리를 얻는다. * @return 거리 */ public int getDistance(){ return distance; } }
|
[TypeViewManager.java]
package yhg.library.typeview.manager;
import java.util.ArrayList; import java.util.Stack; import android.util.Log; import android.widget.ViewFlipper; /** * TypeViewManager는 ViewFlipper를 이용하여 하나의 Activity에서 여러개의 뷰를 전환할 수 있도록 관리해 준다. * 추가되는 Type만 관리되며 나머지 처리는 외부에서 구현하여야 한다. * * @author yoonhg84 */ public class TypeViewManager { /** * TypeViewManager가 관리하게 될 ViewFlipper */ private ViewFlipper mFlipper; /** * Type 을 저장하는 list */ private ArrayList<string> mTypeList; /** * 지정된 Type에서 메뉴가 보여야 하는지를 저장하는 list * index값은 typeList와 동일하다 */ private ArrayList< boolean > mMenuList; /** * Type이 변경될때 기록되는 log */ private Stack<integer> mLog; /** * 현재 type */ private int mType; /** * 이전 type */ private int mPreType; /** * 시작하는 type */ private int mStartType; /** * 수행에 필요한 변수들을 초기화한다 * * @param flipper 가장 핵심이 되는 플립퍼 */ public TypeViewManager(ViewFlipper flipper){ this .mFlipper = flipper; this .mTypeList = new ArrayList<string>(); this .mMenuList = new ArrayList< boolean >(); this .mPreType = - 1 ; this .mType = 0 ; this .mStartType = 0 ; initLog(); mLog.push(mStartType); } /** * 시작 타입을 설정한다 * 반드시 초기화->타입추가->시작타입 순으로 진행되어야 한다. * 시작타입으로 지정할 타입의 추가가 뒤에 오면 오류 발생!! * * @param name 시작 타입으로 지정할 타입명 */ public void setStartType(String name){ mStartType = getType(name); initLog(); mLog.push(mStartType); } /** * 로그를 초기화 한다 */ private void initLog(){ this .mLog = new Stack<integer>(); } /** * 타입명으로 새로운 타입을 추가한다 * * @param name 추가할 타입명 * @return 추가된 타입 번호 */ public int addType(String name){ mTypeList.add(name); mMenuList.add( true ); return getType(name); } /** * 타입명으로 타입 번호를 구한다 * * @param name 번호를 구하고 싶은 타입 이름 * @return 타입 번호 */ private int getType(String name){ return mTypeList.indexOf(name); } /** * 타입 번호로 타입명을 얻는다 * * @param type 이름을 구하고 싶은 타입 번호 * @return 타입명 */ private String getTypeName( int type){ return mTypeList.get(type); } /** * 현재 타입의 이름을 구한다 * * @return 현재 타입의 이름 */ public String getCurrentTypeName(){ return mTypeList.get(mType); } /** * 이전 타입의 이름을 구한다. * @return 이전 타입이 있다면 타입이름을 리턴, 이전 타입이 없 */ public String getPrevTypeName(){ if (mPreType == - 1 ){ return null ; } return mTypeList.get(mPreType); } /** * 타입의 갯수를 구한다 * * @return 타입 갯수 */ private int getNumOfType(){ return mTypeList.size(); } /** * 현재의 타입에서 메뉴가 보여야 하는지를 구한다 * * @param type 메뉴의 보임 여부를 확인하고 싶은 타입 * @return 메뉴가 보여야 하면 true 아니면 false */ private boolean getMenuVisible( int type){ return mMenuList.get(type); } /** * 메뉴 보임 여부를 설정한다 * * @param name 설정할 타임명 * @param visible 보임 여부 */ public void setMenuVisible(String name, boolean visible){ mMenuList.set(getType(name), visible); } /** * 타입과 타입 사이에 가장 가까운 거리와 방향을 구한다 * * @param t1 비교할 타입1 * @param t2 비교할 타입2 * @return 방향과 거리가 저장되는 TypeViewDistance를 리턴한다. 방향은 LEFT,NONE,RIGTH가 존재한다 */ private TypeViewDistance getDistance( int t1, int t2){ int tmp; int direction = TypeViewDistance.NONE; int distance = 0 ; int large, small; if (t1 > t2){ large = t1; small = t2; direction = TypeViewDistance.LEFT; } else if (t1 < t2){ large = t2; small = t1; direction = TypeViewDistance.RIGHT; } else return new TypeViewDistance(direction,distance); distance = large - small; //tmp = (getNumOfType() + small + 1) - large; tmp = getNumOfType() - distance; if (tmp < distance){ distance = tmp; direction = (direction == TypeViewDistance.LEFT) ? TypeViewDistance.RIGHT : TypeViewDistance.LEFT; } return new TypeViewDistance(direction,distance); } /** * 보여지는 타입의 로그를 저장한다 * 시작 타입이 오게 되면 이전 로그 기록은 중요하지 않으므로 초기화되고 시작타입만 들어가게 된다. * * @param type 변경 전 타입 */ private void addLog( int type){ int count = log.search(type); if (log.size() == 0 ){ initLog(); } else if (count != - 1 ){ for ( int i= 0 ; i < count; i++){ log.pop(); } } log.push(type); } /** * 가장 최근에 추가된 로그를 제거한다. * 순서가 꼬이는 문제를 해결하기 위함 * @param type 지정된 type이 최근 로그일 경우 삭 */ public void removeTopLog(String typeName){ int type = getType(typeName); int count = log.search(type); if (log.size() == 0 ){ initLog(); } else if (count == (log.size()- 1 )){ log.pop(); } } /** * BACK 키를 눌렀을 경우 타입뷰에서 처리하는 이벤트 * 시작 타입이면 false를 리턴하여 액티비티에서 처리하게 한다 * 시작 타입이 아니라면 로그에서 정보를 가져와서 전 타입뷰로 이동한다 * * @return 현재 보여지고 있는 타입이 시작 타입이라면 false, 다른 타입이라면 전 타입을 보여주고 true 리턴 */ public boolean onBackKeyDown(){ int prev; // 현재의 뷰를 제거 한다 log.pop(); if (type == startType || log.size() == 0 ){ return false ; } // 이전 뷰를 구한다 prev = log.peek(); showTypeView(getTypeName(prev)); return true ; } private void displayLog(){ int size = log.size(); StringBuilder buffer = new StringBuilder(); for ( int i= 0 ; i < size; i++){ buffer.append(log.get(i)+ " " ); } Log.i( "cauin" ,buffer.toString()); } /** * 메뉴키 이벤트를 처리한다. * 현재 타입에서 보여야 할지 안 보여야 할지 알려 준다 * * @return 화면에 보여야 하면 false, 보이지 말아야 하면 true 이다 */ public boolean onMenuKeyDown(){ if (getMenuVisible(type) == true ) return false ; return true ; } /** * Flipper를 사용하여 화면을 전환한다 * 현재 모드와 원하는 모드의 값을 계산하여 자동으로 이동시켜 준다. * * @param need 보여주고 싶은 모드, 즉 보여주고 싶은 View */ public void showTypeView(String needName){ int need = getType(needName); if (type == need) return ; TypeViewDistance tvd = getDistance(type,need); int distance = tvd.getDistance(); if (tvd.getDirection() == - 1 ){ for ( int i= 0 ; i < distance; i++) flipper.showPrevious(); } else { for ( int i= 0 ; i < distance; i++) flipper.showNext(); } type = need; addLog(type); } }
|
다음에는 view 변경시 이벤트 처리를 하도록 해야겠습니다.
정리를 해보려고 해도 글은 적게 써지네요.....;;
'IT_Programming > Android_Java' 카테고리의 다른 글
[펌] PreferenceActivity 디자인 하기 (0) | 2012.10.05 |
---|---|
[펌] Bitmap 생성 없이도 Bitmap 크기 정보를 구하는 방법 (0) | 2012.10.05 |
[Android/안드로이드] Service 고급정보. (0) | 2012.05.22 |
[Android] XML로 Shape Drawable 만들기 (0) | 2012.05.21 |
[펌] 안드로이드 렌더링의 특징: 디스플레이 리스트 (0) | 2012.03.23 |