webentwicklung-frage-antwort-db.com.de

Wie richtet man die Ansicht vertikal zum Text in TextView aus?

Ich versuche dieses Ergebnis zu erreichen:

Expected result

Was ich jetzt habe, ist ConstraintLayout, das drei Views enthält: TextView, ImageView, ImageView

Designanforderungen:

  1. Text zentriert in TextView;
  2. TextView hat eine feste Größe von 80dp
  3. Die Textgröße sollte automatisch anpassbar sein.
  4. ImageViews SOLLTE DIE POSITION HORIZONTAL ÄNDERN, ABHÄNGIG VON DER TEXTPOSITION IN TextView. Siehe Bilder mit Fall # 1/# 2 als Referenz.

Kann Punkt 4 in XML erreicht werden? Wie sieht es programmgesteuert aus?

[Zusätzliche Information]

Die automatische Größenanpassung funktioniert mit der Breite wrap_content nicht ordnungsgemäß, siehe Dokumentation der automatischen Größenänderung :

Hinweis: Wenn Sie in einer XML-Datei die automatische Größenanpassung festlegen, wird die Verwendung des Werts "wrap_content" für die Attribute layout_width oder layout_height eines TextView nicht empfohlen. Dies kann zu unerwarteten Ergebnissen führen.

15
Mykhailo

Nach einer Untersuchung fanden wir zwei Lösungen dafür:

  • Berechnung der Textbreite und Anwenden einer horizontalen Neigung auf ImageViews;
  • Benutzerdefinierte Textansicht - AutoResizeTextView;

Im ersten Fall erhalten wir die tatsächliche width des Textes in der TextView:

Rect bounds = new Rect();
textView.getPaint().getTextBounds(textView.getText().toString(), 0, textView.getText().length(), bounds);
float width = bounds.width();

Wenden Sie dann einfache Berechnungen an, um horizontal bias für ImageViews zu berechnen. 

Zweite Option dient zum Hinzufügen einer benutzerdefinierten Ansicht. Es unterscheidet sich von autosizing-textview . Nach der Messung in onLayout ändert sich die Größe des Textes. In onTextChanged setzen wir die Textgröße ohne Größenänderung zurück. Ellipsizing ist eine zusätzliche Funktion, die in manchen Fällen nützlich sein kann.

/**
 * Text view that auto adjusts text size to fit within the view.
 * If the text size equals the minimum text size and still does not
 * fit, append with an Ellipsis.
 */
public class AutoResizeTextView extends Android.support.v7.widget.AppCompatTextView {

    // Minimum text size for this text view
    public static final float MIN_TEXT_SIZE = 20;

    // Interface for resize notifications
    public interface OnTextResizeListener {
        public void onTextResize(TextView textView, float oldSize, float newSize);
    }

    // Our ellipse string
    private static final String mEllipsis = "...";

    // Registered resize listener
    private OnTextResizeListener mTextResizeListener;

    // Flag for text and/or size changes to force a resize
    private boolean mNeedsResize = false;

    // Text size that is set from code. This acts as a starting point for resizing
    private float mTextSize;

    // Temporary upper bounds on the starting text size
    private float mMaxTextSize = 0;

    // Lower bounds for text size
    private float mMinTextSize = MIN_TEXT_SIZE;

    // Text view line spacing multiplier
    private float mSpacingMult = 1.0f;

    // Text view additional line spacing
    private float mSpacingAdd = 0.0f;

    // Add Ellipsis to text that overflows at the smallest text size
    private boolean mAddEllipsis = true;

    // Default constructor override
    public AutoResizeTextView(Context context) {
        this(context, null);
    }

