Android 如果有多行,如何使textview在另一个textview下继续

Android 如果有多行,如何使textview在另一个textview下继续,android,android-layout,Android,Android Layout,Iam使用两个文本视图的项目填充RecyclerView,一个是标签(左文本视图),另一个包含内容(右文本视图)。当内容文本变长时,它将创建多行。现在,如果我们有更多的一行,我希望文本继续在标签下面,这是可能的吗?如果没有,如果内容textview中有多行,如何使textview垂直 <?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android=

Iam使用两个文本视图的项目填充RecyclerView,一个是标签(左文本视图),另一个包含内容(右文本视图)。当内容文本变长时,它将创建多行。现在,如果我们有更多的一行,我希望文本继续在标签下面,这是可能的吗?如果没有,如果内容textview中有多行,如何使textview垂直

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">

  <TextView
    android:id="@+id/label"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:ellipsize="marquee"
    android:textColor="#667889"

    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintEnd_toStartOf="@+id/content"

    tools:text="Eros donec ac odio tempor" />

  <TextView
    android:id="@+id/content"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:layout_marginStart="8dp"
    app:layout_constraintStart_toEndOf="@+id/label"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintBottom_toBottomOf="parent"
    tools:text="Content - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua." />

</android.support.constraint.ConstraintLayout>


要使用的属性是

android:ems=""
android:maxLines=""
ems表示字体大小,最大行数表示您希望在文本视图中显示多少行。
这些是您希望在XML中使用的属性。

您可以使用单个文本视图来实现这一点,只需使用StringBuilder并将文本附加到生成器abs将该字符串生成器设置为文本视图

