offsetLeftAndRight() 과 setTranslateX()/scrollTo() 의 차이
ViewGroup() 을 만들고, dispatchDraw() 를 override 해서 drawChild() 로 2개의 view 를 그리도록 했다.지금부터 얘기는 추측성 이야기 이다. 조금 더 확실한 정보를 얻기 위해서는 debugging 을 좀 더 해봐야 할 듯 하다.
둘 다 일정 부분으로 옮겨주는 것은 같다. 하지만 draw 되는 boundary 의 지정에 있어서 차이를 보이는 듯 하다.
둘 다 내부적으로 invalidate() 을 호출하기 때문에 onDraw() 를 호출하게 된다. 하지만 이 때 boundary 때문에 offsetLeftAndRight() 은 제대로 view 가 움직이는 모습을 보여주고, translateX()/scrollTo() 는 움직이면서 사라지는 모습을 보여주기도 한다.
근거
추측의 근거는 이렇다.아래서 보시다시피 offsetLeftAndRight() 는 invalidate() 의 범위를 지정해 주는 부분을 가지고 있다. 그런데 scrollTo() 는 그런 부분이 없다.
둘 다 이후에 draw 함수를 호출하게 되는데, draw 함수 내부에서는 Animation instance 를 처리할 때 말고는 알아서 boundary 를 정하지 않는 듯이 보인다.
그렇기 때문에 animation 의 처리는 TranslateAnimation() 같은 녀석들을 이용하는 것이 바람직 한 듯 하다.
public void offsetLeftAndRight(int offset) { if (offset != 0) { updateMatrix(); final boolean matrixIsIdentity = mTransformationInfo == null || mTransformationInfo.mMatrixIsIdentity; if (matrixIsIdentity) { final ViewParent p = mParent; if (p != null && mAttachInfo != null) { final Rect r = mAttachInfo.mTmpInvalRect; int minLeft; int maxRight; if (offset < 0) { minLeft = mLeft + offset; maxRight = mRight; } else { minLeft = mLeft; maxRight = mRight + offset; } r.set(0, 0, maxRight - minLeft, mBottom - mTop); p.invalidateChild(this, r); } } else { invalidate(false); } mLeft += offset; mRight += offset; if (!matrixIsIdentity) { mPrivateFlags |= DRAWN; // force another invalidation with the new orientation invalidate(false); } invalidateParentIfNeeded(); } }
public void scrollTo(int x, int y) { if (mScrollX != x || mScrollY != y) { int oldX = mScrollX; int oldY = mScrollY; mScrollX = x; mScrollY = y; invalidateParentCaches(); onScrollChanged(mScrollX, mScrollY, oldX, oldY); if (!awakenScrollBars()) { invalidate(true); } } }
scrollTo() 로 그렸을 때의 예
그런 이유로 2개의 view 에 각각 scroller 를 만들고 ViewGroup() 내부에서 호출을 하면, 화면에서 사라져 버린다. 아래 코드가 mHandle 이라는 녀석이 사라지는 코드이다.private Scroller mScroller= new Scroller(getContext()); private Scroller mScrollerFront; private Scroller mScrollerBehind; private int mPrevX = 0; private boolean mExpanded; private int mTotalOffset = 0; @Override protected void onFinishInflate() { mHandle = findViewById(mHandleId); if (mHandle == null) { throw new IllegalArgumentException("The handle attribute is must refer to an" + " existing child."); } mHandle.setOnClickListener(new DrawerToggler()); mContent = findViewById(mContentId); if (mContent == null) { throw new IllegalArgumentException("The content attribute is must refer to an" + " existing child."); } mScrollerFront = new Scroller(mHandle.getContext()); mScrollerBehind = new Scroller(mContent.getContext()); } public void myOpen(){ if (!mScroller.isFinished()) return; mTouchState = mScroller.isFinished() ? TOUCH_STATE_REST : TOUCH_STATE_SCROLLING; mScroller.startScroll(getScrollX(), 0, -100, 0, 5000); mExpanded = true; invalidate(); } @Override public void computeScroll() { if (mScroller.computeScrollOffset()) { scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); // mHandle.setTranslationX(offset); mHandle.scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); postInvalidate(); } } @Override protected void dispatchDraw(Canvas canvas) { final long drawingTime = getDrawingTime(); final View handle = mHandle; final boolean isVertical = mVertical; /** * order is important: * order determines the depth of the layer. */ drawChild(canvas, mContent, drawingTime); drawChild(canvas, handle, drawingTime); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { int childLeft = 0; int childWidth = 0; int childWidthHalf; // behind view childWidth = mContent.getMeasuredWidth(); childWidthHalf = childWidth /2 ; childLeft -= childWidthHalf; if (mContent.getVisibility() != View.GONE){ mContent.layout(childLeft, 0, childLeft + childWidth, mContent.getMeasuredHeight()); } // front view childLeft += childWidthHalf; childWidth = mHandle.getMeasuredWidth(); mHandle.layout(childLeft, 0, childLeft + childWidth, mHandle.getMeasuredHeight()); }
실제 실행 화면은 아래와 같다. 보기처럼 하얀색 아이콘이 움직였으나 그려지지 않는다.(정확히 얘기하면, 녹색부분을 벗어난 부분은 그려지지 않는다.) 예전에 있던 녹색 바탕만 남아있다.
하지만 이것을 offsetLeftAndRight() 로 처리하면 보인다. 코드는 귀찮아서 생략한다. (^^;)
좋은글 감사합니다 많은 도음 되었습니다.
답글삭제