155 |
* automatically when any of the child view changes its preferences |
* automatically when any of the child view changes its preferences |
156 |
* via {@link #preferenceChanged(View, boolean, boolean)}. |
* via {@link #preferenceChanged(View, boolean, boolean)}. |
157 |
* |
* |
158 |
* The layout will be updated the next time when {@link #setSize()} is |
* The layout will be updated the next time when |
159 |
* called, typically from within the {@link #paint()} method. |
* {@link #setSize(float, float)} is called, typically from within the |
160 |
|
* {@link #paint(Graphics, Shape)} method. |
161 |
* |
* |
162 |
* Valid values for the axis are {@link View#X_AXIS} and |
* Valid values for the axis are {@link View#X_AXIS} and |
163 |
* {@link View#Y_AXIS}. |
* {@link View#Y_AXIS}. |
217 |
* @param alloc the allocated region for the child to paint into |
* @param alloc the allocated region for the child to paint into |
218 |
* @param index the index of the child to be painted |
* @param index the index of the child to be painted |
219 |
* |
* |
220 |
* @see {@link #childAllocation} |
* @see #childAllocation(int, Rectangle) |
221 |
*/ |
*/ |
222 |
protected void paintChild(Graphics g, Rectangle alloc, int index) |
protected void paintChild(Graphics g, Rectangle alloc, int index) |
223 |
{ |
{ |
301 |
setSize(bounds.width, bounds.height); |
setSize(bounds.width, bounds.height); |
302 |
|
|
303 |
Rectangle inside = getInsideAllocation(a); |
Rectangle inside = getInsideAllocation(a); |
|
|
|
304 |
Rectangle copy = new Rectangle(inside); |
Rectangle copy = new Rectangle(inside); |
305 |
int count = getViewCount(); |
int count = getViewCount(); |
306 |
for (int i = 0; i < count; ++i) |
for (int i = 0; i < count; ++i) |
307 |
{ |
{ |
308 |
copy.setBounds(inside); |
copy.setBounds(inside); |
309 |
childAllocation(i, copy); |
childAllocation(i, copy); |
310 |
paintChild(g, copy, i); |
if (!copy.isEmpty()) |
311 |
|
paintChild(g, copy, i); |
312 |
} |
} |
313 |
} |
} |
314 |
|
|
358 |
} |
} |
359 |
|
|
360 |
/** |
/** |
361 |
|
* Calculates the layout of the children of this <code>BoxView</code> along |
362 |
|
* the specified axis. |
363 |
|
* |
364 |
|
* @param span the target span |
365 |
|
* @param axis the axis that is examined |
366 |
|
* @param offsets an empty array, filled with the offsets of the children |
367 |
|
* @param spans an empty array, filled with the spans of the children |
368 |
|
*/ |
369 |
|
protected void baselineLayout(int span, int axis, int[] offsets, |
370 |
|
int[] spans) |
371 |
|
{ |
372 |
|
if (axis == myAxis) |
373 |
|
layoutMajorAxis(span, axis, offsets, spans); |
374 |
|
else |
375 |
|
layoutMinorAxis(span, axis, offsets, spans); |
376 |
|
} |
377 |
|
|
378 |
|
/** |
379 |
* Calculates the size requirements of this <code>BoxView</code> along |
* Calculates the size requirements of this <code>BoxView</code> along |
380 |
* its major axis, that is the axis specified in the constructor. |
* its major axis, that is the axis specified in the constructor. |
381 |
* |
* |
389 |
protected SizeRequirements calculateMajorAxisRequirements(int axis, |
protected SizeRequirements calculateMajorAxisRequirements(int axis, |
390 |
SizeRequirements sr) |
SizeRequirements sr) |
391 |
{ |
{ |
392 |
if (sr == null) |
SizeRequirements[] childReqs = getChildRequirements(axis); |
393 |
sr = new SizeRequirements(); |
return SizeRequirements.getTiledSizeRequirements(childReqs); |
|
else |
|
|
{ |
|
|
sr.maximum = 0; |
|
|
sr.minimum = 0; |
|
|
sr.preferred = 0; |
|
|
sr.alignment = 0.5F; |
|
|
} |
|
|
|
|
|
int count = getViewCount(); |
|
|
|
|
|
// Sum up the sizes of the children along the specified axis. |
|
|
for (int i = 0; i < count; ++i) |
|
|
{ |
|
|
View child = getView(i); |
|
|
sr.minimum += child.getMinimumSpan(axis); |
|
|
sr.preferred += child.getPreferredSpan(axis); |
|
|
sr.maximum += child.getMaximumSpan(axis); |
|
|
} |
|
|
return sr; |
|
394 |
} |
} |
395 |
|
|
396 |
/** |
/** |
408 |
protected SizeRequirements calculateMinorAxisRequirements(int axis, |
protected SizeRequirements calculateMinorAxisRequirements(int axis, |
409 |
SizeRequirements sr) |
SizeRequirements sr) |
410 |
{ |
{ |
411 |
if (sr == null) |
SizeRequirements[] childReqs = getChildRequirements(axis); |
412 |
sr = new SizeRequirements(); |
return SizeRequirements.getAlignedSizeRequirements(childReqs); |
|
else |
|
|
{ |
|
|
sr.maximum = 0; |
|
|
sr.minimum = 0; |
|
|
sr.preferred = 0; |
|
|
sr.alignment = 0.5F; |
|
|
} |
|
|
|
|
|
int count = getViewCount(); |
|
|
|
|
|
int aboveBaseline = 0; |
|
|
int belowBaseline = 0; |
|
|
int aboveBaselineMin = 0; |
|
|
int belowBaselineMin = 0; |
|
|
int aboveBaselineMax = 0; |
|
|
int belowBaselineMax = 0; |
|
|
|
|
|
for (int i = 0; i < count; ++i) |
|
|
{ |
|
|
View child = getView(i); |
|
|
float align = child.getAlignment(axis); |
|
|
int pref = (int) child.getPreferredSpan(axis); |
|
|
int min = (int) child.getMinimumSpan(axis); |
|
|
int max = (int) child.getMaximumSpan(axis); |
|
|
aboveBaseline += (int) (align * pref); |
|
|
belowBaseline += (int) ((1.F - align) * pref); |
|
|
aboveBaselineMin += (int) (align * min); |
|
|
belowBaselineMin += (int) ((1.F - align) * min); |
|
|
aboveBaselineMax += (int) (align * max); |
|
|
belowBaselineMax += (int) ((1.F - align) * max); |
|
|
} |
|
|
sr.minimum = aboveBaselineMin + belowBaselineMin; |
|
|
sr.maximum = aboveBaselineMax + belowBaselineMax; |
|
|
sr.preferred = aboveBaseline + belowBaseline; |
|
|
if (aboveBaseline == 0) |
|
|
sr.alignment = 1.0F; |
|
|
else |
|
|
sr.alignment = (float) (sr.preferred / aboveBaseline); |
|
|
|
|
|
return sr; |
|
413 |
} |
} |
414 |
|
|
415 |
/** |
/** |
524 |
*/ |
*/ |
525 |
protected void layout(int width, int height) |
protected void layout(int width, int height) |
526 |
{ |
{ |
527 |
this.width = width; |
baselineLayout(width, X_AXIS, offsetsX, spansX); |
528 |
this.height = height; |
baselineLayout(height, Y_AXIS, offsetsY, spansY); |
|
|
|
|
if (myAxis == X_AXIS) |
|
|
{ |
|
|
layoutMajorAxis(width, X_AXIS, offsetsX, spansX); |
|
|
layoutMinorAxis(height, Y_AXIS, offsetsY, spansY); |
|
|
} |
|
|
else |
|
|
{ |
|
|
layoutMajorAxis(height, Y_AXIS, offsetsY, spansY); |
|
|
layoutMinorAxis(width, X_AXIS, offsetsX, spansX); |
|
|
} |
|
529 |
} |
} |
530 |
|
|
531 |
/** |
/** |
535 |
* to layout the children |
* to layout the children |
536 |
* @param axis the axis along which the layout is performed |
* @param axis the axis along which the layout is performed |
537 |
* @param offsets the array that holds the offsets of the children on exit |
* @param offsets the array that holds the offsets of the children on exit |
538 |
* @param offsets the array that holds the spans of the children on exit |
* @param spans the array that holds the spans of the children on exit |
539 |
*/ |
*/ |
540 |
protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets, |
protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets, |
541 |
int[] spans) |
int[] spans) |
542 |
{ |
{ |
543 |
// Allocate SizeRequirements for each child view. |
SizeRequirements[] childReqs = getChildRequirements(axis); |
|
int count = getViewCount(); |
|
|
SizeRequirements[] childReqs = new SizeRequirements[count]; |
|
|
for (int i = 0; i < count; ++i) |
|
|
{ |
|
|
View view = getView(i); |
|
|
childReqs[i] = new SizeRequirements((int) view.getMinimumSpan(axis), |
|
|
(int) view.getPreferredSpan(axis), |
|
|
(int) view.getMaximumSpan(axis), |
|
|
view.getAlignment(axis)); |
|
|
} |
|
|
|
|
544 |
// Calculate the spans and offsets using the SizeRequirements uility |
// Calculate the spans and offsets using the SizeRequirements uility |
545 |
// methods. |
// methods. |
546 |
SizeRequirements.calculateTiledPositions(targetSpan, null, childReqs, |
SizeRequirements.calculateTiledPositions(targetSpan, null, childReqs, |
547 |
offsets, spans); |
offsets, spans); |
|
|
|
548 |
validateLayout(axis); |
validateLayout(axis); |
549 |
} |
} |
550 |
|
|
555 |
* to layout the children |
* to layout the children |
556 |
* @param axis the axis along which the layout is performed |
* @param axis the axis along which the layout is performed |
557 |
* @param offsets the array that holds the offsets of the children on exit |
* @param offsets the array that holds the offsets of the children on exit |
558 |
* @param offsets the array that holds the spans of the children on exit |
* @param spans the array that holds the spans of the children on exit |
559 |
*/ |
*/ |
560 |
protected void layoutMinorAxis(int targetSpan, int axis, int[] offsets, |
protected void layoutMinorAxis(int targetSpan, int axis, int[] offsets, |
561 |
int[] spans) |
int[] spans) |
562 |
{ |
{ |
563 |
// Allocate SizeRequirements for each child view. |
SizeRequirements[] childReqs = getChildRequirements(axis); |
|
int count = getViewCount(); |
|
|
SizeRequirements[] childReqs = new SizeRequirements[count]; |
|
|
for (int i = 0; i < count; ++i) |
|
|
{ |
|
|
View view = getView(i); |
|
|
childReqs[i] = new SizeRequirements((int) view.getMinimumSpan(axis), |
|
|
(int) view.getPreferredSpan(axis), |
|
|
(int) view.getMaximumSpan(axis), |
|
|
view.getAlignment(axis)); |
|
|
} |
|
|
|
|
564 |
// Calculate the spans and offsets using the SizeRequirements uility |
// Calculate the spans and offsets using the SizeRequirements uility |
565 |
// methods. |
// methods. |
566 |
SizeRequirements.calculateAlignedPositions(targetSpan, null, childReqs, |
// TODO: This might be an opportunity for performance optimization. Here |
567 |
|
// we could use a cached instance of SizeRequirements instead of passing |
568 |
|
// null to baselineRequirements. However, this would involve rewriting |
569 |
|
// the baselineRequirements() method to not use the SizeRequirements |
570 |
|
// utility method, since they cannot reuse a cached instance. |
571 |
|
SizeRequirements total = baselineRequirements(axis, null); |
572 |
|
SizeRequirements.calculateAlignedPositions(targetSpan, total, childReqs, |
573 |
offsets, spans); |
offsets, spans); |
574 |
validateLayout(axis); |
validateLayout(axis); |
575 |
} |
} |
619 |
layoutChanged(X_AXIS); |
layoutChanged(X_AXIS); |
620 |
if (this.height != (int) height) |
if (this.height != (int) height) |
621 |
layoutChanged(Y_AXIS); |
layoutChanged(Y_AXIS); |
622 |
|
|
623 |
|
this.width = (int) width; |
624 |
|
this.height = (int) height; |
625 |
|
|
626 |
Rectangle outside = new Rectangle(0, 0, this.width, this.height); |
Rectangle outside = new Rectangle(0, 0, this.width, this.height); |
627 |
Rectangle inside = getInsideAllocation(outside); |
Rectangle inside = getInsideAllocation(outside); |
641 |
if (axis == Y_AXIS) |
if (axis == Y_AXIS) |
642 |
yLayoutValid = true; |
yLayoutValid = true; |
643 |
} |
} |
644 |
|
|
645 |
|
/** |
646 |
|
* Returns the size requirements of this view's children for the major |
647 |
|
* axis. |
648 |
|
* |
649 |
|
* @return the size requirements of this view's children for the major |
650 |
|
* axis |
651 |
|
*/ |
652 |
|
SizeRequirements[] getChildRequirements(int axis) |
653 |
|
{ |
654 |
|
// Allocate SizeRequirements for each child view. |
655 |
|
int count = getViewCount(); |
656 |
|
SizeRequirements[] childReqs = new SizeRequirements[count]; |
657 |
|
for (int i = 0; i < count; ++i) |
658 |
|
{ |
659 |
|
View view = getView(i); |
660 |
|
childReqs[i] = new SizeRequirements((int) view.getMinimumSpan(axis), |
661 |
|
(int) view.getPreferredSpan(axis), |
662 |
|
(int) view.getMaximumSpan(axis), |
663 |
|
view.getAlignment(axis)); |
664 |
|
} |
665 |
|
return childReqs; |
666 |
|
} |
667 |
|
|
668 |
|
/** |
669 |
|
* Returns the span for the child view with the given index for the specified |
670 |
|
* axis. |
671 |
|
* |
672 |
|
* @param axis the axis to examine, either <code>X_AXIS</code> or |
673 |
|
* <code>Y_AXIS</code> |
674 |
|
* @param childIndex the index of the child for for which to return the span |
675 |
|
* |
676 |
|
* @return the span for the child view with the given index for the specified |
677 |
|
* axis |
678 |
|
*/ |
679 |
|
protected int getSpan(int axis, int childIndex) |
680 |
|
{ |
681 |
|
if (axis == X_AXIS) |
682 |
|
return spansX[childIndex]; |
683 |
|
else |
684 |
|
return spansY[childIndex]; |
685 |
|
} |
686 |
|
|
687 |
|
/** |
688 |
|
* Returns the offset for the child view with the given index for the |
689 |
|
* specified axis. |
690 |
|
* |
691 |
|
* @param axis the axis to examine, either <code>X_AXIS</code> or |
692 |
|
* <code>Y_AXIS</code> |
693 |
|
* @param childIndex the index of the child for for which to return the span |
694 |
|
* |
695 |
|
* @return the offset for the child view with the given index for the |
696 |
|
* specified axis |
697 |
|
*/ |
698 |
|
protected int getOffset(int axis, int childIndex) |
699 |
|
{ |
700 |
|
if (axis == X_AXIS) |
701 |
|
return offsetsX[childIndex]; |
702 |
|
else |
703 |
|
return offsetsY[childIndex]; |
704 |
|
} |
705 |
|
|
706 |
|
/** |
707 |
|
* Returns the alignment for this box view for the specified axis. The |
708 |
|
* axis that is tiled (the major axis) will be requested to be aligned |
709 |
|
* centered (0.5F). The minor axis alignment depends on the child view's |
710 |
|
* total alignment. |
711 |
|
* |
712 |
|
* @param axis the axis which is examined |
713 |
|
* |
714 |
|
* @return the alignment for this box view for the specified axis |
715 |
|
*/ |
716 |
|
public float getAlignment(int axis) |
717 |
|
{ |
718 |
|
if (axis == myAxis) |
719 |
|
return 0.5F; |
720 |
|
else |
721 |
|
return baselineRequirements(axis, null).alignment; |
722 |
|
} |
723 |
|
|
724 |
|
/** |
725 |
|
* Called by a child View when its preferred span has changed. |
726 |
|
* |
727 |
|
* @param width indicates that the preferred width of the child changed. |
728 |
|
* @param height indicates that the preferred height of the child changed. |
729 |
|
* @param child the child View. |
730 |
|
*/ |
731 |
|
public void preferenceChanged (View child, boolean width, boolean height) |
732 |
|
{ |
733 |
|
if (width) |
734 |
|
xLayoutValid = false; |
735 |
|
if (height) |
736 |
|
yLayoutValid = false; |
737 |
|
super.preferenceChanged(child, width, height); |
738 |
|
} |
739 |
} |
} |