web-dev-qa-db-fra.com

Obtenir la hauteur de la vue du texte avant de rendre la mise en page

Impossible de trouver une bonne solution calculer la hauteur de la vue texte où le texte a été placé avant de rendre textview à la mise en page. Toute aide s'il vous plaît

38
support_ms

2 solutions

Utilisé la solution 1 au début et trouvé la solution 2 plus tard Les deux fonctionnent, c'est vraiment ce que vous préférez. 

Il est important de s’assurer que toutes les dimensions sont correctes, car le mélange des tailles de police dans sp ou px donnera une différence considérable en fonction de l’écran que vous testez. 

Un exemple de projet très basique est disponible sur https://github.com/hanscappelle/SO-3654321

Solution 1 en utilisant TextView et MeasureSpec

Le problème principal avec la question initiale est TextView dans la méthode ci-dessous doit être configuré comme notre TextView qui doit être rendu à la mise en page. Je pense que cette solution est précieuse pour de nombreuses personnes confrontées à ce problème.

public static int getHeight(Context context, CharSequence text, int textSize, int deviceWidth, Typeface typeface,int padding) {
            TextView textView = new TextView(context);
            textView.setPadding(padding,0,padding,padding);
            textView.setTypeface(typeface);
            textView.setText(text, TextView.BufferType.SPANNABLE);
            textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, textSize);
            int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(deviceWidth, View.MeasureSpec.AT_MOST);
            int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
            textView.measure(widthMeasureSpec, heightMeasureSpec);
            return textView.getMeasuredHeight();
        }

Et un exemple d'utilisation:

// retrieve deviceWidth
int deviceWidth;
WindowManager wm = (WindowManager) textView.getContext().getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
if(Android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2){
    Point size = new Point();
    display.getSize(size);
    deviceWidth = size.x;
} else {
    deviceWidth = display.getWidth();
}
// the text to check for
String exampleTextToMeasure = "some example text that will be long enough to make this example split over multiple lines so we can't easily predict the final height";
//  some dimensions from dimes resources to take into account
int textSize = getContext().getResources().getDimensionPixelSize(R.dimen.text_size);
int padding = getContext().getResources().getDimensionPixelSize(R.dimen.text_padding);

// final calculation of textView height
int measuredTextHeight = getHeight(getContext(), exampleTextToMeasure, textSize, deviceWidth, TypeFace.DEFAULT, padding); 

Solution 2 utilisant TextPaint et StaticLayout

Cette méthode repose sur TextPaint et StaticLayout, qui donnent également des résultats fiables sur tous les niveaux d'API que j'ai testés jusqu'à présent. Portez une attention particulière aux unités de dimensions; tout devrait être en pixels!

Source: Mesure de la hauteur du texte à dessiner sur Canvas (Android)

    public static int method1UsingTextPaintAndStaticLayout(
            final CharSequence text,
            final int textSize, // in pixels
            final int deviceWidth, // in pixels
            final int padding // in pixels
    ) {

        TextPaint myTextPaint = new TextPaint();
        myTextPaint.setAntiAlias(true);
        // this is how you would convert sp to pixels based on screen density
        //myTextPaint.setTextSize(16 * context.getResources().getDisplayMetrics().density);
        myTextPaint.setTextSize(textSize);
        Layout.Alignment alignment = Layout.Alignment.ALIGN_NORMAL;
        float spacingMultiplier = 1;
        float spacingAddition = padding; // optionally apply padding here
        boolean includePadding = padding != 0;
        StaticLayout myStaticLayout = new StaticLayout(text, myTextPaint, deviceWidth, alignment, spacingMultiplier, spacingAddition, includePadding);
        return myStaticLayout.getHeight();
    }
63
support_ms

De support_ms answer, il existe une méthode plus simple qui prend uniquement un TextView comme paramètre.

/**
 * Get the TextView height before the TextView will render
 * @param textView the TextView to measure
 * @return the height of the textView
 */
public static int getTextViewHeight(TextView textView) {
    WindowManager wm =
            (WindowManager) textView.getContext().getSystemService(Context.WINDOW_SERVICE);
    Display display = wm.getDefaultDisplay();

    int deviceWidth;

    if(Android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2){
        Point size = new Point();
        display.getSize(size);
        deviceWidth = size.x;
    } else {
        deviceWidth = display.getWidth();
    }

    int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(deviceWidth, View.MeasureSpec.AT_MOST);
    int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
    textView.measure(widthMeasureSpec, heightMeasureSpec);
    return textView.getMeasuredHeight();
}
11
Hugo Gresse

Bonne réponse de @support_ms, mais je ne suis pas sûr de l'intérêt de créer un nouveau TextView et de travailler avec tous ces paramètres d'entrée alors que vous pouviez simplement formater votre TextView d'abord, puis appeler la méthode statique avec un seul paramètre, le TextView lui-même. !

De plus, je ne suis pas sûr de savoir pourquoi un paramètre a été étiqueté deviceWidth. J'utilise simplement la largeur de la Textview elle-même. Le mien était match_parent et je suppose que toute TextView avec wrap_content peut ne pas fonctionner du tout. Mais c'est ce que vous obtenez.

public static int getHeight(TextView t) {
    int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(screenWidth(t.getContext()), View.MeasureSpec.AT_MOST);
    int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
    t.measure(widthMeasureSpec, heightMeasureSpec);
    return t.getMeasuredHeight();
}

public static int screenWidth(Context context)
{
    WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
    Display display = wm.getDefaultDisplay();
    return display.getWidth();
}
4
Andrew Gallasch

Voici ma solution facile sa obtenir la taille avant d'être peint

https://stackoverflow.com/a/40133275/1240672

0
jfcogato

Obtenir une ligne de TextView avant le rendu

Ceci est ma base de code sur l'idée ci-dessus. Cela fonctionne pour moi.

private int widthMeasureSpec;
private int heightMeasureSpec;
private int heightOfEachLine;
private int paddingFirstLine;
private void calculateHeightOfEachLine() {
    WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
    Display display = wm.getDefaultDisplay();
    Point size = new Point();
    display.getSize(size);
    int deviceWidth = size.x;
    widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(deviceWidth, View.MeasureSpec.AT_MOST);
    heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
    //1 line = 76; 2 lines = 76 + 66; 3 lines = 76 + 66 + 66
    //=> height of first line = 76 pixel; height of second line = third line =... n line = 66 pixel
    int heightOfFirstLine = getHeightOfTextView("A");
    int heightOfSecondLine = getHeightOfTextView("A\nA") - heightOfFirstLine;
    paddingFirstLine = heightOfFirstLine - heightOfSecondLine;
    heightOfEachLine = heightOfSecondLine;
}

private int getHeightOfTextView(String text) {
    // Getting height of text view before rendering to layout
    TextView textView = new TextView(context);
    textView.setPadding(10, 0, 10, 0);
    //textView.setTypeface(typeface);
    textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, context.getResources().getDimension(R.dimen.tv_size_14sp));
    textView.setText(text, TextView.BufferType.SPANNABLE);
    textView.measure(widthMeasureSpec, heightMeasureSpec);
    return textView.getMeasuredHeight();
}

private int getLineCountOfTextViewBeforeRendering(String text) {
    return (getHeightOfTextView(text) - paddingFirstLine) / heightOfEachLine;
}

Remarque: Ce code doit également être défini pour l'affichage de texte réel à l'écran.

textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, context.getResources().getDimension(R.dimen.tv_size_14sp));
0
Anh Duy