在textView中,如何适应DrawableLeft的高度(android)

32

我想在一块文本旁边显示一条蓝色的线,就像这样:

enter image description here

这是我的代码:

<TextView
            android:id="@+id/textView1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:drawableLeft="@drawable/blue_line" />

blue_line是一个jpg文件,里面有一个蓝色的矩形。它在TextView中显示时始终保持其原始大小。我该如何根据文本高度动态调整它的高度?比如当文本很少时使其变短,而当文本较多时使其变长....


1
使用QuoteSpan或LeadingMarginSpan之一 - pskink
我尝试了QuoteSpan,它看起来很棒,但有没有办法增加行的宽度?还有如何使用LeadingMarginSpan? - user1659274
我认为这可能是一个准确的解决方法:https://dev59.com/sG035IYBdhLWcg3wVud1#59934868 - navid
9个回答

32

您可以通过为图像设置边界来在代码中尝试实现此操作。

textView1.getViewTreeObserver()
        .addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            Drawable img = ActivityName.this.getContext().getResources().getDrawable(
                R.drawable.blue_line);
            img.setBounds(0, 0, img.getIntrinsicWidth() * textView1.getMeasuredHeight() / img.getIntrinsicHeight(), textView1.getMeasuredHeight());
            textView1.setCompoundDrawables(img, null, null, null);
            textView1.getViewTreeObserver().removeOnGlobalLayoutListener(this);
        }
    });

在我的情况下,此视图的父容器在创建时为View.GONE。这会导致getMeasuredHeight() == 0并且图像也变为零大小。我已经通过在两种情况下使用textView1.getLineHeight()而不是textView1.getMeasuredHeight()来解决了这个问题。 - Mikhail Sharin
为什么第一次设置图像作为compundDrawable时,必须在“onGlobalLayout”中完成,而不能只在“onCreate”中完成? - Elad Benda
1
@EladBenda 这需要在OnGlobalLayoutListener中完成,因为当视图被绘制时会调用它,只有当视图被绘制时才能获得正确的高度和宽度。在onCreate方法中,视图尚未绘制,因此您将得到高度和宽度为0。 - Hitesh Bisht

8
最好的方法是将您的可绘制对象包装在一个XML可绘制文件中,并将其设置为文本视图中的可绘制对象,如下所示:
可绘制XML文件:
<?xml version="1.0" encoding="utf-8"?>
<bitmap 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:scaleType="fitXY"
    android:src="@drawable/total_calories"/>

XML中的TextView:

<TextView 
    android:id="@+id/title_total_cal"
    style="@style/title_stats_textview"
    android:drawableLeft="@drawable/total_calories_drawable"/>

13
你测试过这个了吗?对我没用(虽然应用在按钮上)。图片仍然被裁剪。 - hcpl
在一个新的问题中发布您的XML。 - Droid Chris
也许你需要检查一下你的主题是否有限制。这个问题大约在4年前就已经得到了解答,所以很多东西都发生了变化。此外,按钮可能需要不同的XML覆盖来处理不同的按压状态。 - Droid Chris
@ Shan Xeeshi,你试过什么了吗? - Droid Chris
请记住,在位图 XML 中不要使用另一个 XML drawable 作为源 drawable。要使用此解决方案,您应该使用 PNG 或 JPG drawable。 - YUSMLE

4
请尝试以下操作...
<RelativeLayout
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" >

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:src="@drawable/btndr" />

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@+id/imageView" />

</RelativeLayout>

2

不幸的是,setBounds 对我来说无法工作,所以我不得不使用一种变通方法。

// Turn wanted drawable to bitmap
Drawable dr = getResources().getDrawable(R.drawable.somedrawable);
Bitmap bitmap = ((BitmapDrawable) dr).getBitmap();

// I had a square image with same height and width so I needed only TextView height (getLineHeight)
int size = textView1.getLineHeight();
Drawable d = new BitmapDrawable(getResources(), Bitmap.createScaledBitmap(bitmap, size, size, true));
textView1.setCompoundDrawables(d, null, null, null);

// Now we can set some spacing between text and image
textView1.setCompoundDrawablePadding(10);

这不是性能最佳的解决方案,因为会创建新的位图,但仍然有效。


2

简单来说,将您的图像保留为9patch drawable。

您可以将android:drawableLeft="@drawable/checkmark"添加到您的textview中。您还可以设置drawablePadding以使textview整洁有序。

