使用root视图的Android Screen Capture

时间:2016-09-19 12:50:06

标签: android android-view rootview

我正在尝试捕捉屏幕

    View decorView = activity.getWindow().getDecorView();
    decorView.setDrawingCacheEnabled(true);
    Bitmap bitmap = decorView.getDrawingCache();

一切正常,我可以截取屏幕截图。 但对于一种情况,我面临一个问题。 但是当有Dialog片段时,Dialog片段的视图没有被捕获,但是部分可见的背景活动视图被捕获,就好像最顶层的活动的根视图一样。

2 个答案:

答案 0 :(得分:1)

  

但是当有Dialog片段时,Dialog片段的视图没有被捕获,但是部分可见的背景活动视图被捕获,就好像最顶层的活动的根视图一样。

这是因为 #region Camera focus definition public class CameraFocusData { public Position Position { get; set; } public Distance Distance { get; set; } } private static void OnCustomPinsPropertyChanged(BindableObject bindable, object oldValue, object newValue) { CustomMap customMap = ((CustomMap)bindable); if (customMap.CameraFocusParameter == CameraFocusReference.OnPins) { List<double> latitudes = new List<double>(); List<double> longitudes = new List<double>(); foreach (CustomPin pin in (newValue as List<CustomPin>)) { latitudes.Add(pin.Position.Latitude); longitudes.Add(pin.Position.Longitude); } double lowestLat = latitudes.Min(); double highestLat = latitudes.Max(); double lowestLong = longitudes.Min(); double highestLong = longitudes.Max(); double finalLat = (lowestLat + highestLat) / 2; double finalLong = (lowestLong + highestLong) / 2; double distance = DistanceCalculation.GeoCodeCalc.CalcDistance(lowestLat, lowestLong, highestLat, highestLong, DistanceCalculation.GeoCodeCalcMeasurement.Kilometers); customMap.MoveToRegion(MapSpan.FromCenterAndRadius(new Position(finalLat, finalLong), Distance.FromKilometers(distance * 0.7))); } } private class DistanceCalculation { public static class GeoCodeCalc { public const double EarthRadiusInMiles = 3956.0; public const double EarthRadiusInKilometers = 6367.0; public static double ToRadian(double val) { return val * (Math.PI / 180); } public static double DiffRadian(double val1, double val2) { return ToRadian(val2) - ToRadian(val1); } public static double CalcDistance(double lat1, double lng1, double lat2, double lng2) { return CalcDistance(lat1, lng1, lat2, lng2, GeoCodeCalcMeasurement.Miles); } public static double CalcDistance(double lat1, double lng1, double lat2, double lng2, GeoCodeCalcMeasurement m) { double radius = GeoCodeCalc.EarthRadiusInMiles; if (m == GeoCodeCalcMeasurement.Kilometers) { radius = GeoCodeCalc.EarthRadiusInKilometers; } return radius * 2 * Math.Asin(Math.Min(1, Math.Sqrt((Math.Pow(Math.Sin((DiffRadian(lat1, lat2)) / 2.0), 2.0) + Math.Cos(ToRadian(lat1)) * Math.Cos(ToRadian(lat2)) * Math.Pow(Math.Sin((DiffRadian(lng1, lng2)) / 2.0), 2.0))))); } } public enum GeoCodeCalcMeasurement : int { Miles = 0, Kilometers = 1 } } #endregion 在一个单独的窗口中。我不知道你能做些什么。

答案 1 :(得分:0)

您可以借助反射获取应用的所有窗口的装饰视图列表。此列表不仅包含活动的装饰视图,还包含对话框和弹出窗口的装饰视图。

void processDialogWindow(Context context) {
    WindowManager windowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
    Field globalField = Class.forName("android.view.WindowManagerImpl").getDeclaredField("mGlobal");
    globalField.setAccessible(true);
    Object globalFieldValue = globalField.get(windowManager);
    List<?> viewsFieldValue = getViews(globalFieldValue);
    for (int i = viewsFieldValue.size() - 1; i >= 0; i--) {
        View decorView = (View)viewsFieldValue.get(i);
        WindowManager.LayoutParams castedParams = (WindowManager.LayoutParams)decorView.getLayoutParams();
        if (castedParams.type == WindowManager.LayoutParams.TYPE_APPLICATION) { // Dialog
            //TODO: get decorView screenshot.
        }
    }
}

List<?> getViews(Object globalWindowManager) throws NoSuchFieldException, IllegalAccessException {
    Field viewsField = globalWindowManager.getClass().getDeclaredField("mViews");
    viewsField.setAccessible(true);
    Object viewsFieldValue = viewsField.get(globalWindowManager);
    if (viewsFieldValue instanceof List<?>)
        return (List<?>)viewsFieldValue;
    else if (viewsFieldValue instanceof View[]) {
        return new ArrayList<>(Arrays.asList((View[])viewsFieldValue));
    }
    return null;
}

我已经在Android 5,6和7上测试了这种方法。当然,当你使用反射时,你应该检查一些字段的值是否为空并且确实具有预期的类型。因此,通过反射访问的内部数据结构可以在Android的未来版本中更改,也可以由设备供应商更改,即使在现有的Android版本中也是如此。为了简洁起见,我没有在这里添加空或错类型的检查。