StringBuilder builder = new StringBuilder();
builder.append("Your Text1 );
builder.append("Your Text2 );
然后将其设置为textView

textView.setText(builder);

您可以执行以下操作:

这里的想法是采用约束布局 包含两个文本视图:

  • tv\u固定的(从固定的角度来看,我不关心它的文本)
  • tv_变量(从需要对其文本进行进一步处理的角度来看,变量)
注意:我们将正在处理的文本称为Ourtext

并在tv_fixed和tv_variable下面动态添加另一个文本视图(tv_variable_plus)。TextView tv_variable_plus将帮助tv_variable以提供所需效果的方式显示我们的文本

注意:动态添加带有参考id(tv\u固定和tv\u变量id)的屏障,tv\u变量加实际上添加在此屏障下方。 此屏障的目的是确保tv_变量_plus文本不会与其他文本视图文本混合

文本如何在文本视图tv\u变量和添加的文本视图tv\u变量\u plus之间划分?

这里的想法是(当Ourtext使用提供的
setText(stringtext1,stringtext)
方法更改时):

  • Ourtext的每个字符上循环,获取每个字符的宽度
    cCharWidth
    (以像素为单位),递增
    cTotalCharWidth
    (这是计算我们文本中所有字符的宽度),然后检查
    cTotalCharWidth
    是否大于TextView tv\u可变宽度(-padding),如果这样,我们就可以认为我们达到了一条新线(线是用<代码> CaleCurnter < /代码>计数)。

  • 作为下一步,我们需要检查计数的行数是否乘以TextView tv_variable line height
    int cLineHeight=tv_variable.getLineHeight()大于所有TextView电视固定线路
    高度
    int-tAllLineHeight=tv_fixed.getLineCount()*tv_fixed.getLineHeight(),如果是这样的话,我们可以认为当前字符索引(<代码> i>代码>)是<>强> uTrime>强文本>文本索引,在其中文本视图tvii变量文本结束,tvyValueLyPrP文本开始。

2) textViewInDifferentWay.class

公共类文本视图以不同方式{
私有最终字符串标记=textViewInDifferentWay.class.getSimpleName();
私人语境;
私人有限责任公司;
私有文本视图tv_fixed=null;
私有文本视图tv_变量=null;
私有文本视图tv_变量_plus=null;
私有字符串text=“”;
公共静态最终整数计算模式单线=0;
公共静态最终整数计算模式线总高度=1;
私有整数计算模式=计算模式线总高度;
public textViewInDifferentinWay(@NonNull Context Context,
@非空视图布局){
这(上下文、布局、计算、模式、线条、总高度);
}
public textViewInDifferentinWay(@NonNull Context Context,
@非空视图布局,
int计算模式){
this.context=上下文;
如果(calculationMode==计算模式单行||
calculationMode==计算模式线总高度){
this.calculationMode=calculationMode;
}
设置布局(上下文、布局);
}
专用void布局(上下文、视图布局){
if(ConstraintLayout的布局实例){
this.cl=(ConstraintLayout)布局;
if(this.cl.getChildCount()==2){
View child1=this.cl.getChildAt(0);
View child2=this.cl.getChildAt(1);
文本视图的if(child1实例)
&&child2实例(文本视图){
this.tv_fixed=(TextView)child1;
this.tv_变量=(TextView)child2;
this.text=this.tv_变量.getText().toString();
}
}否则{
抛出新的RuntimeException(“必须有两个子项!!”;
}
}
if(tv_fixed!=null&&tv_variable!=null){
/**
*在tv_fixed和tv_variable的底部添加一个屏障,以便始终写入
*具有最大高度的视图的底部
*/
ConstraintLayout.LayoutParams参数=新建ConstraintLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_内容,
ViewGroup.LayoutParams.WRAP_内容);
障碍=新障碍(上下文);
int bId=ViewCompat.generateViewId();
障碍物。setId(投标);
屏障。设置类型(屏障。底部);
barrier.setReferencedId(新int[]{tv_fixed.getId(),
tv_变量.getId()});
barrier.setLayoutParams(params_);
此.cl.addView(屏障);
ConstraintSet ConstraintSet=新ConstraintSet();
constraintSet_u2;.clone(this.cl);
constraintSet.connect(bId,constraintSet.START,this.cl.getId(),constraintSet.START);
constraintSet_2;.connect(bId,constraintSet.END,this.cl.getId(),constraintSet.END);
constraintSet_u2;.applyTo(this.cl);
/**
*添加一个文本视图(t
public class TextViewInADifferentWay {

private final String TAG = TextViewInADifferentWay.class.getSimpleName();
private Context context;
private ConstraintLayout cl;
private TextView tv_fixed = null;
private TextView tv_variable = null;
private TextView tv_variable_plus = null;
private String text = "";
public static final int CALCULATION_MODE_SINGLE_LINE = 0;
public static final int CALCULATION_MODE_LINES_TOTAL_HEIGHT = 1;
private int calculationMode = CALCULATION_MODE_LINES_TOTAL_HEIGHT;

public TextViewInADifferentWay(@NonNull Context context,
                               @NonNull View layout) {
    this(context, layout, CALCULATION_MODE_LINES_TOTAL_HEIGHT);
}

public TextViewInADifferentWay(@NonNull Context context,
                               @NonNull View layout,
                               int calculationMode) {

    this.context = context;
    if(calculationMode == CALCULATION_MODE_SINGLE_LINE ||
            calculationMode == CALCULATION_MODE_LINES_TOTAL_HEIGHT){
        this.calculationMode = calculationMode;
    }
    setUpLayout(context, layout);
}

private void setUpLayout(Context context, View layout) {

    if (layout instanceof ConstraintLayout) {
        this.cl = (ConstraintLayout) layout;
        if (this.cl.getChildCount() == 2) {
            View child1 = this.cl.getChildAt(0);
            View child2 = this.cl.getChildAt(1);
            if (child1 instanceof TextView
                    && child2 instanceof TextView) {
                this.tv_fixed = (TextView) child1;
                this.tv_variable = (TextView) child2;
                this.text = this.tv_variable.getText().toString();
            }
        } else {
            throw new RuntimeException("Must have two children!!");
        }
    }
    if (tv_fixed != null && tv_variable != null) {

        /**
         * Add a barrier in the bottom of tv_fixed and tv_variable in order to always write to
         * the bottom of the view with the largest height
         */
        ConstraintLayout.LayoutParams params_ = new ConstraintLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
                ViewGroup.LayoutParams.WRAP_CONTENT);

        Barrier barrier = new Barrier(context);
        int bId = ViewCompat.generateViewId();
        barrier.setId(bId);
        barrier.setType(Barrier.BOTTOM);
        barrier.setReferencedIds(new int[]{tv_fixed.getId(),
                tv_variable.getId()});
        barrier.setLayoutParams(params_);

        this.cl.addView(barrier);

        ConstraintSet constraintSet_ = new ConstraintSet();
        constraintSet_.clone(this.cl);
        constraintSet_.connect(bId, ConstraintSet.START, this.cl.getId(), ConstraintSet.START);
        constraintSet_.connect(bId, ConstraintSet.END, this.cl.getId(), ConstraintSet.END);
        constraintSet_.applyTo(this.cl);

        /**
         * Add a TextView (tv_variable_plus)
         */
        ConstraintLayout.LayoutParams params = new ConstraintLayout.LayoutParams(0,
                ViewGroup.LayoutParams.WRAP_CONTENT);
        tv_variable_plus = new TextView(context);
        int tId = ViewCompat.generateViewId();
        tv_variable_plus.setId(tId);

        //TODO: Clone as much attribute from base textView (tv_variable)
        tv_variable_plus.setTextSize(convertPixelsToDp(tv_variable.getTextSize(),
                context));
        tv_variable_plus.setTextColor(tv_variable.getCurrentTextColor());
        tv_variable_plus.setTypeface(null, Typeface.BOLD);
        tv_variable_plus.setIncludeFontPadding(false);
        tv_variable_plus.setLayoutParams(params);
        this.cl.addView(tv_variable_plus);

        ConstraintSet constraintSet = new ConstraintSet();
        constraintSet.clone(this.cl);
        constraintSet.connect(tv_variable_plus.getId(), ConstraintSet.TOP, bId, ConstraintSet.BOTTOM);
        constraintSet.connect(tv_variable_plus.getId(), ConstraintSet.START, this.cl.getId(), ConstraintSet.START);
        constraintSet.connect(tv_variable_plus.getId(), ConstraintSet.END, this.cl.getId(), ConstraintSet.END);
        constraintSet.applyTo(this.cl);

        //set Text to default text (xml based) in order to re-calculate
        setText(tv_fixed.getText().toString(), text);

    } else {
        throw new RuntimeException("Both TextViews must be non null!!");
    }
}

/**
 * This method converts device specific pixels to density independent pixels.
 *
 * @param px      A value in px (pixels) unit. Which we need to convert into db
 * @param context Context to get resources and device specific display metrics
 * @return A float value to represent dp equivalent to px value
 */
private static float convertPixelsToDp(float px, Context context) {
    return px / ((float) context.getResources().getDisplayMetrics().densityDpi / DisplayMetrics.DENSITY_DEFAULT);
}

public void calculate() {

    //TODO: Clone as much attribute from base textView (tv_variable)
    tv_variable_plus.setTextSize(convertPixelsToDp(tv_variable.getTextSize(),
            context));
    tv_variable_plus.setTextColor(tv_variable.getCurrentTextColor());
    tv_variable_plus.setTypeface(null, Typeface.BOLD);
    tv_variable_plus.setIncludeFontPadding(false);

    int cTotalCharWidth = 0;
    int cLineCounter = 1;
    int index = 0;
    for (int i = 0; i < text.length(); i++) {
        int cLineHeight = tv_variable.getLineHeight();
        int tLineHeight = tv_fixed.getLineHeight();
        int tAllLineHeight = tv_fixed.getLineCount() * tLineHeight;
        String c = String.valueOf(text.charAt(i));
        float cCharWidth = getStringWidth(tv_variable, c);
        //Log.i(TAG, c + "-- w: " + cCharWidth);
        cTotalCharWidth += cCharWidth;
        if (cTotalCharWidth >= (tv_variable.getWidth() -
                tv_variable.getPaddingLeft() - tv_variable.getPaddingRight())) {
            //Log.i(TAG, "New Line after " + c + " (" + i + ")");
            if (calculationMode == CALCULATION_MODE_LINES_TOTAL_HEIGHT) {
                cTotalCharWidth = 0;
                if (((2 * cLineCounter) * cLineHeight) >= (tAllLineHeight)) {
                    index = i;
                    break;
                }
            } else if (calculationMode == CALCULATION_MODE_SINGLE_LINE) {
                if (cLineCounter == 1) {
                    index = i;
                    break;
                }
            }
            cLineCounter += 1;
        }
    }
    if (index != 0) {
        tv_variable.setText(text.substring(0, index));
        tv_variable_plus.setText(text.substring(index));
        tv_variable_plus.setVisibility(View.VISIBLE);
    } else {
        tv_variable.setText(text);
        tv_variable_plus.setText("");
        tv_variable_plus.setVisibility(View.GONE);
    }
}

private float getStringWidth(TextView tv, String text) {
    Paint textPaint = tv.getPaint();
    float sWidth = textPaint.measureText(text); // in pixels
    return sWidth;
}

public TextView getTvFixed() {
    return this.tv_fixed;
}

public TextView getTvVariable() {
    return this.tv_variable;
}

public TextView getTvVariablePlus() {
    return this.tv_variable_plus;
}

public TextViewInADifferentWay setCalculationMode(int calculationMode) {
    if (calculationMode == CALCULATION_MODE_SINGLE_LINE ||
            calculationMode == CALCULATION_MODE_LINES_TOTAL_HEIGHT) {
        if (calculationMode != this.calculationMode) {
            this.calculationMode = calculationMode;
            calculate();
        }
    }
    return TextViewInADifferentWay.this;
}

public TextViewInADifferentWay setText(String text1, String text) {
    this.text = text;
    tv_fixed.setText(text1);
    tv_variable.setText(text);
    if (tv_variable_plus != null) {
        tv_variable_plus.setText("");
        /**
         * make sure that views are inflated before calculating
         */
        final ViewTreeObserver viewTreeObserver = this.cl.getViewTreeObserver();
        viewTreeObserver.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
            @Override
            public boolean onPreDraw() {
                cl.getViewTreeObserver().removeOnPreDrawListener(this);
                calculate();
                return true;
            }
        });
    }
    return TextViewInADifferentWay.this;
}

