// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.util;
import android.graphics.Canvas;
import android.graphics.Region;
import android.support.annotation.DrawableRes;
import android.view.View;
import android.view.ViewGroup;
/**
* View-related utility methods.
*/
public class ViewUtils {
private static final int[] sLocationTmp = new int[2];
/**
* Invalidates a view and all of its descendants.
*/
private static void recursiveInvalidate(View view) {
view.invalidate();
if (view instanceof ViewGroup) {
ViewGroup group = (ViewGroup) view;
int childCount = group.getChildCount();
for (int i = 0; i < childCount; i++) {
View child = group.getChildAt(i);
if (child.getVisibility() == View.VISIBLE) {
recursiveInvalidate(child);
}
}
}
}
/**
* Captures a bitmap of a View and draws it to a Canvas.
*/
public static void captureBitmap(View view, Canvas canvas) {
// Invalidate all the descendants of view, before calling view.draw(). Otherwise, some of
// the descendant views may optimize away their drawing. http://crbug.com/415251
recursiveInvalidate(view);
view.draw(canvas);
}
/**
* Return the position of {@code childView} relative to {@code rootView}. {@code childView}
* must be a child of {@code rootView}. This returns the relative layout position, which does
* not include translations.
* @param rootView The parent of {@code childView} to calculate the position relative to.
* @param childView The {@link View} to calculate the position of.
* @param outPosition The resulting position with the format [x, y].
*/
public static void getRelativeLayoutPosition(View rootView, View childView, int[] outPosition) {
assert outPosition.length == 2;
outPosition[0] = 0;
outPosition[1] = 0;
while (childView != null && childView != rootView) {
outPosition[0] += childView.getLeft();
outPosition[1] += childView.getTop();
childView = (View) childView.getParent();
}
}
/**
* Return the position of {@code childView} relative to {@code rootView}. {@code childView}
* must be a child of {@code rootView}. This returns the relative draw position, which includes
* translations.
* @param rootView The parent of {@code childView} to calculate the position relative to.
* @param childView The {@link View} to calculate the position of.
* @param outPosition The resulting position with the format [x, y].
*/
public static void getRelativeDrawPosition(View rootView, View childView, int[] outPosition) {
assert outPosition.length == 2;
outPosition[0] = 0;
outPosition[1] = 0;
while (childView != null && childView != rootView) {
outPosition[0] += childView.getX();
outPosition[1] += childView.getY();
childView = (View) childView.getParent();
}
}
/**
* Helper for overriding {@link ViewGroup#gatherTransparentRegion} for views that are fully
* opaque and have children extending beyond their bounds. If the transparent region
* optimization is turned on (which is the case whenever the view hierarchy contains a
* SurfaceView somewhere), the children might otherwise confuse the SurfaceFlinger.
*/
public static void gatherTransparentRegionsForOpaqueView(View view, Region region) {
view.getLocationInWindow(sLocationTmp);
region.op(sLocationTmp[0], sLocationTmp[1],
sLocationTmp[0] + view.getRight() - view.getLeft(),
sLocationTmp[1] + view.getBottom() - view.getTop(), Region.Op.DIFFERENCE);
}
/**
* Sets the background of a view to the given 9-patch resource and restores its padding. This
* works around a bug in Android where the padding is lost when a 9-patch resource is applied
* programmatically.
*/
public static void setNinePatchBackgroundResource(View view, @DrawableRes int resource) {
int left = view.getPaddingLeft();
int top = view.getPaddingTop();
int right = view.getPaddingRight();
int bottom = view.getPaddingBottom();
view.setBackgroundResource(resource);
view.setPadding(left, top, right, bottom);
}
}