    // Default constructor when inflating from XML file
    public AutoResizeTextView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    // Default constructor override
    public AutoResizeTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        mTextSize = getTextSize();
    }

    /**
     * When text changes, set the force resize flag to true and reset the text size.
     */
    @Override
    protected void onTextChanged(final CharSequence text, final int start, final int before, final int after) {
        mNeedsResize = true;
        // Since this view may be reused, it is good to reset the text size
        resetTextSize();
    }

    /**
     * If the text view size changed, set the force resize flag to true
     */
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        if (w != oldw || h != oldh) {
            mNeedsResize = true;
        }
    }

    /**
     * Register listener to receive resize notifications
     *
     * @param listener
     */
    public void setOnResizeListener(AutoResizeTextView.OnTextResizeListener listener) {
        mTextResizeListener = listener;
    }

    /**
     * Override the set text size to update our internal reference values
     */
    @Override
    public void setTextSize(float size) {
        super.setTextSize(size);
        mTextSize = getTextSize();
    }

    /**
     * Override the set text size to update our internal reference values
     */
    @Override
    public void setTextSize(int unit, float size) {
        super.setTextSize(unit, size);
        mTextSize = getTextSize();
    }

    /**
     * Override the set line spacing to update our internal reference values
     */
    @Override
    public void setLineSpacing(float add, float mult) {
        super.setLineSpacing(add, mult);
        mSpacingMult = mult;
        mSpacingAdd = add;
    }

    /**
     * Set the upper text size limit and invalidate the view
     *
     * @param maxTextSize
     */
    public void setMaxTextSize(float maxTextSize) {
        mMaxTextSize = maxTextSize;
        requestLayout();
        invalidate();
    }

    /**
     * Return upper text size limit
     *
     * @return
     */
    public float getMaxTextSize() {
        return mMaxTextSize;
    }

    /**
     * Set the lower text size limit and invalidate the view
     *
     * @param minTextSize
     */
    public void setMinTextSize(float minTextSize) {
        mMinTextSize = minTextSize;
        requestLayout();
        invalidate();
    }

    /**
     * Return lower text size limit
     *
     * @return
     */
    public float getMinTextSize() {
        return mMinTextSize;
    }

    /**
     * Set flag to add Ellipsis to text that overflows at the smallest text size
     *
     * @param addEllipsis
     */
    public void setAddEllipsis(boolean addEllipsis) {
        mAddEllipsis = addEllipsis;
    }

    /**
     * Return flag to add Ellipsis to text that overflows at the smallest text size
     *
     * @return
     */
    public boolean getAddEllipsis() {
        return mAddEllipsis;
    }

    /**
     * Reset the text to the original size
     */
    public void resetTextSize() {
        if (mTextSize > 0) {
            super.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextSize);
            mMaxTextSize = mTextSize;
        }
    }

    /**
     * Resize text after measuring
     */
    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        if (changed || mNeedsResize) {
            int widthLimit = (right - left) - getCompoundPaddingLeft() - getCompoundPaddingRight();
            int heightLimit = (bottom - top) - getCompoundPaddingBottom() - getCompoundPaddingTop();
            resizeText(widthLimit, heightLimit);
        }
        super.onLayout(changed, left, top, right, bottom);
    }

    /**
     * Resize the text size with default width and height
     */
    public void resizeText() {
        int heightLimit = getHeight() - getPaddingBottom() - getPaddingTop();
        int widthLimit = getWidth() - getPaddingLeft() - getPaddingRight();
        resizeText(widthLimit, heightLimit);
    }

    /**
     * Resize the text size with specified width and height
     *
     * @param width
     * @param height
     */
    public void resizeText(int width, int height) {
        CharSequence text = getText();
        // Do not resize if the view does not have dimensions or there is no text
        if (text == null || text.length() == 0 || height <= 0 || width <= 0 || mTextSize == 0) {
            return;
        }

        if (getTransformationMethod() != null) {
            text = getTransformationMethod().getTransformation(text, this);
        }

        // Get the text view's Paint object
        TextPaint textPaint = getPaint();

        // Store the current text size
        float oldTextSize = textPaint.getTextSize();
        // If there is a max text size set, use the lesser of that and the default text size
        float targetTextSize = mMaxTextSize > 0 ? Math.min(mTextSize, mMaxTextSize) : mTextSize;

        // Get the required text height
        int textHeight = getTextHeight(text, textPaint, width, targetTextSize);

        // Until we either fit within our text view or we had reached our min text size, incrementally try smaller sizes
        while (textHeight > height && targetTextSize > mMinTextSize) {
            targetTextSize = Math.max(targetTextSize - 2, mMinTextSize);
            textHeight = getTextHeight(text, textPaint, width, targetTextSize);
        }

        // If we had reached our minimum text size and still don't fit, append an Ellipsis
        if (mAddEllipsis && targetTextSize == mMinTextSize && textHeight > height) {
            // Draw using a static layout
            // modified: use a copy of TextPaint for measuring
            TextPaint Paint = new TextPaint(textPaint);
            // Draw using a static layout
            StaticLayout layout = new StaticLayout(text, Paint, width, Layout.Alignment.ALIGN_NORMAL, mSpacingMult, mSpacingAdd, false);
            // Check that we have a least one line of rendered text
            if (layout.getLineCount() > 0) {
                // Since the line at the specific vertical position would be cut off,
                // we must trim up to the previous line
                int lastLine = layout.getLineForVertical(height) - 1;
                // If the text would not even fit on a single line, clear it
                if (lastLine < 0) {
                    setText("");
                }
                // Otherwise, trim to the previous line and add an Ellipsis
                else {
                    int start = layout.getLineStart(lastLine);
                    int end = layout.getLineEnd(lastLine);
                    float lineWidth = layout.getLineWidth(lastLine);
                    float ellipseWidth = textPaint.measureText(mEllipsis);

                    // Trim characters off until we have enough room to draw the Ellipsis
                    while (width < lineWidth + ellipseWidth) {
                        lineWidth = textPaint.measureText(text.subSequence(start, --end + 1).toString());
                    }
                    setText(text.subSequence(0, end) + mEllipsis);
                }
            }
        }

        // Some devices try to auto adjust line spacing, so force default line spacing
        // and invalidate the layout as a side effect
        setTextSize(TypedValue.COMPLEX_UNIT_PX, targetTextSize);
        setLineSpacing(mSpacingAdd, mSpacingMult);

        // Notify the listener if registered
        if (mTextResizeListener != null) {
            mTextResizeListener.onTextResize(this, oldTextSize, targetTextSize);
        }

        // Reset force resize flag
        mNeedsResize = false;
    }

    // Set the text size of the text Paint object and use a static layout to render text off screen before measuring
    private int getTextHeight(CharSequence source, TextPaint Paint, int width, float textSize) {
        // modified: make a copy of the original TextPaint object for measuring
        // (apparently the object gets modified while measuring, see also the
        // docs for TextView.getPaint() (which states to access it read-only)
        TextPaint paintCopy = new TextPaint(Paint);
        // Update the text Paint object
        paintCopy.setTextSize(textSize);
        // Measure using a static layout
        StaticLayout layout = new StaticLayout(source, paintCopy, width, Layout.Alignment.ALIGN_NORMAL, mSpacingMult, mSpacingAdd, true);
        return layout.getHeight();
    }
}

