请告诉我是否有布局文字的方法 在图像周围? 像这样:
------ text text text
| | text text text
----- text text text
text text text text
text text text text
我从Android开发者那里得到了关于这个问题的回复。但我不确定通过自己的TextView版本意味着什么?感谢任何提示。
2010年2月8日星期一晚上11:05,Romain Guy写道:
您好,
仅使用提供的小部件和布局无法实现。您 可以写你自己的TextView版本来做到这一点,它不应该 硬。
答案 0 :(得分:64)
现在有可能,但仅适用于版本高于或等于2.2的手机,使用API 8中提供的android.text.style.LeadingMarginSpan.LeadingMarginSpan2
界面。
以下是article,但不是英文版,但您可以直接从here下载示例的源代码。
如果要使应用程序与旧设备兼容,则可以显示不带浮动文本的其他布局。 这是一个例子:
布局(旧版本的默认设置,将针对较新版本以编程方式更改)
<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="@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>
助手类
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;
}
}
MyLeadingMarginSpan2类(已更新为支持API 21)
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;
}
}
用法示例
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);
这是应用程序在Android 2.2设备上的外观:
这适用于Android 2.1设备:
答案 1 :(得分:6)
这是FlowTextHelper的改进(来自vorrtex的回复)。 我添加了在文本和图像之间添加额外填充的可能性,并改进了行计算以考虑填充。 享受!
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;
}
}
答案 2 :(得分:5)
现在您可以使用库:https://github.com/deano2390/FlowTextView。像这样:
<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="@drawable/android"/>
</uk.co.deanwild.flowtextview.FlowTextView>
答案 3 :(得分:3)
这个问题似乎与我的问题How to fill the empty spaces with content below the Image in android
相同我找到了使用flowtext库的解决方案,请找到它可能对你有帮助的第一个答案
答案 4 :(得分:3)
ss.setSpan(new MyLeadingMarginSpan2(lines, width), 0, ss.length(), 0);
到
ss.setSpan(new MyLeadingMarginSpan2(lines, width), 0, lines, 0);
在图像后停止了跨度。可能在所有情况下都没有必要,但我想我会分享。
答案 5 :(得分:1)
“但我不确定通过自己的TextView版本意味着什么?”
他的意思是你可以扩展类android.widget.TextView(或Canvas或其他一些可渲染表面)并实现你自己的覆盖版本,它允许嵌入图像并在其周围流动文本。
这可能是相当多的工作,取决于你做多少一般。
答案 6 :(得分:0)
我可以提供更舒适的构造函数 MyLeadingMarginSpan2类
MyLeadingMarginSpan2(Context cc,int textSize,int height,int width) {
int pixelsInLine=(int) (textSize*cc.getResources().getDisplayMetrics().scaledDensity);
if (pixelsInLine>0 && height>0) {
this.lines=height/pixelsInLine;
} else {
this.lines=0;
}
this.margin=width;
}
答案 7 :(得分:0)
vorrtex的答案对我不起作用,但是我从中得到了很多,并提出了自己的解决方案。在这里:
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) {
}
}
在我使用跨度的实际课程中:
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);
}
});
我需要全局布局侦听器,以便为getWidth()
和getHeight()
获得正确的值。
这是结果:
答案 8 :(得分:0)
尝试使用kotlin和androidx这个简单的实现。 首先,创建领先的跨度帮助器类:
class LeadingSpan(private val line: Int, private val margin: Int) : LeadingMarginSpan.LeadingMarginSpan2 {
override fun drawLeadingMargin(canvas: Canvas?, paint: Paint?, x: Int, dir: Int, top: Int, baseline: Int, bottom: Int, text: CharSequence?, start: Int, end: Int, first: Boolean, layout: Layout?) {}
override fun getLeadingMargin(first: Boolean): Int = if (first) margin else 0
override fun getLeadingMarginLineCount(): Int = line
}
然后使用RelativeLayout
创建布局:
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/about_desc"
android:text="@string/about_desc"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/logo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</RelativeLayout>
最后像下面这样在activity
或fragment
中进行设置:
val about = view.findViewById<TextView>(R.id.about_desc)
val logoImage = ContextCompat.getDrawable(view.context, R.mipmap.ic_launcher) as Drawable
@Suppress("DEPRECATION")
view.findViewById<AppCompatImageView>(R.id.logo).setBackgroundDrawable(logoImage)
val spannableString = SpannableString(about.text)
spannableString.setSpan(Helpers.LeadingSpan(5, logoImage.intrinsicWidth + 10), 0, spannableString.length, 0)
about.text = spannableString
根据您的可绘制高度更改Helpers.LeadingSpan(5, logoImage.intrinsicWidth + 10)
中的数字5。