Expand TextView with wrap_content until the neighbor view reaches the end of the parent

杀马特。学长 韩版系。学妹 提交于 2019-11-30 00:01:49
nshmura

You can archive this layout by TableLayout and shrinkColumns attribute.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    <!-- Row 1 -->
    <TableLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:shrinkColumns="0">

        <TableRow
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:gravity="center_vertical">

            <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:padding="4dp"
                    android:maxLines="1"
                    android:ellipsize="end"
                    android:text="abcdefghijklmnopqrstuvwxyz"/>

            <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:padding="4dp"
                    android:maxLines="1"
                    android:ellipsize="none"
                    android:text="rightText"/>
        </TableRow>

    </TableLayout>


    <!-- Row 2 -->
    <TableLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:shrinkColumns="0">

        <TableRow
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:gravity="center_vertical">

            <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:padding="4dp"
                    android:maxLines="1"
                    android:ellipsize="end"
                    android:text="Longer Text view abcdefghijklmnopqrstuvwxyz"/>

            <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:padding="4dp"
                    android:maxLines="1"
                    android:ellipsize="none"
                    android:text="rightText"/>
        </TableRow>

    </TableLayout>

    <!-- Row 3 -->
    <TableLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:shrinkColumns="0">

        <TableRow
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:gravity="center_vertical">

            <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:padding="4dp"
                    android:maxLines="1"
                    android:ellipsize="end"
                    android:text="Text view that is very logn and will not fit the parent width abcdefghijklmnopqrstuvwxyz"/>

            <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:padding="4dp"
                    android:maxLines="1"
                    android:ellipsize="none"
                    android:text="rightText"/>
        </TableRow>

    </TableLayout>

</LinearLayout>

Here is same question ;)

Here is a layout that will do what you'd like it to:

<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="left">

    <TextView
    android:id="@+id/leftTextView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_toLefOf="@+id/rightTextView"
    android:maxLines="1"
    android:textSize="18sp" />

    <TextView
    android:id="@+id/rightTextView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentRight="true"
    android:textSize="18sp" />

</RelativeLayout>

The key parts here are the gravity of the relative layout, and aligning the right textview as alignParentRight with the left textview attached to that on the left.

I suggest wrapping two TextView's into LinearLayout. Then apply android:weightSum="1" to this LinearLayout and apply android:layout_weight="1" to the child TextView that must extend.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:weightSum="1">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:ellipsize="end"
        android:maxLines="1"
        android:padding="8dp"
        android:text="blabla bla bla bla bla bla bla bla bla bla bla bla bla "/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="8dp"
        android:text="static text"/>

</LinearLayout>

Remember to set the two atributes this it to work perfectly:

android:ellipsize="end"
android:maxLines="1"

and LinearLayout must have android:layout_width="wrap_content"

If you would like this ViewGroup to take whole space, wrap it with another ViewGroup:

<RelativeLayout
   android:layout_height="wrap_content"
   android:layout_width="match_parent">

   <!--The previous view group-->

</RelativeLayout>

The Layout you are expected can be created with help of layout_weight attirbute which comes with LinearLayout. So you may need to use LinearLayout with weightSumand layout_weight (passing to its childview) attributes.

Here's a layout which divides your width of layout in four parts which divides in to 3:1 between both Textview. Intacting right TextView making left TextView displays text as much as possible it can show without disurbing right TextView.

Please feel free to try out with variant weightSum and layout_weight combination as per your need.

Layout:

<LinearLayout
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:weightSum="4" >

    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:singleLine="true"
        android:text="StackOverflow StackOverflow StackOverflow "
        />

    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="right"
        android:layout_weight="3"
        android:maxLines="1"
        android:text="TextView"
        android:textColor="@android:color/white" />
</LinearLayout>

I set the maxwidth of left textview base of the width of right textview, take a looking my code. hope this will help.

TextView leftText ;
TextView rightText;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    leftText = (TextView) findViewById(R.id.leftTextView);
    rightText = (TextView) findViewById(R.id.rightTextView);


    measureView(leftText);
    measureView(rightText);

    leftText.setMaxWidth(getWidth() - rightText.getMeasuredWidth());

}

private void measureView(View view) {
    ViewGroup.LayoutParams params = view.getLayoutParams();
    int childWidth = ViewGroup.getChildMeasureSpec(0, view.getPaddingLeft() + view.getPaddingRight(), params.width);
    int childHeight = ViewGroup.getChildMeasureSpec(0, view.getPaddingBottom() + view.getPaddingTop(), params.height);
    view.measure(childWidth, childHeight);

}

private int getWidth() {
    WindowManager wm = (WindowManager)getSystemService(Context.WINDOW_SERVICE);
    Display display = wm.getDefaultDisplay();
    return display.getWidth();
}

and the xml is:

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

<TextView
    android:id="@+id/leftTextView"
    android:layout_width="wrap_content"
    android:layout_height="40dp"
    android:singleLine="true"
    android:text="abadabadabadabadabadabadabadabadabadabaasdfasdfasdfadabadabadabadabadabadabadabadabadabadabaasdfasdfasdfadabadabadabadabadabadabadabadabadabadabaasdfasdfasdfad"/>

<TextView
    android:id="@+id/rightTextView"
    android:layout_width="wrap_content"
    android:layout_height="40dp"
    android:textColor="#adc391"
    android:singleLine="true"
    android:text="adsfasd"/>

</LinearLayout>

this is the screenshot after running:

I have faced this kind of usecase in our app. In our app,there are 3 Views. ImageView | TextView | ImageView. The two ImageViews must be visible in the layout.The TextView should be ellipsized at the end. And I came up with a custom 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);
    }
}

Declare a custom attribute, in values/attrs.xml

<declare-styleable name="PriorityLayoutHorizontal">
        <attr name="priorityHigh" format="reference"/>
</declare-styleable>

Using this layout, you can give high priority to the Views that should be visible in the layout definitely. Remaining one TextView will be drawn based on the remaining width in the screen.

To use this layout:

    <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>

And define the priority_array in values/arrays.xml

<integer-array name="priority_array">
        <item>1</item>
</integer-array>

Here, we have mentioned the priority for the View "1". That is the second TextView in your layout. So the second TextView will be visible always, and the first TextView will be ellipsized.

P.S: this is a generic solution. i.e. this can be used with different Views, and more than 2 Views in a line. You can use this layout, or a custom ViewGroup specific to your usecase could be written.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!