티스토리 뷰
일반적인 인터넷 검색을 통해 드래그를 이용한 화면 전환 구현이라 검색해보면,
ViewFlipper 과 Animation 효과를 이용한 화면 전환되는 소스들이 매우 많이있다.
헌데 이 방식은 드래그와 동시에 화면전환이 되지 않는다!
일단 드래그를 한후에 손을 화면에서 떼는 순간 그제서야 화면전환이되는... 반응성 제로인.. 그런 UI..
인터넷에서 드래그 화면전환을 검색하는 대부분의 사람들은 그런걸 원한게 아니라.. (개인적인 생각으로는)
구글플레이나 안드로이드 런처의 바탕화면 처럼 터치드래그와 동시에 화면이 움직이는
화사고 미려하고 아름다우며, 주인의 말을 찰떡같이 알아듣는 바둑이와 같은 UI를 원했을꺼라 생각된다.
물론 나도 그런걸 원해서 처음 검색을 시작하게 됬었고, 처음에는 적당히 타협해서 viewflipper 를 사용하긴 했었다.
뭐.. 여차저차해서 구현되어 있는 소스를 구하긴 구했지만.. 이해력 부족으로 뭐가 뭔지 매우 복잡해서 잠시 닫아놨었는데..
시간이 널널한 지금 이때에! 기회가 되서 하나하나 뜯어보고 주요 클래스와 메서드들을 알아보자는 의미로 구현해 보았다.
소스의 핵심 클래스는 Scroller !!!!
스크롤 지점만 등록해두면 알아서 스크롤이 되는것을 도와주는 친절한 클래스. ( 물론 손을 좀 보긴해야하지만.. )
아래 소스는 붙여넣기 하면 별다른 문제없이 실행 가능하고. (일부 리소스는 변경해줘야함)
실제 활용되기보다는 동작 구현의 중점을 두고 이해를 목적으로 작성하였다.
참고한 소스는 http://code.google.com/p/andro-views/
으.. 글을 작성하고 보니.. 이전 글들과 다르게 소스가 분량이 조금 많아서 그런지.. 소스코드 보기가 어렵다..
네이버에서 활용할수 있는 하이라이터를 썻는데 별로 맘에 들지가.. 티스토리로 블로그를 옴기던가 해야지... 이런..
1. Activity 클래스
package com.hdh.test.slidingview; import android.app.Activity; import android.graphics.Rect; import android.os.Bundle; import android.util.Log; import android.view.View; import android.view.Window; public class main extends Activity{ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); SlidingView sv = new SlidingView(this); View v1 = View.inflate(this, R.layout.t1, null); View v2 = View.inflate(this, R.layout.t2, null); sv.addView(v1); sv.addView(v2); setContentView(sv); } }
|
2. 제스쳐에 따라 움직이는 뷰 클래스
package com.hdh.test.slidingview; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.PointF; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.View; import android.view.ViewGroup; import android.widget.Scroller; import android.widget.Toast; /* 여러 화면을 구현할때 여러개의 엑티비티가 붙는것아니라 * viewgroup의 childview 로 넣어두고 스크롤을 통해 화면 전환 효과를 이루는 방식이다. * 따라서 viewgroup 을 상속받고 화면에 넣고자하는 layout은 addview() 클래스를 통해 삽입한다. */ public class SlidingView extends ViewGroup { private static final String TAG = "SlidingView"; // 드래그 속도와 방향을 판단하는 클래스 private VelocityTracker mVelocityTracker = null; // 화면 전환을 위한 드래그 속도의 최소값 pixel/s (100 정도으로 속도로 이동하면 화면전환으로 인식) private static final int SNAP_VELOCITY = 100; /* 화면에 대한 터치이벤트가 화면전환을 위한 터치인가? 현 화면의 위젯동작을 위한 터치인가? 구분하는 값 (누른상태에서 10px 이동하면 화면 이동으로 인식) */ private int mTouchSlop = 10; private Bitmap mWallpaper = null; // 배경화면을 위한 비트맵 private Paint mPaint = null; /* 화면 자동 전황을 위한 핵심 클래스 ( 화면 드래그후 손을 뗏을때 화면 전환이나 원래 화면으로 자동으로 스크롤 되는 동작을 구현하는 클래스) */ private Scroller mScroller = null; private PointF mLastPoint = null; // 마지막 터치 지점을 저장하는 클래스 private int mCurPage = 0; // 현재 화면 페이지 private int mCurTouchState; // 현재 터치의 상태 private static final int TOUCH_STATE_SCROLLING = 0; // 현재 스크롤 중이라는 상태 private static final int TOUCH_STATE_NORMAL = 1; // 현재 스크롤 상태가 아님 private Toast mToast; public SlidingView(Context context) { super(context); init(); } public SlidingView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public SlidingView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } private void init() { mWallpaper = BitmapFactory.decodeResource(getResources(), R.drawable.background_black_1280x1024); // 배경화면 불러오기 mPaint = new Paint(); mScroller = new Scroller(getContext()); // 스크롤러 클래스 생성 mLastPoint = new PointF(); } // 차일드뷰의 크기를 지정하는 콜백 메서드 @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); Log.d(TAG, "onMeasure"); for (int i = 0; i < getChildCount(); i++) { // 각 차일드뷰의 크기는 동일하게 설정 getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec); } } // 차일드뷰의 위치를 지정하는 콜백 메서드 @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { Log.d(TAG, "onLayout"); // 핵심 구현 부분으로써 // 차일드뷰들을 겹치지 않게 옆으로 차례대로 나열해서 배치한다. // 옆으로 차례대로 배치를 해놔야 스크롤을 통해 옆으로 이동하는것이 가능해진다. for (int i = 0; i < getChildCount(); i++) { int child_left = getChildAt(i).getMeasuredWidth() * i; getChildAt(i).layout(child_left, t, child_left + getChildAt(i).getMeasuredWidth(),
|
# 기능을 일부 수정한 버전 입니다.
위 소스에서 아래 소스로 onTouchEvent() 를 수정하고 underScroll(), overScroll 메서드를 추가하면, 페이지 무한 루프 기능 가능.
첫번째 페이지와 마지막 페이지가 연결되어 링형을 이루는 구조입니다.
// 추가 boolean isFirstMove = true; // ACTION_MOVE 의 제일 처음 이벤트만 동작하도록 하는 멤버 변수 // 수정 @Override public boolean onTouchEvent(MotionEvent event) { Log.d(TAG, "event Action : " + event.getAction()); if (mVelocityTracker == null) mVelocityTracker = VelocityTracker.obtain(); mVelocityTracker.addMovement(event); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: if (!mScroller.isFinished()) { mScroller.abortAnimation(); } mLastPoint.set(event.getX(), event.getY()); break; case MotionEvent.ACTION_MOVE: int x = (int) (event.getX() - mLastPoint.x); scrollBy(-x, 0); // move 스크롤 이벤트가 가장 처음 일어났을때만 if (isFirstMove && getChildCount() > 2) { // 현재 전체 페이지보다 상위로 스크롤 했을때, overScroll 이벤트 발생 if (x < 0 && mCurPage == getChildCount() - 1) { overScroll(); } else if (x > 0 && mCurPage == 0) { // 하위로 스크롤 했을때 underScroll underScroll(); } } isFirstMove = false; invalidate(); mLastPoint.set(event.getX(), event.getY()); break; case MotionEvent.ACTION_UP: mVelocityTracker.computeCurrentVelocity(1000); int v = (int) mVelocityTracker.getXVelocity(); int gap = getScrollX() - mCurPage * getWidth(); Log.d(TAG, "mVelocityTracker : " + v); int nextPage = mCurPage; if ((v > SNAP_VELOCITY || gap < -getWidth() / 2) && mCurPage > 0) { nextPage--; } else if ((v < -SNAP_VELOCITY || gap > getWidth() / 2) && mCurPage < getChildCount() - 1) { nextPage++; } int move = 0; if (mCurPage != nextPage) { move = getChildAt(0).getWidth() * nextPage - getScrollX(); } else { move = getWidth() * mCurPage - getScrollX(); } mScroller.startScroll(getScrollX(), 0, move, 0, Math.abs(move)); if (mToast != null) { mToast.setText("page : " + nextPage); } else { mToast = Toast.makeText(getContext(), "page : " + nextPage, Toast.LENGTH_SHORT); } mToast.show(); invalidate(); mCurPage = nextPage; mCurTouchState = TOUCH_STATE_NORMAL; mVelocityTracker.recycle(); mVelocityTracker = null; isFirstMove = true; // move 스크롤 체크용 초기화 break; } return true; } // 추가 private void underScroll() { // 마지막 페이지를 가장 처음페이지 앞으로 이동 시킴 View v = getChildAt(getChildCount() - 1); removeViewAt(getChildCount() - 1); addView(v, 0); setPage(getChildCount() - 1); } // 추가 private void overScroll() { // 첫번재 페이지를 가장 마지막 페이지 뒤로 이동시킴 View v = getChildAt(0); removeViewAt(0); setPage(0); addView(v); } // 추가 public void setPage(int p) { if (!mScroller.isFinished()) { mScroller.abortAnimation(); } if (p < 0 || p > getChildCount()) return; mCurPage = p; scrollTo(getWidth() * p, 0); }
|
[출처] [코드] 드래그를 통한 화면 전환 효과 구현|작성자 개구리
'개발 > 개발 자료' 카테고리의 다른 글
[Android] assets 접근하여 파일 가져오기 (0) | 2013.09.10 |
---|---|
입력된 숫자까지의 소수 구하기 (0) | 2013.09.10 |
[Android] mysql 연동하여 데이터 select하기 (서버 php이용) (0) | 2013.09.09 |
[Android] mysql 연동하여 데이터 insert하기 (서버 php이용) (1) | 2013.09.09 |
[Android] GCM설정하는방법 구글 ProjectID얻어서 세팅하기 (0) | 2013.09.09 |