Wie man Text so anordnet, dass er um ein Bild herum fließt

Lesezeit: 9 Minuten

Wie man Text so anordnet dass er um ein Bild
Silberburg

Können Sie mir bitte sagen, ob es eine Möglichkeit gibt, Text um ein Bild herum anzuordnen? So was:

------  text text text
|    |  text text text
-----   text text text
text text text text
text text text text

Ich habe eine Antwort von einem Android-Entwickler zu dieser Frage erhalten. Aber ich bin mir nicht sicher, was er damit meint, meine eigene Version von TextView zu machen? Danke für jeden Tipp.

Am Montag, 8. Februar 2010 um 23:05 Uhr schrieb Romain Guy:

Hallo,

Mit den mitgelieferten Widgets und Layouts ist dies nicht möglich. Sie könnten Ihre eigene Version von TextView schreiben, um dies zu tun, es sollte nicht schwer sein.

  • silverburgh: hast du dafür eine lösung gefunden, die du teilen könntest?

    – znq

    5. März 2010 um 11:05 Uhr

  • stackoverflow.com/questions/13526949/… ist wahrscheinlich die Lösung

    – Viktor

    28. November 2012 um 5:02 Uhr

  • Das geht ganz einfach im Web. Ich werde diese Funktion vorerst überspringen.

    – danny117

    29. September 2014 um 3:40 Uhr

  • Sie können verwenden ImageSpan. Schauen Sie sich diesen Link an

    – Treffen Sie Vora

    13. Dezember 2016 um 13:35 Uhr

1647261187 578 Wie man Text so anordnet dass er um ein Bild
Wirbelwolf

Jetzt ist es möglich, aber nur für Telefone mit Version höher oder gleich 2.2, indem Sie die verwenden android.text.style.LeadingMarginSpan.LeadingMarginSpan2 Schnittstelle, die in API 8 verfügbar ist.

Hier ist das Artikelallerdings nicht in Englisch, aber Sie können den Quellcode des Beispiels direkt von herunterladen Hier.

Wenn Sie Ihre Anwendung mit älteren Geräten kompatibel machen möchten, können Sie ein anderes Layout ohne Fließtext anzeigen. Hier ist ein Beispiel:

Layout (Standard für ältere Versionen, wird programmgesteuert für neuere Versionen geändert)

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content">
    <ImageView 
            android:id="@+id/thumbnail_view"
            android:src="https://stackoverflow.com/questions/2248759/@drawable/icon"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

    <TextView android:id="@+id/message_view"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_toRightOf="@id/thumbnail_view"
            android:textSize="18sp"
            android:text="@string/text" />
</RelativeLayout>

Die Helferklasse

class FlowTextHelper {

    private static boolean mNewClassAvailable;

    static {
        if (Integer.parseInt(Build.VERSION.SDK) >= 8) { // Froyo 2.2, API level 8
           mNewClassAvailable = true;
        }
    }

    public static void tryFlowText(String text, View thumbnailView, TextView messageView, Display display){
        // There is nothing I can do for older versions, so just return
        if(!mNewClassAvailable) return;

        // Get height and width of the image and height of the text line
        thumbnailView.measure(display.getWidth(), display.getHeight());
        int height = thumbnailView.getMeasuredHeight();
        int width = thumbnailView.getMeasuredWidth();
        float textLineHeight = messageView.getPaint().getTextSize();

        // Set the span according to the number of lines and width of the image
        int lines = (int)FloatMath.ceil(height / textLineHeight);
        //For an html text you can use this line: SpannableStringBuilder ss = (SpannableStringBuilder)Html.fromHtml(text);
        SpannableString ss = new SpannableString(text);
        ss.setSpan(new MyLeadingMarginSpan2(lines, width), 0, ss.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        messageView.setText(ss);

        // Align the text with the image by removing the rule that the text is to the right of the image
        RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams)messageView.getLayoutParams();
        int[]rules = params.getRules();
        rules[RelativeLayout.RIGHT_OF] = 0;
    }
}