public String getText() {
    return this.text;
}

}
public class MainActivity extends AppCompatActivity {

private final String TAG = MainActivity.class.getSimpleName();
private RecyclerView rv_before;
private RecyclerView rv_after;
private Button b;
private List<String> one = new ArrayList<>();
private List<String> two = new ArrayList<>();

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

    one.add("Hello, how is work?");
    two.add("Hello, everything is fine, thank you for asking.");
    one.add("?");
    two.add("How are you today?");
    one.add("I not feeling well!");
    two.add("Are you sick, you seem extremely tired?");
    one.add("I've got flu");
    two.add("Go home and please stay there until you feel better. " +
            "You don't want to spread your infection!");

    rv_before = (RecyclerView) findViewById(R.id.rv_before);
    rv_before.setHasFixedSize(true);
    LinearLayoutManager linearLayoutManagerB = new LinearLayoutManager(MainActivity.this);
    rv_before.setLayoutManager(linearLayoutManagerB);

    rv_after = (RecyclerView) findViewById(R.id.rv_after);
    rv_after.setHasFixedSize(true);
    LinearLayoutManager linearLayoutManagerA = new LinearLayoutManager(MainActivity.this);
    rv_after.setLayoutManager(linearLayoutManagerA);

    CustomRecyclerViewAdapter customRecyclerViewAdapterB = new CustomRecyclerViewAdapter(MainActivity.this, true, one, two);
    rv_before.setAdapter(customRecyclerViewAdapterB);

