우동우동우's note

[Android] Paper Flip(Fold) 효과가 적용된 메뉴 구성하기 본문

Java & Android

[Android] Paper Flip(Fold) 효과가 적용된 메뉴 구성하기

우동우동우 2013. 11. 18. 22:54

안드로이드에서 Animation을 구현하는 건 하면 할 수록 참 어려운 것 같다. 

클라이언트가 원하는 Animation의 대부분은 앱에서 기본으로 지원하는 것을 사용하지 않고 구축을 해야하니 말이다. 이번에 paper flip효과를 만들 때도 마찬가지였다. 안드로이드 open souce에서는 paper flip 효과가 들어가 있는 것이 없기 때문이다. 이번 기회로 한번 만들어보자라는......

우선 paper flip 효과는 아래 사진과 같이 좌우로 드래그해서 열고 닫는 형태이며 닫히고 열리는 순간에 종이가 접히는 듯한 Animation이 들어가있다. 현재 구현된 모듈은 제한된 형태의 모듈이다. 그래도 Animation을 하는 방법이 이렇게도 가능하다는 나만의 예제가 되는 것 같아서 구현한 보람은 조금 있는 것 같다. 



구현된 소스 설명에 앞서서 소스를 받아서 보시길 바란다. 

FlipView.zip

src 폴더에는 FlipableView.java파일과 MainActivity.java이렇게 두개의 파일 밖에 없다. 이번 포스트에서는 FlipableView의 구현내용에 대해서 간단하게 기술하려한다. 사용방법은 예제를 보면 어렵지 않게 사용할 수 있을 것이다. 

구현방법

우선 FlipableView는 FrameLayout을 확장하여 구현하였다. 이 뷰의 내부에 2가지의 Child View를 가지게된다. 하나는 좌측 영역에 나오는 Content, 다른 하나는 우측에 나오는 Flip 영역으로 나뉘게 된다. 이 영역은 아이디로 구분하도록 정하였다. 그래서 ids.xml 파일을 열어보면 2개의 아이디가 정의되어 있을 것이다. 

ids.xml



    
    

ids.xml


flipable_flip_view의 경우는 우측에 접혀지는 뷰를 나타내고 flipable_content_view는 좌측 영역을 나타낸다. 

이제 Animation은 어떻게 나타나는지 살펴보자. Animation은 안드로이드에서 지원해주는 방법이 없어서 뷰를 캡쳐하여 캡쳐한 이미지를 뷰에 나타내어 표현하였다. 

			View flip = getFlipView();
			flip.setDrawingCacheEnabled(true);
			Bitmap capture = flip.getDrawingCache();
			int flipHeight = capture.getHeight();
			int peiceWidth = capture.getWidth()/mPieceCount;
			int[] pixels = new int[flipHeight * peiceWidth];
			for(int i = 0 ; i < captruedBitmap.length; i++) {
				Bitmap tmp = Bitmap.createBitmap(peiceWidth, flipHeight, Config.ARGB_8888);
				capture.getPixels(pixels, 0, peiceWidth, peiceWidth * i, 0, peiceWidth, flipHeight);
				tmp.setPixels(pixels, 0, peiceWidth, 0, 0, peiceWidth, flipHeight);
				captruedBitmap[i] = tmp;
			}
			flip.setDrawingCacheEnabled(false);


여기서 보면 뷰의 이미지 캡쳐를 하는 방법을 알 수 있을 것이다. getDrawingCache()함수를 불러오면 Bitmap 이미지를 가져오게 된다. 그리고 이 이미지를 원하는 크기로 잘라서 저장하게 된다. 

그럼 이제 잘려진 이미지가 보여지는 곳을 한번 살펴보자. drawFlipView함수를 살펴보자. 

	private void drawFlipView(Canvas canvas, View child, float ratio) {

		float childRight = child.getRight();
		float childTop = child.getTop();
		float childBottom = child.getBottom();
		float childWidth = child.getWidth();

		float itemHeight = childBottom - childTop;
		if(captruedBitmap != null){
			Bitmap tmp = null;
			if((!mInAnim && !isDragging()) && opened){
				dimLeftBitmap.setPixel(0, 0, 0x00000000);
				dimRightBitmap.setPixel(0, 0, 0x00000000);
			}else{
				dimLeftBitmap.setPixel(0, 0, 0x1000000 * (int) ( 0x44 * ( 1 - ratio )));
				if(ratio < 0.5f){
					dimRightBitmap.setPixel(0, 0, 0x1000000 * (int) ( 0x33 * ( 0.5f - ratio ) * 2));
				}else{
					dimRightBitmap.setPixel(0, 0, 0x00000000);
				}
			}
			childWidth = (childWidth * ratio);
			float itemWidth = (childWidth)/mPieceCount;
			int length = captruedBitmap.length;
			float heightRatio = (1-ratio)/40;
			for(int i = 0; i < length; i++){
				tmp = captruedBitmap[i];
				if(tmp != null){
					float[] verts = new float[8];
					if(i % 2 == 1){
						verts[0] = childRight - ((length - i)) * itemWidth ;
						verts[1] = itemHeight * heightRatio;
						verts[2] = childRight - (length - i - 1) * itemWidth;
						verts[3] = itemHeight * -heightRatio;
						verts[4] = childRight - ((length - i)) * itemWidth;
						verts[5] = itemHeight * (1 - heightRatio);
						verts[6] = childRight - (length - i - 1) * itemWidth ;
						verts[7] = itemHeight * (1 + heightRatio);
						
						canvas.drawBitmapMesh(tmp, 1, 1,
								verts, 0, null, 0, null);
						canvas.drawBitmapMesh(dimRightBitmap, 1, 1,
								verts, 0, null, 0, null);
						
					}else{
						verts[0] = childRight - ((length - i)) * itemWidth ;
						verts[1] = itemHeight * -heightRatio;
						verts[2] = childRight - (length - i - 1) * itemWidth ;
						verts[3] = itemHeight * heightRatio;
						verts[4] = childRight - ((length - i)) * itemWidth ;
						verts[5] = itemHeight * (1 + heightRatio);
						verts[6] = childRight - (length - i - 1) * itemWidth;
						verts[7] = itemHeight * (1 - heightRatio);

						canvas.drawBitmapMesh(tmp, 1, 1,
								verts, 0, null, 0, null);
						canvas.drawBitmapMesh(dimLeftBitmap, 1, 1,
								verts, 0, null, 0, null);
						
					}
				}
			}
		}		
	}


각 비트맵을 비틀어서 그릴 수 있는 drawBitmapMesh()함수를 활용하여 표현하였다. 접히는 듯한 효과를 나타내기 위해서 비틀어서 표현을 하고 그 위에 dimLeftBitmap, dimRightBitmap을 활용하여 그림자 효과도 추가하여 표현하였다. 각도를 계산하고 거리를 계산하는 것은 설명을 생량하도록 하겠다. 



'Java & Android' 카테고리의 다른 글

[Android] 다른 어플리케이션 실행방법  (0) 2013.11.25
[Android] 4.0 이상에서 IP 주소 가져오기  (0) 2013.11.25
[Android] Display Size Check  (0) 2013.11.13
[java] InputStream to String  (0) 2013.11.13
[Android] Memory Check  (0) 2013.11.13
Comments