Die MyLeadingMarginSpan2-Klasse (aktualisiert, um API 21 zu unterstützen)

public class MyLeadingMarginSpan2 implements LeadingMarginSpan2 {
    private int margin;
    private int lines;
    private boolean wasDrawCalled = false;
    private int drawLineCount = 0;

    public MyLeadingMarginSpan2(int lines, int margin) {
        this.margin = margin;
        this.lines = lines;
    }

    @Override
    public int getLeadingMargin(boolean first) {
        boolean isFirstMargin = first;
        // a different algorithm for api 21+
        if (Build.VERSION.SDK_INT >= 21) {
            this.drawLineCount = this.wasDrawCalled ? this.drawLineCount + 1 : 0;
            this.wasDrawCalled = false;
            isFirstMargin = this.drawLineCount <= this.lines;
        }

        return isFirstMargin ? this.margin : 0;
    }

    @Override
    public void drawLeadingMargin(Canvas c, Paint p, int x, int dir, int top, int baseline, int bottom, CharSequence text, int start, int end, boolean first, Layout layout) {
        this.wasDrawCalled = true;
    }

    @Override
    public int getLeadingMarginLineCount() {
        return this.lines;
    }
}

Beispiel für die Verwendung

ImageView thumbnailView = (ImageView) findViewById(R.id.thumbnail_view);
TextView messageView = (TextView) findViewById(R.id.message_view);
String text = getString(R.string.text);

Display display = getWindowManager().getDefaultDisplay();
FlowTextHelper.tryFlowText(text, thumbnailView, messageView, display);

So sieht die Anwendung auf dem Android 2.2-Gerät aus:
Bei Android 2.2 fließt der Text um das Bild herum

Und das ist für das Android 2.1-Gerät:

Android 2.1 Der Text befindet sich neben dem Bild

  • Anstelle des Class.forName-Tricks könnten Sie eine einfache Bedingung verwenden: if (Build.VERSION.SDK_INT < Build.VERSION_CODES.FROYO) {...

    – Wojciech Gorski

    30. August 2012 um 15:29 Uhr

  • Ich verwende dies auch. Aber wenn Daten mit HTML-Tags nicht für Html.fromHtml (HTML-Inhalt) unterstützt werden, helfen Sie mir bitte, ich muss eine Liste mit WrapText-Adapter wie oben anzeigen

    – Harscha

    27. November 2014 um 11:13 Uhr

  • @Harsha Die Methode Html.fromHtml funktioniert nicht mit HTML, es unterstützt nur einfaches HTML mit wenigen Tags.

    – Wirbelwolf

    14. Dezember 2014 um 7:39 Uhr

  • Großartige Arbeit, ich habe fast meinen Tag verschwendet … Tausend Dank!!

    – Palak Darji

    12. März 2015 um 10:13 Uhr

  • Dies fügt jedoch auch einen rechten Rand für die Zeilen nach dem Bild hinzu (so dass der Text nie ganz quer verläuft). Irgendeine Idee, wie man diesen Fehler beheben kann?

    – Parker

    1. April 2016 um 2:43 Uhr

Heutzutage können Sie die Bibliothek verwenden: https://github.com/deano2390/FlowTextView . So was:

<uk.co.deanwild.flowtextview.FlowTextView
    android:id="@+id/ftv"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content" >

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:layout_alignParentTop="true"
            android:padding="10dip"
            android:src="https://stackoverflow.com/questions/2248759/@drawable/android"/>
</uk.co.deanwild.flowtextview.FlowTextView>

Hier ist eine Verbesserung für den FlowTextHelper (aus der Antwort von vorrtex). Ich habe die Möglichkeit hinzugefügt, zusätzliche Auffüllung zwischen dem Text und dem Bild hinzuzufügen, und die Zeilenberechnung verbessert, um auch die Auffüllung zu berücksichtigen. Genießen!

public class FlowTextHelper {
   private static boolean mNewClassAvailable;

   /* class initialization fails when this throws an exception */
   static {
       try {
           Class.forName("android.text.style.LeadingMarginSpan$LeadingMarginSpan2");
           mNewClassAvailable = true;
       } catch (Exception ex) {
           mNewClassAvailable = false;
       }
   }

   public static void tryFlowText(String text, View thumbnailView, TextView messageView, Display display, int addPadding){
       // There is nothing I can do for older versions, so just return
       if(!mNewClassAvailable) return;



       // Get height and width of the image and height of the text line
        thumbnailView.measure(display.getWidth(), display.getHeight());
        int height = thumbnailView.getMeasuredHeight();
        int width = thumbnailView.getMeasuredWidth() + addPadding;
        messageView.measure(width, height); //to allow getTotalPaddingTop
        int padding = messageView.getTotalPaddingTop();
        float textLineHeight = messageView.getPaint().getTextSize();

        // Set the span according to the number of lines and width of the image
        int lines =  (int)Math.round((height - padding) / textLineHeight);
        SpannableString ss = new SpannableString(text);
        //For an html text you can use this line: SpannableStringBuilder ss = (SpannableStringBuilder)Html.fromHtml(text);
        ss.setSpan(new MyLeadingMarginSpan2(lines, width), 0, ss.length(), 0);
        messageView.setText(ss);

        // Align the text with the image by removing the rule that the text is to the right of the image
        RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams)messageView.getLayoutParams();
        int[]rules = params.getRules();
        rules[RelativeLayout.RIGHT_OF] = 0;
   }


}

  • Hallo Ronen. Ich habe große Probleme, die ganze Idee des Problems “Textumbruch um Bild” zu verstehen. Können Sie mir bitte sagen, wo ich Informationen zum Schreiben eines solchen Codes erhalten kann? Ich würde gerne lernen, wie man den Code selbst schreibt, anstatt ihn nur zu kopieren.

    – Ramona

    9. August 2017 um 14:31 Uhr


  • Hi @Ramona Vielleicht schau dir diese Bibliothek an: github.com/deano2390/FlowTextView

    – Ronen Yacobi

    29. August 2017 um 8:31 Uhr

  • Hallo, vielen Dank für Infos. Wissen Sie, wie Sie dies mit dem Bild auf der rechten Seite des Bildschirms erreichen können?

    – Ramona

    14. Oktober 2017 um 9:18 Uhr

  • @Ramona sieht aus, als suche ich auch nach der gleichen Lösung. In unserem Fall haben wir ein Bild auf der rechten Seite des Bildschirms. Sind Sie auf eine Lösung oder Hinweise gestoßen, die hilfreich sein könnten?

    – Chethan Shetty

    6. Oktober 2021 um 5:41 Uhr

Die Antworten von Vorrtex und Ronen funktionieren für mich bis auf ein Detail: Nachdem ich Text um das Bild gewickelt hatte, gab es einen seltsamen “negativen” Rand unter dem Bild und auf der gegenüberliegenden Seite. Ich habe herausgefunden, dass ich beim Festlegen der Spanne auf dem SpannableString geändert habe

ss.setSpan(new MyLeadingMarginSpan2(lines, width), 0, ss.length(), 0);

zu

ss.setSpan(new MyLeadingMarginSpan2(lines, width), 0, lines, 0);

was die Spannweite nach dem Bild stoppte. Vielleicht nicht in allen Fällen notwendig, aber ich dachte, ich würde es teilen.

Wie man Text so anordnet dass er um ein Bild
Sieger

Diese Frage scheint dieselbe zu sein wie meine Frage, wie man die leeren Räume mit Inhalt unter dem Bild in Android füllt

Ich habe die Lösung mit der Flowtext-Bibliothek gefunden. Bitte finden Sie die erste Antwort, die Ihnen bisher helfen könnte