android:drawableLeft="@drawable/button_icon"
android:drawablePadding="2dip"

这是创建9patch可绘制对象的链接。

<TextView android:text="@string/txtUserName" 
android:id="@+id/txtUserName"
android:layout_width="160dip"
android:layout_height="60dip"
android:layout_gravity="center"
android:drawableLeft="@drawable/button_icon"
android:drawablePadding="2dip"
/>  

尝试设置普通的可绘制对象,如果它被拉伸或挤压,请使用9patch。@Tekno Freek。 - Rethinavel

1
你可以在可绘制的画布上绘制一条具有所需高度的线,并将其设置为TextView的左侧绘制项。看看这个例子:
public class FullHeightLineDrawable extends Drawable {
    private Paint mPaint;
    private int mHeight;

    public FullHeightLineDrawable(int height) {
        mPaint = new Paint();
        mPaint.setColor(CompatUtils.getColor(R.color.colorAccent));
        mPaint.setAntiAlias(true);
        mPaint.setStrokeWidth(15);

        mHeight = height;
    }

    @Override
    public void draw(Canvas canvas) {
        canvas.drawLine(0, -mHeight, 0, mHeight, mPaint);
    }

    @Override
    public void setAlpha(int alpha) {
    }

    @Override
    public void setColorFilter(ColorFilter colorFilter) {
    }

    @Override
    public int getOpacity() {
        return 0;
    }
}

使用方法:

final Drawable drawable = new FullHeightLineDrawable(getHeight());
mTextView.setTextColor(watchingColor);
mTextView.setCompoundDrawablesWithIntrinsicBounds(drawable, null, null, null);

0
我创建了一个继承自TextView的类,并在onPreDrawListener中调整可绘制对象的大小。
public class MyTextView extends AppCompatTextView {

    public MyTextView(Context context, AttributeSet attrs, int style) {
        super(context, attrs, style);
        fitCompoundDrawableToLineHeight();
    }

    private void fitCompoundDrawableToLineHeight() {
        OnPreDraw.run(this, () -> {
            final Drawable[] cd = getCompoundDrawables();
            Arrays.stream(cd)
                .filter(drawable -> drawable != null)
                .forEach(d -> d.setBounds(0, 0, getLineHeight(), getLineHeight()));
            setCompoundDrawables(cd[0], cd[1], cd[2], cd[3]);
        });
    }
}

// Convenience class that abstracts onPreDraw logic
public class OnPreDraw {
    public static void run(View view, Runnable task) {
        view.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
            @Override
            public boolean onPreDraw() {
                if (!view.getViewTreeObserver().isAlive()) {
                    return true;
                }
                view.getViewTreeObserver().removeOnPreDrawListener(this);
                task.run();
                return true;
            }
        });
    }
}

0

我将这个方法抽象出来。当可绘制对象位于TextView的左侧并进行动态缩放时,它可以正常工作。如果可绘制对象位于右侧,则此方法无法正常工作,需要找出原因。但是您可以直接使用textView.setcompounddrawableswithintrinsicbounds()方法,并提供正确大小的Drawable资源。

@RequiresApi(api = Build.VERSION_CODES.HONEYCOMB)
public static void ajustCompoundDrawableSizeWithText(final TextView textView, final Drawable leftDrawable, final Drawable topDrawable, final Drawable rightDrawable, final Drawable bottomDrawable) {
    textView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
        @Override
        public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
           if(leftDrawable != null){
               leftDrawable.setBounds(0, 0, (int)textView.getTextSize(), (int)textView.getTextSize());
           }
            if(topDrawable != null){
                topDrawable.setBounds(0, 0, (int)textView.getTextSize(), (int)textView.getTextSize());
            }
            if(rightDrawable != null){
                rightDrawable.setBounds(0, 0, (int)textView.getTextSize(), (int)textView.getTextSize());
            }
            if(bottomDrawable != null){
                bottomDrawable.setBounds(0, 0, (int)textView.getTextSize(), (int)textView.getTextSize());
            }
            textView.setCompoundDrawables(leftDrawable, topDrawable, rightDrawable, bottomDrawable);
                textView.removeOnLayoutChangeListener(this);
        }
    });
}

-1

您需要创建一个水平的XML布局,左侧有蓝色线条,右侧有TextView文本框。然后将该布局用作项,并创建一个包含这些项的ListView列表。类似于here,但更简单一些。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接