/** 向左滑动,根据上面我们知道向左滑动为正值 */ private void scrollLeft() { removeDirection = RemoveDirection.LEFT; final int delta = (screenWidth - itemView.getScrollX()); // 调用startScroll方法来设置一些滚动的参数,我们在computeScroll()方法中调用scrollTo来滚动item scroller.startScroll(itemView.getScrollX(), 0, delta, 0, Math.abs(delta)); postInvalidate(); // 刷新itemView }
@Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_MOVE: int moveX = (int) event.getRawX(); int deltaX = tempX - moveX; tempX = moveX; if (moveX - downX > mTouchSlop && Math.abs((int) event.getRawY() - downY) < mTouchSlop) { isSilding = true; } if (moveX - downX >= 0 && isSilding) { mContentView.scrollBy(deltaX, 0); } break; case MotionEvent.ACTION_UP: isSilding = false; if (mContentView.getScrollX() <= -viewWidth / 2) { isFinish = true; scrollRight(); } else if (mContentView.getScrollX() >= viewWidth / 2) { isFinish = true; } else { scrollOrigin(); isFinish = false; } break; } return true; }
/** * 自定义移动距离 * * @param event * @return */ @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_MOVE: int moveX = (int) event.getRawX(); int deltaX = tempX - moveX; tempX = moveX; System.out.println("downX:" + downX); // downX为移动的最初点 if (moveX - downX > mTouchSlop && Math.abs((int) event.getRawY() - downY) < mTouchSlop) { isSilding = true; } // 慢慢滑动看不到效果滑动?? 设置项目的样式为半透明的样式,再设置布局的背景 if (moveX - downX >= 0 && isSilding) { mContentView.scrollBy(deltaX, 0); } break; case MotionEvent.ACTION_UP: isSilding = false; System.out.println(mContentView.getScrollX()); if (mContentView.getScrollX() <= -viewWidth / 20) { isFinish = true; scrollRight(); } else { scrollOrigin(); isFinish = false; } break; } return true; }
@Override public boolean onTouchEvent(MotionEvent event) { int x = (int) event.getX(); int y = (int) event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: lastX = (int) event.getX(); lastY = (int) event.getY(); break; case MotionEvent.ACTION_MOVE: int offsetX = x - lastX; int offsetY = y - lastY; ((View) getParent()).scrollBy(-offsetX, -offsetY); break; case MotionEvent.ACTION_UP: // 手指离开时,执行滑动过程 View viewGroup = ((View) getParent()); ScrollerHelper.getScroller() .startScroll( viewGroup.getScrollX(), viewGroup.getScrollY(), -viewGroup.getScrollX(), -viewGroup.getScrollY()); invalidate(); break; } return true; }
/** 往右滑动 */ private void scrollToRight() { removeDirection = RemoveDirection.RIGHT; // 方向向右 final int delta = (screenWidth + itemView.getScrollX()); // 调用startScroll方法来设置一些滚动的参数,在computeScroll()方法中调用scrollTo来滚动item scroller.startScroll(itemView.getScrollX(), 0, -delta, 0, Math.abs(delta)); postInvalidate(); // 刷新itemView }
@Override public boolean onInterceptTouchEvent(View view, MotionEvent event) { // We need to account for scroll state for the touched view otherwise // tapping on an "empty" part of the view will still be considered a // valid touch event. if (view.getScrollX() != 0 || view.getScrollY() != 0) { Rect rect = new Rect(); view.getHitRect(rect); rect.offset(-view.getScrollX(), -view.getScrollY()); int[] viewCoords = new int[2]; view.getLocationOnScreen(viewCoords); int x = (int) event.getRawX() - viewCoords[0]; int y = (int) event.getRawY() - viewCoords[1]; if (!rect.contains(x, y)) return false; } // If the tab tray is showing, hide the tab tray and don't send the event to content. if (event.getActionMasked() == MotionEvent.ACTION_DOWN && autoHideTabs()) { mIsHidingTabs = true; return true; } return false; }
/** 向左滑动 左正右负 */ private void scrollToLeft() { removeDirection = RemoveDirection.LEFT; final int delta = (screenWidth - itemView.getScrollX()); // 调用startScroll方法来设置一些滚动的参数,在computeScroll()方法中调用scrollTo来滚动item // 由(startX , startY)在duration时间内前进(dx,dy)个单位,即到达坐标为(startX+dx , startY+dy)出 scroller.startScroll(itemView.getScrollX(), itemView.getScrollY(), delta, 0, Math.abs(delta)); postInvalidate(); // 刷新itemView 会调用computeScroll()方法 }
public static void invalidate(View view) { m_tempRect.set( view.getScrollX(), view.getScrollY(), view.getScrollX() + view.getWidth(), view.getScrollY() + view.getHeight()); view.invalidate(m_tempRect); }
/** 根据手指滚动itemView的距离来判断是滚动到开始位置还是向左或者向右滚动 */ private void scrollByDistanceX() { // 如果向左滚动的距离大于屏幕的二分之一,就让其删除 if (itemView.getScrollX() >= screenWidth / 2) { scrollLeft(); } else if (itemView.getScrollX() <= -screenWidth / 2) { scrollRight(); } else { // 滚回到原始位置 scrollBack(); } }
/** 根据手指滚动itemView的距离来判断是滚动到开始位置还是向左或者向右滚动 */ private void scrollByDistanceX() { // 如果向左滑动的距离大于屏幕的三分之一,让其删除 if (itemView.getScrollX() >= screenWidth / 3) { scrollLeft(); } else if (itemView.getScrollX() <= -screenWidth / 3) { scrollRight(); } else { // 滚回到原始位置 itemView.scrollTo(0, 0); } }
/** 慢速状态下————>判断滑动方向 */ private void scrollByDistanceX() { // 如果向左滚动的距离大于屏幕的二分之一,就让其删除 if (itemView.getScrollX() >= screenWidth / 2) { scrollToLeft(); } else if (itemView.getScrollX() <= -screenWidth / 2) { scrollToRight(); } else { // 滚回到原始位置,为了偷下懒这里是直接调用scrollTo滚动 itemView.scrollTo(0, 0); } }
/** * 判断是否可以滑动 * * @param event * @return */ private boolean canScroll(MotionEvent event) { // LeeLog.p("content scrollX" + mContentView.getScrollX()); switch (mSlideOrientation) { case SLIDING_LEFT: if (mContentView.getScrollX() == 0) return (event.getX() - oldX) < 0; return mContentView.getScrollX() > 0; case SLIDING_RIGHT: if (mContentView.getScrollX() == 0) return (event.getX() - oldX) > 0; return mContentView.getScrollX() < 0; case SLIDING_LEFT_RIGHT: return true; default: return true; } }
private static boolean isTouchEventHandled(final View view, final MotionEvent event) { if (view instanceof RightPaneBackgroundView) return false; if (!(view instanceof ViewGroup)) return true; final MotionEvent ev = MotionEvent.obtain(event); final float xf = ev.getX(); final float yf = ev.getY(); final float scrolledXFloat = xf + view.getScrollX(); final float scrolledYFloat = yf + view.getScrollY(); final Rect frame = new Rect(); final int scrolledXInt = (int) scrolledXFloat; final int scrolledYInt = (int) scrolledYFloat; final int count = ((ViewGroup) view).getChildCount(); for (int i = count - 1; i >= 0; i--) { final View child = ((ViewGroup) view).getChildAt(i); if (child.isShown() || child.getAnimation() != null) { child.getHitRect(frame); if (frame.contains(scrolledXInt, scrolledYInt)) { // offset the event to the view's coordinate system final float xc = scrolledXFloat - child.getLeft(); final float yc = scrolledYFloat - child.getTop(); ev.setLocation(xc, yc); if (isTouchEventHandled(child, ev)) return true; } } } return false; }
private MemberChip constructChipSpan(User user, int offset, boolean pressed) { LayoutInflater lf = (LayoutInflater) getContext().getSystemService(Activity.LAYOUT_INFLATER_SERVICE); View clipView = lf.inflate(R.layout.member_clip, null); ((TextView) clipView.findViewById(R.id.member_clip)).setText(user.name); int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); clipView.measure(spec, spec); clipView.layout(0, 0, clipView.getMeasuredWidth(), clipView.getMeasuredHeight()); Bitmap b = Bitmap.createBitmap(clipView.getWidth(), clipView.getHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(b); canvas.translate(-clipView.getScrollX(), -clipView.getScrollY()); clipView.draw(canvas); clipView.setDrawingCacheEnabled(true); Bitmap cacheBmp = clipView.getDrawingCache(); Bitmap viewBmp = cacheBmp.copy(Bitmap.Config.ARGB_8888, true); clipView.destroyDrawingCache(); Drawable result = new BitmapDrawable(getResources(), viewBmp); result.setBounds(0, 0, viewBmp.getWidth(), viewBmp.getHeight()); MemberChip chip = new MemberChip(result, user); return chip; }
/** Inverse of {@link #getDescendantCoordRelativeToSelf(View, int[])}. */ public static float mapCoordInSelfToDescendent(View descendant, View root, int[] coord) { ArrayList<View> ancestorChain = new ArrayList<View>(); float[] pt = {coord[0], coord[1]}; View v = descendant; while (v != root) { ancestorChain.add(v); v = (View) v.getParent(); } ancestorChain.add(root); float scale = 1.0f; Matrix inverse = new Matrix(); int count = ancestorChain.size(); for (int i = count - 1; i >= 0; i--) { View ancestor = ancestorChain.get(i); View next = i > 0 ? ancestorChain.get(i - 1) : null; pt[0] += ancestor.getScrollX(); pt[1] += ancestor.getScrollY(); if (next != null) { pt[0] -= next.getLeft(); pt[1] -= next.getTop(); next.getMatrix().invert(inverse); inverse.mapPoints(pt); scale *= next.getScaleX(); } } coord[0] = (int) Math.round(pt[0]); coord[1] = (int) Math.round(pt[1]); return scale; }
/** * Given a coordinate relative to the descendant, find the coordinate in a parent view's * coordinates. * * @param descendant The descendant to which the passed coordinate is relative. * @param root The root view to make the coordinates relative to. * @param coord The coordinate that we want mapped. * @param includeRootScroll Whether or not to account for the scroll of the descendant: sometimes * this is relevant as in a child's coordinates within the descendant. * @return The factor by which this descendant is scaled relative to this DragLayer. Caution this * scale factor is assumed to be equal in X and Y, and so if at any point this assumption * fails, we will need to return a pair of scale factors. */ public static float getDescendantCoordRelativeToParent( View descendant, View root, int[] coord, boolean includeRootScroll) { ArrayList<View> ancestorChain = new ArrayList<View>(); float[] pt = {coord[0], coord[1]}; View v = descendant; while (v != root && v != null) { ancestorChain.add(v); v = (View) v.getParent(); } ancestorChain.add(root); float scale = 1.0f; int count = ancestorChain.size(); for (int i = 0; i < count; i++) { View v0 = ancestorChain.get(i); // For TextViews, scroll has a meaning which relates to the text position // which is very strange... ignore the scroll. if (v0 != descendant || includeRootScroll) { pt[0] -= v0.getScrollX(); pt[1] -= v0.getScrollY(); } v0.getMatrix().mapPoints(pt); pt[0] += v0.getLeft(); pt[1] += v0.getTop(); scale *= v0.getScaleX(); } coord[0] = (int) Math.round(pt[0]); coord[1] = (int) Math.round(pt[1]); return scale; }
private void initSlideMode() { mCloseOnRelease = false; View v = getChildAt(1); if (mMode == MODE_READY) { mStartOffset = 0; mEndOffset = mDirection * getChildAt(0).getWidth(); } else { mStartOffset = mDirection * getChildAt(0).getWidth(); mEndOffset = 0; } mOffset = mStartOffset; if (mCachedBitmap == null || mCachedBitmap.isRecycled() || mCachedBitmap.getWidth() != v.getWidth()) { mCachedBitmap = Bitmap.createBitmap(v.getWidth(), v.getHeight(), Bitmap.Config.ARGB_8888); mCachedCanvas = new Canvas(mCachedBitmap); } else { mCachedCanvas.drawColor(Color.TRANSPARENT, Mode.CLEAR); } v.setVisibility(View.VISIBLE); mCachedCanvas.translate(-v.getScrollX(), -v.getScrollY()); v.draw(mCachedCanvas); mMode = MODE_SLIDE; mMenuView.setVisibility(View.VISIBLE); }
@Override public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) { // offset into coordinate space of this scroll view rectangle.offset(child.getLeft() - child.getScrollX(), child.getTop() - child.getScrollY()); return scrollToChildRect(rectangle, immediate); }
@Test public void shouldScrollTo() throws Exception { view.scrollTo(7, 6); assertEquals(7, view.getScrollX()); assertEquals(6, view.getScrollY()); }
public static Bitmap capture( View view, float width, float height, boolean scroll, Bitmap.Config config) { if (!view.isDrawingCacheEnabled()) view.setDrawingCacheEnabled(true); Bitmap bitmap = Bitmap.createBitmap((int) width, (int) height, config); bitmap.eraseColor(Color.WHITE); Canvas canvas = new Canvas(bitmap); int left = view.getLeft(); int top = view.getTop(); if (scroll) { left = view.getScrollX(); top = view.getScrollY(); } int status = canvas.save(); canvas.translate(-left, -top); float scale = width / view.getWidth(); canvas.scale(scale, scale, left, top); view.draw(canvas); canvas.restoreToCount(status); Paint alphaPaint = new Paint(); alphaPaint.setColor(Color.TRANSPARENT); canvas.drawRect(0f, 0f, 1f, height, alphaPaint); canvas.drawRect(width - 1f, 0f, width, height, alphaPaint); canvas.drawRect(0f, 0f, width, 1f, alphaPaint); canvas.drawRect(0f, height - 1f, width, height, alphaPaint); canvas.setBitmap(null); return bitmap; }
public int getScrollX() { View view = mView.get(); if (view == null) { return 0; } return view.getScrollX(); }
/** * Crop the image based on the position of the view on the window. Either the View or one of its * ancestors might have scrolled or translated. This value should be taken into account while * mapping the View to the Bitmap. * * @param view The view requesting a cropped bitmap. */ private Bitmap getCroppedBitmap(View view) { if (mBitmap == null || view == null) { return null; } // Get the global position of the view on the entire screen. Rect rect = new Rect(); view.getGlobalVisibleRect(rect); // Get the activity's window position. This does an IPC call, may be expensive. Rect window = new Rect(); view.getWindowVisibleDisplayFrame(window); // Calculate the coordinates for the cropped bitmap. int screenWidth = view.getContext().getResources().getDisplayMetrics().widthPixels; int left = mBitmap.getWidth() - screenWidth + rect.left; int right = mBitmap.getWidth() - screenWidth + rect.right; int top = rect.top - window.top; int bottom = rect.bottom - window.top; int offsetX = 0; int offsetY = 0; // Find if this view or any of its ancestors has been translated or scrolled. ViewParent parent; View curView = view; do { offsetX += (int) curView.getTranslationX() - curView.getScrollX(); offsetY += (int) curView.getTranslationY() - curView.getScrollY(); parent = curView.getParent(); if (parent instanceof View) { curView = (View) parent; } } while (parent instanceof View); // Adjust the coordinates for the offset. left -= offsetX; right -= offsetX; top -= offsetY; bottom -= offsetY; // The either the required height may be less than the available image height or more than it. // If the height required is more, crop only the available portion on the image. int width = right - left; int height = (bottom > mBitmap.getHeight() ? mBitmap.getHeight() - top : bottom - top); // There is a chance that the view is not visible or doesn't fall within the phone's size. // In this case, 'rect' will have all values as '0'. Hence 'top' and 'bottom' may be negative, // and createBitmap() will fail. // The view will get a background in its next layout pass. try { return Bitmap.createBitmap(mBitmap, left, top, width, height); } catch (Exception e) { return null; } }
private boolean canScrollUp(View view, float x, float y) { if (view instanceof ViewGroup) { ViewGroup vg = (ViewGroup) view; for (int i = 0; i < vg.getChildCount(); i++) { View child = vg.getChildAt(i); int childLeft = child.getLeft() - view.getScrollX(); int childTop = child.getTop() - view.getScrollY(); int childRight = child.getRight() - view.getScrollX(); int childBottom = child.getBottom() - view.getScrollY(); boolean intersects = x > childLeft && x < childRight && y > childTop && y < childBottom; if (intersects && canScrollUp(child, x - childLeft, y - childTop)) { return true; } } } return view.canScrollVertically(-1); }
/** * 根据当前scrollX的位置判断是展开还是折叠 * * @param velocityX 如果不等于0那么这是一次fling事件,否则是一次ACTION_UP或者ACTION_CANCEL */ private boolean smoothHorizontalExpandOrCollapse(float velocityX) { int scrollX = mTargetView.getScrollX(); int scrollRange = getHorizontalRange(); if (mExpandAndCollapseAnim != null) return false; int to = 0; int duration = DEFAULT_DURATION; if (velocityX == 0) { // 如果已经展一半,平滑展开 if (scrollX > scrollRange / 2) { to = scrollRange; } } else { if (velocityX > 0) to = 0; else to = scrollRange; duration = (int) ((1.f - Math.abs(velocityX) / mMaxVelocity) * DEFAULT_DURATION); } if (to == scrollX) return false; mExpandAndCollapseAnim = ObjectAnimator.ofInt(mTargetView, "scrollX", to); mExpandAndCollapseAnim.setDuration(duration); mExpandAndCollapseAnim.addListener( new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animation) {} @Override public void onAnimationEnd(Animator animation) { mExpandAndCollapseAnim = null; if (isCollapsed()) mTargetView = null; Log.d(TAG, "onAnimationEnd"); } @Override public void onAnimationCancel(Animator animation) { // onAnimationEnd(animation); mExpandAndCollapseAnim = null; Log.d(TAG, "onAnimationCancel"); } @Override public void onAnimationRepeat(Animator animation) {} }); mExpandAndCollapseAnim.start(); return true; }
/** * Positions the popup window on screen. When the popup window is too tall to fit under the * anchor, a parent scroll view is seeked and scrolled up to reclaim space. If scrolling is not * possible or not enough, the popup window gets moved on top of the anchor. * * <p>The height must have been set on the layout parameters prior to calling this method. * * @param anchor the view on which the popup window must be anchored * @param p the layout parameters used to display the drop down * @return true if the popup is translated upwards to fit on screen */ private boolean findDropDownPosition( View anchor, WindowManager.LayoutParams p, int xoff, int yoff) { anchor.getLocationInWindow(mDrawingLocation); p.x = mDrawingLocation[0] + xoff; p.y = mDrawingLocation[1] + anchor.getMeasuredHeight() + yoff; boolean onTop = false; p.gravity = Gravity.LEFT | Gravity.TOP; anchor.getLocationOnScreen(mScreenLocation); final Rect displayFrame = new Rect(); anchor.getWindowVisibleDisplayFrame(displayFrame); final View root = anchor.getRootView(); if (mScreenLocation[1] + anchor.getMeasuredHeight() + yoff + mPopupHeight > displayFrame.bottom || p.x + mPopupWidth - root.getWidth() > 0) { // if the drop down disappears at the bottom of the screen. we try to // scroll a parent scrollview or move the drop down back up on top of // the edit box int scrollX = anchor.getScrollX(); int scrollY = anchor.getScrollY(); Rect r = new Rect( scrollX, scrollY, scrollX + mPopupWidth, scrollY + mPopupHeight + anchor.getMeasuredHeight()); anchor.requestRectangleOnScreen(r, true); // now we re-evaluate the space available, and decide from that // whether the pop-up will go above or below the anchor. anchor.getLocationInWindow(mDrawingLocation); p.x = mDrawingLocation[0] + xoff; p.y = mDrawingLocation[1] + anchor.getMeasuredHeight() + yoff; // determine whether there is more space above or below the anchor anchor.getLocationOnScreen(mScreenLocation); onTop = (displayFrame.bottom - mScreenLocation[1] - anchor.getMeasuredHeight() - yoff) < (mScreenLocation[1] - yoff - displayFrame.top); if (onTop) { p.gravity = Gravity.LEFT | Gravity.BOTTOM; p.y = root.getHeight() - mDrawingLocation[1] - yoff; } else { p.y = mDrawingLocation[1] + anchor.getMeasuredHeight() + yoff; } } p.gravity |= Gravity.DISPLAY_CLIP_VERTICAL; return onTop; }
public static Bitmap getBitmapFromView(View view, int width, int height) { view.measure( View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY)); view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight()); Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); canvas.translate(-view.getScrollX(), -view.getScrollY()); view.draw(canvas); return bitmap; }
/* * 根据targetView的scrollX计算出targetView的偏移,这样能够知道这个point * 是在右侧的菜单中 * */ private boolean inView(int x, int y) { if (mTargetView == null) return false; int scrollX = mTargetView.getScrollX(); int left = mTargetView.getWidth() - scrollX; int top = mTargetView.getTop(); int right = left + getHorizontalRange(); int bottom = mTargetView.getBottom(); Rect rect = new Rect(left, top, right, bottom); return rect.contains(x, y); }
@Override public void computeScroll() { // 调用startScroll的时候scroller.computeScrollOffset()返回true, if (mScroller.computeScrollOffset()) { mContentView.scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); postInvalidate(); if (mScroller.isFinished() && isFinish) { if (mContentView.getScrollX() < 0) { mActivity.finish(); } } } }
public void animateView( final DragView view, AnimatorUpdateListener updateCb, int duration, TimeInterpolator interpolator, final Runnable onCompleteRunnable, final int animationEndStyle, View anchorView) { // Clean up the previous animations if (mDropAnim != null) mDropAnim.cancel(); if (mFadeOutAnim != null) mFadeOutAnim.cancel(); // Show the drop view if it was previously hidden mDropView = view; mDropView.cancelAnimation(); mDropView.resetLayoutParams(); // Set the anchor view if the page is scrolling if (anchorView != null) { mAnchorViewInitialScrollX = anchorView.getScrollX(); } mAnchorView = anchorView; // Create and start the animation mDropAnim = new ValueAnimator(); mDropAnim.setInterpolator(interpolator); mDropAnim.setDuration(duration); mDropAnim.setFloatValues(0f, 1f); mDropAnim.addUpdateListener(updateCb); mDropAnim.addListener( new AnimatorListenerAdapter() { public void onAnimationEnd(Animator animation) { if (onCompleteRunnable != null) { onCompleteRunnable.run(); } switch (animationEndStyle) { case ANIMATION_END_DISAPPEAR: clearAnimatedView(); break; case ANIMATION_END_FADE_OUT: fadeOutDragView(); break; case ANIMATION_END_REMAIN_VISIBLE: break; } } }); mDropAnim.start(); }
/** * Snapshot a view into a Bitmap with the indicated background color. * * @param view The target {@link android.view.View}. * @param backgroundColor The background color of the Bitmap. If the view has transparency areas, * these areas will be erased using this color. * @return Returns a Bitmap containing the view content, or {@code null} if any error occurs. Make * sure to call {@link android.graphics.Bitmap#recycle()} as soon as possible, once its * content is not needed anymore. */ public Bitmap snapshotView(View view, int backgroundColor) { if (view == null) { return null; } int viewWidth = view.getRight() - view.getLeft(); int viewHeight = view.getBottom() - view.getTop(); int sampleWidth = viewWidth / mSampleSize; int sampleHeight = viewHeight / mSampleSize; float canvasScale = 1.f / mSampleSize; sampleWidth = sampleWidth > 0 ? sampleWidth : 1; sampleHeight = sampleHeight > 0 ? sampleHeight : 1; performanceTickBegin( "snapshotView " + view + " sampleSize = " + mSampleSize + " (" + sampleWidth + ", " + sampleHeight + "): "); Bitmap bitmap = Bitmap.createBitmap(sampleWidth, sampleHeight, Bitmap.Config.ARGB_8888); if (bitmap == null) { throw new OutOfMemoryError(); } if ((backgroundColor & 0xff000000) != 0) { bitmap.eraseColor(backgroundColor); } bitmap.setDensity(mDisplayMetrics.densityDpi); Canvas canvas = new Canvas(bitmap); canvas.scale(view.getScaleX() * canvasScale, view.getScaleY() * canvasScale); canvas.translate(-view.getScrollX(), -view.getScrollY()); view.computeScroll(); view.draw(canvas); canvas.setBitmap(null); performanceTickEnd(); return bitmap; }