    CustomRecyclerViewAdapter customRecyclerViewAdapterA = new CustomRecyclerViewAdapter(MainActivity.this, false, one, two);
    rv_after.setAdapter(customRecyclerViewAdapterA);

    b = (Button) findViewById(R.id.b);
    b.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            List<String> fixed = new ArrayList<>();
            List<String> variable = new ArrayList<>();
            for (int i = 0; i < one.size(); i++) {
                int oneI = new Random().nextInt(one.size());
                fixed.add(one.get(oneI));
                variable.add(two.get(oneI));
            }
            customRecyclerViewAdapterB.changeText(fixed, variable);
            customRecyclerViewAdapterA.changeText(fixed, variable);
        }
    });
}

private class CustomRecyclerViewAdapter extends RecyclerView.Adapter<CustomRecyclerViewAdapter.CustomViewHolder> {

    private final Context context;
    private List<String> fixed;
    private List<String> variable;
    private final boolean before;

    public CustomRecyclerViewAdapter(Context context, boolean before,
                                     List<String> fixed, List<String> variable) {
        super();
        this.context = context;
        this.before = before;
        this.fixed = fixed;
        this.variable = variable;
    }

    @NonNull
    @Override
    public CustomViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View layout = LayoutInflater.from(context).inflate(R.layout.recycler_view_item, parent, false);
        return new CustomViewHolder(layout);
    }

    @Override
    public void onBindViewHolder(@NonNull CustomViewHolder holder, int position) {
        if(!before) { // after
            holder.textViewInADifferentWay.setText(fixed.get(position), variable.get(position));
        }else{ // before
            TextView tv_fixed = (TextView) holder.text_view_in_a_different_way.findViewById(R.id.tv_fixed);
            TextView tv_variable = (TextView) holder.text_view_in_a_different_way.findViewById(R.id.tv_variable);
            tv_fixed.setText(fixed.get(position));
            tv_variable.setText(variable.get(position));
        }
        holder.tv.setText("Item " + position + " top");
        holder.tv1.setText("Item " + position + " bottom");
    }

    @Override
    public int getItemCount() {
        return fixed.size();
    }

    public class CustomViewHolder extends RecyclerView.ViewHolder {

        private TextViewInADifferentWay textViewInADifferentWay;
        private final View text_view_in_a_different_way;
        private final TextView tv;
        private final TextView tv1;

        public CustomViewHolder(@NonNull View itemView) {
            super(itemView);
            text_view_in_a_different_way = (View)
                    itemView.findViewById(R.id.text_view_in_a_different_way);
            if(!before) { // after
                textViewInADifferentWay = new TextViewInADifferentWay(context,
                        text_view_in_a_different_way);
            }
            tv = (TextView) itemView.findViewById(R.id.tv);
            tv1 = (TextView) itemView.findViewById(R.id.tv1);
        }
    }

    public void changeText(List<String> fixed, List<String> variable) {
        this.fixed = fixed;
        this.variable = variable;
        this.notifyDataSetChanged();
    }
}

}
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
android:id="@+id/rl"
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">

