public override void draw(android.graphics.Canvas canvas) { if (mPicture != null) { android.graphics.Rect bounds = getBounds(); canvas.save(); canvas.clipRect(bounds); canvas.translate(bounds.left, bounds.top); canvas.drawPicture(mPicture); canvas.restore(); } }
/// <summary>Draw one child of this View Group.</summary> /// <remarks> /// Draw one child of this View Group. This method is responsible for getting /// the canvas in the right state. This includes clipping, translating so /// that the child's scrolled origin is at 0, 0, and applying any animation /// transformations. /// </remarks> /// <param name="canvas">The canvas on which to draw the child</param> /// <param name="child">Who to draw</param> /// <param name="drawingTime">The time at which draw is occuring</param> /// <returns>True if an invalidate() was issued</returns> protected internal virtual bool drawChild(android.graphics.Canvas canvas, android.view.View child, long drawingTime) { bool more = false; int cl = child.mLeft; int ct = child.mTop; int cr = child.mRight; int cb = child.mBottom; bool childHasIdentityMatrix = child.hasIdentityMatrix(); int flags = mGroupFlags; if ((flags & FLAG_CLEAR_TRANSFORMATION) == FLAG_CLEAR_TRANSFORMATION) { mChildTransformation.clear(); mGroupFlags &= ~FLAG_CLEAR_TRANSFORMATION; } android.view.animation.Transformation transformToApply = null; android.view.animation.Transformation invalidationTransform; android.view.animation.Animation a = child.getAnimation(); bool concatMatrix = false; bool scalingRequired = false; bool caching; int layerType = mDrawLayers ? child.getLayerType() : LAYER_TYPE_NONE; bool hardwareAccelerated = canvas.isHardwareAccelerated(); if ((flags & FLAG_CHILDREN_DRAWN_WITH_CACHE) == FLAG_CHILDREN_DRAWN_WITH_CACHE || (flags & FLAG_ALWAYS_DRAWN_WITH_CACHE) == FLAG_ALWAYS_DRAWN_WITH_CACHE) { caching = true; if (mAttachInfo != null) { scalingRequired = mAttachInfo.mScalingRequired; } } else { caching = (layerType != LAYER_TYPE_NONE) || hardwareAccelerated; } if (a != null) { bool initialized = a.isInitialized(); if (!initialized) { a.initialize(cr - cl, cb - ct, getWidth(), getHeight()); a.initializeInvalidateRegion(0, 0, cr - cl, cb - ct); child.onAnimationStart(); } more = a.getTransformation(drawingTime, mChildTransformation, scalingRequired ? mAttachInfo .mApplicationScale : 1f); if (scalingRequired && mAttachInfo.mApplicationScale != 1f) { if (mInvalidationTransformation == null) { mInvalidationTransformation = new android.view.animation.Transformation(); } invalidationTransform = mInvalidationTransformation; a.getTransformation(drawingTime, invalidationTransform, 1f); } else { invalidationTransform = mChildTransformation; } transformToApply = mChildTransformation; concatMatrix = a.willChangeTransformationMatrix(); if (more) { if (!a.willChangeBounds()) { if ((flags & (FLAG_OPTIMIZE_INVALIDATE | FLAG_ANIMATION_DONE)) == FLAG_OPTIMIZE_INVALIDATE) { mGroupFlags |= FLAG_INVALIDATE_REQUIRED; } else { if ((flags & FLAG_INVALIDATE_REQUIRED) == 0) { // The child need to draw an animation, potentially offscreen, so // make sure we do not cancel invalidate requests mPrivateFlags |= DRAW_ANIMATION; invalidate(cl, ct, cr, cb); } } } else { if (mInvalidateRegion == null) { mInvalidateRegion = new android.graphics.RectF(); } android.graphics.RectF region = mInvalidateRegion; a.getInvalidateRegion(0, 0, cr - cl, cb - ct, region, invalidationTransform); // The child need to draw an animation, potentially offscreen, so // make sure we do not cancel invalidate requests mPrivateFlags |= DRAW_ANIMATION; int left = cl + (int)region.left; int top = ct + (int)region.top; invalidate(left, top, left + (int)(region.width() + .5f), top + (int)(region.height () + .5f)); } } } else { if ((flags & FLAG_SUPPORT_STATIC_TRANSFORMATIONS) == FLAG_SUPPORT_STATIC_TRANSFORMATIONS) { bool hasTransform = getChildStaticTransformation(child, mChildTransformation); if (hasTransform) { int transformType = mChildTransformation.getTransformationType(); transformToApply = transformType != android.view.animation.Transformation.TYPE_IDENTITY ? mChildTransformation : null; concatMatrix = (transformType & android.view.animation.Transformation.TYPE_MATRIX ) != 0; } } } concatMatrix |= !childHasIdentityMatrix; // Sets the flag as early as possible to allow draw() implementations // to call invalidate() successfully when doing animations child.mPrivateFlags |= DRAWN; if (!concatMatrix && canvas.quickReject(cl, ct, cr, cb, android.graphics.Canvas.EdgeType .BW) && (child.mPrivateFlags & DRAW_ANIMATION) == 0) { return more; } float alpha = child.getAlpha(); // Bail out early if the view does not need to be drawn if (alpha <= android.view.ViewConfiguration.ALPHA_THRESHOLD && (child.mPrivateFlags & ALPHA_SET) == 0 && !(child is android.view.SurfaceView)) { return more; } if (hardwareAccelerated) { // Clear INVALIDATED flag to allow invalidation to occur during rendering, but // retain the flag's value temporarily in the mRecreateDisplayList flag child.mRecreateDisplayList = (child.mPrivateFlags & INVALIDATED) == INVALIDATED; child.mPrivateFlags &= ~INVALIDATED; } child.computeScroll(); int sx = child.mScrollX; int sy = child.mScrollY; android.view.DisplayList displayList = null; android.graphics.Bitmap cache = null; bool hasDisplayList = false; if (caching) { if (!hardwareAccelerated) { if (layerType != LAYER_TYPE_NONE) { layerType = LAYER_TYPE_SOFTWARE; child.buildDrawingCache(true); } cache = child.getDrawingCache(true); } else { switch (layerType) { case LAYER_TYPE_SOFTWARE: { child.buildDrawingCache(true); cache = child.getDrawingCache(true); break; } case LAYER_TYPE_NONE: { // Delay getting the display list until animation-driven alpha values are // set up and possibly passed on to the view hasDisplayList = child.canHaveDisplayList(); break; } } } } bool hasNoCache = cache == null || hasDisplayList; bool offsetForScroll = cache == null && !hasDisplayList && layerType != LAYER_TYPE_HARDWARE; int restoreTo = canvas.save(); if (offsetForScroll) { canvas.translate(cl - sx, ct - sy); } else { canvas.translate(cl, ct); if (scalingRequired) { // mAttachInfo cannot be null, otherwise scalingRequired == false float scale = 1.0f / mAttachInfo.mApplicationScale; canvas.scale(scale, scale); } } if (transformToApply != null || alpha < 1.0f || !child.hasIdentityMatrix()) { if (transformToApply != null || !childHasIdentityMatrix) { int transX = 0; int transY = 0; if (offsetForScroll) { transX = -sx; transY = -sy; } if (transformToApply != null) { if (concatMatrix) { // Undo the scroll translation, apply the transformation matrix, // then redo the scroll translate to get the correct result. canvas.translate(-transX, -transY); canvas.concat(transformToApply.getMatrix()); canvas.translate(transX, transY); mGroupFlags |= FLAG_CLEAR_TRANSFORMATION; } float transformAlpha = transformToApply.getAlpha(); if (transformAlpha < 1.0f) { alpha *= transformToApply.getAlpha(); mGroupFlags |= FLAG_CLEAR_TRANSFORMATION; } } if (!childHasIdentityMatrix) { canvas.translate(-transX, -transY); canvas.concat(child.getMatrix()); canvas.translate(transX, transY); } } if (alpha < 1.0f) { mGroupFlags |= FLAG_CLEAR_TRANSFORMATION; if (hasNoCache) { int multipliedAlpha = (int)(255 * alpha); if (!child.onSetAlpha(multipliedAlpha)) { int layerFlags = android.graphics.Canvas.HAS_ALPHA_LAYER_SAVE_FLAG; if ((flags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN || layerType != LAYER_TYPE_NONE) { layerFlags |= android.graphics.Canvas.CLIP_TO_LAYER_SAVE_FLAG; } if (layerType == LAYER_TYPE_NONE) { int scrollX = hasDisplayList ? 0 : sx; int scrollY = hasDisplayList ? 0 : sy; canvas.saveLayerAlpha(scrollX, scrollY, scrollX + cr - cl, scrollY + cb - ct, multipliedAlpha , layerFlags); } } else { // Alpha is handled by the child directly, clobber the layer's alpha child.mPrivateFlags |= ALPHA_SET; } } } } else { if ((child.mPrivateFlags & ALPHA_SET) == ALPHA_SET) { child.onSetAlpha(255); child.mPrivateFlags &= ~ALPHA_SET; } } if ((flags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN) { if (offsetForScroll) { canvas.clipRect(sx, sy, sx + (cr - cl), sy + (cb - ct)); } else { if (!scalingRequired || cache == null) { canvas.clipRect(0, 0, cr - cl, cb - ct); } else { canvas.clipRect(0, 0, cache.getWidth(), cache.getHeight()); } } } if (hasDisplayList) { displayList = child.getDisplayList(); if (!displayList.isValid()) { // Uncommon, but possible. If a view is removed from the hierarchy during the call // to getDisplayList(), the display list will be marked invalid and we should not // try to use it again. displayList = null; hasDisplayList = false; } } if (hasNoCache) { bool layerRendered = false; if (layerType == LAYER_TYPE_HARDWARE) { android.view.HardwareLayer layer = child.getHardwareLayer(); if (layer != null && layer.isValid()) { child.mLayerPaint.setAlpha((int)(alpha * 255)); ((android.view.HardwareCanvas)canvas).drawHardwareLayer(layer, 0, 0, child.mLayerPaint ); layerRendered = true; } else { int scrollX = hasDisplayList ? 0 : sx; int scrollY = hasDisplayList ? 0 : sy; canvas.saveLayer(scrollX, scrollY, scrollX + cr - cl, scrollY + cb - ct, child.mLayerPaint , android.graphics.Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | android.graphics.Canvas.CLIP_TO_LAYER_SAVE_FLAG ); } } if (!layerRendered) { if (!hasDisplayList) { // Fast path for layouts with no backgrounds if ((child.mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) { child.mPrivateFlags &= ~DIRTY_MASK; child.dispatchDraw(canvas); } else { child.draw(canvas); } } else { child.mPrivateFlags &= ~DIRTY_MASK; ((android.view.HardwareCanvas)canvas).drawDisplayList(displayList, cr - cl, cb - ct, null); } } } else { if (cache != null) { child.mPrivateFlags &= ~DIRTY_MASK; android.graphics.Paint cachePaint; if (layerType == LAYER_TYPE_NONE) { cachePaint = mCachePaint; if (alpha < 1.0f) { cachePaint.setAlpha((int)(alpha * 255)); mGroupFlags |= FLAG_ALPHA_LOWER_THAN_ONE; } else { if ((flags & FLAG_ALPHA_LOWER_THAN_ONE) == FLAG_ALPHA_LOWER_THAN_ONE) { cachePaint.setAlpha(255); mGroupFlags &= ~FLAG_ALPHA_LOWER_THAN_ONE; } } } else { cachePaint = child.mLayerPaint; cachePaint.setAlpha((int)(alpha * 255)); } canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint); } } canvas.restoreToCount(restoreTo); if (a != null && !more) { if (!hardwareAccelerated && !a.getFillAfter()) { child.onSetAlpha(255); } finishAnimatingView(child, a); } if (more && hardwareAccelerated) { // invalidation is the trigger to recreate display lists, so if we're using // display lists to render, force an invalidate to allow the animation to // continue drawing another frame invalidate(true); if (a.hasAlpha() && (child.mPrivateFlags & ALPHA_SET) == ALPHA_SET) { // alpha animations should cause the child to recreate its display list child.invalidate(true); } } child.mRecreateDisplayList = false; return more; }
protected internal override void dispatchDraw(android.graphics.Canvas canvas) { int count = mChildrenCount; android.view.View[] children = mChildren; int flags = mGroupFlags; if ((flags & FLAG_RUN_ANIMATION) != 0 && canAnimate()) { bool cache = (mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE; bool buildCache = !isHardwareAccelerated(); { for (int i = 0; i < count; i++) { android.view.View child = children[i]; if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) { android.view.ViewGroup.LayoutParams @params = child.getLayoutParams(); attachLayoutAnimationParameters(child, @params, i, count); bindLayoutAnimation(child); if (cache) { child.setDrawingCacheEnabled(true); if (buildCache) { child.buildDrawingCache(true); } } } } } android.view.animation.LayoutAnimationController controller = mLayoutAnimationController; if (controller.willOverlap()) { mGroupFlags |= FLAG_OPTIMIZE_INVALIDATE; } controller.start(); mGroupFlags &= ~FLAG_RUN_ANIMATION; mGroupFlags &= ~FLAG_ANIMATION_DONE; if (cache) { mGroupFlags |= FLAG_CHILDREN_DRAWN_WITH_CACHE; } if (mAnimationListener != null) { mAnimationListener.onAnimationStart(controller.getAnimation()); } } int saveCount = 0; bool clipToPadding = (flags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK; if (clipToPadding) { saveCount = canvas.save(); canvas.clipRect(mScrollX + mPaddingLeft, mScrollY + mPaddingTop, mScrollX + mRight - mLeft - mPaddingRight, mScrollY + mBottom - mTop - mPaddingBottom); } mPrivateFlags &= ~DRAW_ANIMATION; mGroupFlags &= ~FLAG_INVALIDATE_REQUIRED; bool more = false; long drawingTime = getDrawingTime(); if ((flags & FLAG_USE_CHILD_DRAWING_ORDER) == 0) { { for (int i = 0; i < count; i++) { android.view.View child = children[i]; if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) { more |= drawChild(canvas, child, drawingTime); } } } } else { { for (int i = 0; i < count; i++) { android.view.View child = children[getChildDrawingOrder(count, i)]; if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) { more |= drawChild(canvas, child, drawingTime); } } } } if (mDisappearingChildren != null) { java.util.ArrayList<android.view.View> disappearingChildren = mDisappearingChildren; int disappearingCount = disappearingChildren.size() - 1; { for (int i = disappearingCount; i >= 0; i--) { android.view.View child = disappearingChildren.get(i); more |= drawChild(canvas, child, drawingTime); } } } if (clipToPadding) { canvas.restoreToCount(saveCount); } flags = mGroupFlags; if ((flags & FLAG_INVALIDATE_REQUIRED) == FLAG_INVALIDATE_REQUIRED) { invalidate(true); } if ((flags & FLAG_ANIMATION_DONE) == 0 && (flags & FLAG_NOTIFY_ANIMATION_LISTENER ) == 0 && mLayoutAnimationController.isDone() && !more) { mGroupFlags |= FLAG_NOTIFY_ANIMATION_LISTENER; java.lang.Runnable end = new _Runnable_2535(this); post(end); } }
public override void draw(android.graphics.Canvas canvas) { if (mClipState.mDrawable.getLevel() == 0) { return; } android.graphics.Rect r = mTmpRect; android.graphics.Rect bounds = getBounds(); int level = getLevel(); int w = bounds.width(); int iw = 0; //mClipState.mDrawable.getIntrinsicWidth(); if ((mClipState.mOrientation & HORIZONTAL) != 0) { w -= (w - iw) * (10000 - level) / 10000; } int h = bounds.height(); int ih = 0; //mClipState.mDrawable.getIntrinsicHeight(); if ((mClipState.mOrientation & VERTICAL) != 0) { h -= (h - ih) * (10000 - level) / 10000; } int layoutDirection = getResolvedLayoutDirectionSelf(); android.view.Gravity.apply(mClipState.mGravity, w, h, bounds, r, layoutDirection); if (w > 0 && h > 0) { canvas.save(); canvas.clipRect(r); mClipState.mDrawable.draw(canvas); canvas.restore(); } }
protected internal override void onDraw(android.graphics.Canvas canvas) { if (mSelectorWheelState == SELECTOR_WHEEL_STATE_NONE) { return; } float x = (mRight - mLeft) / 2; float y = mCurrentScrollOffset; int restoreCount = canvas.save(); if (mSelectorWheelState == SELECTOR_WHEEL_STATE_SMALL) { android.graphics.Rect clipBounds = canvas.getClipBounds(); clipBounds.inset(0, mSelectorElementHeight); canvas.clipRect(clipBounds); } // draw the selector wheel int[] selectorIndices = mSelectorIndices; { for (int i = 0; i < selectorIndices.Length; i++) { int selectorIndex = selectorIndices[i]; string scrollSelectorValue = mSelectorIndexToStringCache.get(selectorIndex); // Do not draw the middle item if input is visible since the input is shown only // if the wheel is static and it covers the middle item. Otherwise, if the user // starts editing the text via the IME he may see a dimmed version of the old // value intermixed with the new one. if (i != SELECTOR_MIDDLE_ITEM_INDEX || mInputText.getVisibility() != VISIBLE) { canvas.drawText(scrollSelectorValue, x, y, mSelectorWheelPaint); } y += mSelectorElementHeight; } } // draw the selection dividers (only if scrolling and drawable specified) if (mSelectionDivider != null) { // draw the top divider int topOfTopDivider = (getHeight() - mSelectorElementHeight - mSelectionDividerHeight ) / 2; int bottomOfTopDivider = topOfTopDivider + mSelectionDividerHeight; mSelectionDivider.setBounds(0, topOfTopDivider, mRight, bottomOfTopDivider); mSelectionDivider.draw(canvas); // draw the bottom divider int topOfBottomDivider = topOfTopDivider + mSelectorElementHeight; int bottomOfBottomDivider = bottomOfTopDivider + mSelectorElementHeight; mSelectionDivider.setBounds(0, topOfBottomDivider, mRight, bottomOfBottomDivider); mSelectionDivider.draw(canvas); } canvas.restoreToCount(restoreCount); }
protected internal override void dispatchDraw(android.graphics.Canvas canvas) { bool expandClipRegion = false; canvas.getClipBounds(stackInvalidateRect); int childCount = getChildCount(); { for (int i = 0; i < childCount; i++) { android.view.View child = getChildAt(i); android.widget.StackView.LayoutParams lp = (android.widget.StackView.LayoutParams )child.getLayoutParams(); if ((lp.horizontalOffset == 0 && lp.verticalOffset == 0) || child.getAlpha() == 0f || child.getVisibility() != VISIBLE) { lp.resetInvalidateRect(); } android.graphics.Rect childInvalidateRect = lp.getInvalidateRect(); if (!childInvalidateRect.isEmpty()) { expandClipRegion = true; stackInvalidateRect.union(childInvalidateRect); } } } // We only expand the clip bounds if necessary. if (expandClipRegion) { canvas.save(android.graphics.Canvas.CLIP_SAVE_FLAG); canvas.clipRect(stackInvalidateRect, android.graphics.Region.Op.UNION); base.dispatchDraw(canvas); canvas.restore(); } else { base.dispatchDraw(canvas); } }
protected internal override void onDraw(android.graphics.Canvas canvas) { base.onDraw(canvas); if (mDrawable == null) { return; } // couldn't resolve the URI if (mDrawableWidth == 0 || mDrawableHeight == 0) { return; } // nothing to draw (empty bounds) if (mDrawMatrix == null && mPaddingTop == 0 && mPaddingLeft == 0) { mDrawable.draw(canvas); } else { int saveCount = canvas.getSaveCount(); canvas.save(); if (mCropToPadding) { int scrollX = mScrollX; int scrollY = mScrollY; canvas.clipRect(scrollX + mPaddingLeft, scrollY + mPaddingTop, scrollX + mRight - mLeft - mPaddingRight, scrollY + mBottom - mTop - mPaddingBottom); } canvas.translate(mPaddingLeft, mPaddingTop); if (mDrawMatrix != null) { canvas.concat(mDrawMatrix); } mDrawable.draw(canvas); canvas.restoreToCount(saveCount); } }