Android 自动调整两个文本视图的大小以显示尽可能多的内容

Android 自动调整两个文本视图的大小以显示尽可能多的内容,android,textview,android-linearlayout,Android,Textview,Android Linearlayout,在水平方向的线性布局中有两个文本视图 LeftText | RightText 目标是充分利用屏幕空间并尽可能多地显示文本值。如果文本超过textview大小,则应使用省略号将其截断。如果其中一个较短,则另一个应扩展到剩余大小 例如, 输入-Short | Short 预期产量Short | Short 输入-短|长 预期产量短|长… 输入-longlong | Short 预期产量LongLong…| Short 输入-longlong | longlong 预期产量LongLong…| Lo

在水平方向的线性布局中有两个文本视图

LeftText | RightText

目标是充分利用屏幕空间并尽可能多地显示文本值。如果文本超过textview大小,则应使用省略号将其截断。如果其中一个较短,则另一个应扩展到剩余大小

例如,

  • 输入-Short | Short
    预期产量Short | Short

  • 输入-短|长
    预期产量短|长…

  • 输入-longlong | Short
    预期产量LongLong…| Short

  • 输入-longlong | longlong
    预期产量LongLong…| LongLong…

  • 我尝试创建一个自定义视图AutoSizingTextLayout(extends LinearLayout),它由两个初始相等布局权重为1的自定义文本视图组成。我为第二个文本视图(右边的一个)添加了一个onDrawListener。第二个文本视图绘制完成后,我会根据截断的文本调整权重

    这种逻辑可行,但并不可靠。在一些运行中,它运行得非常完美,但大多数情况下,第一个文本视图占据整个屏幕

    我正在将代码的相关部分粘贴到下面。有什么需要处理的吗?有更优雅的解决方案吗? PS:此自定义视图正在列表回收器视图中使用

    public class AutoSizingTextLayout extends LinearLayout implements 
    AutoSizingTextView.AutoSizingTextViewDrawListener {
    
    @BindView(R.id.start_text_view)
    AutoSizingTextView mStartTextView;
    
    @BindView(R.id.end_text_view)
    AutoSizingTextView mEndTextView;
    
    private volatile boolean adjusted = false;
    
    //Constructors
    
    @Override
    public void onDraw() {
        if (!adjusted) {
            adjustWeights();
        }
    }
    
    public void setStartViewText(String startText) {
        mStartTextView.setText(startText);
    }
    
    public void setEndViewText(String endText) {
        adjusted = false;
        mEndTextView.setText(endText);
    }
    
    private void initView(AttributeSet attrs) {
        LayoutInflater inflater = LayoutInflater.from(getContext());
        inflater.inflate(R.layout.auto_sizing_text_layout, this);
        ButterKnife.bind(this);
        mEndTextView.setDrawListener(this);
    }
    
    private void adjustWeights() {
        boolean startTextHasEllipses = hasEllipses(mStartTextView);
        boolean endTextHasEllipses = hasEllipses(mEndTextView);
    
        ArrayList<AutoSizingTextView> viewsToUpdate = new ArrayList<>();
    
        if (startTextHasEllipses && endTextHasEllipses) {
            //Both are truncated. Do nothing.
        } else if (startTextHasEllipses) {
            // Starting text is truncated. End text is not truncated. Give more weight to starting text.
            viewsToUpdate.add(mEndTextView);
        } else if (endTextHasEllipses) {
            // Starting text is not truncated. End text is truncated. Give more weight to ending text.
            viewsToUpdate.add(mStartTextView);
        } else {
            // Both are not truncated. Set it to wrap content.
            viewsToUpdate.add(mStartTextView);
            viewsToUpdate.add(mEndTextView);
        }
        updateView(viewsToUpdate);
    }
    
    private void updateView(List<AutoSizingTextView> viewsToUpdate) {
        for (AutoSizingTextView viewToUpdate : viewsToUpdate) {
            LinearLayout.LayoutParams params = (LinearLayout.LayoutParams)
                    viewToUpdate.getLayoutParams();
            params.width = LinearLayout.LayoutParams.WRAP_CONTENT;
            params.weight = 0.0F;
            adjusted = true;
            viewToUpdate.setLayoutParams(params);
        }
        this.requestLayout();
    }
    
    private static boolean hasEllipses(TextView textView) {
        Layout layout = textView.getLayout();
        if (layout != null) {
            int lines = layout.getLineCount();
            if (lines > 0) {
                if (layout.getEllipsisCount(lines - 1) > 0) {
                    return true;
                }
            }
        }
        return false;
    }
    
    }
    
    //自动调整大小文本布局.xml

    <LinearLayout
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    xmlns:android="http://schemas.android.com/apk/res/android">
    
    <AutoSizingTextView
        android:id="@+id/start_text_view"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:maxLines="1"
        android:ellipsize="end"/>
    
    <AutoSizingTextView
        android:id="@+id/end_text_view"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:maxLines="1"
        android:ellipsize="end"/>
    
    
    

    我想以下是预期结果

    我为此编写了一个简单的
    ViewGroup
    。当然,这并不完美。它只是表明它是可以实现的。相应地修改此代码。我已经重写了
    视图组
    的方法,在该方法中,我正在计算子视图所需的大小并相应地布局它们。此
    WeirdView
    包含三个
    TextView
    s,分别用于(左文本、分隔符和右文本)

    package com.example.abhinav.textviewexample;
    
    import android.content.Context;
    import android.support.annotation.Nullable;
    import android.util.AttributeSet;
    import android.view.ViewGroup;
    import android.widget.LinearLayout;
    import android.widget.TextView;
    
    /**
     * Created by abhinav on 16/04/18.
     */
    
    public class WeirdView extends ViewGroup {
    
        private TextView mLeftTV;
        private TextView mSeparatorTV;
        private TextView mRightTV;
    
        public WeirdView(Context context) {
            this(context, null, 0);
        }
    
        public WeirdView(Context context, @Nullable AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public WeirdView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            init(context);
        }
    
        private void init(Context context) {
            mLeftTV = new TextView(context);
            mSeparatorTV = new TextView(context);
            mRightTV = new TextView(context);
    
            mLeftTV.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
            mSeparatorTV.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
            mRightTV.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
    
            addView(mLeftTV);
            addView(mSeparatorTV);
            addView(mRightTV);
        }
    
        public TextView getLeftTextView() {
            return mLeftTV;
        }
    
        public TextView getSeparatorTextView() {
            return mSeparatorTV;
        }
    
        public TextView getRightTextView() {
            return mRightTV;
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }
    
        @Override
        protected void onLayout(boolean changed, int l, int t, int r, int b) {
            // super.onLayout(changed, l, t, r, b);
    
            final int childLeft = this.getPaddingLeft();
            final int childTop = this.getPaddingTop();
            final int childRight = this.getMeasuredWidth() - this.getPaddingRight();
            final int childBottom = this.getMeasuredHeight() - this.getPaddingBottom();
            final int availableWidth = childRight - childLeft;
            final int availableHeight = childBottom - childTop;
    
            mLeftTV.measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(availableHeight, MeasureSpec.AT_MOST));
            mSeparatorTV.measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(availableHeight, MeasureSpec.AT_MOST));
            mRightTV.measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(availableHeight, MeasureSpec.AT_MOST));
    
            // case: |blabla > blablabla         |
            // case: |blablablablablabla > bla   |
            // case: |bla > blablablablablablab..|
            if ((mLeftTV.getMeasuredWidth() + mSeparatorTV.getMeasuredWidth() + mRightTV.getMeasuredWidth() <= availableWidth)
                    || (mLeftTV.getMeasuredWidth() <= availableWidth / 2)) {
                int left = childLeft;
                mLeftTV.layout(left, childTop, left + mLeftTV.getMeasuredWidth(), childBottom);
                left += mLeftTV.getMeasuredWidth();
                mSeparatorTV.layout(left, childTop, left + mSeparatorTV.getMeasuredWidth(), childBottom);
                left += mSeparatorTV.getMeasuredWidth();
                mRightTV.layout(left, childTop, childRight, childBottom);
                mRightTV.setWidth(childRight - left);
            }
            // case: |blablablablablabla.. > blab|
            else if (mRightTV.getMeasuredWidth() <= availableWidth / 2) {
                int left = childLeft;
                mLeftTV.layout(left, childTop, childRight - mSeparatorTV.getMeasuredWidth() - mRightTV.getMeasuredWidth(), childBottom);
                mLeftTV.setWidth(childRight - mSeparatorTV.getMeasuredWidth() - mRightTV.getMeasuredWidth() - left);
                left += mLeftTV.getWidth();
                mSeparatorTV.layout(left, childTop, mSeparatorTV.getMeasuredWidth(), childBottom);
                left += mSeparatorTV.getMeasuredWidth();
                mRightTV.layout(left, childTop, mRightTV.getMeasuredWidth(), childBottom);
            }
            // case: |blablabla.. > blablablabl..|
            else {
                int left = childLeft;
                mLeftTV.layout(left, childTop, left + availableWidth / 2 - mSeparatorTV.getMeasuredWidth() / 2, childBottom);
                mLeftTV.setWidth(availableWidth / 2 - mSeparatorTV.getMeasuredWidth() / 2);
                left += (availableWidth / 2 + mSeparatorTV.getMeasuredWidth() / 2);
                mSeparatorTV.layout(left, childTop, left + mSeparatorTV.getMeasuredWidth(), childBottom);
                left += mSeparatorTV.getMeasuredWidth();
                mRightTV.layout(left, childTop, childRight, childBottom);
                mRightTV.setWidth(childRight - left);
            }
        }
    }
    
    package com.example.abhinav.textviewexample;
    导入android.content.Context;
    导入android.support.annotation.Nullable;
    导入android.util.AttributeSet;
    导入android.view.ViewGroup;
    导入android.widget.LinearLayout;
    导入android.widget.TextView;
    /**
    *abhinav于2018年4月16日创建。
    */
    公共类WeirdView扩展了ViewGroup{
    私人文本视图;
    私有文本视图mseparortv;
    私人文本视图mRightTV;
    公共古怪视图(上下文){
    这个(上下文,null,0);
    }
    公共古怪视图(上下文上下文,@Nullable AttributeSet attrs){
    这(上下文,属性,0);
    }
    公共古怪视图(上下文上下文,@Nullable AttributeSet attrs,int defStyleAttr){
    super(上下文、attrs、defStyleAttr);
    init(上下文);
    }
    私有void init(上下文){
    mLeftTV=新文本视图(上下文);
    mseparortv=新文本视图(上下文);
    mRightTV=新文本视图(上下文);
    mLeftTV.setLayoutParams(新的LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_内容,ViewGroup.LayoutParams.WRAP_内容));
    mseparatorv.setLayoutParams(新的LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_内容,ViewGroup.LayoutParams.WRAP_内容));
    mRightTV.setLayoutParams(新的LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_内容,ViewGroup.LayoutParams.WRAP_内容));
    addView(mLeftTV);
    addView(mseparortv);
    addView(mRightTV);
    }
    公共文本视图getLeftTextView(){
    返回FTTV;
    }
    公共文本视图getSeparatorTextView(){
    返回mseparortv;
    }
    公共文本视图getRightTextView(){
    返回mRightTV;
    }
    @凌驾
    测量时的保护空隙(内部宽度测量等级、内部高度测量等级){
    超级测量(宽度测量、高度测量);
    }
    @凌驾
    仅受保护的void布局(布尔值已更改、int l、int t、int r、int b){
    //超级在线布局(更改,l,t,r,b);
    final int childLeft=this.getPaddingLeft();
    final int childTop=this.getPaddingTop();
    final int childRight=this.getMeasuredWidth()-this.getPaddingRight();
    final int childBottom=this.getMeasuredHeight()-this.getPaddingBottom();
    final int availableWidth=childRight-childLeft;
    final int availableHeight=childBottom-childTop;
    mleftv.measure(MeasureSpec.makeMeasureSpec(可用宽度,最多测量长度),MeasureSpec.makeMeasureSpec(可用高度,最多测量长度));
    mseparortv.measure(MeasureSpec.makeMeasureSpec(可用宽度,最多测量长度),MeasureSpec.makeMeasureSpec(可用高度,最多测量长度));
    mRightTV.measure(MeasureSpec.makeMeasureSpec(可用宽度,最多测量长度),MeasureSpec.makeMeasureSpec(可用高度,最多测量长度));
    //案例:|布拉布拉>布拉布拉|
    //案例:| blablabla>bla|
    //案例:| bla>blab|
    如果((mLeftTV.getMeasuredWidth()+mseparortv.getMeasuredWidth()+mRightTV.getMeasuredWidth())
    
    package com.example.abhinav.textviewexample;
    
    import android.content.Context;
    import android.support.annotation.Nullable;
    import android.util.AttributeSet;
    import android.view.ViewGroup;
    import android.widget.LinearLayout;
    import android.widget.TextView;
    
    /**
     * Created by abhinav on 16/04/18.
     */
    
    public class WeirdView extends ViewGroup {
    
        private TextView mLeftTV;
        private TextView mSeparatorTV;
        private TextView mRightTV;
    
        public WeirdView(Context context) {
            this(context, null, 0);
        }
    
        public WeirdView(Context context, @Nullable AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public WeirdView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            init(context);
        }
    
        private void init(Context context) {
            mLeftTV = new TextView(context);
            mSeparatorTV = new TextView(context);
            mRightTV = new TextView(context);
    
            mLeftTV.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
            mSeparatorTV.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
            mRightTV.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
    
            addView(mLeftTV);
            addView(mSeparatorTV);
            addView(mRightTV);
        }
    
        public TextView getLeftTextView() {
            return mLeftTV;
        }
    
        public TextView getSeparatorTextView() {
            return mSeparatorTV;
        }
    
        public TextView getRightTextView() {
            return mRightTV;
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }
    
        @Override
        protected void onLayout(boolean changed, int l, int t, int r, int b) {
            // super.onLayout(changed, l, t, r, b);
    
            final int childLeft = this.getPaddingLeft();
            final int childTop = this.getPaddingTop();
            final int childRight = this.getMeasuredWidth() - this.getPaddingRight();
            final int childBottom = this.getMeasuredHeight() - this.getPaddingBottom();
            final int availableWidth = childRight - childLeft;
            final int availableHeight = childBottom - childTop;
    
            mLeftTV.measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(availableHeight, MeasureSpec.AT_MOST));
            mSeparatorTV.measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(availableHeight, MeasureSpec.AT_MOST));
            mRightTV.measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(availableHeight, MeasureSpec.AT_MOST));
    
            // case: |blabla > blablabla         |
            // case: |blablablablablabla > bla   |
            // case: |bla > blablablablablablab..|
            if ((mLeftTV.getMeasuredWidth() + mSeparatorTV.getMeasuredWidth() + mRightTV.getMeasuredWidth() <= availableWidth)
                    || (mLeftTV.getMeasuredWidth() <= availableWidth / 2)) {
                int left = childLeft;
                mLeftTV.layout(left, childTop, left + mLeftTV.getMeasuredWidth(), childBottom);
                left += mLeftTV.getMeasuredWidth();
                mSeparatorTV.layout(left, childTop, left + mSeparatorTV.getMeasuredWidth(), childBottom);
                left += mSeparatorTV.getMeasuredWidth();
                mRightTV.layout(left, childTop, childRight, childBottom);
                mRightTV.setWidth(childRight - left);
            }
            // case: |blablablablablabla.. > blab|
            else if (mRightTV.getMeasuredWidth() <= availableWidth / 2) {
                int left = childLeft;
                mLeftTV.layout(left, childTop, childRight - mSeparatorTV.getMeasuredWidth() - mRightTV.getMeasuredWidth(), childBottom);
                mLeftTV.setWidth(childRight - mSeparatorTV.getMeasuredWidth() - mRightTV.getMeasuredWidth() - left);
                left += mLeftTV.getWidth();
                mSeparatorTV.layout(left, childTop, mSeparatorTV.getMeasuredWidth(), childBottom);
                left += mSeparatorTV.getMeasuredWidth();
                mRightTV.layout(left, childTop, mRightTV.getMeasuredWidth(), childBottom);
            }
            // case: |blablabla.. > blablablabl..|
            else {
                int left = childLeft;
                mLeftTV.layout(left, childTop, left + availableWidth / 2 - mSeparatorTV.getMeasuredWidth() / 2, childBottom);
                mLeftTV.setWidth(availableWidth / 2 - mSeparatorTV.getMeasuredWidth() / 2);
                left += (availableWidth / 2 + mSeparatorTV.getMeasuredWidth() / 2);
                mSeparatorTV.layout(left, childTop, left + mSeparatorTV.getMeasuredWidth(), childBottom);
                left += mSeparatorTV.getMeasuredWidth();
                mRightTV.layout(left, childTop, childRight, childBottom);
                mRightTV.setWidth(childRight - left);
            }
        }
    }