1647261189 409 Wie man Text so anordnet dass er um ein Bild
Moses

Die Antwort von vorrtex hat bei mir nicht funktioniert, aber ich habe viel davon mitgenommen und mir eine eigene Lösung ausgedacht. Hier ist es:

package ie.moses.keepitlocal.util;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.support.annotation.IntRange;
import android.text.Layout;
import android.text.style.LeadingMarginSpan;
import android.view.View;
import android.widget.TextView;

import ie.moses.keepitlocal.util.MeasurementUtils;
import ie.moses.keepitlocal.util.TextUtils;

import static com.google.common.base.Preconditions.checkArgument;

public class WrapViewSpan implements LeadingMarginSpan.LeadingMarginSpan2 {

    private final Context _context;
    private final int _lineCount;
    private int _leadingMargin;
    private int _padding;

    public WrapViewSpan(View wrapeeView, TextView wrappingView) {
        this(wrapeeView, wrappingView, 0);
    }

    /**
     * @param padding Padding in DIP.
     */
    public WrapViewSpan(View wrapeeView, TextView wrappingView, @IntRange(from = 0) int padding) {
        _context = wrapeeView.getContext();
        setPadding(padding);

        int wrapeeHeight = wrapeeView.getHeight();
        float lineHeight = TextUtils.getLineHeight(wrappingView);

        int lineCnt = 0;
        float linesHeight = 0F;
        while ((linesHeight += lineHeight) <= wrapeeHeight) {
            lineCnt++;
        }

        _lineCount = lineCnt;
        _leadingMargin = wrapeeView.getWidth();
    }

    public void setPadding(@IntRange(from = 0) int paddingDp) {
        checkArgument(paddingDp >= 0, "padding cannot be negative");
        _padding = (int) MeasurementUtils.dpiToPixels(_context, paddingDp);
    }

    @Override
    public int getLeadingMarginLineCount() {
        return _lineCount;
    }

    @Override
    public int getLeadingMargin(boolean first) {
        if (first) {
            return _leadingMargin + _padding;
        } else {
            return _padding;
        }
    }

    @Override
    public void drawLeadingMargin(Canvas c, Paint p, int x, int dir, int top, int baseline,
                                  int bottom, CharSequence text, int start, int end,
                                  boolean first, Layout layout) {

    }

}

und in meiner aktuellen Klasse, in der die Spanne verwendet wird:

ViewTreeObserver headerViewTreeObserver = _headerView.getViewTreeObserver();
headerViewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
        String descriptionText = _descriptionView.getText().toString();
        SpannableString spannableDescriptionText = new SpannableString(descriptionText);
        LeadingMarginSpan wrapHeaderSpan = new WrapViewSpan(_headerView, _descriptionView, 12);
        spannableDescriptionText.setSpan(
                wrapHeaderSpan,
                0,
                spannableDescriptionText.length(),
                Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
        );
        _descriptionView.setText(spannableDescriptionText);
        ViewTreeObserver headerViewTreeObserver = _headerView.getViewTreeObserver();
        headerViewTreeObserver.removeOnGlobalLayoutListener(this);
    }
});

Ich brauchte den globalen Layout-Listener, um die richtigen Werte für zu bekommen getWidth() und getHeight().

Hier ist das Ergebnis:

Geben Sie hier die Bildbeschreibung ein

1647261190 835 Wie man Text so anordnet dass er um ein Bild
Peter vdl

“Aber ich bin mir nicht sicher, was er damit meint, meine eigene Version von TextView zu erstellen?”

Er meint, dass Sie die Klasse android.widget.TextView (oder Canvas oder eine andere darstellbare Oberfläche) erweitern und Ihre eigene überschreibende Version implementieren können, die eingebettete Bilder mit umfließendem Text zulässt.

Dies kann eine Menge Arbeit sein, je nachdem, wie allgemein Sie es machen.

1001560cookie-checkWie man Text so anordnet, dass er um ein Bild herum fließt

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy