blob: 6c5dd3388cd7937228413441f2d32e0bafe79141 [file] [log] [blame]
package com.android.deskclock.widget;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
/**
* When this layout is in the Horizontal orientation and one and only one child is a TextView with a
* non-null android:ellipsize, this layout will reduce android:maxWidth of that TextView to ensure
* the siblings are not truncated. This class is useful when that ellipsize-text-view "starts"
* before other children of this view group. This layout has no effect if:
* <ul>
* <li>the orientation is not horizontal</li>
* <li>any child has weights.</li>
* <li>more than one child has a non-null android:ellipsize.</li>
* </ul>
*
* <p>The purpose of this horizontal-linear-layout is to ensure that when the sum of widths of the
* children are greater than this parent, the maximum width of the ellipsize-text-view, is reduced
* so that no siblings are truncated.</p>
*
* <p>For example: Given Text1 has android:ellipsize="end" and Text2 has android:ellipsize="none",
* as Text1 and/or Text2 grow in width, both will consume more width until Text2 hits the end
* margin, then Text1 will cease to grow and instead shrink to accommodate any further growth in
* Text2.</p>
* <ul>
* <li>|[text1]|[text2] |</li>
* <li>|[text1 text1]|[text2 text2] |</li>
* <li>|[text...]|[text2 text2 text2]|</li>
* </ul>
*/
public class EllipsizeLayout extends LinearLayout {
@SuppressWarnings("unused")
public EllipsizeLayout(Context context) {
this(context, null);
}
public EllipsizeLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
/**
* This override only acts when the LinearLayout is in the Horizontal orientation and is in it's
* final measurement pass(MeasureSpec.EXACTLY). In this case only, this class
* <ul>
* <li>Identifies the one TextView child with the non-null android:ellipsize.</li>
* <li>Re-measures the needed width of all children (by calling measureChildWithMargins with
* the width measure specification to MeasureSpec.UNSPECIFIED.)</li>
* <li>Sums the children's widths.</li>
* <li>Whenever the sum of the children's widths is greater than this parent was allocated,
* the maximum width of the one TextView child with the non-null android:ellipsize is
* reduced.</li>
* </ul>
*
* @param widthMeasureSpec horizontal space requirements as imposed by the parent
* @param heightMeasureSpec vertical space requirements as imposed by the parent
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (getOrientation() == HORIZONTAL
&& (MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY)) {
int totalLength = 0;
// If any of the constraints of this class are exceeded, outOfSpec becomes true
// and the no alterations are made to the ellipsize-text-view.
boolean outOfSpec = false;
TextView ellipsizeView = null;
final int count = getChildCount();
final int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
final int queryWidthMeasureSpec = MeasureSpec.
makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.UNSPECIFIED);
for (int ii = 0; ii < count && !outOfSpec; ++ii) {
final View child = getChildAt(ii);
if (child != null && child.getVisibility() != GONE) {
// Identify the ellipsize view
if (child instanceof TextView) {
final TextView tv = (TextView) child;
if (tv.getEllipsize() != null) {
if (ellipsizeView == null) {
ellipsizeView = tv;
// Clear the maximum width on ellipsizeView before measurement
ellipsizeView.setMaxWidth(Integer.MAX_VALUE);
} else {
// TODO: support multiple android:ellipsize
outOfSpec = true;
}
}
}
// Ask the child to measure itself
measureChildWithMargins(child, queryWidthMeasureSpec, 0, heightMeasureSpec, 0);
// Get the layout parameters to check for a weighted width and to add the
// child's margins to the total length.
final LinearLayout.LayoutParams layoutParams =
(LinearLayout.LayoutParams) child.getLayoutParams();
if (layoutParams != null) {
outOfSpec |= (layoutParams.weight > 0f);
totalLength += child.getMeasuredWidth()
+ layoutParams.leftMargin + layoutParams.rightMargin;
} else {
outOfSpec = true;
}
}
}
// Last constraint test
outOfSpec |= (ellipsizeView == null) || (totalLength == 0);
if (!outOfSpec && totalLength > parentWidth) {
int maxWidth = ellipsizeView.getMeasuredWidth() - (totalLength - parentWidth);
// TODO: Respect android:minWidth (easy with @TargetApi(16))
final int minWidth = 0;
if (maxWidth < minWidth) {
maxWidth = minWidth;
}
ellipsizeView.setMaxWidth(maxWidth);
}
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}