我在我们的应用程序中遇到了这种用例。在我们的应用程序中,有3个视图。ImageView | TextView | ImageView
。两个ImageView必须在布局中可见。TextView应该在末尾被省略。我想出了一个自定义ViewGroup
。
public class PriorityLayoutHorizontal extends ViewGroup
{
private ArrayList<Integer> mPriorityHighChildren;
public PriorityLayoutHorizontal(Context context)
{
this(context, null);
}
public PriorityLayoutHorizontal(Context context, AttributeSet attrs)
{
this(context, attrs, 0);
}
public PriorityLayoutHorizontal(Context context, AttributeSet attrs, int defStyleAttr)
{
super(context, attrs, defStyleAttr);
TypedArray typedArray = null;
try
{
typedArray = context.obtainStyledAttributes(attrs, R.styleable.PriorityLayoutHorizontal, defStyleAttr, 0);
final int id = typedArray.getResourceId(R.styleable.PriorityLayoutHorizontal_priorityHigh, -1);
if(id != -1)
{
final int[] highPriorityChildren = getResources().getIntArray(id);
setPriorityHigh(highPriorityChildren);
}
}
finally
{
if(typedArray != null)
{
typedArray.recycle();
}
}
}
public void setPriorityHigh(int... priorityHigh)
{
Integer[] priorityHighInteger = new Integer[priorityHigh.length];
int i = 0;
for(int value : priorityHigh)
{
priorityHighInteger[i++] = Integer.valueOf(value);
}
mPriorityHighChildren = new ArrayList<Integer>(Arrays.asList(priorityHighInteger));
}
int mMaxHeight = 0;
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int widthUsed = 0;
int heightUsed = 0;
final int childCount = getChildCount();
for(int childPosition : mPriorityHighChildren)
{
final View childView = getChildAt(childPosition);
if(childView.getVisibility() != View.GONE)
{
measureChildWithMargins(childView, widthMeasureSpec, widthUsed, heightMeasureSpec, heightUsed);
widthUsed += getMeasuredWidthWithMargins(childView);
heightUsed = Math.max(getMeasuredHeightWithMargins(childView), heightUsed);
}
}
for(int childPosition = 0; childPosition < childCount; childPosition++)
{
if(! mPriorityHighChildren.contains(Integer.valueOf(childPosition)))
{
final View childView = getChildAt(childPosition);
if(childView.getVisibility() != View.GONE)
{
measureChildWithMargins(childView, widthMeasureSpec, widthUsed, heightMeasureSpec, heightUsed);
widthUsed += getMeasuredWidthWithMargins(childView);
heightUsed = Math.max(getMeasuredHeightWithMargins(childView), heightUsed);
}
}
}
mMaxHeight = heightUsed;
int heightSize = heightUsed + getPaddingTop() + getPaddingBottom();
setMeasuredDimension(widthSize, heightSize);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b)
{
final int paddingLeft = getPaddingLeft();
final int paddingTop = getPaddingTop();
int spaceUsed = paddingLeft;
for (int childPosition = 0; childPosition < getChildCount(); childPosition++)
{
final View childView = getChildAt(childPosition);
if(childView.getVisibility() != View.GONE)
{
final int top = (mMaxHeight / 2) - (childView.getMeasuredHeight() / 2);
layoutView(childView, spaceUsed, paddingTop + top, childView.getMeasuredWidth(), childView.getMeasuredHeight());
spaceUsed += getWidthWithMargins(childView);
}
}
}
private int getWidthWithMargins(View child)
{
final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
return child.getWidth() + lp.leftMargin + lp.rightMargin;
}
private int getHeightWithMargins(View child)
{
final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
return child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;
}
private int getMeasuredWidthWithMargins(View child)
{
final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
return child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;
}
private int getMeasuredHeightWithMargins(View child)
{
final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
return child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;
}
private void layoutView(View view, int left, int top, int width, int height)
{
MarginLayoutParams margins = (MarginLayoutParams) view.getLayoutParams();
final int leftWithMargins = left + margins.leftMargin;
final int topWithMargins = top + margins.topMargin;
view.layout(leftWithMargins, topWithMargins, leftWithMargins + width, topWithMargins + height);
}
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs)
{
return new MarginLayoutParams(getContext(), attrs);
}
@Override
protected LayoutParams generateDefaultLayoutParams()
{
return new MarginLayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
}
}
在 values/attrs.xml 中声明一个自定义属性
<declare-styleable name="PriorityLayoutHorizontal">
<attr name="priorityHigh" format="reference"/>
</declare-styleable>
使用这个布局,您可以为在布局中一定要可见的视图赋予高优先级。剩下的一个TextView将根据屏幕上剩余的宽度进行绘制。
要使用此布局:
<com.example.component.PriorityLayoutHorizontal
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:priorityHigh="@array/priority_array"
>
<TextView
android:id="@+id/contact_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/your_drawable"
/>
</com.example.component.PriorityLayoutHorizontal>
并在values/arrays.xml中定义priority_array
<integer-array name="priority_array">
<item>1</item>
</integer-array>
这里,我们已经提到了View “1”的优先级。那是您布局中的第二个TextView。因此,第二个TextView将始终可见,而第一个TextView将被省略。
P.S:这是一个通用解决方案。也就是说,这可以与不同的View一起使用,并且在一行中可以有多个View。您可以使用此布局,或编写特定于您用例的自定义ViewGroup。