Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
ViewUtils.java
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5package io.flutter.util;
6
7import android.app.Activity;
8import android.content.Context;
9import android.content.ContextWrapper;
10import android.view.View;
11import android.view.ViewGroup;
12import androidx.annotation.NonNull;
13import androidx.annotation.Nullable;
14import androidx.window.layout.WindowMetrics;
15import androidx.window.layout.WindowMetricsCalculator;
16
17public final class ViewUtils {
18 public interface DisplayUpdater {
19 /** Publishes display metrics to Dart code in Flutter. */
20 public void updateDisplayMetrics(float width, float height, float density);
21 }
22
23 /**
24 * Calculates the maximum display metrics for the given context, and pushes the metric data to the
25 * updater.
26 */
28 @Nullable Context context, @NonNull DisplayUpdater updater) {
29 Activity activity = getActivity(context);
30 if (activity != null) {
31 WindowMetrics metrics =
32 WindowMetricsCalculator.getOrCreate().computeMaximumWindowMetrics(activity);
33 float width = metrics.getBounds().width();
34 float height = metrics.getBounds().height();
35 float density = context.getResources().getDisplayMetrics().density;
36 updater.updateDisplayMetrics(width, height, density);
37 }
38 }
39
40 /**
41 * Retrieves the {@link Activity} from a given {@link Context}.
42 *
43 * <p>This method will recursively traverse up the context chain if it is a {@link ContextWrapper}
44 * until it finds the first instance of the base context that is an {@link Activity}.
45 */
46 @Nullable
47 public static Activity getActivity(@Nullable Context context) {
48 if (context == null) {
49 return null;
50 }
51 if (context instanceof Activity) {
52 return (Activity) context;
53 }
54 if (context instanceof ContextWrapper) {
55 // Recurse up chain of base contexts until we find an Activity.
56 return getActivity(((ContextWrapper) context).getBaseContext());
57 }
58 return null;
59 }
60
61 /**
62 * Determines if the current view or any descendant view has focus.
63 *
64 * @param root The root view.
65 * @return True if the current view or any descendant view has focus.
66 */
67 public static boolean childHasFocus(@Nullable View root) {
68 return traverseHierarchy(root, (View view) -> view.hasFocus());
69 }
70
71 /**
72 * Returns true if the root or any child view is an instance of the given types.
73 *
74 * @param root The root view.
75 * @param viewTypes The types of views.
76 * @return true if any child view is an instance of any of the given types.
77 */
78 public static boolean hasChildViewOfType(@Nullable View root, Class<? extends View>[] viewTypes) {
79 return traverseHierarchy(
80 root,
81 (View view) -> {
82 for (int i = 0; i < viewTypes.length; i++) {
83 final Class<? extends View> viewType = viewTypes[i];
84 if (viewType.isInstance(view)) {
85 return true;
86 }
87 }
88 return false;
89 });
90 }
91
92 /** Allows to visit a view. */
93 public interface ViewVisitor {
94 boolean run(@NonNull View view);
95 }
96
97 /**
98 * Traverses the view hierarchy in pre-order and runs the visitor for each child view including
99 * the root view.
100 *
101 * <p>If the visitor returns true, the traversal stops, and the method returns true.
102 *
103 * <p>If the visitor returns false, the traversal continues until all views are visited.
104 *
105 * @param root The root view.
106 * @param visitor The visitor.
107 * @return true if the visitor returned true for a given view.
108 */
109 public static boolean traverseHierarchy(@Nullable View root, @NonNull ViewVisitor visitor) {
110 if (root == null) {
111 return false;
112 }
113 if (visitor.run(root)) {
114 return true;
115 }
116 if (root instanceof ViewGroup) {
117 final ViewGroup viewGroup = (ViewGroup) root;
118 for (int idx = 0; idx < viewGroup.getChildCount(); idx++) {
119 if (traverseHierarchy(viewGroup.getChildAt(idx), visitor)) {
120 return true;
121 }
122 }
123 }
124 return false;
125 }
126}
static boolean traverseHierarchy(@Nullable View root, @NonNull ViewVisitor visitor)
static Activity getActivity(@Nullable Context context)
static boolean childHasFocus(@Nullable View root)
static boolean hasChildViewOfType(@Nullable View root, Class<? extends View >[] viewTypes)
static void calculateMaximumDisplayMetrics( @Nullable Context context, @NonNull DisplayUpdater updater)
void updateDisplayMetrics(float width, float height, float density)
boolean run(@NonNull View view)
int32_t height
int32_t width