diff options
| author | Adam Powell <adamp@google.com> | 2014-12-18 15:22:26 -0800 |
|---|---|---|
| committer | Adam Powell <adamp@google.com> | 2015-11-19 09:31:56 -0800 |
| commit | c55d5072ac52cee1811b52406419228fa81119ce (patch) | |
| tree | df0dcdd6dab56a679b03c29f93e4a2f51f6ccd4a /core/java/android/widget/LinearLayout.java | |
| parent | 6d198e8c968b038de1a38c230b87d9c93c1a9a4a (diff) | |
Add support for partial view layouts
Traditionally, when a view called requestLayout it would force
recursive requestLayout calls for all parent views up the
hierarchy. This meant that there was no way to determine at traversal
time whether a parent view itself needed layout, or if just one of its
descendants did.
Add a ViewParent method requestPartialLayoutForChild(View). This lets
a caller state that a particular child of a given parent needs a
remeasure and relayout at its current measured size and position
within that parent. This can help prevent the full-tree relayout often
caused by otherwise trivial changes. Partial layouts are processed
after any pending "full" relayout during ViewRoot traversals, but
before drawing.
Add a ViewGroup method requestLayoutForChild(View). This lets a
ViewGroup decide whether it is more appropriate to request a
traditional relayout or a partial layout for itself or just the child
that changed.
Add a ViewParent method findDependentLayoutAxes. This allows a caller
to check if the ViewParent's layout is dependent on a specific direct
child view along one or both axes. Called recursively, this can be
used to determine if a change in a child view can be isolated to a
partial layout, even if its direct parent's own layout is tied to its
other ancestors. (e.g. MATCH_PARENT, LinearLayout weights)
Implement ViewGroup#requestPartialLayoutForChild to call new
ViewParent method findDependentLayoutAxes and based on the result,
either request a full layout for itself or a partial layout for the
child in question.
Implement findDependentLayoutAxes for common framework ViewGroups. A
private implementation in ViewGroup is available for use by framework
classes that will deal with basic LayoutParams. These implementations
specifically check for derived LayoutParams classes and abort the
optimization if they find something beyond their expected parameter
types.
Change-Id: I0a1a9b79293d17d4fae8d9892b96d3586f9401ae
Diffstat (limited to 'core/java/android/widget/LinearLayout.java')
| -rw-r--r-- | core/java/android/widget/LinearLayout.java | 57 |
1 files changed, 57 insertions, 0 deletions
diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java index ad939be13a44..ba868a15ef1e 100644 --- a/core/java/android/widget/LinearLayout.java +++ b/core/java/android/widget/LinearLayout.java @@ -16,6 +16,7 @@ package android.widget; +import android.view.ViewParent; import com.android.internal.R; import android.annotation.IntDef; @@ -37,6 +38,8 @@ import android.widget.RemoteViews.RemoteView; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; +import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; /** * A Layout that arranges its children in a single column or a single row. The direction of @@ -644,6 +647,60 @@ public class LinearLayout extends ViewGroup { } } + @Override + public int findDependentLayoutAxes(View child, int axisFilter) { + // This implementation is almost exactly equivalent to the default implementation + // offered to the rest of the framework in ViewGroup, but we treat weight to be + // functionally equivalent to MATCH_PARENT along the orientation axis. + + if (!checkPartialLayoutParams(child, LayoutParams.class)) return axisFilter; + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + if (child.didLayoutParamsChange()) { + // Anything could have changed about our previous assumptions. + return axisFilter; + } + + // Our layout can always end up depending on a WRAP_CONTENT child. + final int wrapAxisFilter = ((lp.width == WRAP_CONTENT ? FLAG_LAYOUT_AXIS_HORIZONTAL : 0) + | (lp.height == WRAP_CONTENT ? FLAG_LAYOUT_AXIS_VERTICAL : 0)) & axisFilter; + + if (wrapAxisFilter == axisFilter) { + // We know all queried axes are affected, just return early. + return wrapAxisFilter; + } + + // Our layout *may* depend on a MATCH_PARENT child, depending on whether we can determine + // that our layout will remain stable within our parent. We need to ask. + int matchAxisFilter = ((lp.width == MATCH_PARENT ? FLAG_LAYOUT_AXIS_HORIZONTAL : 0) + | (lp.height == MATCH_PARENT ? FLAG_LAYOUT_AXIS_VERTICAL : 0)) & axisFilter; + + // For LinearLayout, a nonzero weight is equivalent to MATCH_PARENT for this purpose. + if (lp.weight > 0) { + if (mOrientation == HORIZONTAL) { + matchAxisFilter |= FLAG_LAYOUT_AXIS_HORIZONTAL & axisFilter; + } else { + matchAxisFilter |= FLAG_LAYOUT_AXIS_VERTICAL & axisFilter; + } + } + + if (matchAxisFilter != 0) { + final ViewParent parent = getParent(); + if (parent != null) { + // If our parent depends on us for an axis, then our layout can also be affected + // by a MATCH_PARENT child along that axis. + return getParent().findDependentLayoutAxes(this, matchAxisFilter) + | wrapAxisFilter; + } + + // If we don't have a parent, assume we're affected + // in any determined affected direction. + return matchAxisFilter | wrapAxisFilter; + } + + // Two exact sizes and LayoutParams didn't change. We're safe. + return 0; + } + /** * Determines where to position dividers between children. * |
