
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.

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:

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

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;
}
}
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.

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

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:


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.
10015600cookie-checkWie man Text so anordnet, dass er um ein Bild herum fließtyes
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