IT_Programming/OpenGL

[펌] OpenGL, Surfaceview 에서 Navigation Drawer, Sliding Menu 구현시 주의사항 & DrawerLayout not working with Android 4.4 & SurfaceView

JJun ™ 2014. 3. 11. 23:30



 출처

 : http://devlsh.tistory.com/entry/OpenGL-Surfaceview-에서-Navigation-Drawer-Sliding-Menu-구현시-주의사항

 : https://stackoverflow.com/a/22402713



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


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로 분리하여서로 화면 갱신이 영향을 안받게 처리 하였다.





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


001public class FadeLayout extends ViewGroup {
002    /**
003     * 하드웨어 가속이면 true
004     */
005    private final static boolean HARDWARE_FADE_LAYOUT = false;
006 
007    public FadeLayout(Context context) {
008        super(context);
009    }
010 
011    private CustomViewAbove mAbove;
012 
013    private View mContent;
014 
015    private CustomViewBehind mBehind;
016 
017    private SlidingMenu mSlidingMenu;
018 
019    public void setBehind(CustomViewBehind mBehind) {
020        this.mBehind = mBehind;
021    }
022 
023    public void setRootView(SlidingMenu slidingMenu) {
024        this.mSlidingMenu = slidingMenu;
025    }
026 
027    public void setContent(View content) {
028        this.mContent = content;
029    }
030 
031    public void setAbove(CustomViewAbove mAbove) {
032        this.mAbove = mAbove;
033    }
034 
035    /**
036     * 하드웨어 가속 여부
037     *
038     * @return
039     */
040    public boolean isHardwareaccelerated() {
041        return HARDWARE_FADE_LAYOUT;
042    }
043 
044    @Override
045    protected void onLayout(boolean changed, int l, int t, int r, int b) {
046    }
047 
048    @Override
049    public void draw(Canvas canvas) {
050        super.draw(canvas);
051    }
052 
053    @Override
054    protected void dispatchDraw(Canvas canvas) {
055        super.dispatchDraw(canvas);
056        if (!HARDWARE_FADE_LAYOUT && isRefresh()) {
057            drawClipMap(canvas);
058            drawFadeContent(canvas);
059        }
060    }
061 
062    /**
063     * 지도화면 영역 페이드 처리 메뉴 영역이 아닌 부분
064     *
065     * @param canvas
066     */
067    private void drawFadeContent(Canvas canvas) {
068        // 메뉴 드래그 이동시 페이드 처리 여부
069        if (mSlidingMenu.isFadeEnabled()) {
070            final int color = Color.argb(mAbove.getFadeAlpha(), 000);
071            final int right = mAbove.getRight() - mAbove.getCustomScrollX();
072            canvas.save();
073            canvas.clipRect(00, mAbove.getRight(), mAbove.getBottom() - mBehind.getSelectViewHeight(), Op.DIFFERENCE);
074            canvas.drawColor(color);
075            canvas.restore();
076 
077            canvas.save();
078            canvas.clipRect(0, mAbove.getBottom() - mBehind.getSelectViewHeight(), right, mAbove.getBottom(), Op.DIFFERENCE);
079            canvas.drawColor(color);
080            canvas.restore();
081        }
082    }
083 
084    /**
085     * OPENGL 부분 갱신을 위해 지도영역만 갱신한다.
086     *
087     * @param canvas
088     */
089    private void drawClipMap(Canvas canvas) {
090        canvas.save();
091        canvas.clipRect(00, mAbove.getRight() - mAbove.getCustomScrollX(), mAbove.getBottom());
092        mContent.draw(canvas);
093        canvas.restore();
094    }
095 
096    private boolean isRefresh() {
097        if (mContent != null && mAbove != null && mBehind != null && mSlidingMenu != null) {
098            return true;
099        }
100        return false;
101    }
102}



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

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







DrawerLayout not working with Android 4.4 & SurfaceView



Have you tried using implementing onDrawerSlide on the drawerListener of the drawerLayour
like this

@Override
public void onDrawerSlide(View drawerView, float slideOffset)
{
    super.onDrawerSlide(drawerView, slideOffset);
    mDrawerLayout.bringChildToFront(drawerView);
    mDrawerLayout.requestLayout();
}