<Button
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="Change Data Set"
    android:id="@+id/b"
    android:textAllCaps="false"
    android:layout_alignParentTop="true"
    android:layout_marginTop="10dp">
</Button>

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_below="@id/b"
    android:orientation="vertical"
    android:layout_marginTop="10dp"
    android:weightSum="100">

<androidx.recyclerview.widget.RecyclerView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_weight="26.5"
    android:id="@+id/rv_before">
</androidx.recyclerview.widget.RecyclerView>

    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="47"
        android:text="Divider (before - after)"
        android:gravity="center"
        android:textColor="@android:color/white"
        android:background="@color/colorAccent">
    </TextView>

<androidx.recyclerview.widget.RecyclerView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_weight="26.5"
    android:id="@+id/rv_after">
</androidx.recyclerview.widget.RecyclerView>

</LinearLayout>

</RelativeLayout>
<?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="wrap_content">

<!-- other stuff -->

<TextView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:textAllCaps="false"
    android:id="@+id/tv"
    android:gravity="center"
    android:textColor="@android:color/white"
    android:background="@color/colorPrimary"
    android:text="Item">
</TextView>

<!-- other stuff -->

<include
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:id="@+id/text_view_in_a_different_way"
    layout="@layout/text_view_in_a_different_way">
</include>

<!-- other stuff -->

<TextView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:textAllCaps="false"
    android:id="@+id/tv1"
    android:gravity="center"
    android:textColor="@android:color/white"
    android:background="@color/colorPrimaryDark"
    android:text="Item">
</TextView>

<!-- other stuff -->

</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/cl"
android:padding="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">

<TextView
    android:id="@+id/tv_fixed"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textColor="@android:color/white"
    android:textSize="15sp"
    android:textStyle="bold"
    android:ellipsize="marquee"
    android:gravity="center_vertical"
    android:includeFontPadding="false"
    android:background="@color/colorPrimary"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintEnd_toStartOf="@id/tv_variable"
    android:text="Hello World World Hello" />

<TextView
    android:id="@+id/tv_variable"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:textSize="18sp"
    android:textStyle="bold"
    android:layout_marginStart="8dp"
    android:layout_marginLeft="8dp"
    android:gravity="center_vertical"
    android:includeFontPadding="false"
    android:textColor="@color/colorAccent"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toEndOf="@id/tv_fixed"
    android:text="Hello World Hello World Hello World" />

</androidx.constraintlayout.widget.ConstraintLayout>