下面列出了android.graphics.Rect#intersect ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
private void reduceVisibleRectangleForWindowsAbove(Rect visibleRect) {
Trace.beginSection("SwitchAccessNodeCompat#reduceVisibleRectangleForWindowsAbove");
Rect windowBoundsInScreen = new Rect();
int visibleRectWidth = visibleRect.right - visibleRect.left;
int visibleRectHeight = visibleRect.bottom - visibleRect.top;
for (int i = 0; i < windowsAbove.size(); ++i) {
windowsAbove.get(i).getBoundsInScreen(windowBoundsInScreen);
windowBoundsInScreen.sort();
Rect intersectingRectangle = new Rect(visibleRect);
if (intersectingRectangle.intersect(windowBoundsInScreen)) {
// If the rect above occupies less than a fraction of both sides of this rect, don't
// adjust this rect's bounds. This prevents things like FABs changing the bounds
// of scroll views under them.
if (((intersectingRectangle.right - intersectingRectangle.left)
< (visibleRectWidth * MIN_INTERSECTION_TO_CROP))
&& ((intersectingRectangle.bottom - intersectingRectangle.top)
< (visibleRectHeight * MIN_INTERSECTION_TO_CROP))) {
Trace.endSection();
return;
}
adjustRectToAvoidIntersection(visibleRect, windowBoundsInScreen);
}
}
Trace.endSection();
}
/**
* Returns the node's bounds clipped to the size of the display
*
* @param node
* @param width pixel width of the display
* @param height pixel height of the display
* @return null if node is null, else a Rect containing visible bounds
*/
static Rect getVisibleBoundsInScreen(AccessibilityNodeInfo node, int width, int height) {
if (node == null) {
return null;
}
// targeted node's bounds
Rect nodeRect = new Rect();
node.getBoundsInScreen(nodeRect);
Rect displayRect = new Rect();
displayRect.top = 0;
displayRect.left = 0;
displayRect.right = width;
displayRect.bottom = height;
nodeRect.intersect(displayRect);
return nodeRect;
}
public int getSnapHeight() {
if (!needSnap) {
return 0;
}
needSnap = false;
Rect displayRect = new Rect(0, scroll, getWidth(), getHeight() + scroll);
int itemCount = getItemCount();
for (int i = 0; i < itemCount; i++) {
Rect itemRect = locationRects.get(i);
if (displayRect.intersect(itemRect)) {
if (lastDy > 0) {
// scroll变大,属于列表往下走,往下找下一个为snapView
if (i < itemCount - 1) {
Rect nextRect = locationRects.get(i + 1);
return nextRect.top - displayRect.top;
}
}
return itemRect.top - displayRect.top;
}
}
return 0;
}
/**
* Determines if two views intersect in the window.
*/
public static boolean viewsIntersect(View view1, View view2) {
final int[] view1Loc = new int[2];
view1.getLocationOnScreen(view1Loc);
final Rect view1Rect = new Rect(view1Loc[0],
view1Loc[1],
view1Loc[0] + view1.getWidth(),
view1Loc[1] + view1.getHeight());
int[] view2Loc = new int[2];
view2.getLocationOnScreen(view2Loc);
final Rect view2Rect = new Rect(view2Loc[0],
view2Loc[1],
view2Loc[0] + view2.getWidth(),
view2Loc[1] + view2.getHeight());
return view1Rect.intersect(view2Rect);
}
/**
* Finds the visible bounds of a partially visible UI element
*
* @param node
* @return null if node is null, else a Rect containing visible bounds
*/
private Rect getVisibleBounds(AccessibilityNodeInfo node) {
if (node == null) {
return null;
}
// targeted node's bounds
int w = MyUiDevice.getInstance().getDisplayWidth();
int h = MyUiDevice.getInstance().getDisplayHeight();
Rect nodeRect = MyAccessibilityNodeInfoHelper.getVisibleBoundsInScreen(node, w, h);
// is the targeted node within a scrollable container?
AccessibilityNodeInfo scrollableParentNode = getScrollableParent(node);
if (scrollableParentNode == null) {
// nothing to adjust for so return the node's Rect as is
return nodeRect;
}
// Scrollable parent's visible bounds
Rect parentRect = MyAccessibilityNodeInfoHelper.getVisibleBoundsInScreen(scrollableParentNode, w, h);
// adjust for partial clipping of targeted by parent node if required
nodeRect.intersect(parentRect);
return nodeRect;
}
public static boolean compareAccessibilityNodeInfo(AccessibilityNodeInfo n1, AccessibilityNodeInfo n2) {
if (n1 != null && n2 != null) {
String c1 = n1.getClassName().toString();
String c2 = n2.getClassName().toString();
Rect b1 = new Rect();
Rect b2 = new Rect();
n1.getBoundsInScreen(b1);
n2.getBoundsInScreen(b2);
int a1 = b1.height() * b1.width();
b1.intersect(b2);
int a2 = b1.height() * b1.width();
return c1.equals(c2) && (a2 > ((int) (a1 * 0.95)));
} else {
return false;
}
}
/**
* Finds the visible bounds of a partially visible UI element
*
* @param node
* @return null if node is null, else a Rect containing visible bounds
*/
private Rect getVisibleBounds(AccessibilityNodeInfo node) {
if (node == null) {
return null;
}
// targeted node's bounds
int w = mDevice.getDisplayWidth();
int h = mDevice.getDisplayHeight();
Rect nodeRect = AccessibilityNodeInfoHelper.getVisibleBoundsInScreen(node, w, h);
// is the targeted node within a scrollable container?
AccessibilityNodeInfo scrollableParentNode = getScrollableParent(node);
if(scrollableParentNode == null) {
// nothing to adjust for so return the node's Rect as is
return nodeRect;
}
// Scrollable parent's visible bounds
Rect parentRect = AccessibilityNodeInfoHelper
.getVisibleBoundsInScreen(scrollableParentNode, w, h);
// adjust for partial clipping of targeted by parent node if required
nodeRect.intersect(parentRect);
return nodeRect;
}
protected boolean iconOverlapsWithRemoveView() {
if (removeView.isShowing()) {
View firstView = removeView.buttonImage;
View secondView = iconView;
int[] firstPosition = new int[2];
int[] secondPosition = new int[2];
firstView.getLocationOnScreen(firstPosition);
secondView.getLocationOnScreen(secondPosition);
// Rect constructor parameters: left, top, right, bottom
Rect rectFirstView = new Rect(firstPosition[0], firstPosition[1],
firstPosition[0] + firstView.getMeasuredWidth(),
firstPosition[1] + firstView.getMeasuredHeight());
Rect rectSecondView = new Rect(secondPosition[0], secondPosition[1],
secondPosition[0] + secondView.getMeasuredWidth(),
secondPosition[1] + secondView.getMeasuredHeight());
return rectFirstView.intersect(rectSecondView);
}
return false;
}
/**
* Returns the node's bounds clipped to the size of the display
*
* @param node
* @param width pixel width of the display
* @param height pixel height of the display
* @return null if node is null, else a Rect containing visible bounds
*/
static Rect getVisibleBoundsInScreen(AccessibilityNodeInfo node, int width, int height) {
if (node == null) {
return null;
}
// targeted node's bounds
Rect nodeRect = new Rect();
node.getBoundsInScreen(nodeRect);
Rect displayRect = new Rect();
displayRect.top = 0;
displayRect.left = 0;
displayRect.right = width;
displayRect.bottom = height;
nodeRect.intersect(displayRect);
return nodeRect;
}
/**
* Calculate framing rectangle, relative to the preview frame.
*
* Note that the SurfaceView may be larger than the container.
*
* Override this for more control over the framing rect calculations.
*
* @param container this container, with left = top = 0
* @param surface the SurfaceView, relative to this container
* @return the framing rect, relative to this container
*/
protected Rect calculateFramingRect(Rect container, Rect surface) {
// intersection is the part of the container that is used for the preview
Rect intersection = new Rect(container);
boolean intersects = intersection.intersect(surface);
if(framingRectSize != null) {
// Specific size is specified. Make sure it's not larger than the container or surface.
int horizontalMargin = Math.max(0, (intersection.width() - framingRectSize.width) / 2);
int verticalMargin = Math.max(0, (intersection.height() - framingRectSize.height) / 2);
intersection.inset(horizontalMargin, verticalMargin);
return intersection;
}
// margin as 10% (default) of the smaller of width, height
int margin = (int)Math.min(intersection.width() * marginFraction, intersection.height() * marginFraction);
intersection.inset(margin, margin);
if (intersection.height() > intersection.width()) {
// We don't want a frame that is taller than wide.
intersection.inset(0, (intersection.height() - intersection.width()) / 2);
}
return intersection;
}
/**
* Determines if two views intersect in the window.
*/
public static boolean viewsIntersect(View view1, View view2) {
if (view1 == null || view2 == null) return false;
final int[] view1Loc = new int[2];
view1.getLocationOnScreen(view1Loc);
final Rect view1Rect = new Rect(view1Loc[0],
view1Loc[1],
view1Loc[0] + view1.getWidth(),
view1Loc[1] + view1.getHeight());
int[] view2Loc = new int[2];
view2.getLocationOnScreen(view2Loc);
final Rect view2Rect = new Rect(view2Loc[0],
view2Loc[1],
view2Loc[0] + view2.getWidth(),
view2Loc[1] + view2.getHeight());
return view1Rect.intersect(view2Rect);
}
public boolean isAppItemShown() {
final Rect placeHolderPosition = new Rect();
appCardView.getLocalVisibleRect(placeHolderPosition);
final Rect screen =
new Rect(0, 0, (int) screenWidth, (int) screenHeight - appCardView.getHeight() * 2);
return placeHolderPosition.intersect(screen);
}
/**
* Computes whether the specified {@link Rect} intersects with the visible
* portion of its parent {@link View}. Modifies {@code localRect} to
* contain only the visible portion.
*
* @param localRect A rectangle in local (parent) coordinates.
* @return Whether the specified {@link Rect} is visible on the screen.
*/
private boolean intersectVisibleToUser(Rect localRect) {
// Missing or empty bounds mean this view is not visible.
if ((localRect == null) || localRect.isEmpty()) {
return false;
}
// Attached to invisible window means this view is not visible.
if (mParentView.getWindowVisibility() != View.VISIBLE) {
return false;
}
// An invisible predecessor or one with alpha zero means
// that this view is not visible to the user.
Object current = this;
while (current instanceof View) {
final View view = (View) current;
// We have attach info so this view is attached and there is no
// need to check whether we reach to ViewRootImpl on the way up.
if ((view.getAlpha() <= 0) || (view.getVisibility() != View.VISIBLE)) {
return false;
}
current = view.getParent();
}
// If no portion of the parent is visible, this view is not visible.
if (!mParentView.getLocalVisibleRect(mTempVisibleRect)) {
return false;
}
// Check if the view intersects the visible portion of the parent.
return localRect.intersect(mTempVisibleRect);
}
/**
* Computes whether the specified {@link Rect} intersects with the visible
* portion of its parent {@link View}. Modifies {@code localRect} to contain
* only the visible portion.
*
* @param localRect A rectangle in local (parent) coordinates.
* @return Whether the specified {@link Rect} is visible on the screen.
*/
private boolean intersectVisibleToUser(Rect localRect) {
// Missing or empty bounds mean this view is not visible.
if ((localRect == null) || localRect.isEmpty()) {
return false;
}
// Attached to invisible window means this view is not visible.
if (mView.getWindowVisibility() != View.VISIBLE) {
return false;
}
// An invisible predecessor means that this view is not visible.
ViewParent viewParent = mView.getParent();
while (viewParent instanceof View) {
final View view = (View) viewParent;
if ((ViewCompat.getAlpha(view) <= 0) || (view.getVisibility() != View.VISIBLE)) {
return false;
}
viewParent = view.getParent();
}
// A null parent implies the view is not visible.
if (viewParent == null) {
return false;
}
// If no portion of the parent is visible, this view is not visible.
if (!mView.getLocalVisibleRect(mTempVisibleRect)) {
return false;
}
// Check if the view intersects the visible portion of the parent.
return localRect.intersect(mTempVisibleRect);
}
/**
* Computes whether the specified {@link Rect} intersects with the visible
* portion of its parent {@link View}. Modifies {@code localRect} to contain
* only the visible portion.
*
* @param localRect A rectangle in local (parent) coordinates.
* @return Whether the specified {@link Rect} is visible on the screen.
*/
private boolean intersectVisibleToUser(Rect localRect) {
// Missing or empty bounds mean this view is not visible.
if ((localRect == null) || localRect.isEmpty()) {
return false;
}
// Attached to invisible window means this view is not visible.
if (mView.getWindowVisibility() != View.VISIBLE) {
return false;
}
// An invisible predecessor means that this view is not visible.
ViewParent viewParent = mView.getParent();
while (viewParent instanceof View) {
final View view = (View) viewParent;
if ((ViewCompat.getAlpha(view) <= 0) || (view.getVisibility() != View.VISIBLE)) {
return false;
}
viewParent = view.getParent();
}
// A null parent implies the view is not visible.
if (viewParent == null) {
return false;
}
// If no portion of the parent is visible, this view is not visible.
if (!mView.getLocalVisibleRect(mTempVisibleRect)) {
return false;
}
// Check if the view intersects the visible portion of the parent.
return localRect.intersect(mTempVisibleRect);
}
/**
* Offset this view's horizontal location by the specified amount of pixels.
*
* @param view view
* @param offset the number of pixels to offset the view by
*/
public static void offsetLeftAndRight(View view, int offset) {
if (view == null || offset == 0) {
return;
}
if (Build.VERSION.SDK_INT >= 23) {
view.offsetLeftAndRight(offset);
} else if (Build.VERSION.SDK_INT >= 21) {
final Rect parentRect = getEmptyTempRect();
boolean needInvalidateWorkaround = false;
final ViewParent parent = view.getParent();
if (parent instanceof View) {
final View p = (View) parent;
parentRect.set(p.getLeft(), p.getTop(), p.getRight(), p.getBottom());
// If the view currently does not currently intersect the parent (and is therefore
// not displayed) we may need need to invalidate
needInvalidateWorkaround = !parentRect.intersects(view.getLeft(), view.getTop(),
view.getRight(), view.getBottom());
}
// Now offset, invoking the API 14+ implementation (which contains its own workarounds)
compatOffsetLeftAndRight(view, offset);
// The view has now been offset, so let's intersect the Rect and invalidate where
// the View is now displayed
if (needInvalidateWorkaround && parentRect.intersect(view.getLeft(), view.getTop(),
view.getRight(), view.getBottom())) {
((View) parent).invalidate(parentRect);
}
} else {
compatOffsetLeftAndRight(view, offset);
}
}
@Override
public void updateHq(boolean update) {
Rect viewArea = new Rect(getLeft(), getTop(), getRight(), getBottom());
if (viewArea.width() == mSize.x || viewArea.height() == mSize.y) {
// If the viewArea's size matches the unzoomed size, there is no need for an hq patch
if (mPatch != null) {
mPatch.setImageBitmap(null);
mPatch.invalidate();
}
} else {
//当前Pageview的实际大小
final Point patchViewSize = new Point(viewArea.width(), viewArea.height());
//表示实际要显示pdf的区域,也就是pdf与屏幕的重叠处
final Rect patchArea = new Rect(0, 0, mParentSize.x, mParentSize.y);
// Intersect and test that there is an intersection
if (!patchArea.intersect(viewArea)) {
return;
}
//重新计算重叠处的坐标,这个坐标是相对于当前PDF实际大小
// Offset patch area to be relative to the view top left
patchArea.offset(-viewArea.left, -viewArea.top);
boolean area_unchanged = patchArea.equals(mPatchArea) && patchViewSize.equals(mPatchViewSize);
// If being asked for the same area as last time and not because of an update then nothing to do
if (area_unchanged && !update)
return;
boolean completeRedraw = !(area_unchanged && update);
// Stop the drawing of previous patch if still going
if (mDrawPatch != null) {
mDrawPatch.cancelAndWait();
mDrawPatch = null;
}
// Create and add the image view if not already done
if (mPatch == null) {
mPatch = new OpaqueImageView(mContext);
mPatch.setScaleType(ImageView.ScaleType.MATRIX);
addView(mPatch);
mSearchView.bringToFront();
}
CancellableTaskDefinition<Void, Void> task;
if (completeRedraw) {
task = getDrawPageTask(mPatchBm, patchViewSize.x, patchViewSize.y,
patchArea.left, patchArea.top,
patchArea.width(), patchArea.height());
} else {
task = getUpdatePageTask(mPatchBm, patchViewSize.x, patchViewSize.y,
patchArea.left, patchArea.top,
patchArea.width(), patchArea.height());
}
mDrawPatch = new CancellableAsyncTask<Void, Void>(task) {
public void onPostExecute(Void result) {
mPatchViewSize = patchViewSize;
mPatchArea = patchArea;
mPatch.setImageBitmap(mPatchBm);
mPatch.invalidate();
//requestLayout();
// Calling requestLayout here doesn't lead to a later call to layout. No idea
// why, but apparently others have run into the problem.
mPatch.layout(mPatchArea.left, mPatchArea.top, mPatchArea.right, mPatchArea.bottom);
}
};
mDrawPatch.execute();
}
}
public void updateHq(boolean update) {
Rect viewArea = new Rect(getLeft(), getTop(), getRight(), getBottom());
if (viewArea.width() == mSize.x || viewArea.height() == mSize.y) {
// If the viewArea's size matches the unzoomed size, there is no need for an hq patch
if (mPatch != null) {
mPatch.setImageBitmap(null);
mPatch.invalidate();
}
} else {
final Point patchViewSize = new Point(viewArea.width(), viewArea.height());
final Rect patchArea = new Rect(0, 0, mParentSize.x, mParentSize.y);
// Intersect and test that there is an intersection
if (!patchArea.intersect(viewArea))
return;
// Offset patch area to be relative to the view top left
patchArea.offset(-viewArea.left, -viewArea.top);
boolean area_unchanged = patchArea.equals(mPatchArea) && patchViewSize.equals(mPatchViewSize);
// If being asked for the same area as last time and not because of an update then nothing to do
if (area_unchanged && !update)
return;
boolean completeRedraw = !(area_unchanged && update);
// Stop the drawing of previous patch if still going
if (mDrawPatch != null) {
mDrawPatch.cancel();
mDrawPatch = null;
}
// Create and add the image view if not already done
if (mPatch == null) {
mPatch = new OpaqueImageView(mContext);
mPatch.setScaleType(ImageView.ScaleType.MATRIX);
addView(mPatch);
mSearchView.bringToFront();
}
CancellableTaskDefinition<Void, Void> task;
if (completeRedraw)
task = getDrawPageTask(mPatchBm, patchViewSize.x, patchViewSize.y,
patchArea.left, patchArea.top,
patchArea.width(), patchArea.height());
else
task = getUpdatePageTask(mPatchBm, patchViewSize.x, patchViewSize.y,
patchArea.left, patchArea.top,
patchArea.width(), patchArea.height());
mDrawPatch = new CancellableAsyncTask<Void, Void>(task) {
public void onPostExecute(Void result) {
mPatchViewSize = patchViewSize;
mPatchArea = patchArea;
mPatch.setImageBitmap(mPatchBm);
mPatch.invalidate();
//requestLayout();
// Calling requestLayout here doesn't lead to a later call to layout. No idea
// why, but apparently others have run into the problem.
mPatch.layout(mPatchArea.left, mPatchArea.top, mPatchArea.right, mPatchArea.bottom);
}
};
mDrawPatch.execute();
}
}
public void updateHq(boolean update) {
Rect viewArea = new Rect(getLeft(),getTop(),getRight(),getBottom());
if (viewArea.width() == mSize.x || viewArea.height() == mSize.y) {
// If the viewArea's size matches the unzoomed size, there is no need for an hq patch
if (mPatch != null) {
mPatch.setImageBitmap(null);
mPatch.invalidate();
}
} else {
final Point patchViewSize = new Point(viewArea.width(), viewArea.height());
final Rect patchArea = new Rect(0, 0, mParentSize.x, mParentSize.y);
// Intersect and test that there is an intersection
if (!patchArea.intersect(viewArea))
return;
// Offset patch area to be relative to the view top left
patchArea.offset(-viewArea.left, -viewArea.top);
boolean area_unchanged = patchArea.equals(mPatchArea) && patchViewSize.equals(mPatchViewSize);
// If being asked for the same area as last time and not because of an update then nothing to do
if (area_unchanged && !update)
return;
boolean completeRedraw = !(area_unchanged && update);
// Stop the drawing of previous patch if still going
if (mDrawPatch != null) {
mDrawPatch.cancel();
mDrawPatch = null;
}
// Create and add the image view if not already done
if (mPatch == null) {
mPatch = new OpaqueImageView(mContext);
mPatch.setScaleType(ImageView.ScaleType.MATRIX);
addView(mPatch);
mSearchView.bringToFront();
}
CancellableTaskDefinition<Void, Void> task;
if (completeRedraw)
task = getDrawPageTask(mPatchBm, patchViewSize.x, patchViewSize.y,
patchArea.left, patchArea.top,
patchArea.width(), patchArea.height());
else
task = getUpdatePageTask(mPatchBm, patchViewSize.x, patchViewSize.y,
patchArea.left, patchArea.top,
patchArea.width(), patchArea.height());
mDrawPatch = new CancellableAsyncTask<Void,Void>(task) {
public void onPostExecute(Void result) {
mPatchViewSize = patchViewSize;
mPatchArea = patchArea;
mPatch.setImageBitmap(mPatchBm);
mPatch.invalidate();
//requestLayout();
// Calling requestLayout here doesn't lead to a later call to layout. No idea
// why, but apparently others have run into the problem.
mPatch.layout(mPatchArea.left, mPatchArea.top, mPatchArea.right, mPatchArea.bottom);
}
};
mDrawPatch.execute();
}
}
/**
* 回收和填充布局
*
* @param recycler Recycler
* @param state State
* @param isStart 是否从头开始,用于控制View遍历方向,true 为从头到尾,false 为从尾到头
*/
@SuppressLint("CheckResult")
private void recycleAndFillItems(RecyclerView.Recycler recycler, RecyclerView.State state,
boolean isStart) {
if (state.isPreLayout()) {
return;
}
Logi("mOffsetX = " + mOffsetX);
Logi("mOffsetY = " + mOffsetY);
// 计算显示区域区前后多存储一列或则一行
Rect displayRect = new Rect(mOffsetX - mItemWidth, mOffsetY - mItemHeight,
getUsableWidth() + mOffsetX + mItemWidth, getUsableHeight() + mOffsetY + mItemHeight);
// 对显显示区域进行修正(计算当前显示区域和最大显示区域对交集)
displayRect.intersect(0, 0, mMaxScrollX + getUsableWidth(), mMaxScrollY + getUsableHeight());
Loge("displayRect = " + displayRect.toString());
int startPos = 0; // 获取第一个条目的Pos
int pageIndex = getPageIndexByOffset();
startPos = pageIndex * mOnePageSize;
Logi("startPos = " + startPos);
startPos = startPos - mOnePageSize * 2;
if (startPos < 0) {
startPos = 0;
}
int stopPos = startPos + mOnePageSize * 4;
if (stopPos > getItemCount()) {
stopPos = getItemCount();
}
Loge("startPos = " + startPos);
Loge("stopPos = " + stopPos);
detachAndScrapAttachedViews(recycler); // 移除所有View
if (isStart) {
for (int i = startPos; i < stopPos; i++) {
addOrRemove(recycler, displayRect, i);
}
} else {
for (int i = stopPos - 1; i >= startPos; i--) {
addOrRemove(recycler, displayRect, i);
}
}
Loge("child count = " + getChildCount());
}