Code-Quelle: https://Gist.github.com/chathudan/61fd2f6e5919738d7821

5
Mykhailo

Ich habe mit ein paar Einstellwerten für die Größenänderung gespielt, die Sie an Ihre App anpassen können. Ich habe dieses Aussehen allein mit XML erzielt.

Die Bilder sind ein Gammy, ich schneide sie aus Originalbild. Ich habe das Constraint-Layout und ein relatives Layout verwendet. Der Text reagiert auf Größenänderung und Drehung.

Eine vertikale Ansicht

 enter image description here

Eine horizontale Ansicht

 enter image description here

Kleiner Text

 enter image description here

Großer Text

 enter image description here

Natürlich spielen Sie mit der Dimensionierung nach Ihren Bedürfnissen.

    <?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="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context="com.yvettecolomb.myapplication.MainActivity"
    tools:showIn="@layout/activity_main">


    <RelativeLayout
        xmlns:Android="http://schemas.Android.com/apk/res/Android"
        Android:id="@+id/ll1"
        Android:layout_width="match_parent"
        Android:layout_height="wrap_content"
        Android:layout_centerHorizontal="true"
        Android:layout_marginLeft="0dp"
        Android:layout_marginRight="0dp"
        Android:layout_marginTop="10dp"
        Android:padding="0dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent">

        <TextView
            Android:id="@+id/tv1"
            Android:layout_width="wrap_content"
            Android:layout_height="wrap_content"
            Android:layout_centerHorizontal="true"
            Android:layout_marginTop="10dp"
            Android:autoSizeTextType="uniform"
            Android:gravity="center"
            Android:padding="2dp"
            Android:text="TEST"/>

        <ImageView
            Android:id="@+id/image1"
            Android:layout_width="wrap_content"
            Android:layout_height="30dp"
            Android:layout_margin="-10dp"
            Android:layout_toLeftOf="@+id/tv1"
            Android:src="@drawable/a"/>

        <ImageView
            Android:id="@+id/image2"
            Android:layout_width="wrap_content"
            Android:layout_height="30dp"
            Android:layout_toRightOf="@+id/tv1"
            Android:src="@drawable/b"/>


        <ImageView
            Android:id="@+id/image3"
            Android:layout_width="wrap_content"
            Android:layout_height="30dp"
            Android:layout_below="@+id/tv1"
            Android:layout_margin="-10dp"
            Android:layout_toLeftOf="@+id/tv2"
            Android:src="@drawable/c"/>

        <TextView
            Android:id="@+id/tv2"
            Android:layout_width="wrap_content"
            Android:layout_height="wrap_content"
            Android:layout_below="@+id/tv1"
            Android:layout_centerHorizontal="true"
            Android:layout_marginTop="10dp"
            Android:autoSizeTextType="uniform"
            Android:gravity="center"
            Android:padding="2dp"
            Android:text="test test test test test"/>

        <ImageView
            Android:id="@+id/image4"
            Android:layout_width="wrap_content"
            Android:layout_height="30dp"
            Android:layout_below="@+id/tv1"
            Android:layout_toRightOf="@+id/tv2"
            Android:src="@drawable/d"/>
    </RelativeLayout>


</Android.support.constraint.ConstraintLayout>
2
Yvette Colomb

Verwenden Sie AppCompatTextView. Ändern Sie die Werte für autoSizeMaxTextSize, autoSizeMinTextSize und autoSizeStepGranularity.

                    <RelativeLayout
                    xmlns:app="http://schemas.Android.com/apk/res-auto"
                    Android:id="@+id/rl_flashcard_back"
                    Android:layout_width="match_parent"
                    Android:layout_height="match_parent"
                    Android:orientation="vertical">

                    <Android.support.v7.widget.AppCompatTextView
                        Android:id="@+id/tv_text"
                        Android:layout_width="match_parent"
                        Android:layout_height="match_parent"
                        Android:layout_centerInParent="true"
                        Android:gravity="center"
                        app:autoSizeMaxTextSize="16sp"
                        app:autoSizeMinTextSize="8sp"
                        app:autoSizeStepGranularity="1sp"
                        app:autoSizeTextType="uniform"
                        />

Android.support.v7.widget.AppCompatTextView tv_text = mRootView.findViewById(R.id.tv_text);

https://developer.Android.com/guide/topics/ui/look-and-feel/autosizing-textview

0
live-love