본문 바로가기

Android/Tip

OpenGL, Surfaceview 에서 Navigation Drawer, Sliding Menu 구현시 주의사항

예전에 개발하면서 문제 됬던 내용 정리 하는 차원에서 작성한다.


1. 재현현상


OpenGL, Surfaceview 위에 Navigation Drawer 구현시 Drag 속도가 현저히 떨어지거나 Drag 중에 검은색 화면으로 잔상이 생기는 문제가 


발생된다


2. 수정방법


내가 작업한 앱의 최소 서비스 지원 OS 버전이 Android 2.2 부터 였다. -_-; 그렇다..  Navigation Drawer API를 사용못한다 ..


그래서 android-support-v4 에서 지원하는 Navigation Drawer 지원하나 찾아봣다.. 안된다 -_-; 어쩔수 없이 Navigation Drawer, View Pager 


Open Souce를 분석하여 비슷한 동작이 되게 구현을 하였고. Fragment 를 이용하여 View가 독립적으로 Life Cycle 이루어지게 구현하였다.


근데 위에 재현현상과 같은 문제점이 발견되었다.. 그래서 차근차근 삽질했다.. 일단 Drag 속도를 최적화 하기위해 찾던중 Android 3.0 이상부터


하드웨어 가속 처리를 이용해여 어느정도 해결 하였고 그 다음.. 잔상이 나오는 문제는 하드웨어 가속처리를 해도 계속 발생 하였다. 그래서 또 


고민햇다.. 그러다가 Canvas API 중에 clipRect 이용하여 해결 하였다. 




방법은 아래 그림과 같이 하여 메뉴 영역과 메뉴 영역이 아닌부분을 clipRect API로 분리하여서로 화면 갱신이 영향을 안받게 처리 하였다.




소스 구현 내용중에 위에 해당되는 부분이다.


 
public class FadeLayout extends ViewGroup {
	/**
	 * 하드웨어 가속이면 true
	 */
	private final static boolean HARDWARE_FADE_LAYOUT = false;

	public FadeLayout(Context context) {
		super(context);
	}

	private CustomViewAbove mAbove;

	private View mContent;

	private CustomViewBehind mBehind;

	private SlidingMenu mSlidingMenu;

	public void setBehind(CustomViewBehind mBehind) {
		this.mBehind = mBehind;
	}

	public void setRootView(SlidingMenu slidingMenu) {
		this.mSlidingMenu = slidingMenu;
	}

	public void setContent(View content) {
		this.mContent = content;
	}

	public void setAbove(CustomViewAbove mAbove) {
		this.mAbove = mAbove;
	}

	/**
	 * 하드웨어 가속 여부
	 * 
	 * @return
	 */
	public boolean isHardwareaccelerated() {
		return HARDWARE_FADE_LAYOUT;
	}

	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
	}

	@Override
	public void draw(Canvas canvas) {
		super.draw(canvas);
	}

	@Override
	protected void dispatchDraw(Canvas canvas) {
		super.dispatchDraw(canvas);
		if (!HARDWARE_FADE_LAYOUT && isRefresh()) {
			drawClipMap(canvas);
			drawFadeContent(canvas);
		}
	}

	/**
	 * 지도화면 영역 페이드 처리 메뉴 영역이 아닌부분
	 * 
	 * @param canvas
	 */
	private void drawFadeContent(Canvas canvas) {
		// 메뉴 드래그 이동시 페이드 처리 여부
		if (mSlidingMenu.isFadeEnabled()) {
			final int color = Color.argb(mAbove.getFadeAlpha(), 0, 0, 0);
			final int right = mAbove.getRight() - mAbove.getCustomScrollX();
			canvas.save();
			canvas.clipRect(0, 0, mAbove.getRight(), mAbove.getBottom() - mBehind.getSelectViewHeight(), Op.DIFFERENCE);
			canvas.drawColor(color);
			canvas.restore();

			canvas.save();
			canvas.clipRect(0, mAbove.getBottom() - mBehind.getSelectViewHeight(), right, mAbove.getBottom(), Op.DIFFERENCE);
			canvas.drawColor(color);
			canvas.restore();
		}
	}

	/**
	 * OPENGL 부분 갱신을 위해 지도영역만 갱신한다.
	 * 
	 * @param canvas
	 */
	private void drawClipMap(Canvas canvas) {
		canvas.save();
		canvas.clipRect(0, 0, mAbove.getRight() - mAbove.getCustomScrollX(), mAbove.getBottom());
		mContent.draw(canvas);
		canvas.restore();
	}

	private boolean isRefresh() {
		if (mContent != null && mAbove != null && mBehind != null && mSlidingMenu != null) {
			return true;
		}
		return false;
	}
}



위에 방식처럼 번거럽게 처리 하기 싫으면 어플 자체에 하드웨어 가속처리를 넣어주면 된다 ^^

근데 그렇게 되면 겹쳐서 배치된 UI Eevent 처리가 문제 될수가 있다.