MEASURE
*
measure(int, int)
f2
M
M M M
M M
→ onMeasure(int, int)
measureHierarchy(...)
Slide 18
Slide 18 text
LAZY MEASURE
Multi-MeasureSpec cache, invalidated
in requestLayout()
Slide 19
Slide 19 text
LAZY MEASURE
public final void measure(int widthMeasureSpec,
int heightMeasureSpec) {
...
int cacheIndex = mMeasureCache.indexOfKey(key);
if (cacheIndex < 0 || sIgnoreMeasureCache) {
onMeasure(widthMeasureSpec, heightMeasureSpec);
mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
} else {
long value = mMeasureCache.valueAt(cacheIndex);
setMeasuredDimensionRaw((int) (value >> 32), (int) value);
mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
}
...
}
View.java
Slide 20
Slide 20 text
LAZY MEASURE
public void layout(int l, int t, int r, int b) {
if ((flags & PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT) != 0) {
onMeasure(mOldWidthMeasureSpec, mOldHeightMeasureSpec);
mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
}
...
}
View.java
Slide 21
Slide 21 text
LAYOUT
*
f2
M L
M L M L M L
M L M L
layout(int, int, int, int)
→ onLayout(boolean, int, int, int, int)
performLayout()
Slide 22
Slide 22 text
FRAME IT
public void layout(int l, int t, int r, int b) {
...
boolean changed = isLayoutModeOptical(mParent) ?
setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b);
...
}
View.java
Slide 23
Slide 23 text
DRAW
*
f2
M L D
M L D M L D M L D
M L D M L D
draw(Canvas)
→ onDraw(Canvas)
performDraw()
INVARIANTS
Layout means measurement is done.
Drawing means layout is done.
Slide 26
Slide 26 text
SMELLS
1. getMeasured*() calls outside onLayout()
2. New allocations during traversal
· onLayout: ok-ish
· onMeasure: avoid
· onDraw: nope
3. post(Runnable) to mean “after layout”
Slide 27
Slide 27 text
HAPPENS TO WORK
public final class MyActivity extends Activity {
...
@Override
public void onCreate() {
final View myView = findViewById(R.id.some_id);
myView.post(new Runnable() {
@Override
public void run() {
Log.d(“LOGTAG”, myView.getWidth());
}
});
}
...
}
OnPreDrawListener
// 1. Save layout state and wait for next frame.
getViewTreeObserver().addOnPreDrawListener(new OnPreDrawListener() {
@Override
public boolean onPreDraw() {
getViewTreeObserver().removeOnPreDrawListener(this);
// 2. Restore original layout state.
// 3. Trigger animators towards new layout state.
}
}
WRAP VIEW METHODS
public class LogRequestLayout extends Interceptor {
@Override
public void requestLayout(View view) {
super.requestLayout(view);
Log.d(LOGTAG, “requestLayout() on ” + view);
}
}
Slide 44
Slide 44 text
DEPLOY
public final class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
Probe.deploy(this, new DrawGreen(),
new Filter.ViewId(R.id.view2));
super.onCreate(savedInstanceState);
setContentView(R.id.main_activity);
}
}
Slide 45
Slide 45 text
FANCY HACKING ON
DEEP LAYOUT STUFF?
We're hiring :-)